Initial add of launchSettings.json support

This commit is contained in:
Mike Lorbetske 2017-05-25 18:47:59 -07:00 committed by mlorbetske
parent c94fe61ba8
commit 0ba2e1feb4
6 changed files with 220 additions and 0 deletions

View file

@ -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);
}
}

View file

@ -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);
}
}
}

View file

@ -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; }
}
}
}

View file

@ -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)";
} }
} }

View file

@ -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
); );
} }

View file

@ -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,