Initial add of launchSettings.json support
This commit is contained in:
parent
c94fe61ba8
commit
0ba2e1feb4
6 changed files with 220 additions and 0 deletions
|
@ -0,0 +1,13 @@
|
||||||
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Tools.Run.LaunchSettings
|
||||||
|
{
|
||||||
|
public interface ILaunchSettingsProvider
|
||||||
|
{
|
||||||
|
string CommandName { get; }
|
||||||
|
|
||||||
|
bool TryApplySettings(JObject document, JObject model, ref ICommand command, out string runAfterLaunch);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Tools.Run.LaunchSettings
|
||||||
|
{
|
||||||
|
internal class LaunchSettingsManager
|
||||||
|
{
|
||||||
|
private const string ProfilesKey = "profiles";
|
||||||
|
private const string CommandNameKey = "commandName";
|
||||||
|
private const string DefaultProfileCommandName = "Project";
|
||||||
|
private static IReadOnlyDictionary<string, ILaunchSettingsProvider> _providers;
|
||||||
|
|
||||||
|
static LaunchSettingsManager()
|
||||||
|
{
|
||||||
|
_providers = new Dictionary<string, ILaunchSettingsProvider>
|
||||||
|
{
|
||||||
|
{ ProjectLaunchSettingsProvider.CommandNameValue, new ProjectLaunchSettingsProvider() }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryApplyLaunchSettings(string launchSettingsJsonContents, ref ICommand command, out string runAfterLaunch, string profileName = null)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var model = JObject.Parse(launchSettingsJsonContents);
|
||||||
|
var profilesObject = model[ProfilesKey] as JObject;
|
||||||
|
|
||||||
|
if (profilesObject == null)
|
||||||
|
{
|
||||||
|
runAfterLaunch = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
JObject profileObject;
|
||||||
|
if (profileName == null)
|
||||||
|
{
|
||||||
|
profileObject = profilesObject
|
||||||
|
.Properties()
|
||||||
|
.FirstOrDefault(IsDefaultProfileType)?.Value as JObject;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
profileObject = profilesObject[profileName] as JObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (profileObject == null)
|
||||||
|
{
|
||||||
|
foreach (var prop in profilesObject.Properties())
|
||||||
|
{
|
||||||
|
var profile = prop.Value as JObject;
|
||||||
|
|
||||||
|
if (profile != null)
|
||||||
|
{
|
||||||
|
var cmdName = profile[CommandNameKey]?.Value<string>();
|
||||||
|
if (_providers.ContainsKey(cmdName))
|
||||||
|
{
|
||||||
|
profileObject = profile;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var commandName = profileObject?[CommandNameKey]?.Value<string>();
|
||||||
|
|
||||||
|
if (profileObject == null || !TryLocateHandler(commandName, out ILaunchSettingsProvider provider))
|
||||||
|
{
|
||||||
|
runAfterLaunch = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return provider.TryApplySettings(model, profileObject, ref command, out runAfterLaunch);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
runAfterLaunch = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool TryLocateHandler(string commandName, out ILaunchSettingsProvider provider)
|
||||||
|
{
|
||||||
|
return _providers.TryGetValue(commandName, out provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsDefaultProfileType(JProperty profileProperty)
|
||||||
|
{
|
||||||
|
JObject profile = profileProperty.Value as JObject;
|
||||||
|
var commandName = profile?[CommandNameKey]?.Value<string>();
|
||||||
|
return string.Equals(commandName, DefaultProfileCommandName, StringComparison.Ordinal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,57 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace Microsoft.DotNet.Tools.Run.LaunchSettings
|
||||||
|
{
|
||||||
|
public class ProjectLaunchSettingsProvider : ILaunchSettingsProvider
|
||||||
|
{
|
||||||
|
public static readonly string CommandNameValue = "Project";
|
||||||
|
|
||||||
|
public string CommandName => CommandNameValue;
|
||||||
|
|
||||||
|
public bool TryApplySettings(JObject document, JObject model, ref ICommand command, out string runAfterLaunch)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var config = model.ToObject<ProjectLaunchSettingsModel>();
|
||||||
|
|
||||||
|
//For now, ignore everything but the environment variables section
|
||||||
|
|
||||||
|
foreach (var entry in config.EnvironmentVariables)
|
||||||
|
{
|
||||||
|
string value = Environment.ExpandEnvironmentVariables(entry.Value);
|
||||||
|
//NOTE: MSBuild variables are not expanded like they are in VS
|
||||||
|
command.EnvironmentVariable(entry.Key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
runAfterLaunch = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
runAfterLaunch = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProjectLaunchSettingsModel
|
||||||
|
{
|
||||||
|
public ProjectLaunchSettingsModel()
|
||||||
|
{
|
||||||
|
EnvironmentVariables = new Dictionary<string, string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CommandLineArgs { get; set; }
|
||||||
|
|
||||||
|
public bool LaunchBrowser { get; set; }
|
||||||
|
|
||||||
|
public string LaunchUrl { get; set; }
|
||||||
|
|
||||||
|
public string ApplicationUrl { get; set; }
|
||||||
|
|
||||||
|
public Dictionary<string, string> EnvironmentVariables { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,10 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
|
|
||||||
public const string CommandOptionProjectDescription = "The path to the project file to run (defaults to the current directory if there is only one project).";
|
public const string CommandOptionProjectDescription = "The path to the project file to run (defaults to the current directory if there is only one project).";
|
||||||
|
|
||||||
|
public const string CommandOptionLaunchProfileDescription = "The name of the launch profile (if any) to use when launching the application.";
|
||||||
|
|
||||||
|
public const string CommandOptionNoLaunchProfileDescription = "Do not attempt to use launchSettings.json to configure the application.";
|
||||||
|
|
||||||
public const string RunCommandException = "The build failed. Please fix the build errors and run again.";
|
public const string RunCommandException = "The build failed. Please fix the build errors and run again.";
|
||||||
|
|
||||||
public const string RunCommandExceptionUnableToRunSpecifyFramework = "Unable to run your project\nYour project targets multiple frameworks. Please specify which framework to run using '{0}'.";
|
public const string RunCommandExceptionUnableToRunSpecifyFramework = "Unable to run your project\nYour project targets multiple frameworks. Please specify which framework to run using '{0}'.";
|
||||||
|
@ -28,5 +32,11 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
public const string RunCommandExceptionMultipleProjects = "Specify which project file to use because {0} contains more than one project file.";
|
public const string RunCommandExceptionMultipleProjects = "Specify which project file to use because {0} contains more than one project file.";
|
||||||
|
|
||||||
public const string RunCommandAdditionalArgsHelpText = "Arguments passed to the application that is being run.";
|
public const string RunCommandAdditionalArgsHelpText = "Arguments passed to the application that is being run.";
|
||||||
|
|
||||||
|
public const string RunCommandExceptionCouldNotLocateALaunchSettingsFile = "The specified launch profile could not be located.";
|
||||||
|
|
||||||
|
public const string RunCommandExceptionCouldNotApplyLaunchSettings = "The launch profile \"{0}\" could not be applied.";
|
||||||
|
|
||||||
|
public const string DefaultLaunchProfileDisplayName = "(Default)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ using System.Linq;
|
||||||
using Microsoft.Build.Evaluation;
|
using Microsoft.Build.Evaluation;
|
||||||
using Microsoft.DotNet.Cli.Utils;
|
using Microsoft.DotNet.Cli.Utils;
|
||||||
using Microsoft.DotNet.Tools.MSBuild;
|
using Microsoft.DotNet.Tools.MSBuild;
|
||||||
|
using Microsoft.DotNet.Tools.Run.LaunchSettings;
|
||||||
|
|
||||||
namespace Microsoft.DotNet.Tools.Run
|
namespace Microsoft.DotNet.Tools.Run
|
||||||
{
|
{
|
||||||
|
@ -22,6 +23,10 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
private List<string> _args;
|
private List<string> _args;
|
||||||
private bool ShouldBuild => !NoBuild;
|
private bool ShouldBuild => !NoBuild;
|
||||||
|
|
||||||
|
public string LaunchProfile { get; private set; }
|
||||||
|
public bool NoLaunchProfile { get; private set; }
|
||||||
|
|
||||||
|
|
||||||
public int Start()
|
public int Start()
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
|
@ -33,6 +38,27 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
|
|
||||||
ICommand runCommand = GetRunCommand();
|
ICommand runCommand = GetRunCommand();
|
||||||
|
|
||||||
|
if (!NoLaunchProfile)
|
||||||
|
{
|
||||||
|
var buildPathContainer = File.Exists(Project) ? Path.GetDirectoryName(Project) : Project;
|
||||||
|
var launchSettingsPath = Path.Combine(buildPathContainer, "Properties", "launchSettings.json");
|
||||||
|
if (File.Exists(launchSettingsPath))
|
||||||
|
{
|
||||||
|
var launchSettingsFileContents = File.ReadAllText(launchSettingsPath);
|
||||||
|
if (!LaunchSettingsManager.TryApplyLaunchSettings(launchSettingsFileContents, ref runCommand, out string runAfterLaunch, LaunchProfile))
|
||||||
|
{
|
||||||
|
string profileName = string.IsNullOrEmpty(LaunchProfile) ? LocalizableStrings.DefaultLaunchProfileDisplayName : LaunchProfile;
|
||||||
|
//Error that the launch profile couldn't be applied
|
||||||
|
Reporter.Error.WriteLine(string.Format(LocalizableStrings.RunCommandExceptionCouldNotApplyLaunchSettings, profileName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!string.IsNullOrEmpty(LaunchProfile))
|
||||||
|
{
|
||||||
|
//Error that the launch profile couldn't be found
|
||||||
|
Reporter.Error.WriteLine(LocalizableStrings.RunCommandExceptionCouldNotLocateALaunchSettingsFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return runCommand
|
return runCommand
|
||||||
.Execute()
|
.Execute()
|
||||||
.ExitCode;
|
.ExitCode;
|
||||||
|
@ -42,12 +68,16 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
string framework,
|
string framework,
|
||||||
bool noBuild,
|
bool noBuild,
|
||||||
string project,
|
string project,
|
||||||
|
string launchProfile,
|
||||||
|
bool noLaunchProfile,
|
||||||
IReadOnlyCollection<string> args)
|
IReadOnlyCollection<string> args)
|
||||||
{
|
{
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
Framework = framework;
|
Framework = framework;
|
||||||
NoBuild = noBuild;
|
NoBuild = noBuild;
|
||||||
Project = project;
|
Project = project;
|
||||||
|
LaunchProfile = launchProfile;
|
||||||
|
NoLaunchProfile = noLaunchProfile;
|
||||||
Args = args;
|
Args = args;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,6 +85,8 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
string framework = null,
|
string framework = null,
|
||||||
bool? noBuild = null,
|
bool? noBuild = null,
|
||||||
string project = null,
|
string project = null,
|
||||||
|
string launchProfile = null,
|
||||||
|
bool? noLaunchProfile = null,
|
||||||
IReadOnlyCollection<string> args = null)
|
IReadOnlyCollection<string> args = null)
|
||||||
{
|
{
|
||||||
return new RunCommand(
|
return new RunCommand(
|
||||||
|
@ -62,6 +94,8 @@ namespace Microsoft.DotNet.Tools.Run
|
||||||
framework ?? this.Framework,
|
framework ?? this.Framework,
|
||||||
noBuild ?? this.NoBuild,
|
noBuild ?? this.NoBuild,
|
||||||
project ?? this.Project,
|
project ?? this.Project,
|
||||||
|
launchProfile ?? this.LaunchProfile,
|
||||||
|
noLaunchProfile ?? this.NoLaunchProfile,
|
||||||
args ?? this.Args
|
args ?? this.Args
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace Microsoft.DotNet.Cli
|
||||||
framework: o.SingleArgumentOrDefault("--framework"),
|
framework: o.SingleArgumentOrDefault("--framework"),
|
||||||
noBuild: o.HasOption("--no-build"),
|
noBuild: o.HasOption("--no-build"),
|
||||||
project: o.SingleArgumentOrDefault("--project"),
|
project: o.SingleArgumentOrDefault("--project"),
|
||||||
|
launchProfile: o.SingleArgumentOrDefault("--launch-profile"),
|
||||||
|
noLaunchProfile: o.HasOption("--no-launch-profile"),
|
||||||
args: o.Arguments
|
args: o.Arguments
|
||||||
)),
|
)),
|
||||||
options: new[]
|
options: new[]
|
||||||
|
@ -32,6 +34,14 @@ namespace Microsoft.DotNet.Cli
|
||||||
"-p|--project",
|
"-p|--project",
|
||||||
LocalizableStrings.CommandOptionProjectDescription,
|
LocalizableStrings.CommandOptionProjectDescription,
|
||||||
Accept.ExactlyOneArgument()),
|
Accept.ExactlyOneArgument()),
|
||||||
|
Create.Option(
|
||||||
|
"--launch-profile",
|
||||||
|
LocalizableStrings.CommandOptionLaunchProfileDescription,
|
||||||
|
Accept.ExactlyOneArgument()),
|
||||||
|
Create.Option(
|
||||||
|
"--no-launch-profile",
|
||||||
|
LocalizableStrings.CommandOptionNoLaunchProfileDescription,
|
||||||
|
Accept.NoArguments()),
|
||||||
Create.Option(
|
Create.Option(
|
||||||
"--no-build",
|
"--no-build",
|
||||||
LocalizableStrings.CommandOptionNoBuildDescription,
|
LocalizableStrings.CommandOptionNoBuildDescription,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue