From cbeb5b9912cc23fa0197533c4478faac96d426c5 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Thu, 13 Oct 2016 17:08:05 -0500 Subject: [PATCH 1/4] Report a meaningful error when trying to run a multi-TFM project. Add `--no-build` option to `dotnet run3` since even incrementally building a project takes a non-trivial amount of time. --- src/dotnet/commands/dotnet-run3/Program.cs | 4 ++ .../commands/dotnet-run3/Run3Command.cs | 47 ++++++++++++++----- 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/src/dotnet/commands/dotnet-run3/Program.cs b/src/dotnet/commands/dotnet-run3/Program.cs index 843735376..00f5ae63e 100644 --- a/src/dotnet/commands/dotnet-run3/Program.cs +++ b/src/dotnet/commands/dotnet-run3/Program.cs @@ -28,6 +28,9 @@ namespace Microsoft.DotNet.Tools.Run CommandOption framework = app.Option( "-f|--framework ", "Compile a specific framework", CommandOptionType.SingleValue); + CommandOption noBuild = app.Option( + "--no-build", "Do not build the project before running.", + CommandOptionType.BoolValue); CommandOption project = app.Option( "-p|--project", "The path to the project file to run (defaults to the current directory if there is only one project).", CommandOptionType.SingleValue); @@ -38,6 +41,7 @@ namespace Microsoft.DotNet.Tools.Run runCmd.Configuration = configuration.Value(); runCmd.Framework = framework.Value(); + runCmd.NoBuild = noBuild.BoolValue ?? false; runCmd.Project = project.Value(); runCmd.Args = app.RemainingArguments; diff --git a/src/dotnet/commands/dotnet-run3/Run3Command.cs b/src/dotnet/commands/dotnet-run3/Run3Command.cs index c7c3ee09f..d23d20981 100644 --- a/src/dotnet/commands/dotnet-run3/Run3Command.cs +++ b/src/dotnet/commands/dotnet-run3/Run3Command.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.IO; using System.Linq; -using Microsoft.Build.Execution; +using Microsoft.Build.Evaluation; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.Tools.MSBuild; @@ -15,6 +15,7 @@ namespace Microsoft.DotNet.Tools.Run { public string Configuration { get; set; } public string Framework { get; set; } + public bool NoBuild { get; set; } public string Project { get; set; } public IReadOnlyList Args { get; set; } @@ -28,7 +29,10 @@ namespace Microsoft.DotNet.Tools.Run { Initialize(); - EnsureProjectIsBuilt(); + if (!NoBuild) + { + EnsureProjectIsBuilt(); + } ICommand runCommand = GetRunCommand(); @@ -80,21 +84,16 @@ namespace Microsoft.DotNet.Tools.Run globalProperties.Add("TargetFramework", Framework); } - ProjectInstance projectInstance = new ProjectInstance(Project, globalProperties, null); + Project project = new Project(Project, globalProperties, null); - string runProgram = projectInstance.GetPropertyValue("RunCommand"); + string runProgram = project.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}'.")); + ThrowUnableToRunError(project); } - string runArguments = projectInstance.GetPropertyValue("RunArguments"); - string runWorkingDirectory = projectInstance.GetPropertyValue("RunWorkingDirectory"); + string runArguments = project.GetPropertyValue("RunArguments"); + string runWorkingDirectory = project.GetPropertyValue("RunWorkingDirectory"); string fullArguments = runArguments; if (_args.Any()) @@ -108,6 +107,30 @@ namespace Microsoft.DotNet.Tools.Run .WorkingDirectory(runWorkingDirectory); } + private void ThrowUnableToRunError(Project project) + { + string unableToRunYourProjectMessage = "Unable to run your project."; + + string targetFrameworks = project.GetPropertyValue("TargetFrameworks"); + if (!string.IsNullOrEmpty(targetFrameworks)) + { + string targetFramework = project.GetPropertyValue("TargetFramework"); + if (string.IsNullOrEmpty(targetFramework)) + { + throw new GracefulException(string.Join(Environment.NewLine, + unableToRunYourProjectMessage, + "Your project targets multiple frameworks. Please specify which framework to run using '--framework'.")); + } + } + + string outputType = project.GetPropertyValue("OutputType"); + + throw new GracefulException(string.Join(Environment.NewLine, + unableToRunYourProjectMessage, + "Please ensure you have a runnable project type and ensure 'dotnet run' supports this project.", + $"The current OutputType is '{outputType}'.")); + } + private void Initialize() { if (string.IsNullOrWhiteSpace(Project)) From 469f7be5c3fb6ac54cffa9b9964e635d083c3940 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Thu, 13 Oct 2016 17:26:21 -0500 Subject: [PATCH 2/4] Add test for dotnet run with multiple frameworks. --- Microsoft.DotNet.Cli.sln | 19 +++++++++++++ .../MSBuildAppWithMultipleFrameworks.csproj | 28 +++++++++++++++++++ .../Program.cs | 12 ++++++++ .../GivenDotnetRun3RunsCsProj.cs | 26 +++++++++++++++++ .../dotnet-run3.Tests/dotnet-run3.Tests.xproj | 18 ++++++++++++ 5 files changed, 103 insertions(+) create mode 100644 TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/MSBuildAppWithMultipleFrameworks.csproj create mode 100644 TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/Program.cs create mode 100644 test/dotnet-run3.Tests/dotnet-run3.Tests.xproj diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index f3813694a..e16bf0d86 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -174,6 +174,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-test3.Tests", "test\ EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dotnet-cli-build", "build_projects\dotnet-cli-build\dotnet-cli-build.csproj", "{8A2FA2D8-0DA1-4814-B5C1-2ECEAA613EB1}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-run3.Tests", "test\dotnet-run3.Tests\dotnet-run3.Tests.xproj", "{9229D2A5-E2D1-4BEE-BC89-EFE65042842F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -1018,6 +1020,22 @@ Global {8A2FA2D8-0DA1-4814-B5C1-2ECEAA613EB1}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {8A2FA2D8-0DA1-4814-B5C1-2ECEAA613EB1}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {8A2FA2D8-0DA1-4814-B5C1-2ECEAA613EB1}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.Debug|x64.ActiveCfg = Debug|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.Debug|x64.Build.0 = Debug|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.Release|Any CPU.Build.0 = Release|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.Release|x64.ActiveCfg = Release|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.Release|x64.Build.0 = Release|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -1083,5 +1101,6 @@ Global {FBE4F1D6-BA4C-46D9-8286-4EE4B032D01E} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {90236A80-4B84-41D3-A161-AA20709776B1} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} {8A2FA2D8-0DA1-4814-B5C1-2ECEAA613EB1} = {88278B81-7649-45DC-8A6A-D3A645C5AFC3} + {9229D2A5-E2D1-4BEE-BC89-EFE65042842F} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} EndGlobalSection EndGlobal diff --git a/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/MSBuildAppWithMultipleFrameworks.csproj b/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/MSBuildAppWithMultipleFrameworks.csproj new file mode 100644 index 000000000..abcd6d58c --- /dev/null +++ b/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/MSBuildAppWithMultipleFrameworks.csproj @@ -0,0 +1,28 @@ + + + + + + Exe + net451;netcoreapp1.0 + + + + + 1.0.0-alpha-20161010-1 + All + + + + + 1.0.1 + + + + + + + + + + \ No newline at end of file diff --git a/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/Program.cs b/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/Program.cs new file mode 100644 index 000000000..f5f4b6d13 --- /dev/null +++ b/TestAssets/TestProjects/MSBuildAppWithMultipleFrameworks/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace ConsoleApplication +{ + public class Program + { + public static void Main() + { + Console.WriteLine("Hello World!"); + } + } +} diff --git a/test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs b/test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs index 62183ef9e..5583ea382 100644 --- a/test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs +++ b/test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs @@ -87,5 +87,31 @@ namespace Microsoft.DotNet.Cli.Run3.Tests .And .HaveStdOutContaining("Hello World!"); } + + [Fact] + public void ItReportsAGoodErrorWhenProjectHasMultipleFrameworks() + { + var testAppName = "MSBuildAppWithMultipleFrameworks"; + var testInstance = TestAssetsManager + .CreateTestInstance(testAppName); + + var testProjectDirectory = testInstance.TestRoot; + + new Restore3Command() + .WithWorkingDirectory(testProjectDirectory) + .Execute() + .Should() + .Pass(); + + // use --no-build so this test can run on all platforms. + // the test app targets net451, which can't be built on non-Windows + new Run3Command() + .WithWorkingDirectory(testProjectDirectory) + .ExecuteWithCapturedOutput("--no-build") + .Should() + .Fail() + .And + .HaveStdErrContaining("--framework"); + } } } \ No newline at end of file diff --git a/test/dotnet-run3.Tests/dotnet-run3.Tests.xproj b/test/dotnet-run3.Tests/dotnet-run3.Tests.xproj new file mode 100644 index 000000000..781162867 --- /dev/null +++ b/test/dotnet-run3.Tests/dotnet-run3.Tests.xproj @@ -0,0 +1,18 @@ + + + + 14.0.24720 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + 9229D2A5-E2D1-4BEE-BC89-EFE65042842F + Microsoft.DotNet.Cli.Run3.Tests + ..\..\artifacts\obj\$(MSBuildProjectName) + ..\..\artifacts\bin + + + 2.0 + + + \ No newline at end of file From b32aedde5a1b7dd80688f271c2d8e82bd19a2ab1 Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 17 Oct 2016 18:38:03 -0500 Subject: [PATCH 3/4] Add /p:SkipInvalidConfigurations=true to fix the test --- test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs b/test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs index 5583ea382..a946e23b9 100644 --- a/test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs +++ b/test/dotnet-run3.Tests/GivenDotnetRun3RunsCsProj.cs @@ -99,7 +99,7 @@ namespace Microsoft.DotNet.Cli.Run3.Tests new Restore3Command() .WithWorkingDirectory(testProjectDirectory) - .Execute() + .Execute("/p:SkipInvalidConfigurations=true") .Should() .Pass(); From 1b6502848e1c2b3909b4d278a849a287d1ccc97c Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Mon, 17 Oct 2016 21:00:48 -0500 Subject: [PATCH 4/4] Respond to PR feedback. --- src/dotnet/commands/dotnet-run3/Run3Command.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dotnet/commands/dotnet-run3/Run3Command.cs b/src/dotnet/commands/dotnet-run3/Run3Command.cs index d23d20981..531a0a7e5 100644 --- a/src/dotnet/commands/dotnet-run3/Run3Command.cs +++ b/src/dotnet/commands/dotnet-run3/Run3Command.cs @@ -20,6 +20,7 @@ namespace Microsoft.DotNet.Tools.Run public IReadOnlyList Args { get; set; } private List _args; + private bool ShouldBuild => !NoBuild; public Run3Command() { @@ -29,7 +30,7 @@ namespace Microsoft.DotNet.Tools.Run { Initialize(); - if (!NoBuild) + if (ShouldBuild) { EnsureProjectIsBuilt(); }