2015-11-20 19:00:56 -08:00
|
|
|
|
// Copyright (c) .NET Foundation and contributors. All rights reserved.
|
|
|
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
|
|
|
|
|
|
using System;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.IO;
|
|
|
|
|
using System.Linq;
|
2017-03-21 13:46:08 -05:00
|
|
|
|
using Microsoft.Build.Evaluation;
|
2015-11-20 19:00:56 -08:00
|
|
|
|
using Microsoft.DotNet.Cli.Utils;
|
2017-06-01 21:25:06 -07:00
|
|
|
|
using Microsoft.DotNet.Tools;
|
2016-10-27 18:46:43 -07:00
|
|
|
|
using Microsoft.DotNet.Tools.MSBuild;
|
2017-05-25 18:47:59 -07:00
|
|
|
|
using Microsoft.DotNet.Tools.Run.LaunchSettings;
|
2015-11-20 19:00:56 -08:00
|
|
|
|
|
|
|
|
|
namespace Microsoft.DotNet.Tools.Run
|
|
|
|
|
{
|
2016-01-30 21:47:50 -08:00
|
|
|
|
public partial class RunCommand
|
2015-11-20 19:00:56 -08:00
|
|
|
|
{
|
2017-04-12 16:03:45 -07:00
|
|
|
|
public string Configuration { get; private set; }
|
|
|
|
|
public string Framework { get; private set; }
|
|
|
|
|
public bool NoBuild { get; private set; }
|
|
|
|
|
public string Project { get; private set; }
|
|
|
|
|
public IReadOnlyCollection<string> Args { get; private set; }
|
2017-06-01 21:25:06 -07:00
|
|
|
|
public bool NoRestore { get; private set; }
|
2017-06-02 23:32:53 -07:00
|
|
|
|
public IEnumerable<string> RestoreArgs { get; private set; }
|
2015-11-20 19:00:56 -08:00
|
|
|
|
|
2016-05-12 10:24:57 -05:00
|
|
|
|
private List<string> _args;
|
2017-03-21 13:46:08 -05:00
|
|
|
|
private bool ShouldBuild => !NoBuild;
|
2016-04-25 13:53:02 -07:00
|
|
|
|
|
2017-05-25 18:47:59 -07:00
|
|
|
|
public string LaunchProfile { get; private set; }
|
|
|
|
|
public bool NoLaunchProfile { get; private set; }
|
2017-05-30 22:30:14 -07:00
|
|
|
|
private bool UseLaunchProfile => !NoLaunchProfile;
|
2017-05-25 18:47:59 -07:00
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
public int Start()
|
2016-05-12 10:24:57 -05:00
|
|
|
|
{
|
2016-10-27 18:46:43 -07:00
|
|
|
|
Initialize();
|
|
|
|
|
|
2017-03-21 13:46:08 -05:00
|
|
|
|
if (ShouldBuild)
|
|
|
|
|
{
|
|
|
|
|
EnsureProjectIsBuilt();
|
|
|
|
|
}
|
2016-10-27 18:46:43 -07:00
|
|
|
|
|
|
|
|
|
ICommand runCommand = GetRunCommand();
|
2017-05-30 22:42:24 -07:00
|
|
|
|
int launchSettingsApplicationResult = ApplyLaunchProfileSettingsIfNeeded(ref runCommand);
|
|
|
|
|
|
|
|
|
|
if (launchSettingsApplicationResult != 0)
|
|
|
|
|
{
|
|
|
|
|
return launchSettingsApplicationResult;
|
|
|
|
|
}
|
2017-05-25 18:47:59 -07:00
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
return runCommand
|
|
|
|
|
.Execute()
|
|
|
|
|
.ExitCode;
|
2016-05-12 10:24:57 -05:00
|
|
|
|
}
|
2015-11-20 19:00:56 -08:00
|
|
|
|
|
2017-04-12 16:03:45 -07:00
|
|
|
|
public RunCommand(string configuration,
|
|
|
|
|
string framework,
|
|
|
|
|
bool noBuild,
|
|
|
|
|
string project,
|
2017-05-25 18:47:59 -07:00
|
|
|
|
string launchProfile,
|
|
|
|
|
bool noLaunchProfile,
|
2017-06-01 21:25:06 -07:00
|
|
|
|
bool noRestore,
|
2017-06-02 23:32:53 -07:00
|
|
|
|
IEnumerable<string> restoreArgs,
|
2017-04-12 16:03:45 -07:00
|
|
|
|
IReadOnlyCollection<string> args)
|
|
|
|
|
{
|
|
|
|
|
Configuration = configuration;
|
|
|
|
|
Framework = framework;
|
|
|
|
|
NoBuild = noBuild;
|
|
|
|
|
Project = project;
|
2017-05-25 18:47:59 -07:00
|
|
|
|
LaunchProfile = launchProfile;
|
|
|
|
|
NoLaunchProfile = noLaunchProfile;
|
2017-04-12 16:03:45 -07:00
|
|
|
|
Args = args;
|
2017-06-02 23:32:53 -07:00
|
|
|
|
RestoreArgs = restoreArgs;
|
2017-06-01 21:25:06 -07:00
|
|
|
|
NoRestore = noRestore;
|
2017-04-12 16:03:45 -07:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public RunCommand MakeNewWithReplaced(string configuration = null,
|
|
|
|
|
string framework = null,
|
|
|
|
|
bool? noBuild = null,
|
|
|
|
|
string project = null,
|
2017-05-25 18:47:59 -07:00
|
|
|
|
string launchProfile = null,
|
|
|
|
|
bool? noLaunchProfile = null,
|
2017-06-01 21:25:06 -07:00
|
|
|
|
bool? noRestore = null,
|
2017-06-02 23:32:53 -07:00
|
|
|
|
IEnumerable<string> restoreArgs = null,
|
2017-04-12 16:03:45 -07:00
|
|
|
|
IReadOnlyCollection<string> args = null)
|
|
|
|
|
{
|
|
|
|
|
return new RunCommand(
|
|
|
|
|
configuration ?? this.Configuration,
|
|
|
|
|
framework ?? this.Framework,
|
|
|
|
|
noBuild ?? this.NoBuild,
|
|
|
|
|
project ?? this.Project,
|
2017-05-25 18:47:59 -07:00
|
|
|
|
launchProfile ?? this.LaunchProfile,
|
|
|
|
|
noLaunchProfile ?? this.NoLaunchProfile,
|
2017-06-01 21:25:06 -07:00
|
|
|
|
noRestore ?? this.NoRestore,
|
2017-06-02 23:32:53 -07:00
|
|
|
|
restoreArgs ?? this.RestoreArgs,
|
2017-04-12 16:03:45 -07:00
|
|
|
|
args ?? this.Args
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-30 22:42:24 -07:00
|
|
|
|
private int ApplyLaunchProfileSettingsIfNeeded(ref ICommand runCommand)
|
2017-05-30 22:30:14 -07:00
|
|
|
|
{
|
|
|
|
|
if (UseLaunchProfile)
|
|
|
|
|
{
|
|
|
|
|
var buildPathContainer = File.Exists(Project) ? Path.GetDirectoryName(Project) : Project;
|
|
|
|
|
var launchSettingsPath = Path.Combine(buildPathContainer, "Properties", "launchSettings.json");
|
|
|
|
|
if (File.Exists(launchSettingsPath))
|
|
|
|
|
{
|
|
|
|
|
Reporter.Output.WriteLine(string.Format(LocalizableStrings.UsingLaunchSettingsFromMessage, launchSettingsPath));
|
|
|
|
|
string profileName = string.IsNullOrEmpty(LaunchProfile) ? LocalizableStrings.DefaultLaunchProfileDisplayName : LaunchProfile;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var launchSettingsFileContents = File.ReadAllText(launchSettingsPath);
|
|
|
|
|
var applyResult = LaunchSettingsManager.TryApplyLaunchSettings(launchSettingsFileContents, ref runCommand, LaunchProfile);
|
|
|
|
|
if (!applyResult.Success)
|
|
|
|
|
{
|
|
|
|
|
//Error that the launch profile couldn't be applied
|
|
|
|
|
Reporter.Error.WriteLine(string.Format(LocalizableStrings.RunCommandExceptionCouldNotApplyLaunchSettings, profileName, applyResult.FailureReason).Bold().Red());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (IOException ex)
|
|
|
|
|
{
|
|
|
|
|
Reporter.Error.WriteLine(string.Format(LocalizableStrings.RunCommandExceptionCouldNotApplyLaunchSettings, profileName).Bold().Red());
|
|
|
|
|
Reporter.Error.WriteLine(ex.Message.Bold().Red());
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (!string.IsNullOrEmpty(LaunchProfile))
|
|
|
|
|
{
|
|
|
|
|
//Error that the launch profile couldn't be found
|
|
|
|
|
Reporter.Error.WriteLine(LocalizableStrings.RunCommandExceptionCouldNotLocateALaunchSettingsFile.Bold().Red());
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-05-30 22:42:24 -07:00
|
|
|
|
|
|
|
|
|
return 0;
|
2017-05-30 22:30:14 -07:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
private void EnsureProjectIsBuilt()
|
2015-11-20 19:00:56 -08:00
|
|
|
|
{
|
2016-10-27 18:46:43 -07:00
|
|
|
|
List<string> buildArgs = new List<string>();
|
2017-03-21 13:46:08 -05:00
|
|
|
|
|
|
|
|
|
buildArgs.Add(Project);
|
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
buildArgs.Add("/nologo");
|
|
|
|
|
buildArgs.Add("/verbosity:quiet");
|
|
|
|
|
|
2017-06-02 23:32:53 -07:00
|
|
|
|
buildArgs.AddRange(RestoreArgs);
|
2015-11-20 19:00:56 -08:00
|
|
|
|
|
2017-06-01 21:25:06 -07:00
|
|
|
|
var buildResult = new RestoringCommand(buildArgs, NoRestore).Execute();
|
2016-10-27 18:46:43 -07:00
|
|
|
|
if (buildResult != 0)
|
2015-11-20 19:00:56 -08:00
|
|
|
|
{
|
2016-10-27 18:46:43 -07:00
|
|
|
|
Reporter.Error.WriteLine();
|
2016-11-19 11:45:46 -08:00
|
|
|
|
throw new GracefulException(LocalizableStrings.RunCommandException);
|
2015-11-20 19:00:56 -08:00
|
|
|
|
}
|
2015-11-23 16:31:27 -08:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
private ICommand GetRunCommand()
|
2015-11-23 16:31:27 -08:00
|
|
|
|
{
|
2017-02-07 15:14:43 -08:00
|
|
|
|
var globalProperties = new Dictionary<string, string>
|
2015-11-23 19:58:11 -08:00
|
|
|
|
{
|
2017-02-07 15:14:43 -08:00
|
|
|
|
{ Constants.MSBuildExtensionsPath, AppContext.BaseDirectory }
|
2016-10-27 18:46:43 -07:00
|
|
|
|
};
|
2015-11-20 19:00:56 -08:00
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
if (!string.IsNullOrWhiteSpace(Configuration))
|
2015-11-20 19:00:56 -08:00
|
|
|
|
{
|
2017-02-07 15:14:43 -08:00
|
|
|
|
globalProperties.Add("Configuration", Configuration);
|
2015-11-20 19:00:56 -08:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
if (!string.IsNullOrWhiteSpace(Framework))
|
2015-11-20 19:00:56 -08:00
|
|
|
|
{
|
2017-02-07 15:14:43 -08:00
|
|
|
|
globalProperties.Add("TargetFramework", Framework);
|
2015-11-20 19:00:56 -08:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-21 13:46:08 -05:00
|
|
|
|
Project project = new Project(Project, globalProperties, null);
|
2016-10-27 18:46:43 -07:00
|
|
|
|
|
2017-03-21 13:46:08 -05:00
|
|
|
|
string runProgram = project.GetPropertyValue("RunCommand");
|
2016-10-27 18:46:43 -07:00
|
|
|
|
if (string.IsNullOrEmpty(runProgram))
|
2016-04-25 13:53:02 -07:00
|
|
|
|
{
|
2017-03-21 13:46:08 -05:00
|
|
|
|
ThrowUnableToRunError(project);
|
2016-04-25 13:53:02 -07:00
|
|
|
|
}
|
|
|
|
|
|
2017-03-21 13:46:08 -05:00
|
|
|
|
string runArguments = project.GetPropertyValue("RunArguments");
|
|
|
|
|
string runWorkingDirectory = project.GetPropertyValue("RunWorkingDirectory");
|
2016-04-25 13:53:02 -07:00
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
string fullArguments = runArguments;
|
|
|
|
|
if (_args.Any())
|
2015-11-20 19:00:56 -08:00
|
|
|
|
{
|
2016-10-27 18:46:43 -07:00
|
|
|
|
fullArguments += " " + ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(_args);
|
2015-11-20 19:00:56 -08:00
|
|
|
|
}
|
2016-04-22 15:01:56 -07:00
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
CommandSpec commandSpec = new CommandSpec(runProgram, fullArguments, CommandResolutionStrategy.None);
|
2015-11-23 19:58:11 -08:00
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
return Command.Create(commandSpec)
|
|
|
|
|
.WorkingDirectory(runWorkingDirectory);
|
|
|
|
|
}
|
2015-11-20 19:00:56 -08:00
|
|
|
|
|
2017-03-21 13:46:08 -05:00
|
|
|
|
private void ThrowUnableToRunError(Project project)
|
|
|
|
|
{
|
|
|
|
|
string targetFrameworks = project.GetPropertyValue("TargetFrameworks");
|
|
|
|
|
if (!string.IsNullOrEmpty(targetFrameworks))
|
|
|
|
|
{
|
|
|
|
|
string targetFramework = project.GetPropertyValue("TargetFramework");
|
|
|
|
|
if (string.IsNullOrEmpty(targetFramework))
|
|
|
|
|
{
|
|
|
|
|
var framework = "--framework";
|
|
|
|
|
|
|
|
|
|
throw new GracefulException(LocalizableStrings.RunCommandExceptionUnableToRunSpecifyFramework, framework);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
string outputType = project.GetPropertyValue("OutputType");
|
|
|
|
|
|
|
|
|
|
throw new GracefulException(
|
|
|
|
|
string.Format(
|
|
|
|
|
LocalizableStrings.RunCommandExceptionUnableToRun,
|
|
|
|
|
"dotnet run",
|
|
|
|
|
"OutputType",
|
|
|
|
|
outputType));
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
private void Initialize()
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(Project))
|
2016-03-31 09:00:25 -07:00
|
|
|
|
{
|
2017-03-24 06:44:53 +01:00
|
|
|
|
Project = Directory.GetCurrentDirectory();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Directory.Exists(Project))
|
|
|
|
|
{
|
|
|
|
|
Project = FindSingleProjectInDirectory(Project);
|
2015-11-20 19:00:56 -08:00
|
|
|
|
}
|
|
|
|
|
|
2016-10-27 18:46:43 -07:00
|
|
|
|
if (Args == null)
|
2016-03-15 11:50:14 -07:00
|
|
|
|
{
|
2016-10-27 18:46:43 -07:00
|
|
|
|
_args = new List<string>();
|
2016-03-15 11:50:14 -07:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-10-27 18:46:43 -07:00
|
|
|
|
_args = new List<string>(Args);
|
2016-05-12 10:24:57 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
2017-03-24 06:44:53 +01:00
|
|
|
|
|
|
|
|
|
private static string FindSingleProjectInDirectory(string directory)
|
|
|
|
|
{
|
|
|
|
|
string[] projectFiles = Directory.GetFiles(directory, "*.*proj");
|
|
|
|
|
|
|
|
|
|
if (projectFiles.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
var project = "--project";
|
|
|
|
|
|
|
|
|
|
throw new GracefulException(LocalizableStrings.RunCommandExceptionNoProjects, directory, project);
|
|
|
|
|
}
|
|
|
|
|
else if (projectFiles.Length > 1)
|
|
|
|
|
{
|
|
|
|
|
throw new GracefulException(LocalizableStrings.RunCommandExceptionMultipleProjects, directory);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return projectFiles[0];
|
|
|
|
|
}
|
2015-11-20 19:00:56 -08:00
|
|
|
|
}
|
|
|
|
|
}
|