From fc92b28f87599ac25d35399dc2df2f356a285960 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 12 Jul 2018 22:27:09 -0700 Subject: Refactor command line parsing to enable extensions there in light.exe Fixes wixtoolset/issues#5845 --- src/light/LightCommandLine.cs | 196 ++++++++++++++---------------------------- src/light/light.cs | 49 +++-------- 2 files changed, 80 insertions(+), 165 deletions(-) (limited to 'src/light') diff --git a/src/light/LightCommandLine.cs b/src/light/LightCommandLine.cs index 9a90b9ce..2aa9ea59 100644 --- a/src/light/LightCommandLine.cs +++ b/src/light/LightCommandLine.cs @@ -6,8 +6,8 @@ namespace WixToolset.Tools using System.Collections.Generic; using System.Globalization; using System.IO; - using WixToolset.Core.CommandLine; using WixToolset.Data; + using WixToolset.Extensibility; using WixToolset.Extensibility.Services; public class LightCommandLine @@ -22,7 +22,6 @@ namespace WixToolset.Tools this.SuppressIces = new List(); this.Ices = new List(); this.BindPaths = new List(); - this.Extensions = new List(); this.Files = new List(); this.LocalizationFiles = new List(); this.Variables = new Dictionary(); @@ -80,8 +79,6 @@ namespace WixToolset.Tools public List BindPaths { get; private set; } - public List Extensions { get; private set; } - public List Files { get; private set; } public List LocalizationFiles { get; private set; } @@ -96,35 +93,40 @@ namespace WixToolset.Tools /// Parse the commandline arguments. /// /// Commandline arguments. - public string[] Parse(string[] args) + public string[] Parse(ICommandLineContext context) { - List unprocessed = new List(); + var unprocessed = new List(); + + var extensions = context.ExtensionManager.Create(); + + foreach (var extension in extensions) + { + extension.PreParse(context); + } + + var parser = context.Arguments.Parse(); - for (int i = 0; i < args.Length; ++i) + while (!this.ShowHelp && + String.IsNullOrEmpty(parser.ErrorArgument) && + parser.TryGetNextSwitchOrArgument(out var arg)) { - string arg = args[i]; - if (String.IsNullOrEmpty(arg)) // skip blank arguments + if (String.IsNullOrWhiteSpace(arg)) // skip blank arguments. { continue; } - if (1 == arg.Length) // treat '-' and '@' as filenames when by themselves. + if (parser.IsSwitch(arg)) { - unprocessed.Add(arg); - } - else if ('-' == arg[0] || '/' == arg[0]) - { - string parameter = arg.Substring(1); + var parameter = arg.Substring(1); if (parameter.Equals("b", StringComparison.Ordinal)) { - if (!CommandLineHelper.IsValidArg(args, ++i)) + var result = parser.GetNextArgumentOrError(arg); + if (!String.IsNullOrEmpty(result)) { - break; - } + var bindPath = BindPath.Parse(result); - var bindPath = BindPath.Parse(args[i]); - - this.BindPaths.Add(bindPath); + this.BindPaths.Add(bindPath); + } } else if (parameter.StartsWith("cultures:", StringComparison.Ordinal)) { @@ -184,25 +186,9 @@ namespace WixToolset.Tools this.Variables.Add(value[0], value[1]); } } - else if (parameter.Equals("ext", StringComparison.Ordinal)) - { - if (!CommandLineHelper.IsValidArg(args, ++i)) - { - this.Messaging.Write(ErrorMessages.TypeSpecificationForExtensionRequired("-ext")); - break; - } - - this.Extensions.Add(args[i]); - } else if (parameter.Equals("loc", StringComparison.Ordinal)) { - string locFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - if (String.IsNullOrEmpty(locFile)) - { - break; - } - - this.LocalizationFiles.Add(locFile); + parser.GetNextArgumentAsFilePathOrError(arg, "localization files", this.LocalizationFiles); } else if (parameter.Equals("nologo", StringComparison.Ordinal)) { @@ -214,11 +200,7 @@ namespace WixToolset.Tools } else if ("o" == parameter || "out" == parameter) { - this.OutputFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - if (String.IsNullOrEmpty(this.OutputFile)) - { - break; - } + this.OutputFile = parser.GetNextArgumentAsFilePathOrError(arg); } else if (parameter.Equals("pedantic", StringComparison.Ordinal)) { @@ -230,12 +212,7 @@ namespace WixToolset.Tools } else if (parameter.Equals("usf", StringComparison.Ordinal)) { - this.UnreferencedSymbolsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(this.UnreferencedSymbolsFile)) - { - break; - } + this.UnreferencedSymbolsFile = parser.GetNextArgumentAsDirectoryOrError(arg); } else if (parameter.Equals("xo", StringComparison.Ordinal)) { @@ -243,41 +220,27 @@ namespace WixToolset.Tools } else if (parameter.Equals("cc", StringComparison.Ordinal)) { - this.CabCachePath = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(this.CabCachePath)) - { - break; - } + this.CabCachePath = parser.GetNextArgumentAsDirectoryOrError(arg); } else if (parameter.Equals("ct", StringComparison.Ordinal)) { - if (!CommandLineHelper.IsValidArg(args, ++i)) + var result = parser.GetNextArgumentOrError(arg); + if (!String.IsNullOrEmpty(result)) { - this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(String.Empty)); - break; - } + if (!Int32.TryParse(result, out var ct) || 0 >= ct) + { + this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(result)); + parser.ErrorArgument = arg; + break; + } - int ct = 0; - if (!Int32.TryParse(args[i], out ct) || 0 >= ct) - { - this.Messaging.Write(ErrorMessages.IllegalCabbingThreadCount(args[i])); - break; + this.CabbingThreadCount = ct; + this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); } - - this.CabbingThreadCount = ct; - this.Messaging.Write(VerboseMessages.SetCabbingThreadCount(this.CabbingThreadCount.ToString())); } else if (parameter.Equals("cub", StringComparison.Ordinal)) { - string cubeFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(cubeFile)) - { - break; - } - - this.CubeFiles.Add(cubeFile); + parser.GetNextArgumentAsFilePathOrError(arg, "static validation files", this.CubeFiles); } else if (parameter.StartsWith("ice:", StringComparison.Ordinal)) { @@ -285,57 +248,27 @@ namespace WixToolset.Tools } else if (parameter.Equals("intermediatefolder", StringComparison.OrdinalIgnoreCase)) { - this.IntermediateFolder = CommandLineHelper.GetDirectory(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(this.IntermediateFolder)) - { - break; - } + this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(arg); } else if (parameter.Equals("contentsfile", StringComparison.Ordinal)) { - this.ContentsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(this.ContentsFile)) - { - break; - } + this.ContentsFile = parser.GetNextArgumentAsFilePathOrError(arg); } else if (parameter.Equals("outputsfile", StringComparison.Ordinal)) { - this.OutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(this.OutputsFile)) - { - break; - } + this.OutputsFile = parser.GetNextArgumentAsFilePathOrError(arg); } else if (parameter.Equals("builtoutputsfile", StringComparison.Ordinal)) { - this.BuiltOutputsFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(this.BuiltOutputsFile)) - { - break; - } + this.BuiltOutputsFile = parser.GetNextArgumentAsFilePathOrError(arg); } else if (parameter.Equals("wixprojectfile", StringComparison.Ordinal)) { - this.WixprojectFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(this.WixprojectFile)) - { - break; - } + this.WixprojectFile = parser.GetNextArgumentAsFilePathOrError(arg); } else if (parameter.Equals("pdbout", StringComparison.Ordinal)) { - this.PdbFile = CommandLineHelper.GetFile(parameter, this.Messaging, args, ++i); - - if (String.IsNullOrEmpty(this.PdbFile)) - { - break; - } + this.PdbFile = parser.GetNextArgumentAsFilePathOrError(arg); } else if (parameter.StartsWith("sice:", StringComparison.Ordinal)) { @@ -410,45 +343,35 @@ namespace WixToolset.Tools this.ShowHelp = true; break; } - else + else if (!this.TryParseCommandLineArgumentWithExtension(arg, parser, extensions)) { unprocessed.Add(arg); } } - else if ('@' == arg[0]) - { - string[] parsedArgs = CommandLineResponseFile.Parse(arg.Substring(1)); - string[] unparsedArgs = this.Parse(parsedArgs); - unprocessed.AddRange(unparsedArgs); - } - else + else if (!this.TryParseCommandLineArgumentWithExtension(arg, parser, extensions)) { unprocessed.Add(arg); } } - return unprocessed.ToArray(); + return this.ParsePostExtensions(parser, unprocessed.ToArray()); } - public string[] ParsePostExtensions(string[] remaining) + private string[] ParsePostExtensions(IParseCommandLine parser, string[] remaining) { - List unprocessed = new List(); + var unprocessed = new List(); for (int i = 0; i < remaining.Length; ++i) { - string arg = remaining[i]; - if (String.IsNullOrEmpty(arg)) // skip blank arguments - { - continue; - } + var arg = remaining[i]; - if (1 < arg.Length && ('-' == arg[0] || '/' == arg[0])) + if (parser.IsSwitch(arg)) { unprocessed.Add(arg); } else { - this.Files.AddRange(CommandLineHelper.GetFiles(arg, "Source")); + parser.GetArgumentAsFilePathOrError(arg, "source files", this.Files); } } @@ -469,7 +392,7 @@ namespace WixToolset.Tools // Add the directories of the input files as unnamed bind paths. foreach (string file in this.Files) { - BindPath bindPath = new BindPath(Path.GetDirectoryName(Path.GetFullPath(file))); + var bindPath = new BindPath(Path.GetDirectoryName(Path.GetFullPath(file))); this.BindPaths.Add(bindPath); } } @@ -481,5 +404,18 @@ namespace WixToolset.Tools return unprocessed.ToArray(); } + + private bool TryParseCommandLineArgumentWithExtension(string arg, IParseCommandLine parser, IEnumerable extensions) + { + foreach (var extension in extensions) + { + if (extension.TryParseArgument(parser, arg)) + { + return true; + } + } + + return false; + } } } diff --git a/src/light/light.cs b/src/light/light.cs index c0967caa..0f467bbb 100644 --- a/src/light/light.cs +++ b/src/light/light.cs @@ -22,7 +22,6 @@ namespace WixToolset.Tools public sealed class Light { LightCommandLine commandLine; - private IEnumerable extensionData; //private IEnumerable binderExtensions; //private IEnumerable fileManagers; @@ -101,45 +100,20 @@ namespace WixToolset.Tools /// Command line arguments to be parsed. private IEnumerable ParseCommandLineAndLoadExtensions(IServiceProvider serviceProvider, IMessaging messaging, string[] args) { - this.commandLine = new LightCommandLine(messaging); + var arguments = serviceProvider.GetService(); + arguments.Populate(args); - string[] unprocessed = this.commandLine.Parse(args); - if (messaging.EncounteredError) - { - return unprocessed; - } + var extensionManager = CreateExtensionManagerWithStandardBackends(serviceProvider, arguments.Extensions); - // Load extensions. - var extensionManager = CreateExtensionManagerWithStandardBackends(serviceProvider); - foreach (string extension in this.commandLine.Extensions) - { - extensionManager.Load(extension); - } - - // Extension data command line processing. var context = serviceProvider.GetService(); - context.Arguments = null; context.ExtensionManager = extensionManager; context.Messaging = messaging; - context.ParsedArguments = args; - - var commandLineExtensions = extensionManager.Create(); - foreach (var extension in commandLineExtensions) - { - extension.PreParse(context); - } + context.Arguments = arguments; - // Process unproccessed arguments. - List actuallyUnprocessed = new List(); - foreach (var arg in unprocessed) - { - if (!this.TryParseCommandLineArgumentWithExtension(arg, commandLineExtensions)) - { - actuallyUnprocessed.Add(arg); - } - } + this.commandLine = new LightCommandLine(messaging); + var unprocessed = this.commandLine.Parse(context); - return this.commandLine.ParsePostExtensions(actuallyUnprocessed.ToArray()); + return unprocessed; } private void Bind(IServiceProvider serviceProvider, IMessaging messaging) @@ -194,7 +168,7 @@ namespace WixToolset.Tools binder.IntermediateRepresentation = resolveResult.IntermediateRepresentation; binder.OutputPath = this.commandLine.OutputFile; binder.OutputPdbPath = Path.ChangeExtension(this.commandLine.OutputFile, ".wixpdb"); - binder.SuppressIces = this.commandLine.SuppressIces; + binder.SuppressIces = this.commandLine.SuppressIces; binder.SuppressValidation = this.commandLine.SuppressValidation; bindResult = binder.Execute(); @@ -526,7 +500,7 @@ namespace WixToolset.Tools return Intermediate.Load(path); } - private static IExtensionManager CreateExtensionManagerWithStandardBackends(IServiceProvider serviceProvider) + private static IExtensionManager CreateExtensionManagerWithStandardBackends(IServiceProvider serviceProvider, IEnumerable extensions) { var extensionManager = serviceProvider.GetService(); @@ -535,6 +509,11 @@ namespace WixToolset.Tools extensionManager.Add(type.Assembly); } + foreach (var extension in extensions) + { + extensionManager.Load(extension); + } + return extensionManager; } -- cgit v1.2.3-55-g6feb