From a5c63c90a02665267c11c8bf2c653fd6db8d0107 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Wed, 24 Oct 2018 21:02:24 -0700 Subject: Update to command-line parsing re-organization --- src/WixToolset.Core/CommandLine/CommandLine.cs | 210 +++++++++++++++++++++++++ 1 file changed, 210 insertions(+) create mode 100644 src/WixToolset.Core/CommandLine/CommandLine.cs (limited to 'src/WixToolset.Core/CommandLine/CommandLine.cs') diff --git a/src/WixToolset.Core/CommandLine/CommandLine.cs b/src/WixToolset.Core/CommandLine/CommandLine.cs new file mode 100644 index 00000000..9aefc50a --- /dev/null +++ b/src/WixToolset.Core/CommandLine/CommandLine.cs @@ -0,0 +1,210 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Core.CommandLine +{ + using System; + using System.Collections.Generic; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + internal enum CommandTypes + { + Unknown, + Build, + Preprocess, + Compile, + Link, + Bind, + Decompile, + } + + internal class CommandLine : ICommandLine + { + private static readonly char[] BindPathSplit = { '=' }; + + public CommandLine(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + + this.Messaging = this.ServiceProvider.GetService(); + } + + private IServiceProvider ServiceProvider { get; } + + private IMessaging Messaging { get; set; } + + public IExtensionManager ExtensionManager { get; set; } + + public ICommandLineArguments Arguments { get; set; } + + public static string ExpectedArgument { get; } = "expected argument"; + + public bool ShowHelp { get; private set; } + + public ICommandLineCommand ParseStandardCommandLine() + { + var context = this.ServiceProvider.GetService(); + context.ExtensionManager = this.ExtensionManager ?? this.ServiceProvider.GetService(); + context.Arguments = this.Arguments; + + var command = this.Parse(context); + + if (command.ShowLogo) + { + AppCommon.DisplayToolHeader(); + } + + return command; + //switch (commandType) + //{ + //case CommandTypes.Build: + //{ + // var sourceFiles = GatherSourceFiles(files, outputFolder); + // var variables = this.GatherPreprocessorVariables(defines); + // var bindPathList = this.GatherBindPaths(bindPaths); + // var filterCultures = CalculateFilterCultures(cultures); + // var type = CalculateOutputType(outputType, outputFile); + // var platform = CalculatePlatform(platformType); + // return new BuildCommand(this.ServiceProvider, sourceFiles, variables, locFiles, libraryFiles, filterCultures, outputFile, type, platform, cabCachePath, bindFiles, bindPathList, includePaths, intermediateFolder, contentsFile, outputsFile, builtOutputsFile); + //} + + //case CommandTypes.Compile: + //{ + // var sourceFiles = GatherSourceFiles(files, outputFolder); + // var variables = this.GatherPreprocessorVariables(defines); + // var platform = CalculatePlatform(platformType); + // return new CompileCommand(this.ServiceProvider, sourceFiles, variables, platform); + //} + + //case CommandTypes.Decompile: + //{ + // var sourceFiles = GatherSourceFiles(files, outputFolder); + // return new DecompileCommand(this.ServiceProvider, sourceFiles, outputFile); + //} + //} + + //return null; + } + + private ICommandLineCommand Parse(ICommandLineContext context) + { + var extensions = this.ExtensionManager.Create(); + + foreach (var extension in extensions) + { + extension.PreParse(context); + } + + ICommandLineCommand command = null; + var parser = context.Arguments.Parse(); + + while (command?.StopParsing != true && + String.IsNullOrEmpty(parser.ErrorArgument) && + parser.TryGetNextSwitchOrArgument(out var arg)) + { + if (String.IsNullOrWhiteSpace(arg)) // skip blank arguments. + { + continue; + } + + // First argument must be the command or global switch (that creates a command). + if (command == null) + { + if (!this.TryParseUnknownCommandArg(arg, parser, out command, extensions)) + { + parser.ErrorArgument = arg; + } + } + else if (parser.IsSwitch(arg)) + { + if (!command.TryParseArgument(parser, arg) && !TryParseCommandLineArgumentWithExtension(arg, parser, extensions)) + { + parser.ErrorArgument = arg; + } + } + else if (!TryParseCommandLineArgumentWithExtension(arg, parser, extensions) && command?.TryParseArgument(parser, arg) == false) + { + parser.ErrorArgument = arg; + } + } + + foreach (var extension in extensions) + { + extension.PostParse(); + } + + return command ?? new HelpCommand(); + } + + private bool TryParseUnknownCommandArg(string arg, ICommandLineParser parser, out ICommandLineCommand command, IEnumerable extensions) + { + command = null; + + if (parser.IsSwitch(arg)) + { + var parameter = arg.Substring(1); + switch (parameter.ToLowerInvariant()) + { + case "?": + case "h": + case "help": + command = new HelpCommand(); + break; + + case "version": + case "-version": + command = new VersionCommand(); + break; + } + } + else + { + if (Enum.TryParse(arg, true, out CommandTypes commandType)) + { + switch (commandType) + { + case CommandTypes.Build: + command = new BuildCommand(this.ServiceProvider); + break; + + case CommandTypes.Compile: + command = new CompileCommand(this.ServiceProvider); + break; + + case CommandTypes.Decompile: + command = new DecompileCommand(this.ServiceProvider); + break; + } + } + else + { + foreach (var extension in extensions) + { + if (extension.TryParseCommand(parser, out command)) + { + break; + } + + command = null; + } + } + } + + return command != null; + } + + private static bool TryParseCommandLineArgumentWithExtension(string arg, ICommandLineParser parse, IEnumerable extensions) + { + foreach (var extension in extensions) + { + if (extension.TryParseArgument(parse, arg)) + { + return true; + } + } + + return false; + } + } +} -- cgit v1.2.3-55-g6feb