[WIP] Removes *3 verbs, making msbuild the driver (#4456)

Removes *3 verbs, making msbuild the driver
This commit is contained in:
Piotr Puszkiewicz 2016-10-27 18:46:43 -07:00 committed by GitHub
parent 55c59d621e
commit 6fcbefa4f7
746 changed files with 4256 additions and 32434 deletions

View file

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