From 44483ddc98c4091dd455fe4e89c449c449b0eaec Mon Sep 17 00:00:00 2001 From: Eric Erhardt Date: Tue, 19 Apr 2016 22:51:32 -0500 Subject: [PATCH] Remove System.CommandLine dependency. Also removed the dependency on Microsoft.Extensions.CommandLineUtils.Sources NuGet package and instead just checking the source files into our repo as internal classes. Fix #2526 --- Microsoft.DotNet.Cli.sln | 21 +- .../DotnetBaseParams.cs | 6 +- .../project.json | 11 +- .../AssemblyInfoOptions.cs | 66 +-- .../CommonCompilerOptionsExtensions.cs | 126 +---- .../project.json | 3 +- src/dotnet-compile-fsc/Program.cs | 450 +++++++-------- src/dotnet-compile-fsc/project.json | 7 +- src/dotnet/CommandLine/CommandArgument.cs | 29 + .../CommandLine/CommandLineApplication.cs | 530 ++++++++++++++++++ src/dotnet/CommandLine/CommandOption.cs | 106 ++++ src/dotnet/CommandLine/CommandOptionType.cs | 13 + .../CommandLine/CommandParsingException.cs | 18 + .../AssemblyInfoOptionsCommandLine.cs | 79 +++ .../CommonCompilerOptionsCommandLine.cs | 104 ++++ .../commands/dotnet-compile-csc/Program.cs | 169 +++--- .../dotnet-compile-native/ArgumentsParser.cs | 230 ++++---- .../DirectoryExtensions.cs | 9 - .../IPlatformNativeStep.cs | 12 +- .../IntermediateCompiler.cs | 9 +- .../Mac/MacCppCompileStep.cs | 5 - .../Windows/WindowsCppCompileStep.cs | 4 - .../Windows/WindowsLinkStep.cs | 4 - .../RuntimeExtensions.cs | 11 - .../RuntimeInformationExtensions.cs | 9 - .../commands/dotnet-compile/Compiler.cs | 35 +- .../dotnet-compile/ManagedCompiler.cs | 2 +- src/dotnet/commands/dotnet-new/Program.cs | 2 +- src/dotnet/commands/dotnet-pack/Program.cs | 4 +- .../dotnet-projectmodel-server/Program.cs | 2 +- src/dotnet/commands/dotnet-publish/Program.cs | 4 +- .../commands/dotnet-repl-csi/Program.cs | 4 +- src/dotnet/commands/dotnet-repl/Program.cs | 2 +- src/dotnet/commands/dotnet-resgen/Program.cs | 56 +- .../commands/dotnet-resgen/ResgenCommand.cs | 4 +- src/dotnet/commands/dotnet-restore/Program.cs | 8 +- src/dotnet/commands/dotnet-run/Program.cs | 67 +-- .../commands/dotnet-test/DotnetTestParams.cs | 4 +- src/dotnet/dotnet.xproj | 1 - src/dotnet/project.json | 6 - .../Tests.cs | 19 - 41 files changed, 1411 insertions(+), 840 deletions(-) create mode 100644 src/dotnet/CommandLine/CommandArgument.cs create mode 100644 src/dotnet/CommandLine/CommandLineApplication.cs create mode 100644 src/dotnet/CommandLine/CommandOption.cs create mode 100644 src/dotnet/CommandLine/CommandOptionType.cs create mode 100644 src/dotnet/CommandLine/CommandParsingException.cs create mode 100644 src/dotnet/commands/dotnet-compile-csc/AssemblyInfoOptionsCommandLine.cs create mode 100644 src/dotnet/commands/dotnet-compile-csc/CommonCompilerOptionsCommandLine.cs diff --git a/Microsoft.DotNet.Cli.sln b/Microsoft.DotNet.Cli.sln index 8ca363601..a4edf1147 100644 --- a/Microsoft.DotNet.Cli.sln +++ b/Microsoft.DotNet.Cli.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.23107.0 +VisualStudioVersion = 14.0.25123.0 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{ED2FE3E2-F7E7-4389-8231-B65123F2076F}" EndProject @@ -101,6 +101,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "TestPackages", "TestPackage EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "dotnet-dependency-tool-invoker", "TestAssets\TestPackages\dotnet-dependency-tool-invoker\dotnet-dependency-tool-invoker.xproj", "{C26A48BB-193F-450C-AB09-4D3324C78188}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.DotNet.Compiler.Common.Tests", "test\Microsoft.DotNet.Compiler.Common.Tests\Microsoft.DotNet.Compiler.Common.Tests.xproj", "{44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -705,6 +707,22 @@ Global {C26A48BB-193F-450C-AB09-4D3324C78188}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU {C26A48BB-193F-450C-AB09-4D3324C78188}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU {C26A48BB-193F-450C-AB09-4D3324C78188}.RelWithDebInfo|x64.Build.0 = Release|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Debug|x64.ActiveCfg = Debug|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Debug|x64.Build.0 = Debug|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.MinSizeRel|Any CPU.ActiveCfg = Debug|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.MinSizeRel|Any CPU.Build.0 = Debug|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.MinSizeRel|x64.ActiveCfg = Debug|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.MinSizeRel|x64.Build.0 = Debug|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Release|Any CPU.Build.0 = Release|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Release|x64.ActiveCfg = Release|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.Release|x64.Build.0 = Release|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|Any CPU.ActiveCfg = Release|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|Any CPU.Build.0 = Release|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|x64.ActiveCfg = Release|Any CPU + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5}.RelWithDebInfo|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -752,5 +770,6 @@ Global {ADA7052B-884B-4776-8B8D-D04191D0AA70} = {ED2FE3E2-F7E7-4389-8231-B65123F2076F} {1AB5B24B-B317-4142-A5D1-A6E84F15BA34} = {ADA7052B-884B-4776-8B8D-D04191D0AA70} {C26A48BB-193F-450C-AB09-4D3324C78188} = {1AB5B24B-B317-4142-A5D1-A6E84F15BA34} + {44E7D1AC-DCF1-4A18-9C22-F09E6BB302B5} = {17735A9D-BFD9-4585-A7CB-3208CA6EA8A7} EndGlobalSection EndGlobal diff --git a/TestAssets/TestPackages/dotnet-dependency-tool-invoker/DotnetBaseParams.cs b/TestAssets/TestPackages/dotnet-dependency-tool-invoker/DotnetBaseParams.cs index 5e092fdef..0d9e07748 100644 --- a/TestAssets/TestPackages/dotnet-dependency-tool-invoker/DotnetBaseParams.cs +++ b/TestAssets/TestPackages/dotnet-dependency-tool-invoker/DotnetBaseParams.cs @@ -1,15 +1,11 @@ // 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.Diagnostics; using System.IO; -using System.Linq; -using Microsoft.Dnx.Runtime.Common.CommandLine; +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; using NuGet.Frameworks; -using static System.Int32; namespace Microsoft.DotNet.Tools.DependencyInvoker { diff --git a/TestAssets/TestPackages/dotnet-dependency-tool-invoker/project.json b/TestAssets/TestPackages/dotnet-dependency-tool-invoker/project.json index 5d0e1c94d..bdf52e12f 100644 --- a/TestAssets/TestPackages/dotnet-dependency-tool-invoker/project.json +++ b/TestAssets/TestPackages/dotnet-dependency-tool-invoker/project.json @@ -3,6 +3,10 @@ "compilationOptions": { "emitEntryPoint": true }, + "compile": [ + "**/*.cs", + "../../../src/dotnet/CommandLine/*.cs" + ], "dependencies": { "Microsoft.NETCore.App": { "type": "platform", @@ -10,12 +14,7 @@ }, "Microsoft.DotNet.Cli.Utils": "1.0.0-*", "Microsoft.DotNet.ProjectModel": "1.0.0-*", - "Microsoft.DotNet.Compiler.Common": "1.0.0-*", - "Microsoft.Extensions.CommandLineUtils.Sources": { - "type": "build", - "version": "1.0.0-rc2-16453" - }, - "System.CommandLine": "0.1.0-e160323-1" + "Microsoft.DotNet.Compiler.Common": "1.0.0-*" }, "frameworks": { "netcoreapp1.0": { diff --git a/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoOptions.cs b/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoOptions.cs index 0fe593c8d..251d0f48f 100644 --- a/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoOptions.cs +++ b/src/Microsoft.DotNet.Compiler.Common/AssemblyInfoOptions.cs @@ -3,30 +3,29 @@ using Microsoft.DotNet.ProjectModel; using System.Collections.Generic; -using System.CommandLine; using NuGet.Frameworks; namespace Microsoft.DotNet.Cli.Compiler.Common { public class AssemblyInfoOptions { - private const string TitleOptionName = "title"; + public static readonly string TitleOptionName = "title"; - private const string DescriptionOptionName = "description"; + public static readonly string DescriptionOptionName = "description"; - private const string CopyrightOptionName = "copyright"; + public static readonly string CopyrightOptionName = "copyright"; - private const string AssemblyFileVersionOptionName = "file-version"; + public static readonly string AssemblyFileVersionOptionName = "file-version"; - private const string AssemblyVersionOptionName = "version"; + public static readonly string AssemblyVersionOptionName = "version"; - private const string InformationalVersionOptionName = "informational-version"; + public static readonly string InformationalVersionOptionName = "informational-version"; - private const string CultureOptionName = "culture"; + public static readonly string CultureOptionName = "culture"; - private const string NeutralCultureOptionName = "neutral-language"; + public static readonly string NeutralCultureOptionName = "neutral-language"; - private const string TargetFrameworkOptionName = "target-framework"; + public static readonly string TargetFrameworkOptionName = "target-framework"; public string Title { get; set; } @@ -73,49 +72,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common }; } - public static AssemblyInfoOptions Parse(ArgumentSyntax syntax) - { - string version = null; - string informationalVersion = null; - string fileVersion = null; - string title = null; - string description = null; - string copyright = null; - string culture = null; - string neutralCulture = null; - string targetFramework = null; - - syntax.DefineOption(AssemblyVersionOptionName, ref version, UnescapeNewlines, "Assembly version"); - - syntax.DefineOption(TitleOptionName, ref title, UnescapeNewlines, "Assembly title"); - - syntax.DefineOption(DescriptionOptionName, ref description, UnescapeNewlines, "Assembly description"); - - syntax.DefineOption(CopyrightOptionName, ref copyright, UnescapeNewlines, "Assembly copyright"); - - syntax.DefineOption(NeutralCultureOptionName, ref neutralCulture, UnescapeNewlines, "Assembly neutral culture"); - - syntax.DefineOption(CultureOptionName, ref culture, UnescapeNewlines, "Assembly culture"); - - syntax.DefineOption(InformationalVersionOptionName, ref informationalVersion, UnescapeNewlines, "Assembly informational version"); - - syntax.DefineOption(AssemblyFileVersionOptionName, ref fileVersion, UnescapeNewlines, "Assembly title"); - - syntax.DefineOption(TargetFrameworkOptionName, ref targetFramework, UnescapeNewlines, "Assembly target framework"); - - return new AssemblyInfoOptions() - { - AssemblyFileVersion = fileVersion, - AssemblyVersion = version, - Copyright = copyright, - NeutralLanguage = neutralCulture, - Description = description, - InformationalVersion = informationalVersion, - Title = title, - TargetFramework = targetFramework - }; - } - public static IEnumerable SerializeToArgs(AssemblyInfoOptions assemblyInfoOptions) { var options = new List(); @@ -165,10 +121,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common return $"--{optionName}:{EscapeNewlines(value)}"; } - private static string UnescapeNewlines(string text) - { - return text.Replace("\\r", "\r").Replace("\\n", "\n"); - } private static string EscapeNewlines(string text) { return text.Replace("\r", "\\r").Replace("\n", "\\n"); diff --git a/src/Microsoft.DotNet.Compiler.Common/CommonCompilerOptionsExtensions.cs b/src/Microsoft.DotNet.Compiler.Common/CommonCompilerOptionsExtensions.cs index fe945e3a3..0c47686c1 100644 --- a/src/Microsoft.DotNet.Compiler.Common/CommonCompilerOptionsExtensions.cs +++ b/src/Microsoft.DotNet.Compiler.Common/CommonCompilerOptionsExtensions.cs @@ -1,9 +1,7 @@ // 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.CommandLine; using System.Linq; using Microsoft.DotNet.ProjectModel; @@ -12,115 +10,51 @@ namespace Microsoft.DotNet.Cli.Compiler.Common { public static class CommonCompilerOptionsExtensions { - internal static readonly OptionTemplate s_definesTemplate = new OptionTemplate("define"); + public static readonly string DefineOptionName = "define"; + public static readonly string SuppressWarningOptionName = "suppress-warning"; + public static readonly string LanguageVersionOptionName = "language-version"; + public static readonly string PlatformOptionName = "platform"; + public static readonly string AllowUnsafeOptionName = "allow-unsafe"; + public static readonly string WarningsAsErrorsOptionName = "warnings-as-errors"; + public static readonly string OptimizeOptionName = "optimize"; + public static readonly string KeyFileOptionName = "key-file"; + public static readonly string DelaySignOptionName = "delay-sign"; + public static readonly string PublicSignOptionName = "public-sign"; + public static readonly string DebugTypeOptionName = "debug-type"; + public static readonly string EmitEntryPointOptionName = "emit-entry-point"; + public static readonly string GenerateXmlDocumentationOptionName = "generate-xml-documentation"; + public static readonly string AdditionalArgumentsOptionName = "additional-argument"; + public static readonly string OutputNameOptionName = "output-name"; - internal static readonly OptionTemplate s_suppressWarningTemplate = new OptionTemplate("suppress-warning"); + internal static readonly OptionTemplate s_definesTemplate = new OptionTemplate(DefineOptionName); - internal static readonly OptionTemplate s_languageVersionTemplate = new OptionTemplate("language-version"); + internal static readonly OptionTemplate s_suppressWarningTemplate = new OptionTemplate(SuppressWarningOptionName); - internal static readonly OptionTemplate s_platformTemplate = new OptionTemplate("platform"); + internal static readonly OptionTemplate s_languageVersionTemplate = new OptionTemplate(LanguageVersionOptionName); - internal static readonly OptionTemplate s_allowUnsafeTemplate = new OptionTemplate("allow-unsafe"); + internal static readonly OptionTemplate s_platformTemplate = new OptionTemplate(PlatformOptionName); - internal static readonly OptionTemplate s_warningsAsErrorsTemplate = new OptionTemplate("warnings-as-errors"); + internal static readonly OptionTemplate s_allowUnsafeTemplate = new OptionTemplate(AllowUnsafeOptionName); - internal static readonly OptionTemplate s_optimizeTemplate = new OptionTemplate("optimize"); + internal static readonly OptionTemplate s_warningsAsErrorsTemplate = new OptionTemplate(WarningsAsErrorsOptionName); - internal static readonly OptionTemplate s_keyFileTemplate = new OptionTemplate("key-file"); + internal static readonly OptionTemplate s_optimizeTemplate = new OptionTemplate(OptimizeOptionName); - internal static readonly OptionTemplate s_delaySignTemplate = new OptionTemplate("delay-sign"); + internal static readonly OptionTemplate s_keyFileTemplate = new OptionTemplate(KeyFileOptionName); - internal static readonly OptionTemplate s_publicSignTemplate = new OptionTemplate("public-sign"); + internal static readonly OptionTemplate s_delaySignTemplate = new OptionTemplate(DelaySignOptionName); - internal static readonly OptionTemplate s_debugTypeTemplate = new OptionTemplate("debug-type"); + internal static readonly OptionTemplate s_publicSignTemplate = new OptionTemplate(PublicSignOptionName); - internal static readonly OptionTemplate s_emitEntryPointTemplate = new OptionTemplate("emit-entry-point"); + internal static readonly OptionTemplate s_debugTypeTemplate = new OptionTemplate(DebugTypeOptionName); - internal static readonly OptionTemplate s_generateXmlDocumentation = new OptionTemplate("generate-xml-documentation"); + internal static readonly OptionTemplate s_emitEntryPointTemplate = new OptionTemplate(EmitEntryPointOptionName); - internal static readonly OptionTemplate s_additionalArgumentsTemplate = new OptionTemplate("additional-argument"); + internal static readonly OptionTemplate s_generateXmlDocumentation = new OptionTemplate(GenerateXmlDocumentationOptionName); - internal static readonly OptionTemplate s_outputNameTemplate = new OptionTemplate("output-name"); + internal static readonly OptionTemplate s_additionalArgumentsTemplate = new OptionTemplate(AdditionalArgumentsOptionName); - public static CommonCompilerOptions Parse(ArgumentSyntax syntax) - { - IReadOnlyList defines = null; - IReadOnlyList suppressWarnings = null; - string languageVersion = null; - string platform = null; - string debugType = null; - bool? allowUnsafe = null; - bool? warningsAsErrors = null; - bool? optimize = null; - string keyFile = null; - bool? delaySign = null; - bool? publicSign = null; - bool? emitEntryPoint = null; - bool? generateXmlDocumentation = null; - string outputName = null; - IReadOnlyList additionalArguments = null; - - Func nullableBoolConverter = v => bool.Parse(v); - - syntax.DefineOptionList(s_definesTemplate.LongName, ref defines, "Preprocessor definitions"); - - syntax.DefineOptionList(s_suppressWarningTemplate.LongName, ref suppressWarnings, "Suppresses the specified warning"); - - syntax.DefineOptionList(s_additionalArgumentsTemplate.LongName, ref additionalArguments, "Pass the additional argument directly to the compiler"); - - syntax.DefineOption(s_debugTypeTemplate.LongName, ref debugType, "The type of PDB to emit: portable or full"); - - syntax.DefineOption(s_languageVersionTemplate.LongName, ref languageVersion, - "The version of the language used to compile"); - - syntax.DefineOption(s_platformTemplate.LongName, ref platform, - "The target platform"); - - syntax.DefineOption(s_allowUnsafeTemplate.LongName, ref allowUnsafe, - nullableBoolConverter, "Allow unsafe code"); - - syntax.DefineOption(s_warningsAsErrorsTemplate.LongName, ref warningsAsErrors, - nullableBoolConverter, "Turn all warnings into errors"); - - syntax.DefineOption(s_optimizeTemplate.LongName, ref optimize, - nullableBoolConverter, "Enable compiler optimizations"); - - syntax.DefineOption(s_keyFileTemplate.LongName, ref keyFile, - "Path to file containing the key to strong-name sign the output assembly"); - - syntax.DefineOption(s_delaySignTemplate.LongName, ref delaySign, - nullableBoolConverter, "Delay-sign the output assembly"); - - syntax.DefineOption(s_publicSignTemplate.LongName, ref publicSign, - nullableBoolConverter, "Public-sign the output assembly"); - - syntax.DefineOption(s_emitEntryPointTemplate.LongName, ref emitEntryPoint, - nullableBoolConverter, "Output an executable console program"); - - syntax.DefineOption(s_generateXmlDocumentation.LongName, ref generateXmlDocumentation, - nullableBoolConverter, "Generate XML documentation file"); - - syntax.DefineOption(s_outputNameTemplate.LongName, ref outputName, "Output assembly name"); - - return new CommonCompilerOptions - { - Defines = defines, - SuppressWarnings = suppressWarnings, - LanguageVersion = languageVersion, - Platform = platform, - AllowUnsafe = allowUnsafe, - WarningsAsErrors = warningsAsErrors, - Optimize = optimize, - KeyFile = keyFile, - DelaySign = delaySign, - PublicSign = publicSign, - DebugType = debugType, - EmitEntryPoint = emitEntryPoint, - GenerateXmlDocumentation = generateXmlDocumentation, - OutputName = outputName, - AdditionalArguments = additionalArguments - }; - } + internal static readonly OptionTemplate s_outputNameTemplate = new OptionTemplate(OutputNameOptionName); public static IEnumerable SerializeToArgs(this CommonCompilerOptions options) { diff --git a/src/Microsoft.DotNet.Compiler.Common/project.json b/src/Microsoft.DotNet.Compiler.Common/project.json index 5d64a9153..6ca18863b 100644 --- a/src/Microsoft.DotNet.Compiler.Common/project.json +++ b/src/Microsoft.DotNet.Compiler.Common/project.json @@ -7,8 +7,7 @@ "Microsoft.CodeAnalysis.CSharp": "1.3.0-beta1-20160410-01 ", "Microsoft.DotNet.ProjectModel": "1.0.0-*", "Microsoft.DotNet.Cli.Utils": "1.0.0-*", - "Microsoft.DotNet.Files": "1.0.0-*", - "System.CommandLine": "0.1.0-e160323-1" + "Microsoft.DotNet.Files": "1.0.0-*" }, "frameworks": { "netstandard1.5": { diff --git a/src/dotnet-compile-fsc/Program.cs b/src/dotnet-compile-fsc/Program.cs index 6c1be025c..d6e28b04e 100644 --- a/src/dotnet-compile-fsc/Program.cs +++ b/src/dotnet-compile-fsc/Program.cs @@ -2,19 +2,17 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.CommandLine; using System.Collections.Generic; using System.IO; using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using System.Text; - +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Compiler.Common; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.ProjectModel.Resolution; -using NuGet.Frameworks; -using System.Reflection; namespace Microsoft.DotNet.Tools.Compiler.Fsc { @@ -25,240 +23,228 @@ namespace Microsoft.DotNet.Tools.Compiler.Fsc { DebugHelper.HandleDebugSwitch(ref args); - CommonCompilerOptions commonOptions = null; - AssemblyInfoOptions assemblyInfoOptions = null; - string tempOutDir = null; - IReadOnlyList references = Array.Empty(); - IReadOnlyList resources = Array.Empty(); - IReadOnlyList sources = Array.Empty(); - string outputName = null; - var help = false; - var returnCode = 0; - string helpText = null; + CommandLineApplication app = new CommandLineApplication(); + app.Name = "dotnet compile-fsc"; + app.FullName = ".NET F# Compiler"; + app.Description = "F# Compiler for the .NET Platform"; + app.HelpOption("-h|--help"); + + CommonCompilerOptionsCommandLine commonCompilerCommandLine = CommonCompilerOptionsCommandLine.AddOptions(app); + AssemblyInfoOptionsCommandLine assemblyInfoCommandLine = AssemblyInfoOptionsCommandLine.AddOptions(app); + + CommandOption tempOutputOption = app.Option("--temp-output ", "Compilation temporary directory", CommandOptionType.SingleValue); + CommandOption outputNameOption = app.Option("--out ", "Name of the output assembly", CommandOptionType.SingleValue); + CommandOption referencesOption = app.Option("--reference ...", "Path to a compiler metadata reference", CommandOptionType.MultipleValue); + CommandOption resourcesOption = app.Option("--resource ...", "Resources to embed", CommandOptionType.MultipleValue); + CommandArgument sourcesArgument = app.Argument("...", "Compilation sources", multipleValues: true); + + app.OnExecute(() => + { + if (!tempOutputOption.HasValue()) + { + Reporter.Error.WriteLine("Option '--temp-output' is required"); + return ExitFailed; + } + + CommonCompilerOptions commonOptions = commonCompilerCommandLine.GetOptionValues(); + + AssemblyInfoOptions assemblyInfoOptions = assemblyInfoCommandLine.GetOptionValues(); + + // TODO less hacky + bool targetNetCore = + commonOptions.Defines.Contains("DNXCORE50") || + commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARDAPP1_")).Any() || + commonOptions.Defines.Where(d => d.StartsWith("NETCOREAPP1_")).Any() || + commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARD1_")).Any(); + + // Get FSC Path upfront to use it for win32manifest path + string tempOutDir = tempOutputOption.Value(); + var fscCommandSpec = ResolveFsc(null, tempOutDir); + var fscExeFile = fscCommandSpec.FscExeFile; + var fscExeDir = fscCommandSpec.FscExeDir; + + // FSC arguments + var allArgs = new List(); + + //HACK fsc raise error FS0208 if target exe doesnt have extension .exe + bool hackFS0208 = targetNetCore && commonOptions.EmitEntryPoint == true; + + string outputName = outputNameOption.Value(); + var originalOutputName = outputName; + + if (outputName != null) + { + if (hackFS0208) + { + outputName = Path.ChangeExtension(outputName, ".exe"); + } + + allArgs.Add($"--out:{outputName}"); + } + + //let's pass debugging type only if options.DebugType is specified, until + //portablepdb are confirmed to work. + //so it's possibile to test portable pdb without breaking existing build + if (string.IsNullOrEmpty(commonOptions.DebugType)) + { + //debug info (only windows pdb supported, not portablepdb) + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + allArgs.Add("--debug"); + //TODO check if full or pdbonly + allArgs.Add("--debug:pdbonly"); + } + else + allArgs.Add("--debug-"); + } + else + { + allArgs.Add("--debug"); + allArgs.Add($"--debug:{commonOptions.DebugType}"); + } + + // Default options + allArgs.Add("--noframework"); + allArgs.Add("--nologo"); + allArgs.Add("--simpleresolution"); + allArgs.Add("--nocopyfsharpcore"); + + // project.json compilationOptions + if (commonOptions.Defines != null) + { + allArgs.AddRange(commonOptions.Defines.Select(def => $"--define:{def}")); + } + + if (commonOptions.GenerateXmlDocumentation == true) + { + allArgs.Add($"--doc:{Path.ChangeExtension(outputName, "xml")}"); + } + + if (commonOptions.KeyFile != null) + { + allArgs.Add($"--keyfile:{commonOptions.KeyFile}"); + } + + if (commonOptions.Optimize == true) + { + allArgs.Add("--optimize+"); + } + + //--resource doesnt expect " + //bad: --resource:"path/to/file",name + //ok: --resource:path/to/file,name + allArgs.AddRange(resourcesOption.Values.Select(resource => $"--resource:{resource.Replace("\"", "")}")); + + allArgs.AddRange(referencesOption.Values.Select(r => $"-r:{r}")); + + if (commonOptions.EmitEntryPoint != true) + { + allArgs.Add("--target:library"); + } + else + { + allArgs.Add("--target:exe"); + + //HACK we need default.win32manifest for exe + var win32manifestPath = Path.Combine(fscExeDir, "..", "..", "runtimes", "any", "native", "default.win32manifest"); + allArgs.Add($"--win32manifest:{win32manifestPath}"); + } + + if (commonOptions.SuppressWarnings != null && commonOptions.SuppressWarnings.Any()) + { + allArgs.Add("--nowarn:" + string.Join(",", commonOptions.SuppressWarnings.ToArray())); + } + + if (commonOptions.LanguageVersion != null) + { + // Not used in fsc + } + + if (commonOptions.Platform != null) + { + allArgs.Add($"--platform:{commonOptions.Platform}"); + } + + if (commonOptions.AllowUnsafe == true) + { + } + + if (commonOptions.WarningsAsErrors == true) + { + allArgs.Add("--warnaserror"); + } + + //set target framework + if (targetNetCore) + { + allArgs.Add("--targetprofile:netcore"); + } + + if (commonOptions.DelaySign == true) + { + allArgs.Add("--delaysign+"); + } + + if (commonOptions.PublicSign == true) + { + } + + if (commonOptions.AdditionalArguments != null) + { + // Additional arguments are added verbatim + allArgs.AddRange(commonOptions.AdditionalArguments); + } + + // Generate assembly info + var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.fs"); + File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateFSharp(assemblyInfoOptions)); + + //source files + assemblyInfo + allArgs.AddRange(GetSourceFiles(sourcesArgument.Values, assemblyInfo).ToArray()); + + //TODO check the switch enabled in fsproj in RELEASE and DEBUG configuration + + var rsp = Path.Combine(tempOutDir, "dotnet-compile-fsc.rsp"); + File.WriteAllLines(rsp, allArgs, Encoding.UTF8); + + // Execute FSC! + var result = RunFsc(new List { $"@{rsp}" }, tempOutDir) + .ForwardStdErr() + .ForwardStdOut() + .Execute(); + + bool successFsc = result.ExitCode == 0; + + if (hackFS0208 && File.Exists(outputName)) + { + if (File.Exists(originalOutputName)) + File.Delete(originalOutputName); + File.Move(outputName, originalOutputName); + } + + //HACK dotnet build require a pdb (crash without), fsc atm cant generate a portable pdb, so an empty pdb is created + string pdbPath = Path.ChangeExtension(outputName, ".pdb"); + if (successFsc && !File.Exists(pdbPath)) + { + File.WriteAllBytes(pdbPath, Array.Empty()); + } + + return result.ExitCode; + }); try { - ArgumentSyntax.Parse(args, syntax => - { - syntax.HandleHelp = false; - syntax.HandleErrors = false; - - commonOptions = CommonCompilerOptionsExtensions.Parse(syntax); - - assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax); - - syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory"); - - syntax.DefineOption("out", ref outputName, "Name of the output assembly"); - - syntax.DefineOptionList("reference", ref references, "Path to a compiler metadata reference"); - - syntax.DefineOptionList("resource", ref resources, "Resources to embed"); - - syntax.DefineOption("h|help", ref help, "Help for compile native."); - - syntax.DefineParameterList("source-files", ref sources, "Compilation sources"); - - helpText = syntax.GetHelpText(); - - if (tempOutDir == null) - { - syntax.ReportError("Option '--temp-output' is required"); - } - }); + return app.Execute(args); } - catch (ArgumentSyntaxException exception) + catch (Exception ex) { - Console.Error.WriteLine(exception.Message); - help = true; - returnCode = ExitFailed; +#if DEBUG + Reporter.Error.WriteLine(ex.ToString()); +#else + Reporter.Error.WriteLine(ex.Message); +#endif + return ExitFailed; } - - if (help) - { - Console.WriteLine(helpText); - - return returnCode; - } - - // TODO less hacky - bool targetNetCore = - commonOptions.Defines.Contains("DNXCORE50") || - commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARDAPP1_")).Any() || - commonOptions.Defines.Where(d => d.StartsWith("NETCOREAPP1_")).Any() || - commonOptions.Defines.Where(d => d.StartsWith("NETSTANDARD1_")).Any(); - - // Get FSC Path upfront to use it for win32manifest path - var fscCommandSpec = ResolveFsc(null, tempOutDir); - var fscExeFile = fscCommandSpec.FscExeFile; - var fscExeDir = fscCommandSpec.FscExeDir; - - // FSC arguments - var allArgs = new List(); - - //HACK fsc raise error FS0208 if target exe doesnt have extension .exe - bool hackFS0208 = targetNetCore && commonOptions.EmitEntryPoint == true; - - var originalOutputName = outputName; - - if (outputName != null) - { - if (hackFS0208) - { - outputName = Path.ChangeExtension(outputName, ".exe"); - } - - allArgs.Add($"--out:{outputName}"); - } - - //let's pass debugging type only if options.DebugType is specified, until - //portablepdb are confirmed to work. - //so it's possibile to test portable pdb without breaking existing build - if (string.IsNullOrEmpty(commonOptions.DebugType)) - { - //debug info (only windows pdb supported, not portablepdb) - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - allArgs.Add("--debug"); - //TODO check if full or pdbonly - allArgs.Add("--debug:pdbonly"); - } - else - allArgs.Add("--debug-"); - } - else - { - allArgs.Add("--debug"); - allArgs.Add($"--debug:{commonOptions.DebugType}"); - } - - // Default options - allArgs.Add("--noframework"); - allArgs.Add("--nologo"); - allArgs.Add("--simpleresolution"); - allArgs.Add("--nocopyfsharpcore"); - - // project.json compilationOptions - if (commonOptions.Defines != null) - { - allArgs.AddRange(commonOptions.Defines.Select(def => $"--define:{def}")); - } - - if (commonOptions.GenerateXmlDocumentation == true) - { - allArgs.Add($"--doc:{Path.ChangeExtension(outputName, "xml")}"); - } - - if (commonOptions.KeyFile != null) - { - allArgs.Add($"--keyfile:{commonOptions.KeyFile}"); - } - - if (commonOptions.Optimize == true) - { - allArgs.Add("--optimize+"); - } - - //--resource doesnt expect " - //bad: --resource:"path/to/file",name - //ok: --resource:path/to/file,name - allArgs.AddRange(resources.Select(resource => $"--resource:{resource.Replace("\"", "")}")); - - allArgs.AddRange(references.Select(r => $"-r:{r}")); - - if (commonOptions.EmitEntryPoint != true) - { - allArgs.Add("--target:library"); - } - else - { - allArgs.Add("--target:exe"); - - //HACK we need default.win32manifest for exe - var win32manifestPath = Path.Combine(fscExeDir, "..", "..", "runtimes", "any", "native", "default.win32manifest"); - allArgs.Add($"--win32manifest:{win32manifestPath}"); - } - - if (commonOptions.SuppressWarnings != null) - { - allArgs.Add("--nowarn:" + string.Join(",", commonOptions.SuppressWarnings.ToArray())); - } - - if (commonOptions.LanguageVersion != null) - { - // Not used in fsc - } - - if (commonOptions.Platform != null) - { - allArgs.Add($"--platform:{commonOptions.Platform}"); - } - - if (commonOptions.AllowUnsafe == true) - { - } - - if (commonOptions.WarningsAsErrors == true) - { - allArgs.Add("--warnaserror"); - } - - //set target framework - if (targetNetCore) - { - allArgs.Add("--targetprofile:netcore"); - } - - if (commonOptions.DelaySign == true) - { - allArgs.Add("--delaysign+"); - } - - if (commonOptions.PublicSign == true) - { - } - - if (commonOptions.AdditionalArguments != null) - { - // Additional arguments are added verbatim - allArgs.AddRange(commonOptions.AdditionalArguments); - } - - // Generate assembly info - var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.fs"); - File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateFSharp(assemblyInfoOptions)); - - //source files + assemblyInfo - allArgs.AddRange(GetSourceFiles(sources, assemblyInfo).ToArray()); - - //TODO check the switch enabled in fsproj in RELEASE and DEBUG configuration - - var rsp = Path.Combine(tempOutDir, "dotnet-compile-fsc.rsp"); - File.WriteAllLines(rsp, allArgs, Encoding.UTF8); - - // Execute FSC! - var result = RunFsc(new List { $"@{rsp}" }, tempOutDir) - .ForwardStdErr() - .ForwardStdOut() - .Execute(); - - bool successFsc = result.ExitCode == 0; - - if (hackFS0208 && File.Exists(outputName)) - { - if (File.Exists(originalOutputName)) - File.Delete(originalOutputName); - File.Move(outputName, originalOutputName); - } - - //HACK dotnet build require a pdb (crash without), fsc atm cant generate a portable pdb, so an empty pdb is created - string pdbPath = Path.ChangeExtension(outputName, ".pdb"); - if (successFsc && !File.Exists(pdbPath)) - { - File.WriteAllBytes(pdbPath, Array.Empty()); - } - - return result.ExitCode; } // The assembly info must be in the last minus 1 position because: diff --git a/src/dotnet-compile-fsc/project.json b/src/dotnet-compile-fsc/project.json index 191cb9050..4bf7e04a3 100644 --- a/src/dotnet-compile-fsc/project.json +++ b/src/dotnet-compile-fsc/project.json @@ -3,9 +3,14 @@ "compilationOptions": { "emitEntryPoint": true }, + "compile": [ + "**/*.cs", + "../dotnet/CommandLine/*.cs", + "../dotnet/commands/dotnet-compile-csc/AssemblyInfoOptionsCommandLine.cs", + "../dotnet/commands/dotnet-compile-csc/CommonCompilerOptionsCommandLine.cs" + ], "dependencies": { "Microsoft.FSharp.Compiler.netcore": "1.0.0-alpha-160318", - "System.CommandLine": "0.1.0-e160323-1", "Microsoft.DotNet.ProjectModel": "1.0.0-*", "Microsoft.DotNet.Compiler.Common": "1.0.0-*", "Microsoft.DotNet.Cli.Utils": "1.0.0-*", diff --git a/src/dotnet/CommandLine/CommandArgument.cs b/src/dotnet/CommandLine/CommandArgument.cs new file mode 100644 index 000000000..045609d79 --- /dev/null +++ b/src/dotnet/CommandLine/CommandArgument.cs @@ -0,0 +1,29 @@ +// 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.Linq; + +namespace Microsoft.DotNet.Cli.CommandLine +{ + internal class CommandArgument + { + public CommandArgument() + { + Values = new List(); + } + + public string Name { get; set; } + public string Description { get; set; } + public List Values { get; private set; } + public bool MultipleValues { get; set; } + public string Value + { + get + { + return Values.FirstOrDefault(); + } + } + } +} diff --git a/src/dotnet/CommandLine/CommandLineApplication.cs b/src/dotnet/CommandLine/CommandLineApplication.cs new file mode 100644 index 000000000..892631207 --- /dev/null +++ b/src/dotnet/CommandLine/CommandLineApplication.cs @@ -0,0 +1,530 @@ +// 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; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.DotNet.Cli.CommandLine +{ + internal class CommandLineApplication + { + // Indicates whether the parser should throw an exception when it runs into an unexpected argument. + // If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all + // remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property. + private readonly bool _throwOnUnexpectedArg; + + public CommandLineApplication(bool throwOnUnexpectedArg = true) + { + _throwOnUnexpectedArg = throwOnUnexpectedArg; + Options = new List(); + Arguments = new List(); + Commands = new List(); + RemainingArguments = new List(); + Invoke = () => 0; + } + + public CommandLineApplication Parent { get; set; } + public string Name { get; set; } + public string FullName { get; set; } + public string Syntax { get; set; } + public string Description { get; set; } + public List Options { get; private set; } + public CommandOption OptionHelp { get; private set; } + public CommandOption OptionVersion { get; private set; } + public List Arguments { get; private set; } + public List RemainingArguments { get; private set; } + public bool IsShowingInformation { get; protected set; } // Is showing help or version? + public Func Invoke { get; set; } + public Func LongVersionGetter { get; set; } + public Func ShortVersionGetter { get; set; } + public List Commands { get; private set; } + + public CommandLineApplication Command(string name, Action configuration, + bool throwOnUnexpectedArg = true) + { + var command = new CommandLineApplication(throwOnUnexpectedArg) { Name = name, Parent = this }; + Commands.Add(command); + configuration(command); + return command; + } + + public CommandOption Option(string template, string description, CommandOptionType optionType) + { + return Option(template, description, optionType, _ => { }); + } + + public CommandOption Option(string template, string description, CommandOptionType optionType, Action configuration) + { + var option = new CommandOption(template, optionType) { Description = description }; + Options.Add(option); + configuration(option); + return option; + } + + public CommandArgument Argument(string name, string description, bool multipleValues = false) + { + return Argument(name, description, _ => { }, multipleValues); + } + + public CommandArgument Argument(string name, string description, Action configuration, bool multipleValues = false) + { + var lastArg = Arguments.LastOrDefault(); + if (lastArg != null && lastArg.MultipleValues) + { + var message = string.Format("The last argument '{0}' accepts multiple values. No more argument can be added.", + lastArg.Name); + throw new InvalidOperationException(message); + } + + var argument = new CommandArgument { Name = name, Description = description, MultipleValues = multipleValues }; + Arguments.Add(argument); + configuration(argument); + return argument; + } + + public void OnExecute(Func invoke) + { + Invoke = invoke; + } + + public void OnExecute(Func> invoke) + { + Invoke = () => invoke().Result; + } + + public int Execute(params string[] args) + { + CommandLineApplication command = this; + CommandOption option = null; + IEnumerator arguments = null; + + for (var index = 0; index < args.Length; index++) + { + var arg = args[index]; + var processed = false; + if (!processed && option == null) + { + string[] longOption = null; + string[] shortOption = null; + + if (arg.StartsWith("--")) + { + longOption = arg.Substring(2).Split(new[] { ':', '=' }, 2); + } + else if (arg.StartsWith("-")) + { + shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2); + } + if (longOption != null) + { + processed = true; + option = command.Options.SingleOrDefault(opt => string.Equals(opt.LongName, longOption[0], StringComparison.Ordinal)); + + if (option == null) + { + HandleUnexpectedArg(command, args, index, argTypeName: "option"); + break; + } + + // If we find a help/version option, show information and stop parsing + if (command.OptionHelp == option) + { + command.ShowHelp(); + return 0; + } + else if (command.OptionVersion == option) + { + command.ShowVersion(); + return 0; + } + + if (longOption.Length == 2) + { + if (!option.TryParse(longOption[1])) + { + command.ShowHint(); + throw new CommandParsingException(command, $"Unexpected value '{longOption[1]}' for option '{option.LongName}'"); + } + option = null; + } + else if (option.OptionType == CommandOptionType.NoValue) + { + // No value is needed for this option + option.TryParse(null); + option = null; + } + } + if (shortOption != null) + { + processed = true; + option = command.Options.SingleOrDefault(opt => string.Equals(opt.ShortName, shortOption[0], StringComparison.Ordinal)); + + // If not a short option, try symbol option + if (option == null) + { + option = command.Options.SingleOrDefault(opt => string.Equals(opt.SymbolName, shortOption[0], StringComparison.Ordinal)); + } + + if (option == null) + { + HandleUnexpectedArg(command, args, index, argTypeName: "option"); + break; + } + + // If we find a help/version option, show information and stop parsing + if (command.OptionHelp == option) + { + command.ShowHelp(); + return 0; + } + else if (command.OptionVersion == option) + { + command.ShowVersion(); + return 0; + } + + if (shortOption.Length == 2) + { + if (!option.TryParse(shortOption[1])) + { + command.ShowHint(); + throw new CommandParsingException(command, $"Unexpected value '{shortOption[1]}' for option '{option.LongName}'"); + } + option = null; + } + else if (option.OptionType == CommandOptionType.NoValue) + { + // No value is needed for this option + option.TryParse(null); + option = null; + } + } + } + + if (!processed && option != null) + { + processed = true; + if (!option.TryParse(arg)) + { + command.ShowHint(); + throw new CommandParsingException(command, $"Unexpected value '{arg}' for option '{option.LongName}'"); + } + option = null; + } + + if (!processed && arguments == null) + { + var currentCommand = command; + foreach (var subcommand in command.Commands) + { + if (string.Equals(subcommand.Name, arg, StringComparison.OrdinalIgnoreCase)) + { + processed = true; + command = subcommand; + break; + } + } + + // If we detect a subcommand + if (command != currentCommand) + { + processed = true; + } + } + if (!processed) + { + if (arguments == null) + { + arguments = new CommandArgumentEnumerator(command.Arguments.GetEnumerator()); + } + if (arguments.MoveNext()) + { + processed = true; + arguments.Current.Values.Add(arg); + } + } + if (!processed) + { + HandleUnexpectedArg(command, args, index, argTypeName: "command or argument"); + break; + } + } + + if (option != null) + { + command.ShowHint(); + throw new CommandParsingException(command, $"Missing value for option '{option.LongName}'"); + } + + return command.Invoke(); + } + + // Helper method that adds a help option + public CommandOption HelpOption(string template) + { + // Help option is special because we stop parsing once we see it + // So we store it separately for further use + OptionHelp = Option(template, "Show help information", CommandOptionType.NoValue); + + return OptionHelp; + } + + public CommandOption VersionOption(string template, + string shortFormVersion, + string longFormVersion = null) + { + if (longFormVersion == null) + { + return VersionOption(template, () => shortFormVersion); + } + else + { + return VersionOption(template, () => shortFormVersion, () => longFormVersion); + } + } + + // Helper method that adds a version option + public CommandOption VersionOption(string template, + Func shortFormVersionGetter, + Func longFormVersionGetter = null) + { + // Version option is special because we stop parsing once we see it + // So we store it separately for further use + OptionVersion = Option(template, "Show version information", CommandOptionType.NoValue); + ShortVersionGetter = shortFormVersionGetter; + LongVersionGetter = longFormVersionGetter ?? shortFormVersionGetter; + + return OptionVersion; + } + + // Show short hint that reminds users to use help option + public void ShowHint() + { + if (OptionHelp != null) + { + Console.WriteLine(string.Format("Specify --{0} for a list of available options and commands.", OptionHelp.LongName)); + } + } + + // Show full help + public void ShowHelp(string commandName = null) + { + var headerBuilder = new StringBuilder("Usage:"); + for (var cmd = this; cmd != null; cmd = cmd.Parent) + { + cmd.IsShowingInformation = true; + headerBuilder.Insert(6, string.Format(" {0}", cmd.Name)); + } + + CommandLineApplication target; + + if (commandName == null || string.Equals(Name, commandName, StringComparison.OrdinalIgnoreCase)) + { + target = this; + } + else + { + target = Commands.SingleOrDefault(cmd => string.Equals(cmd.Name, commandName, StringComparison.OrdinalIgnoreCase)); + + if (target != null) + { + headerBuilder.AppendFormat(" {0}", commandName); + } + else + { + // The command name is invalid so don't try to show help for something that doesn't exist + target = this; + } + + } + + var optionsBuilder = new StringBuilder(); + var commandsBuilder = new StringBuilder(); + var argumentsBuilder = new StringBuilder(); + + if (target.Arguments.Any()) + { + headerBuilder.Append(" [arguments]"); + + argumentsBuilder.AppendLine(); + argumentsBuilder.AppendLine("Arguments:"); + var maxArgLen = MaxArgumentLength(target.Arguments); + var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxArgLen + 2); + foreach (var arg in target.Arguments) + { + argumentsBuilder.AppendFormat(outputFormat, arg.Name, arg.Description); + argumentsBuilder.AppendLine(); + } + } + + if (target.Options.Any()) + { + headerBuilder.Append(" [options]"); + + optionsBuilder.AppendLine(); + optionsBuilder.AppendLine("Options:"); + var maxOptLen = MaxOptionTemplateLength(target.Options); + var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxOptLen + 2); + foreach (var opt in target.Options) + { + optionsBuilder.AppendFormat(outputFormat, opt.Template, opt.Description); + optionsBuilder.AppendLine(); + } + } + + if (target.Commands.Any()) + { + headerBuilder.Append(" [command]"); + + commandsBuilder.AppendLine(); + commandsBuilder.AppendLine("Commands:"); + var maxCmdLen = MaxCommandLength(target.Commands); + var outputFormat = string.Format(" {{0, -{0}}}{{1}}", maxCmdLen + 2); + foreach (var cmd in target.Commands.OrderBy(c => c.Name)) + { + commandsBuilder.AppendFormat(outputFormat, cmd.Name, cmd.Description); + commandsBuilder.AppendLine(); + } + + if (OptionHelp != null) + { + commandsBuilder.AppendLine(); + commandsBuilder.AppendFormat("Use \"{0} [command] --help\" for more information about a command.", Name); + commandsBuilder.AppendLine(); + } + } + + headerBuilder.AppendLine(); + + var nameAndVersion = new StringBuilder(); + nameAndVersion.AppendLine(GetFullNameAndVersion()); + nameAndVersion.AppendLine(); + + Console.Write("{0}{1}{2}{3}{4}", nameAndVersion, headerBuilder, argumentsBuilder, optionsBuilder, commandsBuilder); + } + + public void ShowVersion() + { + for (var cmd = this; cmd != null; cmd = cmd.Parent) + { + cmd.IsShowingInformation = true; + } + + Console.WriteLine(FullName); + Console.WriteLine(LongVersionGetter()); + } + + public string GetFullNameAndVersion() + { + return ShortVersionGetter == null ? FullName : string.Format("{0} {1}", FullName, ShortVersionGetter()); + } + + public void ShowRootCommandFullNameAndVersion() + { + var rootCmd = this; + while (rootCmd.Parent != null) + { + rootCmd = rootCmd.Parent; + } + + Console.WriteLine(rootCmd.GetFullNameAndVersion()); + Console.WriteLine(); + } + + private int MaxOptionTemplateLength(IEnumerable options) + { + var maxLen = 0; + foreach (var opt in options) + { + maxLen = opt.Template.Length > maxLen ? opt.Template.Length : maxLen; + } + return maxLen; + } + + private int MaxCommandLength(IEnumerable commands) + { + var maxLen = 0; + foreach (var cmd in commands) + { + maxLen = cmd.Name.Length > maxLen ? cmd.Name.Length : maxLen; + } + return maxLen; + } + + private int MaxArgumentLength(IEnumerable arguments) + { + var maxLen = 0; + foreach (var arg in arguments) + { + maxLen = arg.Name.Length > maxLen ? arg.Name.Length : maxLen; + } + return maxLen; + } + + private void HandleUnexpectedArg(CommandLineApplication command, string[] args, int index, string argTypeName) + { + if (command._throwOnUnexpectedArg) + { + command.ShowHint(); + throw new CommandParsingException(command, $"Unrecognized {argTypeName} '{args[index]}'"); + } + else + { + // All remaining arguments are stored for further use + command.RemainingArguments.AddRange(new ArraySegment(args, index, args.Length - index)); + } + } + + private class CommandArgumentEnumerator : IEnumerator + { + private readonly IEnumerator _enumerator; + + public CommandArgumentEnumerator(IEnumerator enumerator) + { + _enumerator = enumerator; + } + + public CommandArgument Current + { + get + { + return _enumerator.Current; + } + } + + object IEnumerator.Current + { + get + { + return Current; + } + } + + public void Dispose() + { + _enumerator.Dispose(); + } + + public bool MoveNext() + { + if (Current == null || !Current.MultipleValues) + { + return _enumerator.MoveNext(); + } + + // If current argument allows multiple values, we don't move forward and + // all later values will be added to current CommandArgument.Values + return true; + } + + public void Reset() + { + _enumerator.Reset(); + } + } + } +} diff --git a/src/dotnet/CommandLine/CommandOption.cs b/src/dotnet/CommandLine/CommandOption.cs new file mode 100644 index 000000000..7379ec5a2 --- /dev/null +++ b/src/dotnet/CommandLine/CommandOption.cs @@ -0,0 +1,106 @@ +// 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.Linq; + +namespace Microsoft.DotNet.Cli.CommandLine +{ + internal class CommandOption + { + public CommandOption(string template, CommandOptionType optionType) + { + Template = template; + OptionType = optionType; + Values = new List(); + + foreach (var part in Template.Split(new[] { ' ', '|' }, StringSplitOptions.RemoveEmptyEntries)) + { + if (part.StartsWith("--")) + { + LongName = part.Substring(2); + } + else if (part.StartsWith("-")) + { + var optName = part.Substring(1); + + // If there is only one char and it is not an English letter, it is a symbol option (e.g. "-?") + if (optName.Length == 1 && !IsEnglishLetter(optName[0])) + { + SymbolName = optName; + } + else + { + ShortName = optName; + } + } + else if (part.StartsWith("<") && part.EndsWith(">")) + { + ValueName = part.Substring(1, part.Length - 2); + } + else + { + throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template)); + } + } + + if (string.IsNullOrEmpty(LongName) && string.IsNullOrEmpty(ShortName) && string.IsNullOrEmpty(SymbolName)) + { + throw new ArgumentException($"Invalid template pattern '{template}'", nameof(template)); + } + } + + public string Template { get; set; } + public string ShortName { get; set; } + public string LongName { get; set; } + public string SymbolName { get; set; } + public string ValueName { get; set; } + public string Description { get; set; } + public List Values { get; private set; } + public CommandOptionType OptionType { get; private set; } + + public bool TryParse(string value) + { + switch (OptionType) + { + case CommandOptionType.MultipleValue: + Values.Add(value); + break; + case CommandOptionType.SingleValue: + if (Values.Any()) + { + return false; + } + Values.Add(value); + break; + case CommandOptionType.NoValue: + if (value != null) + { + return false; + } + // Add a value to indicate that this option was specified + Values.Add("on"); + break; + default: + break; + } + return true; + } + + public bool HasValue() + { + return Values.Any(); + } + + public string Value() + { + return HasValue() ? Values[0] : null; + } + + private bool IsEnglishLetter(char c) + { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); + } + } +} \ No newline at end of file diff --git a/src/dotnet/CommandLine/CommandOptionType.cs b/src/dotnet/CommandLine/CommandOptionType.cs new file mode 100644 index 000000000..ccf96e68b --- /dev/null +++ b/src/dotnet/CommandLine/CommandOptionType.cs @@ -0,0 +1,13 @@ +// 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. + + +namespace Microsoft.DotNet.Cli.CommandLine +{ + internal enum CommandOptionType + { + MultipleValue, + SingleValue, + NoValue + } +} diff --git a/src/dotnet/CommandLine/CommandParsingException.cs b/src/dotnet/CommandLine/CommandParsingException.cs new file mode 100644 index 000000000..1b7ed2171 --- /dev/null +++ b/src/dotnet/CommandLine/CommandParsingException.cs @@ -0,0 +1,18 @@ +// 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; + +namespace Microsoft.DotNet.Cli.CommandLine +{ + internal class CommandParsingException : Exception + { + public CommandParsingException(CommandLineApplication command, string message) + : base(message) + { + Command = command; + } + + public CommandLineApplication Command { get; } + } +} diff --git a/src/dotnet/commands/dotnet-compile-csc/AssemblyInfoOptionsCommandLine.cs b/src/dotnet/commands/dotnet-compile-csc/AssemblyInfoOptionsCommandLine.cs new file mode 100644 index 000000000..aacfc21a5 --- /dev/null +++ b/src/dotnet/commands/dotnet-compile-csc/AssemblyInfoOptionsCommandLine.cs @@ -0,0 +1,79 @@ +// 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 Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Compiler.Common; +using static Microsoft.DotNet.Cli.Compiler.Common.AssemblyInfoOptions; + +namespace Microsoft.DotNet.Tools.Compiler +{ + internal class AssemblyInfoOptionsCommandLine + { + private const string ArgTemplate = ""; + + public CommandOption VersionOption { get; set; } + public CommandOption TitleOption { get; set; } + public CommandOption DescriptionOption { get; set; } + public CommandOption CopyrightOption { get; set; } + public CommandOption NeutralCultureOption { get; set; } + public CommandOption CultureOption { get; set; } + public CommandOption InformationalVersionOption { get; set; } + public CommandOption FileVersionOption { get; set; } + public CommandOption TargetFrameworkOption { get; set; } + + public static AssemblyInfoOptionsCommandLine AddOptions(CommandLineApplication app) + { + AssemblyInfoOptionsCommandLine commandLineOptions = new AssemblyInfoOptionsCommandLine(); + + commandLineOptions.VersionOption = + app.Option($"{AssemblyVersionOptionName} {ArgTemplate}", "Assembly version", CommandOptionType.SingleValue); + + commandLineOptions.TitleOption = + app.Option($"{TitleOptionName} {ArgTemplate}", "Assembly title", CommandOptionType.SingleValue); + + commandLineOptions.DescriptionOption = + app.Option($"{DescriptionOptionName} {ArgTemplate}", "Assembly description", CommandOptionType.SingleValue); + + commandLineOptions.CopyrightOption = + app.Option($"{CopyrightOptionName} {ArgTemplate}", "Assembly copyright", CommandOptionType.SingleValue); + + commandLineOptions.NeutralCultureOption = + app.Option($"{NeutralCultureOptionName} {ArgTemplate}", "Assembly neutral culture", CommandOptionType.SingleValue); + + commandLineOptions.CultureOption = + app.Option($"{CultureOptionName} {ArgTemplate}", "Assembly culture", CommandOptionType.SingleValue); + + commandLineOptions.InformationalVersionOption = + app.Option($"{InformationalVersionOptionName} {ArgTemplate}", "Assembly informational version", CommandOptionType.SingleValue); + + commandLineOptions.FileVersionOption = + app.Option($"{AssemblyFileVersionOptionName} {ArgTemplate}", "Assembly file version", CommandOptionType.SingleValue); + + commandLineOptions.TargetFrameworkOption = + app.Option($"{TargetFrameworkOptionName} {ArgTemplate}", "Assembly target framework", CommandOptionType.SingleValue); + + return commandLineOptions; + } + + public AssemblyInfoOptions GetOptionValues() + { + return new AssemblyInfoOptions() + { + AssemblyVersion = UnescapeNewlines(VersionOption.Value()), + Title = UnescapeNewlines(TitleOption.Value()), + Description = UnescapeNewlines(DescriptionOption.Value()), + Copyright = UnescapeNewlines(CopyrightOption.Value()), + NeutralLanguage = UnescapeNewlines(NeutralCultureOption.Value()), + Culture = UnescapeNewlines(CultureOption.Value()), + InformationalVersion = UnescapeNewlines(InformationalVersionOption.Value()), + AssemblyFileVersion = UnescapeNewlines(FileVersionOption.Value()), + TargetFramework = UnescapeNewlines(TargetFrameworkOption.Value()), + }; + } + + private static string UnescapeNewlines(string text) + { + return text.Replace("\\r", "\r").Replace("\\n", "\n"); + } + } +} \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-compile-csc/CommonCompilerOptionsCommandLine.cs b/src/dotnet/commands/dotnet-compile-csc/CommonCompilerOptionsCommandLine.cs new file mode 100644 index 000000000..2aa9f1353 --- /dev/null +++ b/src/dotnet/commands/dotnet-compile-csc/CommonCompilerOptionsCommandLine.cs @@ -0,0 +1,104 @@ +// 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 Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.ProjectModel; +using static Microsoft.DotNet.Cli.Compiler.Common.CommonCompilerOptionsExtensions; + +namespace Microsoft.DotNet.Tools.Compiler +{ + internal class CommonCompilerOptionsCommandLine + { + private const string ArgTemplate = ""; + + public CommandOption DefineOption { get; set; } + public CommandOption SuppressWarningOption { get; set; } + public CommandOption LanguageVersionOption { get; set; } + public CommandOption PlatformOption { get; set; } + public CommandOption AllowUnsafeOption { get; set; } + public CommandOption WarningsAsErrorsOption { get; set; } + public CommandOption OptimizeOption { get; set; } + public CommandOption KeyFileOption { get; set; } + public CommandOption DelaySignOption { get; set; } + public CommandOption PublicSignOption { get; set; } + public CommandOption DebugTypeOption { get; set; } + public CommandOption EmitEntryPointOption { get; set; } + public CommandOption GenerateXmlDocumentationOption { get; set; } + public CommandOption AdditionalArgumentsOption { get; set; } + public CommandOption OutputNameOption { get; set; } + + public static CommonCompilerOptionsCommandLine AddOptions(CommandLineApplication app) + { + CommonCompilerOptionsCommandLine commandLineOptions = new CommonCompilerOptionsCommandLine(); + + commandLineOptions.DefineOption = + app.Option($"{DefineOptionName} {ArgTemplate}...", "Preprocessor definitions", CommandOptionType.MultipleValue); + + commandLineOptions.SuppressWarningOption = + app.Option($"{SuppressWarningOptionName} {ArgTemplate}...", "Suppresses the specified warning", CommandOptionType.MultipleValue); + + commandLineOptions.LanguageVersionOption = + app.Option($"{LanguageVersionOptionName} {ArgTemplate}", "The version of the language used to compile", CommandOptionType.SingleValue); + + commandLineOptions.PlatformOption = + app.Option($"{PlatformOptionName} {ArgTemplate}", "The target platform", CommandOptionType.SingleValue); + + commandLineOptions.AllowUnsafeOption = + app.Option($"{AllowUnsafeOptionName} {ArgTemplate}", "Allow unsafe code", CommandOptionType.SingleValue); + + commandLineOptions.WarningsAsErrorsOption = + app.Option($"{WarningsAsErrorsOptionName} {ArgTemplate}", "Turn all warnings into errors", CommandOptionType.SingleValue); + + commandLineOptions.OptimizeOption = + app.Option($"{OptimizeOptionName} {ArgTemplate}", "Enable compiler optimizations", CommandOptionType.SingleValue); + + commandLineOptions.KeyFileOption = + app.Option($"{KeyFileOptionName} {ArgTemplate}", "Path to file containing the key to strong-name sign the output assembly", CommandOptionType.SingleValue); + + commandLineOptions.DelaySignOption = + app.Option($"{DelaySignOptionName} {ArgTemplate}", "Delay-sign the output assembly", CommandOptionType.SingleValue); + + commandLineOptions.PublicSignOption = + app.Option($"{PublicSignOptionName} {ArgTemplate}", "Public-sign the output assembly", CommandOptionType.SingleValue); + + commandLineOptions.DebugTypeOption = + app.Option($"{DebugTypeOptionName} {ArgTemplate}", "The type of PDB to emit: portable or full", CommandOptionType.SingleValue); + + commandLineOptions.EmitEntryPointOption = + app.Option($"{EmitEntryPointOptionName} {ArgTemplate}", "Output an executable console program", CommandOptionType.SingleValue); + + commandLineOptions.GenerateXmlDocumentationOption = + app.Option($"{GenerateXmlDocumentationOptionName} {ArgTemplate}", "Generate XML documentation file", CommandOptionType.SingleValue); + + commandLineOptions.AdditionalArgumentsOption = + app.Option($"{AdditionalArgumentsOptionName} {ArgTemplate}...", "Pass the additional argument directly to the compiler", CommandOptionType.MultipleValue); + + commandLineOptions.OutputNameOption = + app.Option($"{OutputNameOptionName} {ArgTemplate}", "Output assembly name", CommandOptionType.SingleValue); + + return commandLineOptions; + } + + public CommonCompilerOptions GetOptionValues() + { + return new CommonCompilerOptions() + { + Defines = DefineOption.Values, + SuppressWarnings = SuppressWarningOption.Values, + LanguageVersion = LanguageVersionOption.Value(), + Platform = PlatformOption.Value(), + AllowUnsafe = bool.Parse(AllowUnsafeOption.Value()), + WarningsAsErrors = bool.Parse(WarningsAsErrorsOption.Value()), + Optimize = bool.Parse(OptimizeOption.Value()), + KeyFile = KeyFileOption.Value(), + DelaySign = bool.Parse(DelaySignOption.Value()), + PublicSign = bool.Parse(PublicSignOption.Value()), + DebugType = DebugTypeOption.Value(), + EmitEntryPoint = bool.Parse(EmitEntryPointOption.Value()), + GenerateXmlDocumentation = bool.Parse(GenerateXmlDocumentationOption.Value()), + AdditionalArguments = AdditionalArgumentsOption.Values, + OutputName = OutputNameOption.Value(), + }; + } + } +} \ No newline at end of file diff --git a/src/dotnet/commands/dotnet-compile-csc/Program.cs b/src/dotnet/commands/dotnet-compile-csc/Program.cs index 2413b1934..798b7c929 100644 --- a/src/dotnet/commands/dotnet-compile-csc/Program.cs +++ b/src/dotnet/commands/dotnet-compile-csc/Program.cs @@ -2,13 +2,12 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.CommandLine; using System.Collections.Generic; using System.IO; using System.Linq; using System.Runtime.InteropServices; using System.Text; - +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Compiler.Common; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.ProjectModel; @@ -23,103 +22,87 @@ namespace Microsoft.DotNet.Tools.Compiler.Csc { DebugHelper.HandleDebugSwitch(ref args); - CommonCompilerOptions commonOptions = null; - AssemblyInfoOptions assemblyInfoOptions = null; - string tempOutDir = null; - IReadOnlyList references = Array.Empty(); - IReadOnlyList resources = Array.Empty(); - IReadOnlyList sources = Array.Empty(); - IReadOnlyList analyzers = Array.Empty(); - string outputName = null; - var help = false; - var returnCode = 0; - string helpText = null; + CommandLineApplication app = new CommandLineApplication(); + app.Name = "dotnet compile-csc"; + app.FullName = ".NET C# Compiler"; + app.Description = "C# Compiler for the .NET Platform"; + app.HelpOption("-h|--help"); + + CommonCompilerOptionsCommandLine commonCompilerCommandLine = CommonCompilerOptionsCommandLine.AddOptions(app); + AssemblyInfoOptionsCommandLine assemblyInfoCommandLine = AssemblyInfoOptionsCommandLine.AddOptions(app); + + CommandOption tempOutput = app.Option("--temp-output ", "Compilation temporary directory", CommandOptionType.SingleValue); + CommandOption outputName = app.Option("--out ", "Name of the output assembly", CommandOptionType.SingleValue); + CommandOption references = app.Option("--reference ...", "Path to a compiler metadata reference", CommandOptionType.MultipleValue); + CommandOption analyzers = app.Option("--analyzer ...", "Path to an analyzer assembly", CommandOptionType.MultipleValue); + CommandOption resources = app.Option("--resource ...", "Resources to embed", CommandOptionType.MultipleValue); + CommandArgument sources = app.Argument("...", "Compilation sources", multipleValues: true); + + app.OnExecute(() => + { + if (!tempOutput.HasValue()) + { + Reporter.Error.WriteLine("Option '--temp-output' is required"); + return ExitFailed; + } + + CommonCompilerOptions commonOptions = commonCompilerCommandLine.GetOptionValues(); + + AssemblyInfoOptions assemblyInfoOptions = assemblyInfoCommandLine.GetOptionValues(); + + var translated = TranslateCommonOptions(commonOptions, outputName.Value()); + + var allArgs = new List(translated); + allArgs.AddRange(GetDefaultOptions()); + + // Generate assembly info + var assemblyInfo = Path.Combine(tempOutput.Value(), $"dotnet-compile.assemblyinfo.cs"); + + File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sources.Values)); + + allArgs.Add($"\"{assemblyInfo}\""); + + if (outputName.HasValue()) + { + allArgs.Add($"-out:\"{outputName.Value()}\""); + } + + allArgs.AddRange(analyzers.Values.Select(a => $"-a:\"{a}\"")); + allArgs.AddRange(references.Values.Select(r => $"-r:\"{r}\"")); + + // Resource has two parts separated by a comma + // Only the first should be quoted. This is handled + // in dotnet-compile where the information is present. + allArgs.AddRange(resources.Values.Select(resource => $"-resource:{resource}")); + + allArgs.AddRange(sources.Values.Select(s => $"\"{s}\"")); + + var rsp = Path.Combine(tempOutput.Value(), "dotnet-compile-csc.rsp"); + + File.WriteAllLines(rsp, allArgs, Encoding.UTF8); + + // Execute CSC! + var result = RunCsc(new string[] { $"-noconfig", "@" + $"{rsp}" }) + .ForwardStdErr() + .ForwardStdOut() + .Execute(); + + return result.ExitCode; + }); try { - ArgumentSyntax.Parse(args, syntax => - { - syntax.HandleHelp = false; - syntax.HandleErrors = false; - - commonOptions = CommonCompilerOptionsExtensions.Parse(syntax); - - assemblyInfoOptions = AssemblyInfoOptions.Parse(syntax); - - syntax.DefineOption("temp-output", ref tempOutDir, "Compilation temporary directory"); - - syntax.DefineOption("out", ref outputName, "Name of the output assembly"); - - syntax.DefineOptionList("reference", ref references, "Path to a compiler metadata reference"); - - syntax.DefineOptionList("analyzer", ref analyzers, "Path to an analyzer assembly"); - - syntax.DefineOptionList("resource", ref resources, "Resources to embed"); - - syntax.DefineOption("h|help", ref help, "Help for compile native."); - - syntax.DefineParameterList("source-files", ref sources, "Compilation sources"); - - helpText = syntax.GetHelpText(); - - if (tempOutDir == null) - { - syntax.ReportError("Option '--temp-output' is required"); - } - }); + return app.Execute(args); } - catch (ArgumentSyntaxException exception) + catch (Exception ex) { - Console.Error.WriteLine(exception.Message); - help = true; - returnCode = ExitFailed; +#if DEBUG + Reporter.Error.WriteLine(ex.ToString()); +#else + Reporter.Error.WriteLine(ex.Message); +#endif + return ExitFailed; } - - if (help) - { - Console.WriteLine(helpText); - - return returnCode; - } - - var translated = TranslateCommonOptions(commonOptions, outputName); - - var allArgs = new List(translated); - allArgs.AddRange(GetDefaultOptions()); - - // Generate assembly info - var assemblyInfo = Path.Combine(tempOutDir, $"dotnet-compile.assemblyinfo.cs"); - - File.WriteAllText(assemblyInfo, AssemblyInfoFileGenerator.GenerateCSharp(assemblyInfoOptions, sources)); - - allArgs.Add($"\"{assemblyInfo}\""); - - if (outputName != null) - { - allArgs.Add($"-out:\"{outputName}\""); - } - - allArgs.AddRange(analyzers.Select(a => $"-a:\"{a}\"")); - allArgs.AddRange(references.Select(r => $"-r:\"{r}\"")); - - // Resource has two parts separated by a comma - // Only the first should be quoted. This is handled - // in dotnet-compile where the information is present. - allArgs.AddRange(resources.Select(resource => $"-resource:{resource}")); - - allArgs.AddRange(sources.Select(s => $"\"{s}\"")); - - var rsp = Path.Combine(tempOutDir, "dotnet-compile-csc.rsp"); - - File.WriteAllLines(rsp, allArgs, Encoding.UTF8); - - // Execute CSC! - var result = RunCsc(new string[] { $"-noconfig", "@" + $"{rsp}" }) - .ForwardStdErr() - .ForwardStdOut() - .Execute(); - - return result.ExitCode; } // TODO: Review if this is the place for default options diff --git a/src/dotnet/commands/dotnet-compile-native/ArgumentsParser.cs b/src/dotnet/commands/dotnet-compile-native/ArgumentsParser.cs index 885cf0cd0..1b64b294c 100644 --- a/src/dotnet/commands/dotnet-compile-native/ArgumentsParser.cs +++ b/src/dotnet/commands/dotnet-compile-native/ArgumentsParser.cs @@ -1,7 +1,8 @@ using System; using System.Collections.Generic; -using System.CommandLine; using System.Linq; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Tools.Compiler.Native { @@ -9,146 +10,115 @@ namespace Microsoft.DotNet.Tools.Compiler.Native { internal static ArgValues Parse(IEnumerable args) { - string inputAssembly = null; - string outputDirectory = null; - string temporaryOutputDirectory = null; - string configuration = null; - BuildConfiguration? buildConfiguration = null; - string mode = null; - NativeIntermediateMode? nativeMode = null; - IReadOnlyList ilcArgs = Array.Empty(); - IEnumerable unquotIlcArgs = Array.Empty(); - string ilcPath = null; - string ilcSdkPath = null; - string appDepSdk = null; - string logPath = null; - var help = false; - string helpText = null; - var returnCode = 0; - string cppCompilerFlags = null; + CommandLineApplication app = new CommandLineApplication(); + app.HelpOption("-h|--help"); - IReadOnlyList references = Array.Empty(); - IReadOnlyList linklib = Array.Empty(); + CommandOption output = app.Option("--output ", "Output Directory for native executable.", CommandOptionType.SingleValue); + CommandOption tempOutput = app.Option("--temp-output ", "Directory for intermediate files.", CommandOptionType.SingleValue); + + CommandOption configuration = app.Option("--configuration ", "debug/release build configuration. Defaults to debug.", CommandOptionType.SingleValue); + CommandOption mode = app.Option("--mode ", "Code Generation mode. Defaults to ryujit.", CommandOptionType.SingleValue); + + CommandOption reference = app.Option("--reference ...", "Use to specify Managed DLL references of the app.", CommandOptionType.MultipleValue); + + // Custom Extensibility Points to support CoreRT workflow TODO better descriptions + CommandOption ilcarg = app.Option("--ilcarg ...", "Use to specify custom arguments for the IL Compiler.", CommandOptionType.MultipleValue); + CommandOption ilcpath = app.Option("--ilcpath ", "Use to specify a custom build of IL Compiler.", CommandOptionType.SingleValue); + CommandOption ilcsdkpath = app.Option("ilcsdkpath ", "Use to specify a custom build of IL Compiler SDK", CommandOptionType.SingleValue); + + CommandOption linklib = app.Option("--linklib ...", "Use to link in additional static libs", CommandOptionType.MultipleValue); + + // TEMPORARY Hack until CoreRT compatible Framework Libs are available + CommandOption appdepsdk = app.Option("--appdepsdk ", "Use to plug in custom appdepsdk path", CommandOptionType.SingleValue); + + // Optional Log Path + CommandOption logpath = app.Option("--logpath ", "Use to dump Native Compilation Logs to a file.", CommandOptionType.SingleValue); + + // Optional flags to be passed to the native compiler + CommandOption cppcompilerflags = app.Option("--cppcompilerflags ", "Additional flags to be passed to the native compiler.", CommandOptionType.SingleValue); + + CommandArgument inputAssembly = app.Argument("INPUT_ASSEMBLY", "The managed input assembly to compile to native."); + + ArgValues argValues = new ArgValues(); + app.OnExecute(() => + { + if (string.IsNullOrEmpty(inputAssembly.Value)) + { + Reporter.Error.WriteLine("Input Assembly is a required parameter."); + return 1; + } + + if (configuration.HasValue()) + { + try + { + argValues.BuildConfiguration = EnumExtensions.Parse(configuration.Value()); + } + catch (ArgumentException) + { + Reporter.Error.WriteLine($"Invalid Configuration Option: {configuration}"); + return 1; + } + } + + if (mode.HasValue()) + { + try + { + argValues.NativeMode = EnumExtensions.Parse(mode.Value()); + } + catch (ArgumentException) + { + Reporter.Error.WriteLine($"Invalid Mode Option: {mode}"); + return 1; + } + } + + argValues.InputManagedAssemblyPath = inputAssembly.Value; + argValues.OutputDirectory = output.Value(); + argValues.IntermediateDirectory = tempOutput.Value(); + argValues.Architecture = ArchitectureMode.x64; + argValues.ReferencePaths = reference.Values; + argValues.IlcArgs = ilcarg.Values.Select(s => + { + if (!s.StartsWith("\"") || !s.EndsWith("\"")) + { + throw new ArgumentException("--ilcarg must be specified in double quotes", "ilcarg"); + } + return s.Substring(1, s.Length - 2); + }); + argValues.IlcPath = ilcpath.Value(); + argValues.IlcSdkPath = ilcsdkpath.Value(); + argValues.LinkLibPaths = linklib.Values; + argValues.AppDepSDKPath = appdepsdk.Value(); + argValues.LogPath = logpath.Value(); + argValues.CppCompilerFlags = cppcompilerflags.Value(); + + Reporter.Output.WriteLine($"Input Assembly: {inputAssembly}"); + + return 0; + }); try { - ArgumentSyntax.Parse(args, syntax => - { - syntax.HandleHelp = false; - syntax.HandleErrors = false; - - syntax.DefineOption("output", ref outputDirectory, "Output Directory for native executable."); - syntax.DefineOption("temp-output", ref temporaryOutputDirectory, "Directory for intermediate files."); - - syntax.DefineOption("configuration", ref configuration, - "debug/release build configuration. Defaults to debug."); - syntax.DefineOption("mode", ref mode, "Code Generation mode. Defaults to ryujit."); - - syntax.DefineOptionList("reference", ref references, - "Use to specify Managed DLL references of the app."); - - // Custom Extensibility Points to support CoreRT workflow TODO better descriptions - syntax.DefineOptionList("ilcarg", ref ilcArgs, "Use to specify custom arguments for the IL Compiler."); - syntax.DefineOption("ilcpath", ref ilcPath, "Use to specify a custom build of IL Compiler."); - syntax.DefineOption("ilcsdkpath", ref ilcSdkPath, "Use to specify a custom build of IL Compiler SDK"); - - syntax.DefineOptionList("linklib", ref linklib, "Use to link in additional static libs"); - - // TEMPORARY Hack until CoreRT compatible Framework Libs are available - syntax.DefineOption("appdepsdk", ref appDepSdk, "Use to plug in custom appdepsdk path"); - - // Optional Log Path - syntax.DefineOption("logpath", ref logPath, "Use to dump Native Compilation Logs to a file."); - - // Optional flags to be passed to the native compiler - syntax.DefineOption("cppcompilerflags", ref cppCompilerFlags, "Additional flags to be passed to the native compiler."); - - syntax.DefineOption("h|help", ref help, "Help for compile native."); - - syntax.DefineParameter("INPUT_ASSEMBLY", ref inputAssembly, - "The managed input assembly to compile to native."); - - helpText = syntax.GetHelpText(); - - if (string.IsNullOrWhiteSpace(inputAssembly)) - { - syntax.ReportError("Input Assembly is a required parameter."); - help = true; - } - - if (!string.IsNullOrEmpty(configuration)) - { - try - { - buildConfiguration = EnumExtensions.Parse(configuration); - } - catch (ArgumentException) - { - syntax.ReportError($"Invalid Configuration Option: {configuration}"); - help = true; - } - } - - if (!string.IsNullOrEmpty(mode)) - { - try - { - nativeMode = EnumExtensions.Parse(mode); - } - catch (ArgumentException) - { - syntax.ReportError($"Invalid Mode Option: {mode}"); - help = true; - } - } - - unquotIlcArgs = ilcArgs.Select(s => - { - if (!s.StartsWith("\"") || !s.EndsWith("\"")) - { - throw new ArgumentSyntaxException("--ilcarg must be specified in double quotes"); - } - return s.Substring(1, s.Length - 2); - }); - }); + argValues.ReturnCode = app.Execute(args.ToArray()); } - catch (ArgumentSyntaxException exception) + catch (Exception ex) { - Console.Error.WriteLine(exception.Message); - help = true; - returnCode = 1; +#if DEBUG + Console.Error.WriteLine(ex); +#else + Console.Error.WriteLine(ex.Message); +#endif + argValues.ReturnCode = 1; } - if (help) + if (argValues.ReturnCode != 0) { - Console.WriteLine(helpText); - - return new ArgValues - { - IsHelp = help, - ReturnCode = returnCode - }; + argValues.IsHelp = true; } - Console.WriteLine($"Input Assembly: {inputAssembly}"); - - return new ArgValues - { - InputManagedAssemblyPath = inputAssembly, - OutputDirectory = outputDirectory, - IntermediateDirectory = temporaryOutputDirectory, - Architecture = ArchitectureMode.x64, - BuildConfiguration = buildConfiguration, - NativeMode = nativeMode, - ReferencePaths = references, - IlcArgs = unquotIlcArgs, - IlcPath = ilcPath, - IlcSdkPath = ilcSdkPath, - LinkLibPaths = linklib, - AppDepSDKPath = appDepSdk, - LogPath = logPath, - CppCompilerFlags = cppCompilerFlags - }; + return argValues; } } } diff --git a/src/dotnet/commands/dotnet-compile-native/DirectoryExtensions.cs b/src/dotnet/commands/dotnet-compile-native/DirectoryExtensions.cs index fab09bdf0..4b84e2eba 100644 --- a/src/dotnet/commands/dotnet-compile-native/DirectoryExtensions.cs +++ b/src/dotnet/commands/dotnet-compile-native/DirectoryExtensions.cs @@ -1,15 +1,6 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Runtime.InteropServices; using System.IO; -using Microsoft.Dnx.Runtime.Common.CommandLine; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; - namespace Microsoft.DotNet.Tools.Compiler.Native { public static class DirectoryExtensions diff --git a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/IPlatformNativeStep.cs b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/IPlatformNativeStep.cs index eeea35ed0..1bc1c668a 100644 --- a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/IPlatformNativeStep.cs +++ b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/IPlatformNativeStep.cs @@ -1,16 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; - -using Microsoft.Dnx.Runtime.Common.CommandLine; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; - namespace Microsoft.DotNet.Tools.Compiler.Native { - public interface IPlatformNativeStep + public interface IPlatformNativeStep { int Invoke(); string DetermineOutputFile(NativeCompileSettings config); diff --git a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/IntermediateCompiler.cs b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/IntermediateCompiler.cs index 0c0c9efef..b11657e8e 100644 --- a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/IntermediateCompiler.cs +++ b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/IntermediateCompiler.cs @@ -1,16 +1,9 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Linq; - -using Microsoft.Dnx.Runtime.Common.CommandLine; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; namespace Microsoft.DotNet.Tools.Compiler.Native { - public class IntermediateCompiler + public class IntermediateCompiler { public static IntermediateCompiler Create(NativeCompileSettings config) { diff --git a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacCppCompileStep.cs b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacCppCompileStep.cs index a628535b6..654cdeee9 100644 --- a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacCppCompileStep.cs +++ b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Mac/MacCppCompileStep.cs @@ -1,12 +1,7 @@ -using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; - -using Microsoft.Dnx.Runtime.Common.CommandLine; using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; namespace Microsoft.DotNet.Tools.Compiler.Native { diff --git a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Windows/WindowsCppCompileStep.cs b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Windows/WindowsCppCompileStep.cs index 196304a1e..1be36ae63 100644 --- a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Windows/WindowsCppCompileStep.cs +++ b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Windows/WindowsCppCompileStep.cs @@ -1,12 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; - -using Microsoft.Dnx.Runtime.Common.CommandLine; using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; namespace Microsoft.DotNet.Tools.Compiler.Native { diff --git a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Windows/WindowsLinkStep.cs b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Windows/WindowsLinkStep.cs index 817badef9..07b340695 100644 --- a/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Windows/WindowsLinkStep.cs +++ b/src/dotnet/commands/dotnet-compile-native/IntermediateCompilation/Windows/WindowsLinkStep.cs @@ -1,12 +1,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; using System.Linq; - -using Microsoft.Dnx.Runtime.Common.CommandLine; using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; namespace Microsoft.DotNet.Tools.Compiler.Native { diff --git a/src/dotnet/commands/dotnet-compile-native/RuntimeExtensions.cs b/src/dotnet/commands/dotnet-compile-native/RuntimeExtensions.cs index d4d7278c0..452f23230 100644 --- a/src/dotnet/commands/dotnet-compile-native/RuntimeExtensions.cs +++ b/src/dotnet/commands/dotnet-compile-native/RuntimeExtensions.cs @@ -1,14 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using System.Runtime.InteropServices; -using System.IO; - -using Microsoft.Dnx.Runtime.Common.CommandLine; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; namespace Microsoft.DotNet.Tools.Compiler.Native { @@ -22,6 +12,5 @@ namespace Microsoft.DotNet.Tools.Compiler.Native return IntPtr.Size == 8 ? ArchitectureMode.x64 : ArchitectureMode.x86; #endif } - } } diff --git a/src/dotnet/commands/dotnet-compile-native/RuntimeInformationExtensions.cs b/src/dotnet/commands/dotnet-compile-native/RuntimeInformationExtensions.cs index b982631e4..c55e7f527 100644 --- a/src/dotnet/commands/dotnet-compile-native/RuntimeInformationExtensions.cs +++ b/src/dotnet/commands/dotnet-compile-native/RuntimeInformationExtensions.cs @@ -1,14 +1,5 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Runtime.InteropServices; -using System.IO; - -using Microsoft.Dnx.Runtime.Common.CommandLine; -using Microsoft.DotNet.Cli.Utils; -using Microsoft.DotNet.Tools.Common; namespace Microsoft.DotNet.Tools.Compiler.Native { diff --git a/src/dotnet/commands/dotnet-compile/Compiler.cs b/src/dotnet/commands/dotnet-compile/Compiler.cs index 350685ee8..e13457b74 100644 --- a/src/dotnet/commands/dotnet-compile/Compiler.cs +++ b/src/dotnet/commands/dotnet-compile/Compiler.cs @@ -54,17 +54,12 @@ namespace Microsoft.DotNet.Tools.Compiler { if (ResourceUtility.IsResxFile(resgenFile.InputFile)) { - var arguments = new[] - { - $"{resgenFile.InputFile}", - $"-o:{resgenFile.OutputFile}", - $"-v:{project.Version.Version}" - }; - - var rsp = Path.Combine(intermediateOutputPath, $"dotnet-resgen-resx.rsp"); - File.WriteAllLines(rsp, arguments); - - var result = Resgen.ResgenCommand.Run(new[] { $"@{rsp}" }); + var result = Resgen.ResgenCommand.Run( + new[] { resgenFile.InputFile }, + culture: null, + outputFile: resgenFile.OutputFile, + version: project.Version.Version.ToString(), + compilationReferences: null); if (result != 0) { @@ -85,11 +80,9 @@ namespace Microsoft.DotNet.Tools.Compiler protected static bool GenerateCultureResourceAssemblies( Project project, List dependencies, - string intermediateOutputPath, string outputPath) { var referencePaths = CompilerUtil.GetReferencePathsForCultureResgen(dependencies); - var resgenReferenceArgs = referencePaths.Select(path => $"-r:{path}").ToList(); var cultureResgenFiles = CompilerUtil.GetCultureResources(project, outputPath); foreach (var resgenFile in cultureResgenFiles) @@ -101,17 +94,13 @@ namespace Microsoft.DotNet.Tools.Compiler Directory.CreateDirectory(resourceOutputPath); } - var arguments = new List(); + var result = Resgen.ResgenCommand.Run( + resgenFile.InputFileToMetadata.Select(fileToMetadata => $"{fileToMetadata.Key},{fileToMetadata.Value}"), + resgenFile.Culture, + resgenFile.OutputFile, + project.Version.Version.ToString(), + referencePaths); - arguments.AddRange(resgenReferenceArgs); - arguments.Add($"-o:{resgenFile.OutputFile}"); - arguments.Add($"-c:{resgenFile.Culture}"); - arguments.Add($"-v:{project.Version.Version}"); - arguments.AddRange(resgenFile.InputFileToMetadata.Select(fileToMetadata => $"{fileToMetadata.Key},{fileToMetadata.Value}")); - var rsp = Path.Combine(intermediateOutputPath, $"dotnet-resgen.rsp"); - File.WriteAllLines(rsp, arguments); - - var result = Resgen.ResgenCommand.Run(new[] { $"@{rsp}" }); if (result != 0) { return false; diff --git a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs index 0057d1b16..e9bd3ff69 100644 --- a/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs +++ b/src/dotnet/commands/dotnet-compile/ManagedCompiler.cs @@ -207,7 +207,7 @@ namespace Microsoft.DotNet.Tools.Compiler if (success) { - success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, intermediateOutputPath, outputPath); + success &= GenerateCultureResourceAssemblies(context.ProjectFile, dependencies, outputPath); } return PrintSummary(diagnostics, sw, success); diff --git a/src/dotnet/commands/dotnet-new/Program.cs b/src/dotnet/commands/dotnet-new/Program.cs index dbeb51a4e..969dccdd0 100644 --- a/src/dotnet/commands/dotnet-new/Program.cs +++ b/src/dotnet/commands/dotnet-new/Program.cs @@ -1,4 +1,4 @@ -using Microsoft.Dnx.Runtime.Common.CommandLine; +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; using System; using System.Collections.Generic; diff --git a/src/dotnet/commands/dotnet-pack/Program.cs b/src/dotnet/commands/dotnet-pack/Program.cs index 3bb40b9df..4f0bfd723 100644 --- a/src/dotnet/commands/dotnet-pack/Program.cs +++ b/src/dotnet/commands/dotnet-pack/Program.cs @@ -4,9 +4,9 @@ using System; using System.IO; using System.Linq; -using Microsoft.DotNet.ProjectModel; -using Microsoft.Dnx.Runtime.Common.CommandLine; +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; +using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.Tools.Pack; namespace Microsoft.DotNet.Tools.Compiler diff --git a/src/dotnet/commands/dotnet-projectmodel-server/Program.cs b/src/dotnet/commands/dotnet-projectmodel-server/Program.cs index f4603eaaf..be3f55b21 100644 --- a/src/dotnet/commands/dotnet-projectmodel-server/Program.cs +++ b/src/dotnet/commands/dotnet-projectmodel-server/Program.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using System.Diagnostics; using System.Net; using System.Net.Sockets; -using Microsoft.Dnx.Runtime.Common.CommandLine; +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.Extensions.Logging; namespace Microsoft.DotNet.ProjectModel.Server diff --git a/src/dotnet/commands/dotnet-publish/Program.cs b/src/dotnet/commands/dotnet-publish/Program.cs index 849fec5fd..e68014b7c 100644 --- a/src/dotnet/commands/dotnet-publish/Program.cs +++ b/src/dotnet/commands/dotnet-publish/Program.cs @@ -1,10 +1,10 @@ // 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 Microsoft.Dnx.Runtime.Common.CommandLine; -using Microsoft.DotNet.Cli.Utils; using System; using System.IO; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Tools.Publish { diff --git a/src/dotnet/commands/dotnet-repl-csi/Program.cs b/src/dotnet/commands/dotnet-repl-csi/Program.cs index 57bef2fda..6f085fecf 100644 --- a/src/dotnet/commands/dotnet-repl-csi/Program.cs +++ b/src/dotnet/commands/dotnet-repl-csi/Program.cs @@ -3,9 +3,9 @@ using System; using System.Collections.Generic; -using System.Linq; using System.IO; -using Microsoft.Dnx.Runtime.Common.CommandLine; +using System.Linq; +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; using Microsoft.DotNet.ProjectModel; using NuGet.Frameworks; diff --git a/src/dotnet/commands/dotnet-repl/Program.cs b/src/dotnet/commands/dotnet-repl/Program.cs index aed67a969..335330fdf 100644 --- a/src/dotnet/commands/dotnet-repl/Program.cs +++ b/src/dotnet/commands/dotnet-repl/Program.cs @@ -3,7 +3,7 @@ using System; using System.Collections.Generic; -using Microsoft.Dnx.Runtime.Common.CommandLine; +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Tools.Repl diff --git a/src/dotnet/commands/dotnet-resgen/Program.cs b/src/dotnet/commands/dotnet-resgen/Program.cs index dd3158d9a..665bcbb49 100644 --- a/src/dotnet/commands/dotnet-resgen/Program.cs +++ b/src/dotnet/commands/dotnet-resgen/Program.cs @@ -2,61 +2,29 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; -using System.CommandLine; +using System.Collections.Generic; +using System.Linq; using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Tools.Resgen { public partial class ResgenCommand { - public static int Run(string[] args) + public static int Run(IEnumerable inputFiles, string culture, string outputFile, string version, IEnumerable compilationReferences) { - DebugHelper.HandleDebugSwitch(ref args); - - var help = false; - string helpText = null; - var returnCode = 0; - - var resgenCommand = new ResgenCommand(); - try - { - ArgumentSyntax.Parse(args, syntax => - { - syntax.ApplicationName = "Resource compiler"; - - syntax.HandleHelp = false; - syntax.HandleErrors = false; - - syntax.DefineOption("o|output", ref resgenCommand.OutputFileName, "Output file name"); - syntax.DefineOption("c|culture", ref resgenCommand.AssemblyCulture, "Ouput assembly culture"); - syntax.DefineOption("v|version", ref resgenCommand.AssemblyVersion, "Ouput assembly version"); - syntax.DefineOption("h|help", ref help, "Help for compile native."); - - syntax.DefineOptionList("r", ref resgenCommand.CompilationReferences, "Compilation references"); - syntax.DefineParameterList("args", ref resgenCommand.Args, "Input files"); - - helpText = syntax.GetHelpText(); - }); - } - catch (ArgumentSyntaxException exception) - { - Console.Error.WriteLine(exception.Message); - help = true; - returnCode = 1; - } - - if (resgenCommand.Args.Count == 0) + if (!inputFiles.Any()) { Reporter.Error.WriteLine("No input files specified"); - help = true; - returnCode = 1; + return 1; } - if (help) - { - Console.WriteLine(helpText); - return returnCode; - } + ResgenCommand resgenCommand = new ResgenCommand(); + + resgenCommand.Args = inputFiles; + resgenCommand.OutputFileName = outputFile; + resgenCommand.AssemblyCulture = culture; + resgenCommand.AssemblyVersion = version; + resgenCommand.CompilationReferences = compilationReferences; try { diff --git a/src/dotnet/commands/dotnet-resgen/ResgenCommand.cs b/src/dotnet/commands/dotnet-resgen/ResgenCommand.cs index 594d51b2f..f5e6def2b 100644 --- a/src/dotnet/commands/dotnet-resgen/ResgenCommand.cs +++ b/src/dotnet/commands/dotnet-resgen/ResgenCommand.cs @@ -14,8 +14,8 @@ namespace Microsoft.DotNet.Tools.Resgen public string OutputFileName = null; public string AssemblyCulture = null; public string AssemblyVersion = null; - public IReadOnlyList CompilationReferences = null; - public IReadOnlyList Args = null; + public IEnumerable CompilationReferences = null; + public IEnumerable Args = null; public int Execute() { diff --git a/src/dotnet/commands/dotnet-restore/Program.cs b/src/dotnet/commands/dotnet-restore/Program.cs index 049130a69..a9b3a99dc 100644 --- a/src/dotnet/commands/dotnet-restore/Program.cs +++ b/src/dotnet/commands/dotnet-restore/Program.cs @@ -2,15 +2,9 @@ // 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.Text; +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; -using Microsoft.Dnx.Runtime.Common.CommandLine; -using Microsoft.DotNet.ProjectModel; -using Microsoft.DotNet.ProjectModel.Graph; -using NuGet.Frameworks; using Microsoft.Extensions.PlatformAbstractions; namespace Microsoft.DotNet.Tools.Restore diff --git a/src/dotnet/commands/dotnet-run/Program.cs b/src/dotnet/commands/dotnet-run/Program.cs index fe5ab79c7..8f6805d54 100644 --- a/src/dotnet/commands/dotnet-run/Program.cs +++ b/src/dotnet/commands/dotnet-run/Program.cs @@ -1,9 +1,9 @@ // 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 Microsoft.DotNet.Cli.Utils; using System; -using System.CommandLine; +using Microsoft.DotNet.Cli.CommandLine; +using Microsoft.DotNet.Cli.Utils; namespace Microsoft.DotNet.Tools.Run { @@ -13,56 +13,41 @@ namespace Microsoft.DotNet.Tools.Run { DebugHelper.HandleDebugSwitch(ref args); - var help = false; - string helpText = null; - var returnCode = 0; + CommandLineApplication app = new CommandLineApplication(); + app.Name = "dotnet run"; + app.FullName = ".NET Run Command"; + app.Description = "Command used to run .NET apps"; + app.HelpOption("-h|--help"); - RunCommand runCmd = new RunCommand(); + CommandOption framework = app.Option("-f|--framework", "Compile a specific framework", CommandOptionType.SingleValue); + CommandOption configuration = app.Option("-c|--configuration", "Configuration under which to build", CommandOptionType.SingleValue); + CommandOption project = app.Option("-p|--project", "The path to the project to run (defaults to the current directory). Can be a path to a project.json or a project directory", CommandOptionType.SingleValue); - try + // TODO: this is not supporting args which can be switches (i.e. --test) + // TODO: we need to make a change in CommandLine utils or parse args ourselves. + CommandArgument runArgs = app.Argument("args", "Arguments to pass to the executable or script", multipleValues: true); + + app.OnExecute(() => { - ArgumentSyntax.Parse(args, syntax => - { - syntax.HandleHelp = false; - syntax.HandleErrors = false; + RunCommand runCmd = new RunCommand(); - syntax.DefineOption("f|framework", ref runCmd.Framework, "Compile a specific framework"); - syntax.DefineOption("c|configuration", ref runCmd.Configuration, "Configuration under which to build"); - syntax.DefineOption("p|project", ref runCmd.Project, "The path to the project to run (defaults to the current directory). Can be a path to a project.json or a project directory"); + runCmd.Framework = framework.Value(); + runCmd.Configuration = configuration.Value(); + runCmd.Project = project.Value(); + runCmd.Args = runArgs.Values; - syntax.DefineOption("h|help", ref help, "Help for compile native."); - - // TODO: this is not supporting args which can be switches (i.e. --test) - // TODO: we need to make a change in System.CommandLine or parse args ourselves. - syntax.DefineParameterList("args", ref runCmd.Args, "Arguments to pass to the executable or script"); - - helpText = syntax.GetHelpText(); - }); - } - catch (ArgumentSyntaxException exception) - { - Console.Error.WriteLine(exception.Message); - help = true; - returnCode = 1; - } - - if (help) - { - Console.WriteLine(helpText); - - return returnCode; - } - - try - { return runCmd.Start(); + }); + try + { + return app.Execute(args); } catch (Exception ex) { #if DEBUG - Console.Error.WriteLine(ex); + Reporter.Error.WriteLine(ex.ToString()); #else - Console.Error.WriteLine(ex.Message); + Reporter.Error.WriteLine(ex.Message); #endif return 1; } diff --git a/src/dotnet/commands/dotnet-test/DotnetTestParams.cs b/src/dotnet/commands/dotnet-test/DotnetTestParams.cs index 092ce3e45..a06c1ab56 100644 --- a/src/dotnet/commands/dotnet-test/DotnetTestParams.cs +++ b/src/dotnet/commands/dotnet-test/DotnetTestParams.cs @@ -3,10 +3,8 @@ using System; using System.Collections.Generic; -using System.Diagnostics; using System.IO; -using System.Linq; -using Microsoft.Dnx.Runtime.Common.CommandLine; +using Microsoft.DotNet.Cli.CommandLine; using Microsoft.DotNet.Cli.Utils; using NuGet.Frameworks; using static System.Int32; diff --git a/src/dotnet/dotnet.xproj b/src/dotnet/dotnet.xproj index eb07f538d..e28c05834 100644 --- a/src/dotnet/dotnet.xproj +++ b/src/dotnet/dotnet.xproj @@ -11,7 +11,6 @@ ..\..\artifacts\obj\$(MSBuildProjectName) ..\..\artifacts\bin - 2.0 diff --git a/src/dotnet/project.json b/src/dotnet/project.json index 0ac174b3e..e6a5217d1 100644 --- a/src/dotnet/project.json +++ b/src/dotnet/project.json @@ -24,18 +24,12 @@ "Newtonsoft.Json": "7.0.1", "System.Text.Encoding.CodePages": "4.0.1-rc2-24018", "System.Diagnostics.FileVersionInfo": "4.0.0-rc2-24018", - "System.CommandLine": "0.1.0-e160323-1", "Microsoft.ApplicationInsights": "2.0.0", "Microsoft.DotNet.ProjectModel": "1.0.0-*", "Microsoft.DotNet.Compiler.Common": "1.0.0-*", "Microsoft.DotNet.Cli.Utils": "1.0.0-*", - "Microsoft.DotNet.ILCompiler.SDK": "1.0.6-prerelease-00003", "Microsoft.Extensions.Logging": "1.0.0-rc2-20581", "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-20581", - "Microsoft.Extensions.CommandLineUtils.Sources": { - "type": "build", - "version": "1.0.0-rc2-20221" - }, "Microsoft.Extensions.Testing.Abstractions": "1.0.0-*", "Microsoft.NETCore.ConsoleHost": "1.0.0-rc2-24018", "Microsoft.NETCore.TestHost": "1.0.0-rc2-24018", diff --git a/test/Microsoft.DotNet.Compiler.Common.Tests/Tests.cs b/test/Microsoft.DotNet.Compiler.Common.Tests/Tests.cs index daf589064..b678464b1 100644 --- a/test/Microsoft.DotNet.Compiler.Common.Tests/Tests.cs +++ b/test/Microsoft.DotNet.Compiler.Common.Tests/Tests.cs @@ -1,8 +1,6 @@ // 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.Collections.Generic; -using System.CommandLine; using Microsoft.DotNet.ProjectModel; using Microsoft.DotNet.Tools.Test.Utilities; using Xunit; @@ -11,19 +9,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common { public class Tests : TestBase { - private static void EqualAfterDeserialize(IEnumerable args, CommonCompilerOptions original) - { - CommonCompilerOptions newOptions = null; - - ArgumentSyntax.Parse(args, syntax => - { - newOptions = CommonCompilerOptionsExtensions.Parse(syntax); - }); - - Assert.Equal(original, newOptions); - - } - [Fact] public void SimpleSerialize() { @@ -32,8 +17,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common var args = options.SerializeToArgs(); Assert.Equal(new [] { "--additional-argument:-highentropyva+" }, args); - - EqualAfterDeserialize(args, options); } [Fact] @@ -47,8 +30,6 @@ namespace Microsoft.DotNet.Cli.Compiler.Common "--additional-argument:-highentropyva+", "--additional-argument:-addmodule:\"path with spaces\";\"after semicolon\"" }, args); - - EqualAfterDeserialize(args, options); } } }