// 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; using System.Runtime.InteropServices; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.ProjectModel; using NuGet.Frameworks; namespace Microsoft.DotNet.Tools.Run { public partial class RunCommand { public string Framework = null; public string Configuration = null; public bool PreserveTemporary = false; public string Project = null; public IReadOnlyList Args = null; ProjectContext _context; List _args; public int Start() { if (IsInteractive()) { return RunInteractive(Project); } else { return RunExecutable(); } } private bool IsInteractive() { if (!string.IsNullOrEmpty(Project)) { if (File.Exists(Project) && (Path.GetExtension(Project).ToLowerInvariant() == ".csx")) { return true; } } return false; } private void CalculateDefaultsForNonAssigned() { if (string.IsNullOrWhiteSpace(Project)) { Project = Directory.GetCurrentDirectory(); } if (string.IsNullOrWhiteSpace(Configuration)) { Configuration = Constants.DefaultConfiguration; } var contexts = ProjectContext.CreateContextForEachFramework(Project); if (Framework == null) { _context = contexts.First(); } else { var fx = NuGetFramework.Parse(Framework); _context = contexts.FirstOrDefault(c => c.TargetFramework.Equals(fx)); } if (Args == null) { _args = new List(); } else { _args = new List(Args); } } private int RunExecutable() { CalculateDefaultsForNonAssigned(); // Create a temporary directory under the project root // REVIEW: MAX_PATH? var tempDir = Path.Combine(_context.ProjectDirectory, "bin", ".dotnetrun", Guid.NewGuid().ToString("N")); // Compile to that directory var result = Command.CreateDotNet($"build", new [] { $"--output", $"{tempDir}", $"--temp-output", $"{tempDir}", $"--framework", $"{_context.TargetFramework}", $"--configuration", $"{Configuration}", $"{_context.ProjectFile.ProjectDirectory}" }) .ForwardStdOut(onlyIfVerbose: true) .ForwardStdErr() .Execute(); if (result.ExitCode != 0) { return result.ExitCode; } // Now launch the output and give it the results var outputName = _context.GetOutputPathCalculator(tempDir).GetExecutablePath(Configuration); 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"; } } // Locate the runtime string dotnetHome = Environment.GetEnvironmentVariable("DOTNET_HOME"); if (string.IsNullOrEmpty(dotnetHome)) { // Use the runtime deployed with the tools, if present var candidateBase = Path.Combine(AppContext.BaseDirectory, ".."); var candidate = Path.Combine(candidateBase, "runtime/coreclr"); if (File.Exists(Path.Combine(candidate, Constants.LibCoreClrName))) { dotnetHome = Path.GetFullPath(candidateBase); } } result = Command.Create(outputName, _args) .ForwardStdOut() .ForwardStdErr() .EnvironmentVariable("DOTNET_HOME", dotnetHome) .Execute(); // Clean up if (!PreserveTemporary) { Directory.Delete(tempDir, recursive: true); } return result.ExitCode; } private static int RunInteractive(string scriptName) { var command = Command.CreateDotNet($"repl-csi", new [] {scriptName}) .ForwardStdOut() .ForwardStdErr(); var result = command.Execute(); return result.ExitCode; } } }