Adding support for seeding the repl with a project context.

This commit is contained in:
Tanner Gooding 2015-12-29 12:29:13 -08:00
parent 8bccd0b93b
commit adc24fd301
2 changed files with 119 additions and 5 deletions

View file

@ -33,5 +33,7 @@ namespace Microsoft.DotNet.Cli.Utils
RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx.10.10-x64" : "ubuntu.14.04-x64"; RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx.10.10-x64" : "ubuntu.14.04-x64";
public static readonly string StaticLibSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".lib" : ".a" ; public static readonly string StaticLibSuffix = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".lib" : ".a" ;
public static readonly string ResponseFileSuffix = ".rsp";
} }
} }

View file

@ -2,9 +2,14 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information. // Licensed under the MIT license. See LICENSE file in the project root for full license information.
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.IO; using System.IO;
using System.Text;
using Microsoft.Dnx.Runtime.Common.CommandLine; using Microsoft.Dnx.Runtime.Common.CommandLine;
using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Cli.Utils;
using Microsoft.DotNet.ProjectModel;
using NuGet.Frameworks;
namespace Microsoft.DotNet.Tools.Repl.Csi namespace Microsoft.DotNet.Tools.Repl.Csi
{ {
@ -19,21 +24,128 @@ namespace Microsoft.DotNet.Tools.Repl.Csi
app.FullName = "C# REPL"; app.FullName = "C# REPL";
app.Description = "C# REPL for the .NET platform"; app.Description = "C# REPL for the .NET platform";
app.HelpOption("-h|--help"); app.HelpOption("-h|--help");
var script = app.Argument("<SCRIPT>", "The .csx file to run. Defaults to interactive mode.");
app.OnExecute(() => Run(script.Value)); var script = app.Argument("<SCRIPT>", "The .csx file to run. Defaults to interactive mode.");
var framework = app.Option("-f|--framework <FRAMEWORK>", "Compile a specific framework", CommandOptionType.MultipleValue);
var configuration = app.Option("-c|--configuration <CONFIGURATION>", "Configuration under which to build", CommandOptionType.SingleValue);
var preserveTemporary = app.Option("-t|--preserve-temporary", "Keep the output's temporary directory around", CommandOptionType.NoValue);
var project = app.Option("-p|--project <PROJECT>", "The path to the project to run. Can be a path to a project.json or a project directory", CommandOptionType.SingleValue);
app.OnExecute(() => Run(script.Value, framework.Values, (configuration.Value() ?? Constants.DefaultConfiguration), preserveTemporary.HasValue(), project.Value()));
return app.Execute(args); return app.Execute(args);
} }
private static int Run(string scriptOpt) private static ProjectContext GetProjectContext(IEnumerable<string> targetFrameworks, string projectPath)
{
var contexts = ProjectContext.CreateContextForEachFramework(projectPath);
var context = contexts.First();
if (targetFrameworks.Any())
{
var framework = NuGetFramework.Parse(targetFrameworks.First());
context = contexts.FirstOrDefault(c => c.TargetFramework.Equals(framework));
}
return context;
}
private static CommandResult CompileProject(ProjectContext projectContext, string configuration, out string tempOutputDir)
{
tempOutputDir = Path.Combine(projectContext.ProjectDirectory, "bin", ".dotnetrepl", Guid.NewGuid().ToString("N"));
Reporter.Output.WriteLine($"Compiling {projectContext.RootProject.Identity.Name.Yellow()} for {projectContext.TargetFramework.DotNetFrameworkName.Yellow()} to use with the {"C# REPL".Yellow()} environment.");
return Command.Create($"dotnet-compile", $"--output \"{tempOutputDir}\" --temp-output \"{tempOutputDir}\" --framework \"{projectContext.TargetFramework}\" --configuration \"{configuration}\" {projectContext.ProjectFile.ProjectDirectory}")
.ForwardStdOut(onlyIfVerbose: true)
.ForwardStdErr()
.Execute();
}
private static List<string> GetRuntimeDependencies(ProjectContext projectContext, string buildConfiguration)
{
var runtimeDependencies = new List<string>();
var projectExporter = projectContext.CreateExporter(buildConfiguration);
var projectDependencies = projectExporter.GetDependencies();
foreach (var projectDependency in projectDependencies)
{
var runtimeAssemblies = projectDependency.RuntimeAssemblies;
foreach (var runtimeAssembly in runtimeAssemblies)
{
var runtimeAssemblyPath = runtimeAssembly.ResolvedPath;
if (!runtimeDependencies.Contains(runtimeAssemblyPath))
{
runtimeDependencies.Add(runtimeAssemblyPath);
}
}
}
return runtimeDependencies;
}
private static string CreateResponseFile(ProjectContext projectContext, string buildConfiguration, string tempOutputDir)
{
var outputFileName = projectContext.ProjectFile.Name;
var outputFilePath = Path.Combine(tempOutputDir, $"{outputFileName}{Constants.DynamicLibSuffix}");
var projectResponseFilePath = Path.Combine(tempOutputDir, $"dotnet-repl.{outputFileName}{Constants.ResponseFileSuffix}");
var runtimeDependencies = GetRuntimeDependencies(projectContext, buildConfiguration);
using (var fileStream = new FileStream(projectResponseFilePath, FileMode.Create))
{
var streamWriter = new StreamWriter(fileStream);
streamWriter.WriteLine($"/r:\"{outputFilePath}\"");
foreach (var projectDependency in runtimeDependencies)
{
streamWriter.WriteLine($"/r:\"{projectDependency}\"");
}
streamWriter.Flush();
}
return projectResponseFilePath;
}
private static int Run(string script, IEnumerable<string> targetFrameworks, string buildConfiguration, bool preserveTemporaryOutput, string projectPath)
{ {
var corerun = Path.Combine(AppContext.BaseDirectory, Constants.HostExecutableName); var corerun = Path.Combine(AppContext.BaseDirectory, Constants.HostExecutableName);
var csiExe = Path.Combine(AppContext.BaseDirectory, "csi.exe"); var csiExe = Path.Combine(AppContext.BaseDirectory, "csi.exe");
var csiArgs = string.IsNullOrEmpty(scriptOpt) ? "-i" : scriptOpt; var csiArgs = new StringBuilder();
var result = Command.Create(csiExe, csiArgs)
var tempOutputDir = string.Empty;
if (!string.IsNullOrWhiteSpace(projectPath))
{
var projectContext = GetProjectContext(targetFrameworks, projectPath);
var compileResult = CompileProject(projectContext, buildConfiguration, out tempOutputDir);
if (compileResult.ExitCode != 0)
{
return compileResult.ExitCode;
}
string responseFile = CreateResponseFile(projectContext, buildConfiguration, tempOutputDir);
csiArgs.Append($"@\"{responseFile}\" ");
}
csiArgs.Append(string.IsNullOrEmpty(script) ? "-i" : script);
var result = Command.Create(csiExe, csiArgs.ToString())
.ForwardStdOut() .ForwardStdOut()
.ForwardStdErr() .ForwardStdErr()
.Execute(); .Execute();
if (!string.IsNullOrWhiteSpace(tempOutputDir) && !preserveTemporaryOutput)
{
Directory.Delete(tempOutputDir, recursive: true);
}
return result.ExitCode; return result.ExitCode;
} }
} }