[WIP] Removes *3 verbs, making msbuild the driver (#4456)
Removes *3 verbs, making msbuild the driver
This commit is contained in:
parent
55c59d621e
commit
6fcbefa4f7
746 changed files with 4256 additions and 32434 deletions
|
@ -5,115 +5,133 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.DotNet.Cli;
|
||||
using Microsoft.Build.Execution;
|
||||
using Microsoft.DotNet.Cli.Utils;
|
||||
using Microsoft.DotNet.InternalAbstractions;
|
||||
using Microsoft.DotNet.ProjectModel;
|
||||
using Microsoft.DotNet.Tools.Common;
|
||||
using NuGet.Frameworks;
|
||||
using Microsoft.DotNet.Tools.MSBuild;
|
||||
|
||||
namespace Microsoft.DotNet.Tools.Run
|
||||
{
|
||||
public partial class RunCommand
|
||||
{
|
||||
public string Framework = null;
|
||||
public string Configuration = null;
|
||||
public string Project = null;
|
||||
public IReadOnlyList<string> Args = null;
|
||||
public string Configuration { get; set; }
|
||||
public string Framework { get; set; }
|
||||
public string Project { get; set; }
|
||||
public IReadOnlyList<string> Args { get; set; }
|
||||
|
||||
private readonly ICommandFactory _commandFactory;
|
||||
private ProjectContext _context;
|
||||
private List<string> _args;
|
||||
private BuildWorkspace _workspace;
|
||||
|
||||
public static readonly string[] DefaultFrameworks = new[]
|
||||
{
|
||||
FrameworkConstants.FrameworkIdentifiers.NetCoreApp,
|
||||
FrameworkConstants.FrameworkIdentifiers.NetStandardApp,
|
||||
};
|
||||
|
||||
public RunCommand()
|
||||
: this(new RunCommandFactory())
|
||||
{
|
||||
}
|
||||
|
||||
public RunCommand(ICommandFactory commandFactory)
|
||||
{
|
||||
_commandFactory = commandFactory;
|
||||
}
|
||||
|
||||
public int Start()
|
||||
{
|
||||
if (IsInteractive())
|
||||
{
|
||||
return RunInteractive(Project);
|
||||
}
|
||||
else
|
||||
{
|
||||
return RunExecutable();
|
||||
}
|
||||
Initialize();
|
||||
|
||||
EnsureProjectIsBuilt();
|
||||
|
||||
ICommand runCommand = GetRunCommand();
|
||||
|
||||
return runCommand
|
||||
.Execute()
|
||||
.ExitCode;
|
||||
}
|
||||
|
||||
private bool IsInteractive()
|
||||
private void EnsureProjectIsBuilt()
|
||||
{
|
||||
if (!string.IsNullOrEmpty(Project))
|
||||
List<string> buildArgs = new List<string>();
|
||||
|
||||
buildArgs.Add(Project);
|
||||
|
||||
buildArgs.Add("/nologo");
|
||||
buildArgs.Add("/verbosity:quiet");
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Configuration))
|
||||
{
|
||||
if (File.Exists(Project) && (Path.GetExtension(Project).ToLowerInvariant() == ".csx"))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
buildArgs.Add($"/p:Configuration={Configuration}");
|
||||
}
|
||||
|
||||
return false;
|
||||
if (!string.IsNullOrWhiteSpace(Framework))
|
||||
{
|
||||
buildArgs.Add($"/p:TargetFramework={Framework}");
|
||||
}
|
||||
|
||||
var buildResult = new MSBuildForwardingApp(buildArgs).Execute();
|
||||
|
||||
if (buildResult != 0)
|
||||
{
|
||||
Reporter.Error.WriteLine();
|
||||
throw new GracefulException("The build failed. Please fix the build errors and run again.");
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateDefaultsForNonAssigned()
|
||||
private ICommand GetRunCommand()
|
||||
{
|
||||
Dictionary<string, string> globalProperties = new Dictionary<string, string>()
|
||||
{
|
||||
{ "MSBuildExtensionsPath", AppContext.BaseDirectory }
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Configuration))
|
||||
{
|
||||
globalProperties.Add("Configuration", Configuration);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Framework))
|
||||
{
|
||||
globalProperties.Add("TargetFramework", Framework);
|
||||
}
|
||||
|
||||
ProjectInstance projectInstance = new ProjectInstance(Project, globalProperties, null);
|
||||
|
||||
string runProgram = projectInstance.GetPropertyValue("RunCommand");
|
||||
if (string.IsNullOrEmpty(runProgram))
|
||||
{
|
||||
string outputType = projectInstance.GetPropertyValue("OutputType");
|
||||
|
||||
throw new GracefulException(string.Join(Environment.NewLine,
|
||||
"Unable to run your project.",
|
||||
"Please ensure you have a runnable project type and ensure 'dotnet run' supports this project.",
|
||||
$"The current OutputType is '{outputType}'."));
|
||||
}
|
||||
|
||||
string runArguments = projectInstance.GetPropertyValue("RunArguments");
|
||||
string runWorkingDirectory = projectInstance.GetPropertyValue("RunWorkingDirectory");
|
||||
|
||||
string fullArguments = runArguments;
|
||||
if (_args.Any())
|
||||
{
|
||||
fullArguments += " " + ArgumentEscaper.EscapeAndConcatenateArgArrayForProcessStart(_args);
|
||||
}
|
||||
|
||||
CommandSpec commandSpec = new CommandSpec(runProgram, fullArguments, CommandResolutionStrategy.None);
|
||||
|
||||
return Command.Create(commandSpec)
|
||||
.WorkingDirectory(runWorkingDirectory);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Project))
|
||||
{
|
||||
Project = Directory.GetCurrentDirectory();
|
||||
}
|
||||
string directory = Directory.GetCurrentDirectory();
|
||||
string[] projectFiles = Directory.GetFiles(directory, "*.*proj");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(Configuration))
|
||||
{
|
||||
Configuration = Constants.DefaultConfiguration;
|
||||
}
|
||||
|
||||
var frameworkContexts = _workspace.GetProjectContextCollection(Project)
|
||||
.EnsureValid(Project)
|
||||
.FrameworkOnlyContexts;
|
||||
|
||||
var rids = DotnetRuntimeIdentifiers.InferCurrentRuntimeIdentifiers(DotnetFiles.VersionFileObject);
|
||||
|
||||
ProjectContext frameworkContext;
|
||||
if (Framework == null)
|
||||
{
|
||||
if (frameworkContexts.Count() == 1)
|
||||
if (projectFiles.Length == 0)
|
||||
{
|
||||
frameworkContext = frameworkContexts.Single();
|
||||
throw new InvalidOperationException(
|
||||
$"Couldn't find a project to run. Ensure a project exists in {directory}." + Environment.NewLine +
|
||||
"Or pass the path to the project using --project");
|
||||
}
|
||||
else
|
||||
else if (projectFiles.Length > 1)
|
||||
{
|
||||
frameworkContext = frameworkContexts.FirstOrDefault(c => DefaultFrameworks.Contains(c.TargetFramework.Framework));
|
||||
throw new InvalidOperationException(
|
||||
$"Specify which project file to use because this '{directory}' contains more than one project file.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
frameworkContext = frameworkContexts.FirstOrDefault(c => Equals(c.TargetFramework, NuGetFramework.Parse(Framework)));
|
||||
}
|
||||
|
||||
if (frameworkContext == null)
|
||||
{
|
||||
throw new InvalidOperationException($"Couldn't find target to run. Possible causes:" + Environment.NewLine +
|
||||
"1. No project.lock.json file or restore failed - run `dotnet restore`" + Environment.NewLine +
|
||||
Framework == null ?
|
||||
$"2. project.lock.json has multiple targets none of which is in default list ({string.Join(", ", DefaultFrameworks)})" :
|
||||
$"2. The project does not support the desired framework: {Framework}");
|
||||
Project = projectFiles[0];
|
||||
}
|
||||
|
||||
_context = _workspace.GetRuntimeContext(frameworkContext, rids);
|
||||
|
||||
if (Args == null)
|
||||
{
|
||||
_args = new List<string>();
|
||||
|
@ -123,102 +141,5 @@ namespace Microsoft.DotNet.Tools.Run
|
|||
_args = new List<string>(Args);
|
||||
}
|
||||
}
|
||||
|
||||
private int RunExecutable()
|
||||
{
|
||||
// Set up the workspace
|
||||
_workspace = new BuildWorkspace(ProjectReaderSettings.ReadFromEnvironment());
|
||||
|
||||
CalculateDefaultsForNonAssigned();
|
||||
|
||||
// Compile to that directory
|
||||
var result = Build.BuildCommand.Run(new[]
|
||||
{
|
||||
$"--framework",
|
||||
$"{_context.TargetFramework}",
|
||||
$"--configuration",
|
||||
Configuration,
|
||||
$"{_context.ProjectFile.ProjectDirectory}"
|
||||
}, _workspace);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
List<string> hostArgs = new List<string>();
|
||||
if (!_context.TargetFramework.IsDesktop() && _context.LockFile != null)
|
||||
{
|
||||
// Add Nuget Packages Probing Paths
|
||||
const string probingPathArg = "--additionalprobingpath";
|
||||
|
||||
foreach (var packageFolder in _context.LockFile.PackageFolders)
|
||||
{
|
||||
// DotNetHost doesn't handle additional probing paths with a trailing slash
|
||||
hostArgs.Insert(0, PathUtility.EnsureNoTrailingDirectorySeparator(packageFolder.Path));
|
||||
hostArgs.Insert(0, probingPathArg);
|
||||
}
|
||||
}
|
||||
|
||||
// Now launch the output and give it the results
|
||||
var outputPaths = _context.GetOutputPaths(Configuration);
|
||||
var outputName = outputPaths.RuntimeFiles.Executable;
|
||||
|
||||
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
if (_context.TargetFramework.IsDesktop())
|
||||
{
|
||||
// Run mono if we're running a desktop target on non windows
|
||||
_args.Insert(0, outputName);
|
||||
|
||||
if (string.Equals(Configuration, "Debug", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// If we're compiling for the debug configuration then add the --debug flag
|
||||
// other options may be passed using the MONO_OPTIONS env var
|
||||
_args.Insert(0, "--debug");
|
||||
}
|
||||
|
||||
outputName = "mono";
|
||||
}
|
||||
}
|
||||
|
||||
ICommand command;
|
||||
if (outputName.EndsWith(FileNameSuffixes.DotNet.DynamicLib, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// The executable is a ".dll", we need to call it through dotnet.exe
|
||||
var muxer = new Muxer();
|
||||
|
||||
command = _commandFactory.Create(muxer.MuxerPath, Enumerable.Concat(
|
||||
Enumerable.Concat(new string[] { "exec" }, hostArgs),
|
||||
Enumerable.Concat(new string[] { outputName }, _args)));
|
||||
}
|
||||
else
|
||||
{
|
||||
command = _commandFactory.Create(outputName, Enumerable.Concat(hostArgs, _args));
|
||||
}
|
||||
|
||||
result = command
|
||||
.Execute()
|
||||
.ExitCode;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int RunInteractive(string scriptName)
|
||||
{
|
||||
var command = Command.CreateDotNet($"repl-csi", new[] { scriptName })
|
||||
.ForwardStdOut()
|
||||
.ForwardStdErr();
|
||||
var result = command.Execute();
|
||||
return result.ExitCode;
|
||||
}
|
||||
|
||||
private class RunCommandFactory : ICommandFactory
|
||||
{
|
||||
public ICommand Create(string commandName, IEnumerable<string> args, NuGetFramework framework = null, string configuration = "Debug")
|
||||
{
|
||||
return Command.Create(commandName, args, framework, configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue