From cc00d9d8399f6c7f4593536cefd38c79a56fe418 Mon Sep 17 00:00:00 2001 From: Andrew Stanton-Nurse Date: Tue, 15 Mar 2016 11:50:14 -0700 Subject: [PATCH] update project templates for portable app also fix dotnet run --- .../ArgumentEscaper.cs | 4 +- .../RuntimeOutputFiles.cs | 14 +++++-- .../commands/dotnet-build/CompileContext.cs | 14 ++++--- .../CSharp_Console/project.json.template | 6 +-- .../FSharp_Console/project.json.template | 6 +-- src/dotnet/commands/dotnet-run/RunCommand.cs | 20 ++++++++-- test/EndToEnd/EndToEndTest.cs | 28 +++++++------- .../Commands/BuildCommand.cs | 5 +++ .../Commands/PublishCommand.cs | 5 +++ .../Commands/TestCommand.cs | 38 ++++++++++++++----- 10 files changed, 95 insertions(+), 45 deletions(-) diff --git a/src/Microsoft.DotNet.Cli.Utils/ArgumentEscaper.cs b/src/Microsoft.DotNet.Cli.Utils/ArgumentEscaper.cs index 4a5d0f4fe..c8469a9ac 100644 --- a/src/Microsoft.DotNet.Cli.Utils/ArgumentEscaper.cs +++ b/src/Microsoft.DotNet.Cli.Utils/ArgumentEscaper.cs @@ -54,7 +54,7 @@ namespace Microsoft.DotNet.Cli.Utils foreach (var arg in args) { - escapedArgs.Add(EscapeArg(arg)); + escapedArgs.Add(EscapeSingleArg(arg)); } return escapedArgs; @@ -82,7 +82,7 @@ namespace Microsoft.DotNet.Cli.Utils return escapedArgs; } - private static string EscapeArg(string arg) + public static string EscapeSingleArg(string arg) { var sb = new StringBuilder(); diff --git a/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs b/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs index 8e9bdca3b..6368f173b 100644 --- a/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs +++ b/src/Microsoft.DotNet.ProjectModel/RuntimeOutputFiles.cs @@ -26,12 +26,18 @@ namespace Microsoft.DotNet.ProjectModel { var extension = FileNameSuffixes.CurrentPlatform.Exe; - // This is the check for mono, if we're not on windows and producing outputs for - // the desktop framework then it's an exe if (Framework.IsDesktop()) { + // This is the check for mono, if we're not on windows and producing outputs for + // the desktop framework then it's an exe extension = FileNameSuffixes.DotNet.Exe; } + else if (string.IsNullOrEmpty(_runtimeIdentifier)) + { + // The executable is a DLL in this case + extension = FileNameSuffixes.DotNet.DynamicLib; + } + return Path.Combine(BasePath, Project.Name + extension); } } @@ -81,9 +87,9 @@ namespace Microsoft.DotNet.ProjectModel yield return RuntimeConfigJson; } - // If the project actually has an entry point AND we're doing a standalone build + // If the project actually has an entry point var hasEntryPoint = Project.GetCompilerOptions(targetFramework: null, configurationName: Configuration).EmitEntryPoint ?? false; - if (hasEntryPoint && !string.IsNullOrEmpty(_runtimeIdentifier)) + if (hasEntryPoint) { // Yield the executable yield return Executable; diff --git a/src/dotnet/commands/dotnet-build/CompileContext.cs b/src/dotnet/commands/dotnet-build/CompileContext.cs index b6b5c2adb..4768f12e7 100644 --- a/src/dotnet/commands/dotnet-build/CompileContext.cs +++ b/src/dotnet/commands/dotnet-build/CompileContext.cs @@ -405,6 +405,13 @@ namespace Microsoft.DotNet.Tools.Build { var dest = outputPaths.RuntimeOutputPath; var source = outputPaths.CompilationOutputPath; + + // No need to copy if dest and source are the same + if(string.Equals(dest, source, StringComparison.OrdinalIgnoreCase)) + { + return; + } + foreach (var file in outputPaths.CompilationFiles.All()) { var destFileName = file.Replace(source, dest); @@ -423,12 +430,7 @@ namespace Microsoft.DotNet.Tools.Build var outputPaths = runtimeContext.GetOutputPaths(_args.ConfigValue, _args.BuildBasePathValue, _args.OutputValue); var libraryExporter = runtimeContext.CreateExporter(_args.ConfigValue, _args.BuildBasePathValue); - // If we're building for a specific RID, we need to copy the RID-less compilation output into - // the RID-specific output dir - if (!string.IsNullOrEmpty(runtimeContext.RuntimeIdentifier)) - { - CopyCompilationOutput(outputPaths); - } + CopyCompilationOutput(outputPaths); var options = runtimeContext.ProjectFile.GetCompilerOptions(runtimeContext.TargetFramework, _args.ConfigValue); var executable = new Executable(runtimeContext, outputPaths, libraryExporter, _args.ConfigValue); diff --git a/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template b/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template index 2e5ebbe30..5f0805e14 100644 --- a/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template +++ b/src/dotnet/commands/dotnet-new/CSharp_Console/project.json.template @@ -4,11 +4,11 @@ "emitEntryPoint": true }, "dependencies": { - "NETStandard.Library": "1.5.0-rc2-23911" + "Microsoft.NETCore.App": "1.0.0-rc2-23911" }, "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" + "netstandard1.5": { + "imports": [ "portable-net45+win8", "dnxcore50" ] } } } diff --git a/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template b/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template index 84d87f6df..501e3dd6c 100644 --- a/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template +++ b/src/dotnet/commands/dotnet-new/FSharp_Console/project.json.template @@ -9,11 +9,11 @@ ], "dependencies": { "Microsoft.FSharp.Core.netcore": "1.0.0-alpha-151221", - "NETStandard.Library": "1.5.0-rc2-23911" + "Microsoft.NETCore.App": "1.0.0-rc2-23911" }, "frameworks": { - "netstandardapp1.5": { - "imports": "dnxcore50" + "netstandard1.5": { + "imports": [ "portable-net45+win8", "dnxcore50" ] } } } diff --git a/src/dotnet/commands/dotnet-run/RunCommand.cs b/src/dotnet/commands/dotnet-run/RunCommand.cs index cc8c65e32..db67a4394 100644 --- a/src/dotnet/commands/dotnet-run/RunCommand.cs +++ b/src/dotnet/commands/dotnet-run/RunCommand.cs @@ -84,7 +84,7 @@ namespace Microsoft.DotNet.Tools.Run { 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 + - $"2. project.lock.json has multiple targets none of which is in default list ({string.Join(", " , defaultFrameworks)})"); + $"2. project.lock.json has multiple targets none of which is in default list ({string.Join(", ", defaultFrameworks)})"); } } @@ -125,7 +125,8 @@ namespace Microsoft.DotNet.Tools.Run } // Now launch the output and give it the results - var outputName = _context.GetOutputPaths(Configuration).RuntimeFiles.Executable; + var outputPaths = _context.GetOutputPaths(Configuration); + var outputName = outputPaths.RuntimeFiles.Executable; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -145,7 +146,18 @@ namespace Microsoft.DotNet.Tools.Run } } - result = Command.Create(outputName, _args) + Command command; + if (outputName.EndsWith(FileNameSuffixes.DotNet.DynamicLib, StringComparison.OrdinalIgnoreCase)) + { + // The executable is a ".dll", we need to call it through dotnet.exe + command = Command.Create("corehost", Enumerable.Concat(new[] { outputName }, _args)); + } + else + { + command = Command.Create(outputName, _args); + } + + result = command .ForwardStdOut() .ForwardStdErr() .Execute() @@ -156,7 +168,7 @@ namespace Microsoft.DotNet.Tools.Run private static int RunInteractive(string scriptName) { - var command = Command.CreateDotNet($"repl-csi", new [] {scriptName}) + var command = Command.CreateDotNet($"repl-csi", new[] { scriptName }) .ForwardStdOut() .ForwardStdErr(); var result = command.Execute(); diff --git a/test/EndToEnd/EndToEndTest.cs b/test/EndToEnd/EndToEndTest.cs index be21d46ca..a07507602 100644 --- a/test/EndToEnd/EndToEndTest.cs +++ b/test/EndToEnd/EndToEndTest.cs @@ -8,11 +8,13 @@ using System.Runtime.InteropServices; using Microsoft.DotNet.Tools.Test.Utilities; using Microsoft.Extensions.PlatformAbstractions; using Xunit; +using System.Diagnostics; namespace Microsoft.DotNet.Tests.EndToEnd { public class EndToEndTest : TestBase { + private static readonly string NetStandardTfm = "netstandard1.5"; private static readonly string s_expectedOutput = "Hello World!" + Environment.NewLine; private static readonly string s_testdirName = "e2etestroot"; private static readonly string s_outputdirName = "test space/bin"; @@ -42,20 +44,20 @@ namespace Microsoft.DotNet.Tests.EndToEnd [Fact] public void TestDotnetBuild() { - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: NetStandardTfm); buildCommand.Execute().Should().Pass(); - TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); + TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput); } [Fact] public void TestDotnetIncrementalBuild() { // first build - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, framework: NetStandardTfm); buildCommand.Execute().Should().Pass(); - TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); + TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput); var binariesOutputDirectory = GetCompilationOutputPath(OutputDirectory, false); var latestWriteTimeFirstBuild = GetLastWriteTimeUtcOfDirectoryFiles( @@ -63,7 +65,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd // second build; should get skipped (incremental because no inputs changed) buildCommand.Execute().Should().Pass(); - TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); + TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput); var latestWriteTimeUtcSecondBuild = GetLastWriteTimeUtcOfDirectoryFiles( binariesOutputDirectory); @@ -73,14 +75,14 @@ namespace Microsoft.DotNet.Tests.EndToEnd // third build; should get compiled because the source file got touched buildCommand.Execute().Should().Pass(); - TestOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); + TestOutputExecutable(OutputDirectory, buildCommand.GetPortableOutputName(), s_expectedOutput); var latestWriteTimeUtcThirdBuild = GetLastWriteTimeUtcOfDirectoryFiles( binariesOutputDirectory); Assert.NotEqual(latestWriteTimeUtcSecondBuild, latestWriteTimeUtcThirdBuild); } - [Fact] + [Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")] public void TestDotnetBuildNativeRyuJit() { if (!IsNativeCompilationSupported()) @@ -88,14 +90,14 @@ namespace Microsoft.DotNet.Tests.EndToEnd return; } - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, framework: NetStandardTfm); buildCommand.Execute().Should().Pass(); TestNativeOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); } - [Fact] + [Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")] public void TestDotnetBuildNativeCpp() { if (!IsNativeCompilationSupported()) @@ -103,14 +105,14 @@ namespace Microsoft.DotNet.Tests.EndToEnd return; } - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: NetStandardTfm); buildCommand.Execute().Should().Pass(); TestNativeOutputExecutable(OutputDirectory, buildCommand.GetOutputExecutableName(), s_expectedOutput); } - [Fact] + [Fact(Skip = "Native compilation isn't shipping in 1.0 and we're moving it out anyway")] public void TestDotnetCompileNativeCppIncremental() { if (!IsNativeCompilationSupported()) @@ -119,7 +121,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd } // first build - var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: DefaultFramework); + var buildCommand = new BuildCommand(TestProject, output: OutputDirectory, native: true, nativeCppMode: true, framework: NetStandardTfm); var binariesOutputDirectory = GetCompilationOutputPath(OutputDirectory, false); buildCommand.Execute().Should().Pass(); @@ -163,7 +165,7 @@ namespace Microsoft.DotNet.Tests.EndToEnd var publishCommand = new PublishCommand(TestProject, output: OutputDirectory); publishCommand.Execute().Should().Pass(); - TestExecutable(OutputDirectory, publishCommand.GetOutputExecutable(), s_expectedOutput); + TestExecutable(OutputDirectory, publishCommand.GetPortableOutputName(), s_expectedOutput); } [Fact] diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs index 4f36ac973..693b32586 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/BuildCommand.cs @@ -254,6 +254,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return base.ExecuteWithCapturedOutput(args); } + public string GetPortableOutputName() + { + return $"{_project.Name}.dll"; + } + public string GetOutputExecutableName() { var result = _project.Name; diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs index ec24eb73a..785a1d386 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/PublishCommand.cs @@ -74,6 +74,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return new DirectoryInfo(output); } + public string GetPortableOutputName() + { + return $"{_project.Name}.dll"; + } + public string GetOutputExecutable() { var result = _project.Name; diff --git a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/TestCommand.cs b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/TestCommand.cs index 16a677add..ef0f086e2 100644 --- a/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/TestCommand.cs +++ b/test/Microsoft.DotNet.Tools.Tests.Utilities/Commands/TestCommand.cs @@ -23,11 +23,7 @@ namespace Microsoft.DotNet.Tools.Test.Utilities public virtual CommandResult Execute(string args = "") { var commandPath = _command; - if (!Path.IsPathRooted(_command)) - { - _command = Env.GetCommandPath(_command) ?? - Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, _command); - } + ResolveCommand(ref commandPath, ref args); Console.WriteLine($"Executing - {_command} {args}"); @@ -44,9 +40,11 @@ namespace Microsoft.DotNet.Tools.Test.Utilities { Console.WriteLine($"Executing (Captured Output) - {_command} {args}"); - var commandPath = Env.GetCommandPath(_command, ".exe", ".cmd", "") ?? - Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, _command, ".exe", ".cmd", ""); - + var command = _command; + ResolveCommand(ref command, ref args); + var commandPath = Env.GetCommandPath(command, ".exe", ".cmd", "") ?? + Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, command, ".exe", ".cmd", ""); + var stdOut = new StreamForwarder(); var stdErr = new StreamForwarder(); @@ -56,6 +54,26 @@ namespace Microsoft.DotNet.Tools.Test.Utilities return RunProcess(commandPath, args, stdOut, stdErr); } + private void ResolveCommand(ref string executable, ref string args) + { + if (executable.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) + { + var newArgs = ArgumentEscaper.EscapeSingleArg(executable); + if (!string.IsNullOrEmpty(args)) + { + newArgs += " " + args; + } + args = newArgs; + executable = "corehost"; + } + + if (!Path.IsPathRooted(executable)) + { + executable = Env.GetCommandPath(executable) ?? + Env.GetCommandPathFromRootPath(AppContext.BaseDirectory, executable); + } + } + private CommandResult RunProcess(string executable, string args, StreamForwarder stdOut, StreamForwarder stdErr) { var psi = new ProcessStartInfo @@ -88,8 +106,8 @@ namespace Microsoft.DotNet.Tools.Test.Utilities var result = new CommandResult( process.StartInfo, - process.ExitCode, - stdOut.CapturedOutput, + process.ExitCode, + stdOut.CapturedOutput, stdErr.CapturedOutput); return result;