diff options
| author | Rob Mensching <rob@firegiant.com> | 2018-10-24 21:02:24 -0700 |
|---|---|---|
| committer | Rob Mensching <rob@robmensching.com> | 2018-10-24 21:17:34 -0700 |
| commit | a5c63c90a02665267c11c8bf2c653fd6db8d0107 (patch) | |
| tree | ebd38c870168ec613bc36b0ddf9d34d9e6e78b8e /src | |
| parent | 0ecb2ac1ba28d33b0b3d17a2d7134d2f5485814d (diff) | |
| download | wix-a5c63c90a02665267c11c8bf2c653fd6db8d0107.tar.gz wix-a5c63c90a02665267c11c8bf2c653fd6db8d0107.tar.bz2 wix-a5c63c90a02665267c11c8bf2c653fd6db8d0107.zip | |
Update to command-line parsing re-organization
Diffstat (limited to 'src')
| -rw-r--r-- | src/WixToolset.Core.TestPackage/WixRunner.cs | 2 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/BuildCommand.cs | 478 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/CommandLine.cs | 210 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/CommandLineArguments.cs | 4 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/CommandLineParser.cs | 514 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/CompileCommand.cs | 18 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/HelpCommand.cs | 22 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/ParseCommandLine.cs | 263 | ||||
| -rw-r--r-- | src/WixToolset.Core/CommandLine/VersionCommand.cs | 10 | ||||
| -rw-r--r-- | src/WixToolset.Core/WixToolsetServiceProvider.cs | 4 | ||||
| -rw-r--r-- | src/test/Example.Extension/ExamplePreprocessorExtensionAndCommandLine.cs | 14 |
11 files changed, 824 insertions, 715 deletions
diff --git a/src/WixToolset.Core.TestPackage/WixRunner.cs b/src/WixToolset.Core.TestPackage/WixRunner.cs index d7487f6d..ab5045fa 100644 --- a/src/WixToolset.Core.TestPackage/WixRunner.cs +++ b/src/WixToolset.Core.TestPackage/WixRunner.cs | |||
| @@ -35,7 +35,7 @@ namespace WixToolset.Core.TestPackage | |||
| 35 | var arguments = serviceProvider.GetService<ICommandLineArguments>(); | 35 | var arguments = serviceProvider.GetService<ICommandLineArguments>(); |
| 36 | arguments.Populate(args); | 36 | arguments.Populate(args); |
| 37 | 37 | ||
| 38 | var commandLine = serviceProvider.GetService<ICommandLineParser>(); | 38 | var commandLine = serviceProvider.GetService<ICommandLine>(); |
| 39 | commandLine.ExtensionManager = CreateExtensionManagerWithStandardBackends(serviceProvider, arguments.Extensions); | 39 | commandLine.ExtensionManager = CreateExtensionManagerWithStandardBackends(serviceProvider, arguments.Extensions); |
| 40 | commandLine.Arguments = arguments; | 40 | commandLine.Arguments = arguments; |
| 41 | var command = commandLine.ParseStandardCommandLine(); | 41 | var command = commandLine.ParseStandardCommandLine(); |
diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs index 6052d979..87a3cd30 100644 --- a/src/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // 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. | 1 | // 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. |
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.CommandLine | 3 | namespace WixToolset.Core.CommandLine |
| 4 | { | 4 | { |
| @@ -14,83 +14,84 @@ namespace WixToolset.Core.CommandLine | |||
| 14 | 14 | ||
| 15 | internal class BuildCommand : ICommandLineCommand | 15 | internal class BuildCommand : ICommandLineCommand |
| 16 | { | 16 | { |
| 17 | public BuildCommand(IServiceProvider serviceProvider, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, IEnumerable<string> locFiles, IEnumerable<string> libraryFiles, IEnumerable<string> filterCultures, string outputPath, OutputType outputType, Platform platform, string cabCachePath, bool bindFiles, IEnumerable<BindPath> bindPaths, IEnumerable<string> includeSearchPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile) | 17 | private readonly CommandLine commandLine; |
| 18 | |||
| 19 | public BuildCommand(IServiceProvider serviceProvider) | ||
| 18 | { | 20 | { |
| 19 | this.ServiceProvider = serviceProvider; | 21 | this.ServiceProvider = serviceProvider; |
| 20 | this.Messaging = serviceProvider.GetService<IMessaging>(); | 22 | this.Messaging = serviceProvider.GetService<IMessaging>(); |
| 21 | this.ExtensionManager = serviceProvider.GetService<IExtensionManager>(); | 23 | this.ExtensionManager = serviceProvider.GetService<IExtensionManager>(); |
| 22 | this.LocFiles = locFiles; | 24 | this.commandLine = new CommandLine(this.Messaging); |
| 23 | this.LibraryFiles = libraryFiles; | ||
| 24 | this.FilterCultures = filterCultures; | ||
| 25 | this.PreprocessorVariables = preprocessorVariables; | ||
| 26 | this.SourceFiles = sources; | ||
| 27 | this.OutputPath = outputPath; | ||
| 28 | this.OutputType = outputType; | ||
| 29 | this.Platform = platform; | ||
| 30 | |||
| 31 | this.CabCachePath = cabCachePath; | ||
| 32 | this.BindFiles = bindFiles; | ||
| 33 | this.BindPaths = bindPaths; | ||
| 34 | this.IncludeSearchPaths = includeSearchPaths; | ||
| 35 | |||
| 36 | this.IntermediateFolder = intermediateFolder ?? Path.GetTempPath(); | ||
| 37 | this.ContentsFile = contentsFile; | ||
| 38 | this.OutputsFile = outputsFile; | ||
| 39 | this.BuiltOutputsFile = builtOutputsFile; | ||
| 40 | } | 25 | } |
| 41 | 26 | ||
| 42 | public IServiceProvider ServiceProvider { get; } | 27 | public bool ShowLogo => this.commandLine.ShowLogo; |
| 43 | 28 | ||
| 44 | public IMessaging Messaging { get; } | 29 | public bool StopParsing => this.commandLine.ShowHelp; |
| 45 | 30 | ||
| 46 | public IExtensionManager ExtensionManager { get; } | 31 | private IServiceProvider ServiceProvider { get; } |
| 47 | 32 | ||
| 48 | public IEnumerable<string> FilterCultures { get; } | 33 | private IMessaging Messaging { get; } |
| 49 | 34 | ||
| 50 | public IEnumerable<string> IncludeSearchPaths { get; } | 35 | private IExtensionManager ExtensionManager { get; } |
| 51 | 36 | ||
| 52 | public IEnumerable<string> LocFiles { get; } | 37 | private string IntermediateFolder { get; set; } |
| 53 | 38 | ||
| 54 | public IEnumerable<string> LibraryFiles { get; } | 39 | private OutputType OutputType { get; set; } |
| 55 | 40 | ||
| 56 | private IEnumerable<SourceFile> SourceFiles { get; } | 41 | private List<string> IncludeSearchPaths { get; set; } |
| 57 | 42 | ||
| 58 | private IDictionary<string, string> PreprocessorVariables { get; } | 43 | private Platform Platform { get; set; } |
| 59 | 44 | ||
| 60 | private string OutputPath { get; } | 45 | private string OutputFile { get; set; } |
| 61 | 46 | ||
| 62 | private OutputType OutputType { get; } | 47 | private string ContentsFile { get; set; } |
| 63 | 48 | ||
| 64 | private Platform Platform { get; } | 49 | private string OutputsFile { get; set; } |
| 65 | 50 | ||
| 66 | public string CabCachePath { get; } | 51 | private string BuiltOutputsFile { get; set; } |
| 67 | 52 | ||
| 68 | public bool BindFiles { get; } | 53 | public int Execute() |
| 54 | { | ||
| 55 | if (this.commandLine.ShowHelp) | ||
| 56 | { | ||
| 57 | Console.WriteLine("TODO: Show build command help"); | ||
| 58 | return -1; | ||
| 59 | } | ||
| 69 | 60 | ||
| 70 | public IEnumerable<BindPath> BindPaths { get; } | 61 | this.IntermediateFolder = this.commandLine.CalculateIntermedateFolder(); |
| 71 | 62 | ||
| 72 | public string IntermediateFolder { get; } | 63 | this.OutputType = this.commandLine.CalculateOutputType(); |
| 73 | 64 | ||
| 74 | public string ContentsFile { get; } | 65 | this.IncludeSearchPaths = this.commandLine.IncludeSearchPaths; |
| 75 | 66 | ||
| 76 | public string OutputsFile { get; } | 67 | this.Platform = this.commandLine.Platform; |
| 77 | 68 | ||
| 78 | public string BuiltOutputsFile { get; } | 69 | this.OutputFile = this.commandLine.OutputFile; |
| 70 | |||
| 71 | this.ContentsFile = this.commandLine.ContentsFile; | ||
| 72 | |||
| 73 | this.OutputsFile = this.commandLine.OutputsFile; | ||
| 74 | |||
| 75 | this.BuiltOutputsFile = this.commandLine.BuiltOutputsFile; | ||
| 76 | |||
| 77 | var preprocessorVariables = this.commandLine.GatherPreprocessorVariables(); | ||
| 78 | |||
| 79 | var sourceFiles = this.commandLine.GatherSourceFiles(this.IntermediateFolder); | ||
| 80 | |||
| 81 | var filterCultures = this.commandLine.CalculateFilterCultures(); | ||
| 79 | 82 | ||
| 80 | public int Execute() | ||
| 81 | { | ||
| 82 | var creator = this.ServiceProvider.GetService<ITupleDefinitionCreator>(); | 83 | var creator = this.ServiceProvider.GetService<ITupleDefinitionCreator>(); |
| 83 | 84 | ||
| 84 | this.EvaluateSourceFiles(creator, out var codeFiles, out var wixipl); | 85 | this.EvaluateSourceFiles(sourceFiles, creator, out var codeFiles, out var wixipl); |
| 85 | 86 | ||
| 86 | if (this.Messaging.EncounteredError) | 87 | if (this.Messaging.EncounteredError) |
| 87 | { | 88 | { |
| 88 | return this.Messaging.LastErrorNumber; | 89 | return this.Messaging.LastErrorNumber; |
| 89 | } | 90 | } |
| 90 | 91 | ||
| 91 | var wixobjs = this.CompilePhase(codeFiles); | 92 | var wixobjs = this.CompilePhase(preprocessorVariables, codeFiles); |
| 92 | 93 | ||
| 93 | var wxls = this.LoadLocalizationFiles().ToList(); | 94 | var wxls = this.LoadLocalizationFiles(this.commandLine.LocalizationFilePaths, preprocessorVariables); |
| 94 | 95 | ||
| 95 | if (this.Messaging.EncounteredError) | 96 | if (this.Messaging.EncounteredError) |
| 96 | { | 97 | { |
| @@ -99,29 +100,29 @@ namespace WixToolset.Core.CommandLine | |||
| 99 | 100 | ||
| 100 | if (this.OutputType == OutputType.Library) | 101 | if (this.OutputType == OutputType.Library) |
| 101 | { | 102 | { |
| 102 | var wixlib = this.LibraryPhase(wixobjs, wxls); | 103 | var wixlib = this.LibraryPhase(wixobjs, wxls, this.commandLine.BindFiles, this.commandLine.BindPaths); |
| 103 | 104 | ||
| 104 | if (!this.Messaging.EncounteredError) | 105 | if (!this.Messaging.EncounteredError) |
| 105 | { | 106 | { |
| 106 | wixlib.Save(this.OutputPath); | 107 | wixlib.Save(this.commandLine.OutputFile); |
| 107 | } | 108 | } |
| 108 | } | 109 | } |
| 109 | else | 110 | else |
| 110 | { | 111 | { |
| 111 | if (wixipl == null) | 112 | if (wixipl == null) |
| 112 | { | 113 | { |
| 113 | wixipl = this.LinkPhase(wixobjs, creator); | 114 | wixipl = this.LinkPhase(wixobjs, this.commandLine.LibraryFilePaths, creator); |
| 114 | } | 115 | } |
| 115 | 116 | ||
| 116 | if (!this.Messaging.EncounteredError) | 117 | if (!this.Messaging.EncounteredError) |
| 117 | { | 118 | { |
| 118 | if (this.OutputType == OutputType.IntermediatePostLink) | 119 | if (this.OutputType == OutputType.IntermediatePostLink) |
| 119 | { | 120 | { |
| 120 | wixipl.Save(this.OutputPath); | 121 | wixipl.Save(this.commandLine.OutputFile); |
| 121 | } | 122 | } |
| 122 | else | 123 | else |
| 123 | { | 124 | { |
| 124 | this.BindPhase(wixipl, wxls); | 125 | this.BindPhase(wixipl, wxls, filterCultures, this.commandLine.CabCachePath, this.commandLine.BindPaths); |
| 125 | } | 126 | } |
| 126 | } | 127 | } |
| 127 | } | 128 | } |
| @@ -129,13 +130,18 @@ namespace WixToolset.Core.CommandLine | |||
| 129 | return this.Messaging.LastErrorNumber; | 130 | return this.Messaging.LastErrorNumber; |
| 130 | } | 131 | } |
| 131 | 132 | ||
| 132 | private void EvaluateSourceFiles(ITupleDefinitionCreator creator, out List<SourceFile> codeFiles, out Intermediate wixipl) | 133 | public bool TryParseArgument(ICommandLineParser parser, string argument) |
| 134 | { | ||
| 135 | return this.commandLine.TryParseArgument(argument, parser); | ||
| 136 | } | ||
| 137 | |||
| 138 | private void EvaluateSourceFiles(IEnumerable<SourceFile> sourceFiles, ITupleDefinitionCreator creator, out List<SourceFile> codeFiles, out Intermediate wixipl) | ||
| 133 | { | 139 | { |
| 134 | codeFiles = new List<SourceFile>(); | 140 | codeFiles = new List<SourceFile>(); |
| 135 | 141 | ||
| 136 | wixipl = null; | 142 | wixipl = null; |
| 137 | 143 | ||
| 138 | foreach (var sourceFile in this.SourceFiles) | 144 | foreach (var sourceFile in sourceFiles) |
| 139 | { | 145 | { |
| 140 | var extension = Path.GetExtension(sourceFile.SourcePath); | 146 | var extension = Path.GetExtension(sourceFile.SourcePath); |
| 141 | 147 | ||
| @@ -167,13 +173,13 @@ namespace WixToolset.Core.CommandLine | |||
| 167 | } | 173 | } |
| 168 | } | 174 | } |
| 169 | 175 | ||
| 170 | private IEnumerable<Intermediate> CompilePhase(IEnumerable<SourceFile> sourceFiles) | 176 | private IEnumerable<Intermediate> CompilePhase(IDictionary<string, string> preprocessorVariables, IEnumerable<SourceFile> sourceFiles) |
| 171 | { | 177 | { |
| 172 | var intermediates = new List<Intermediate>(); | 178 | var intermediates = new List<Intermediate>(); |
| 173 | 179 | ||
| 174 | foreach (var sourceFile in sourceFiles) | 180 | foreach (var sourceFile in sourceFiles) |
| 175 | { | 181 | { |
| 176 | var document = this.Preprocess(sourceFile.SourcePath); | 182 | var document = this.Preprocess(preprocessorVariables, sourceFile.SourcePath); |
| 177 | 183 | ||
| 178 | if (this.Messaging.EncounteredError) | 184 | if (this.Messaging.EncounteredError) |
| 179 | { | 185 | { |
| @@ -208,11 +214,11 @@ namespace WixToolset.Core.CommandLine | |||
| 208 | return intermediates; | 214 | return intermediates; |
| 209 | } | 215 | } |
| 210 | 216 | ||
| 211 | private Intermediate LibraryPhase(IEnumerable<Intermediate> intermediates, IEnumerable<Localization> localizations) | 217 | private Intermediate LibraryPhase(IEnumerable<Intermediate> intermediates, IEnumerable<Localization> localizations, bool bindFiles, IEnumerable<BindPath> bindPaths) |
| 212 | { | 218 | { |
| 213 | var context = this.ServiceProvider.GetService<ILibraryContext>(); | 219 | var context = this.ServiceProvider.GetService<ILibraryContext>(); |
| 214 | context.BindFiles = this.BindFiles; | 220 | context.BindFiles = bindFiles; |
| 215 | context.BindPaths = this.BindPaths; | 221 | context.BindPaths = bindPaths; |
| 216 | context.Extensions = this.ExtensionManager.Create<ILibrarianExtension>(); | 222 | context.Extensions = this.ExtensionManager.Create<ILibrarianExtension>(); |
| 217 | context.Localizations = localizations; | 223 | context.Localizations = localizations; |
| 218 | context.Intermediates = intermediates; | 224 | context.Intermediates = intermediates; |
| @@ -230,10 +236,10 @@ namespace WixToolset.Core.CommandLine | |||
| 230 | 236 | ||
| 231 | return library; | 237 | return library; |
| 232 | } | 238 | } |
| 233 | 239 | ||
| 234 | private Intermediate LinkPhase(IEnumerable<Intermediate> intermediates, ITupleDefinitionCreator creator) | 240 | private Intermediate LinkPhase(IEnumerable<Intermediate> intermediates, IEnumerable<string> libraryFiles, ITupleDefinitionCreator creator) |
| 235 | { | 241 | { |
| 236 | var libraries = this.LoadLibraries(creator); | 242 | var libraries = this.LoadLibraries(libraryFiles, creator); |
| 237 | 243 | ||
| 238 | if (this.Messaging.EncounteredError) | 244 | if (this.Messaging.EncounteredError) |
| 239 | { | 245 | { |
| @@ -251,7 +257,7 @@ namespace WixToolset.Core.CommandLine | |||
| 251 | return linker.Link(context); | 257 | return linker.Link(context); |
| 252 | } | 258 | } |
| 253 | 259 | ||
| 254 | private void BindPhase(Intermediate output, IEnumerable<Localization> localizations) | 260 | private void BindPhase(Intermediate output, IEnumerable<Localization> localizations, IEnumerable<string> filterCultures, string cabCachePath, IEnumerable<BindPath> bindPaths) |
| 255 | { | 261 | { |
| 256 | var intermediateFolder = this.IntermediateFolder; | 262 | var intermediateFolder = this.IntermediateFolder; |
| 257 | if (String.IsNullOrEmpty(intermediateFolder)) | 263 | if (String.IsNullOrEmpty(intermediateFolder)) |
| @@ -262,10 +268,10 @@ namespace WixToolset.Core.CommandLine | |||
| 262 | ResolveResult resolveResult; | 268 | ResolveResult resolveResult; |
| 263 | { | 269 | { |
| 264 | var context = this.ServiceProvider.GetService<IResolveContext>(); | 270 | var context = this.ServiceProvider.GetService<IResolveContext>(); |
| 265 | context.BindPaths = this.BindPaths; | 271 | context.BindPaths = bindPaths; |
| 266 | context.Extensions = this.ExtensionManager.Create<IResolverExtension>(); | 272 | context.Extensions = this.ExtensionManager.Create<IResolverExtension>(); |
| 267 | context.ExtensionData = this.ExtensionManager.Create<IExtensionData>(); | 273 | context.ExtensionData = this.ExtensionManager.Create<IExtensionData>(); |
| 268 | context.FilterCultures = this.FilterCultures; | 274 | context.FilterCultures = filterCultures; |
| 269 | context.IntermediateFolder = intermediateFolder; | 275 | context.IntermediateFolder = intermediateFolder; |
| 270 | context.IntermediateRepresentation = output; | 276 | context.IntermediateRepresentation = output; |
| 271 | context.Localizations = localizations; | 277 | context.Localizations = localizations; |
| @@ -284,7 +290,7 @@ namespace WixToolset.Core.CommandLine | |||
| 284 | { | 290 | { |
| 285 | var context = this.ServiceProvider.GetService<IBindContext>(); | 291 | var context = this.ServiceProvider.GetService<IBindContext>(); |
| 286 | //context.CabbingThreadCount = this.CabbingThreadCount; | 292 | //context.CabbingThreadCount = this.CabbingThreadCount; |
| 287 | context.CabCachePath = this.CabCachePath; | 293 | context.CabCachePath = cabCachePath; |
| 288 | context.Codepage = resolveResult.Codepage; | 294 | context.Codepage = resolveResult.Codepage; |
| 289 | //context.DefaultCompressionLevel = this.DefaultCompressionLevel; | 295 | //context.DefaultCompressionLevel = this.DefaultCompressionLevel; |
| 290 | context.DelayedFields = resolveResult.DelayedFields; | 296 | context.DelayedFields = resolveResult.DelayedFields; |
| @@ -293,8 +299,8 @@ namespace WixToolset.Core.CommandLine | |||
| 293 | context.Ices = Array.Empty<string>(); // TODO: set this correctly | 299 | context.Ices = Array.Empty<string>(); // TODO: set this correctly |
| 294 | context.IntermediateFolder = intermediateFolder; | 300 | context.IntermediateFolder = intermediateFolder; |
| 295 | context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; | 301 | context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; |
| 296 | context.OutputPath = this.OutputPath; | 302 | context.OutputPath = this.OutputFile; |
| 297 | context.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb"); | 303 | context.OutputPdbPath = Path.ChangeExtension(this.OutputFile, ".wixpdb"); |
| 298 | context.SuppressIces = Array.Empty<string>(); // TODO: set this correctly | 304 | context.SuppressIces = Array.Empty<string>(); // TODO: set this correctly |
| 299 | context.SuppressValidation = true; // TODO: set this correctly | 305 | context.SuppressValidation = true; // TODO: set this correctly |
| 300 | 306 | ||
| @@ -323,41 +329,39 @@ namespace WixToolset.Core.CommandLine | |||
| 323 | } | 329 | } |
| 324 | } | 330 | } |
| 325 | 331 | ||
| 326 | private IEnumerable<Intermediate> LoadLibraries(ITupleDefinitionCreator creator) | 332 | private IEnumerable<Intermediate> LoadLibraries(IEnumerable<string> libraryFiles, ITupleDefinitionCreator creator) |
| 327 | { | 333 | { |
| 328 | var libraries = new List<Intermediate>(); | 334 | var libraries = new List<Intermediate>(); |
| 329 | 335 | ||
| 330 | if (this.LibraryFiles != null) | 336 | foreach (var libraryFile in libraryFiles) |
| 331 | { | 337 | { |
| 332 | foreach (var libraryFile in this.LibraryFiles) | 338 | try |
| 333 | { | 339 | { |
| 334 | try | 340 | var library = Intermediate.Load(libraryFile, creator); |
| 335 | { | ||
| 336 | var library = Intermediate.Load(libraryFile, creator); | ||
| 337 | 341 | ||
| 338 | libraries.Add(library); | 342 | libraries.Add(library); |
| 339 | } | 343 | } |
| 340 | catch (WixCorruptFileException e) | 344 | catch (WixCorruptFileException e) |
| 341 | { | 345 | { |
| 342 | this.Messaging.Write(e.Error); | 346 | this.Messaging.Write(e.Error); |
| 343 | } | 347 | } |
| 344 | catch (WixUnexpectedFileFormatException e) | 348 | catch (WixUnexpectedFileFormatException e) |
| 345 | { | 349 | { |
| 346 | this.Messaging.Write(e.Error); | 350 | this.Messaging.Write(e.Error); |
| 347 | } | ||
| 348 | } | 351 | } |
| 349 | } | 352 | } |
| 350 | 353 | ||
| 351 | return libraries; | 354 | return libraries; |
| 352 | } | 355 | } |
| 353 | 356 | ||
| 354 | private IEnumerable<Localization> LoadLocalizationFiles() | 357 | private IEnumerable<Localization> LoadLocalizationFiles(IEnumerable<string> locFiles, IDictionary<string, string> preprocessorVariables) |
| 355 | { | 358 | { |
| 356 | var localizer = new Localizer(this.ServiceProvider); | 359 | var localizations = new List<Localization>(); |
| 360 | var localizer = this.ServiceProvider.GetService<ILocalizer>(); | ||
| 357 | 361 | ||
| 358 | foreach (var loc in this.LocFiles) | 362 | foreach (var loc in locFiles) |
| 359 | { | 363 | { |
| 360 | var document = this.Preprocess(loc); | 364 | var document = this.Preprocess(preprocessorVariables, loc); |
| 361 | 365 | ||
| 362 | if (this.Messaging.EncounteredError) | 366 | if (this.Messaging.EncounteredError) |
| 363 | { | 367 | { |
| @@ -365,18 +369,20 @@ namespace WixToolset.Core.CommandLine | |||
| 365 | } | 369 | } |
| 366 | 370 | ||
| 367 | var localization = localizer.ParseLocalizationFile(document); | 371 | var localization = localizer.ParseLocalizationFile(document); |
| 368 | yield return localization; | 372 | localizations.Add(localization); |
| 369 | } | 373 | } |
| 374 | |||
| 375 | return localizations; | ||
| 370 | } | 376 | } |
| 371 | 377 | ||
| 372 | private XDocument Preprocess(string sourcePath) | 378 | private XDocument Preprocess(IDictionary<string, string> preprocessorVariables, string sourcePath) |
| 373 | { | 379 | { |
| 374 | var context = this.ServiceProvider.GetService<IPreprocessContext>(); | 380 | var context = this.ServiceProvider.GetService<IPreprocessContext>(); |
| 375 | context.Extensions = this.ExtensionManager.Create<IPreprocessorExtension>(); | 381 | context.Extensions = this.ExtensionManager.Create<IPreprocessorExtension>(); |
| 376 | context.Platform = this.Platform; | 382 | context.Platform = this.Platform; |
| 377 | context.IncludeSearchPaths = this.IncludeSearchPaths; | 383 | context.IncludeSearchPaths = this.IncludeSearchPaths; |
| 378 | context.SourcePath = sourcePath; | 384 | context.SourcePath = sourcePath; |
| 379 | context.Variables = this.PreprocessorVariables; | 385 | context.Variables = preprocessorVariables; |
| 380 | 386 | ||
| 381 | XDocument document = null; | 387 | XDocument document = null; |
| 382 | try | 388 | try |
| @@ -391,5 +397,301 @@ namespace WixToolset.Core.CommandLine | |||
| 391 | 397 | ||
| 392 | return document; | 398 | return document; |
| 393 | } | 399 | } |
| 400 | |||
| 401 | private class CommandLine | ||
| 402 | { | ||
| 403 | private static readonly char[] BindPathSplit = { '=' }; | ||
| 404 | |||
| 405 | public bool BindFiles { get; private set; } | ||
| 406 | |||
| 407 | public List<BindPath> BindPaths { get; } = new List<BindPath>(); | ||
| 408 | |||
| 409 | public string CabCachePath { get; private set; } | ||
| 410 | |||
| 411 | public List<string> Cultures { get; } = new List<string>(); | ||
| 412 | |||
| 413 | public List<string> Defines { get; } = new List<string>(); | ||
| 414 | |||
| 415 | public List<string> IncludeSearchPaths { get; } = new List<string>(); | ||
| 416 | |||
| 417 | public List<string> LocalizationFilePaths { get; } = new List<string>(); | ||
| 418 | |||
| 419 | public List<string> LibraryFilePaths { get; } = new List<string>(); | ||
| 420 | |||
| 421 | public List<string> SourceFilePaths { get; } = new List<string>(); | ||
| 422 | |||
| 423 | public Platform Platform { get; private set; } | ||
| 424 | |||
| 425 | public bool ShowLogo { get; private set; } | ||
| 426 | |||
| 427 | public bool ShowHelp { get; private set; } | ||
| 428 | |||
| 429 | public string IntermediateFolder { get; private set; } | ||
| 430 | |||
| 431 | public string OutputFile { get; private set; } | ||
| 432 | |||
| 433 | public string OutputType { get; private set; } | ||
| 434 | |||
| 435 | public string ContentsFile { get; private set; } | ||
| 436 | |||
| 437 | public string OutputsFile { get; private set; } | ||
| 438 | |||
| 439 | public string BuiltOutputsFile { get; private set; } | ||
| 440 | |||
| 441 | public CommandLine(IMessaging messaging) | ||
| 442 | { | ||
| 443 | this.Messaging = messaging; | ||
| 444 | } | ||
| 445 | |||
| 446 | private IMessaging Messaging { get; } | ||
| 447 | |||
| 448 | public bool TryParseArgument(string arg, ICommandLineParser parser) | ||
| 449 | { | ||
| 450 | if (parser.IsSwitch(arg)) | ||
| 451 | { | ||
| 452 | var parameter = arg.Substring(1); | ||
| 453 | switch (parameter.ToLowerInvariant()) | ||
| 454 | { | ||
| 455 | case "?": | ||
| 456 | case "h": | ||
| 457 | case "help": | ||
| 458 | this.ShowHelp = true; | ||
| 459 | return true; | ||
| 460 | |||
| 461 | case "arch": | ||
| 462 | case "platform": | ||
| 463 | { | ||
| 464 | var value = parser.GetNextArgumentOrError(arg); | ||
| 465 | if (Enum.TryParse(value, true, out Platform platform)) | ||
| 466 | { | ||
| 467 | this.Platform = platform; | ||
| 468 | return true; | ||
| 469 | } | ||
| 470 | break; | ||
| 471 | } | ||
| 472 | |||
| 473 | case "bindfiles": | ||
| 474 | this.BindFiles = true; | ||
| 475 | return true; | ||
| 476 | |||
| 477 | case "bindpath": | ||
| 478 | { | ||
| 479 | var value = parser.GetNextArgumentOrError(arg); | ||
| 480 | if (this.TryParseBindPath(value, out var bindPath)) | ||
| 481 | { | ||
| 482 | this.BindPaths.Add(bindPath); | ||
| 483 | return true; | ||
| 484 | } | ||
| 485 | break; | ||
| 486 | } | ||
| 487 | case "cc": | ||
| 488 | this.CabCachePath = parser.GetNextArgumentOrError(arg); | ||
| 489 | return true; | ||
| 490 | |||
| 491 | case "culture": | ||
| 492 | parser.GetNextArgumentOrError(arg, this.Cultures); | ||
| 493 | return true; | ||
| 494 | |||
| 495 | case "contentsfile": | ||
| 496 | this.ContentsFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 497 | return true; | ||
| 498 | case "outputsfile": | ||
| 499 | this.OutputsFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 500 | return true; | ||
| 501 | case "builtoutputsfile": | ||
| 502 | this.BuiltOutputsFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 503 | return true; | ||
| 504 | |||
| 505 | case "d": | ||
| 506 | case "define": | ||
| 507 | parser.GetNextArgumentOrError(arg, this.Defines); | ||
| 508 | return true; | ||
| 509 | |||
| 510 | case "i": | ||
| 511 | case "includepath": | ||
| 512 | parser.GetNextArgumentOrError(arg, this.IncludeSearchPaths); | ||
| 513 | return true; | ||
| 514 | |||
| 515 | case "intermediatefolder": | ||
| 516 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(arg); | ||
| 517 | return true; | ||
| 518 | |||
| 519 | case "loc": | ||
| 520 | parser.GetNextArgumentAsFilePathOrError(arg, "localization files", this.LocalizationFilePaths); | ||
| 521 | return true; | ||
| 522 | |||
| 523 | case "lib": | ||
| 524 | parser.GetNextArgumentAsFilePathOrError(arg, "library files", this.LibraryFilePaths); | ||
| 525 | return true; | ||
| 526 | |||
| 527 | case "o": | ||
| 528 | case "out": | ||
| 529 | this.OutputFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 530 | return true; | ||
| 531 | |||
| 532 | case "outputtype": | ||
| 533 | this.OutputType = parser.GetNextArgumentOrError(arg); | ||
| 534 | return true; | ||
| 535 | |||
| 536 | case "nologo": | ||
| 537 | this.ShowLogo = false; | ||
| 538 | return true; | ||
| 539 | |||
| 540 | case "v": | ||
| 541 | case "verbose": | ||
| 542 | this.Messaging.ShowVerboseMessages = true; | ||
| 543 | return true; | ||
| 544 | |||
| 545 | case "sval": | ||
| 546 | // todo: implement | ||
| 547 | return true; | ||
| 548 | |||
| 549 | case "sw": | ||
| 550 | case "suppresswarning": | ||
| 551 | var warning = parser.GetNextArgumentOrError(arg); | ||
| 552 | if (!String.IsNullOrEmpty(warning)) | ||
| 553 | { | ||
| 554 | var warningNumber = Convert.ToInt32(warning); | ||
| 555 | this.Messaging.SuppressWarningMessage(warningNumber); | ||
| 556 | } | ||
| 557 | return true; | ||
| 558 | } | ||
| 559 | |||
| 560 | return false; | ||
| 561 | } | ||
| 562 | else | ||
| 563 | { | ||
| 564 | parser.GetArgumentAsFilePathOrError(arg, "source code", this.SourceFilePaths); | ||
| 565 | return true; | ||
| 566 | } | ||
| 567 | } | ||
| 568 | |||
| 569 | public string CalculateIntermedateFolder() | ||
| 570 | { | ||
| 571 | return String.IsNullOrEmpty(this.IntermediateFolder) ? Path.GetTempPath() : this.IntermediateFolder; | ||
| 572 | } | ||
| 573 | |||
| 574 | public OutputType CalculateOutputType() | ||
| 575 | { | ||
| 576 | if (String.IsNullOrEmpty(this.OutputType)) | ||
| 577 | { | ||
| 578 | this.OutputType = Path.GetExtension(this.OutputFile); | ||
| 579 | } | ||
| 580 | |||
| 581 | switch (this.OutputType.ToLowerInvariant()) | ||
| 582 | { | ||
| 583 | case "bundle": | ||
| 584 | case ".exe": | ||
| 585 | return Data.OutputType.Bundle; | ||
| 586 | |||
| 587 | case "library": | ||
| 588 | case ".wixlib": | ||
| 589 | return Data.OutputType.Library; | ||
| 590 | |||
| 591 | case "module": | ||
| 592 | case ".msm": | ||
| 593 | return Data.OutputType.Module; | ||
| 594 | |||
| 595 | case "patch": | ||
| 596 | case ".msp": | ||
| 597 | return Data.OutputType.Patch; | ||
| 598 | |||
| 599 | case ".pcp": | ||
| 600 | return Data.OutputType.PatchCreation; | ||
| 601 | |||
| 602 | case "product": | ||
| 603 | case "package": | ||
| 604 | case ".msi": | ||
| 605 | return Data.OutputType.Product; | ||
| 606 | |||
| 607 | case "transform": | ||
| 608 | case ".mst": | ||
| 609 | return Data.OutputType.Transform; | ||
| 610 | |||
| 611 | case "intermediatepostlink": | ||
| 612 | case ".wixipl": | ||
| 613 | return Data.OutputType.IntermediatePostLink; | ||
| 614 | } | ||
| 615 | |||
| 616 | return Data.OutputType.Unknown; | ||
| 617 | } | ||
| 618 | |||
| 619 | public IEnumerable<string> CalculateFilterCultures() | ||
| 620 | { | ||
| 621 | var result = new List<string>(); | ||
| 622 | |||
| 623 | if (this.Cultures == null) | ||
| 624 | { | ||
| 625 | } | ||
| 626 | else if (this.Cultures.Count == 1 && this.Cultures[0].Equals("null", StringComparison.OrdinalIgnoreCase)) | ||
| 627 | { | ||
| 628 | // When null is used treat it as if cultures wasn't specified. This is | ||
| 629 | // needed for batching in the MSBuild task since MSBuild doesn't support | ||
| 630 | // empty items. | ||
| 631 | } | ||
| 632 | else | ||
| 633 | { | ||
| 634 | foreach (var culture in this.Cultures) | ||
| 635 | { | ||
| 636 | // Neutral is different from null. For neutral we still want to do culture filtering. | ||
| 637 | // Set the culture to the empty string = identifier for the invariant culture. | ||
| 638 | var filter = (culture.Equals("neutral", StringComparison.OrdinalIgnoreCase)) ? String.Empty : culture; | ||
| 639 | result.Add(filter); | ||
| 640 | } | ||
| 641 | } | ||
| 642 | |||
| 643 | return result; | ||
| 644 | } | ||
| 645 | |||
| 646 | public IDictionary<string, string> GatherPreprocessorVariables() | ||
| 647 | { | ||
| 648 | var variables = new Dictionary<string, string>(); | ||
| 649 | |||
| 650 | foreach (var pair in this.Defines) | ||
| 651 | { | ||
| 652 | var value = pair.Split(new[] { '=' }, 2); | ||
| 653 | |||
| 654 | if (variables.ContainsKey(value[0])) | ||
| 655 | { | ||
| 656 | this.Messaging.Write(ErrorMessages.DuplicateVariableDefinition(value[0], (1 == value.Length) ? String.Empty : value[1], variables[value[0]])); | ||
| 657 | continue; | ||
| 658 | } | ||
| 659 | |||
| 660 | variables.Add(value[0], (1 == value.Length) ? String.Empty : value[1]); | ||
| 661 | } | ||
| 662 | |||
| 663 | return variables; | ||
| 664 | } | ||
| 665 | |||
| 666 | |||
| 667 | public IEnumerable<SourceFile> GatherSourceFiles(string intermediateDirectory) | ||
| 668 | { | ||
| 669 | var files = new List<SourceFile>(); | ||
| 670 | |||
| 671 | foreach (var item in this.SourceFilePaths) | ||
| 672 | { | ||
| 673 | var sourcePath = item; | ||
| 674 | var outputPath = Path.Combine(intermediateDirectory, Path.GetFileNameWithoutExtension(sourcePath) + ".wir"); | ||
| 675 | |||
| 676 | files.Add(new SourceFile(sourcePath, outputPath)); | ||
| 677 | } | ||
| 678 | |||
| 679 | return files; | ||
| 680 | } | ||
| 681 | |||
| 682 | private bool TryParseBindPath(string bindPath, out BindPath bp) | ||
| 683 | { | ||
| 684 | var namedPath = bindPath.Split(BindPathSplit, 2); | ||
| 685 | bp = (1 == namedPath.Length) ? new BindPath(namedPath[0]) : new BindPath(namedPath[0], namedPath[1]); | ||
| 686 | |||
| 687 | if (File.Exists(bp.Path)) | ||
| 688 | { | ||
| 689 | this.Messaging.Write(ErrorMessages.ExpectedDirectoryGotFile("-bindpath", bp.Path)); | ||
| 690 | return false; | ||
| 691 | } | ||
| 692 | |||
| 693 | return true; | ||
| 694 | } | ||
| 695 | } | ||
| 394 | } | 696 | } |
| 395 | } | 697 | } |
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 @@ | |||
| 1 | // 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. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.CommandLine | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using WixToolset.Extensibility; | ||
| 8 | using WixToolset.Extensibility.Data; | ||
| 9 | using WixToolset.Extensibility.Services; | ||
| 10 | |||
| 11 | internal enum CommandTypes | ||
| 12 | { | ||
| 13 | Unknown, | ||
| 14 | Build, | ||
| 15 | Preprocess, | ||
| 16 | Compile, | ||
| 17 | Link, | ||
| 18 | Bind, | ||
| 19 | Decompile, | ||
| 20 | } | ||
| 21 | |||
| 22 | internal class CommandLine : ICommandLine | ||
| 23 | { | ||
| 24 | private static readonly char[] BindPathSplit = { '=' }; | ||
| 25 | |||
| 26 | public CommandLine(IServiceProvider serviceProvider) | ||
| 27 | { | ||
| 28 | this.ServiceProvider = serviceProvider; | ||
| 29 | |||
| 30 | this.Messaging = this.ServiceProvider.GetService<IMessaging>(); | ||
| 31 | } | ||
| 32 | |||
| 33 | private IServiceProvider ServiceProvider { get; } | ||
| 34 | |||
| 35 | private IMessaging Messaging { get; set; } | ||
| 36 | |||
| 37 | public IExtensionManager ExtensionManager { get; set; } | ||
| 38 | |||
| 39 | public ICommandLineArguments Arguments { get; set; } | ||
| 40 | |||
| 41 | public static string ExpectedArgument { get; } = "expected argument"; | ||
| 42 | |||
| 43 | public bool ShowHelp { get; private set; } | ||
| 44 | |||
| 45 | public ICommandLineCommand ParseStandardCommandLine() | ||
| 46 | { | ||
| 47 | var context = this.ServiceProvider.GetService<ICommandLineContext>(); | ||
| 48 | context.ExtensionManager = this.ExtensionManager ?? this.ServiceProvider.GetService<IExtensionManager>(); | ||
| 49 | context.Arguments = this.Arguments; | ||
| 50 | |||
| 51 | var command = this.Parse(context); | ||
| 52 | |||
| 53 | if (command.ShowLogo) | ||
| 54 | { | ||
| 55 | AppCommon.DisplayToolHeader(); | ||
| 56 | } | ||
| 57 | |||
| 58 | return command; | ||
| 59 | //switch (commandType) | ||
| 60 | //{ | ||
| 61 | //case CommandTypes.Build: | ||
| 62 | //{ | ||
| 63 | // var sourceFiles = GatherSourceFiles(files, outputFolder); | ||
| 64 | // var variables = this.GatherPreprocessorVariables(defines); | ||
| 65 | // var bindPathList = this.GatherBindPaths(bindPaths); | ||
| 66 | // var filterCultures = CalculateFilterCultures(cultures); | ||
| 67 | // var type = CalculateOutputType(outputType, outputFile); | ||
| 68 | // var platform = CalculatePlatform(platformType); | ||
| 69 | // return new BuildCommand(this.ServiceProvider, sourceFiles, variables, locFiles, libraryFiles, filterCultures, outputFile, type, platform, cabCachePath, bindFiles, bindPathList, includePaths, intermediateFolder, contentsFile, outputsFile, builtOutputsFile); | ||
| 70 | //} | ||
| 71 | |||
| 72 | //case CommandTypes.Compile: | ||
| 73 | //{ | ||
| 74 | // var sourceFiles = GatherSourceFiles(files, outputFolder); | ||
| 75 | // var variables = this.GatherPreprocessorVariables(defines); | ||
| 76 | // var platform = CalculatePlatform(platformType); | ||
| 77 | // return new CompileCommand(this.ServiceProvider, sourceFiles, variables, platform); | ||
| 78 | //} | ||
| 79 | |||
| 80 | //case CommandTypes.Decompile: | ||
| 81 | //{ | ||
| 82 | // var sourceFiles = GatherSourceFiles(files, outputFolder); | ||
| 83 | // return new DecompileCommand(this.ServiceProvider, sourceFiles, outputFile); | ||
| 84 | //} | ||
| 85 | //} | ||
| 86 | |||
| 87 | //return null; | ||
| 88 | } | ||
| 89 | |||
| 90 | private ICommandLineCommand Parse(ICommandLineContext context) | ||
| 91 | { | ||
| 92 | var extensions = this.ExtensionManager.Create<IExtensionCommandLine>(); | ||
| 93 | |||
| 94 | foreach (var extension in extensions) | ||
| 95 | { | ||
| 96 | extension.PreParse(context); | ||
| 97 | } | ||
| 98 | |||
| 99 | ICommandLineCommand command = null; | ||
| 100 | var parser = context.Arguments.Parse(); | ||
| 101 | |||
| 102 | while (command?.StopParsing != true && | ||
| 103 | String.IsNullOrEmpty(parser.ErrorArgument) && | ||
| 104 | parser.TryGetNextSwitchOrArgument(out var arg)) | ||
| 105 | { | ||
| 106 | if (String.IsNullOrWhiteSpace(arg)) // skip blank arguments. | ||
| 107 | { | ||
| 108 | continue; | ||
| 109 | } | ||
| 110 | |||
| 111 | // First argument must be the command or global switch (that creates a command). | ||
| 112 | if (command == null) | ||
| 113 | { | ||
| 114 | if (!this.TryParseUnknownCommandArg(arg, parser, out command, extensions)) | ||
| 115 | { | ||
| 116 | parser.ErrorArgument = arg; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | else if (parser.IsSwitch(arg)) | ||
| 120 | { | ||
| 121 | if (!command.TryParseArgument(parser, arg) && !TryParseCommandLineArgumentWithExtension(arg, parser, extensions)) | ||
| 122 | { | ||
| 123 | parser.ErrorArgument = arg; | ||
| 124 | } | ||
| 125 | } | ||
| 126 | else if (!TryParseCommandLineArgumentWithExtension(arg, parser, extensions) && command?.TryParseArgument(parser, arg) == false) | ||
| 127 | { | ||
| 128 | parser.ErrorArgument = arg; | ||
| 129 | } | ||
| 130 | } | ||
| 131 | |||
| 132 | foreach (var extension in extensions) | ||
| 133 | { | ||
| 134 | extension.PostParse(); | ||
| 135 | } | ||
| 136 | |||
| 137 | return command ?? new HelpCommand(); | ||
| 138 | } | ||
| 139 | |||
| 140 | private bool TryParseUnknownCommandArg(string arg, ICommandLineParser parser, out ICommandLineCommand command, IEnumerable<IExtensionCommandLine> extensions) | ||
| 141 | { | ||
| 142 | command = null; | ||
| 143 | |||
| 144 | if (parser.IsSwitch(arg)) | ||
| 145 | { | ||
| 146 | var parameter = arg.Substring(1); | ||
| 147 | switch (parameter.ToLowerInvariant()) | ||
| 148 | { | ||
| 149 | case "?": | ||
| 150 | case "h": | ||
| 151 | case "help": | ||
| 152 | command = new HelpCommand(); | ||
| 153 | break; | ||
| 154 | |||
| 155 | case "version": | ||
| 156 | case "-version": | ||
| 157 | command = new VersionCommand(); | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | else | ||
| 162 | { | ||
| 163 | if (Enum.TryParse(arg, true, out CommandTypes commandType)) | ||
| 164 | { | ||
| 165 | switch (commandType) | ||
| 166 | { | ||
| 167 | case CommandTypes.Build: | ||
| 168 | command = new BuildCommand(this.ServiceProvider); | ||
| 169 | break; | ||
| 170 | |||
| 171 | case CommandTypes.Compile: | ||
| 172 | command = new CompileCommand(this.ServiceProvider); | ||
| 173 | break; | ||
| 174 | |||
| 175 | case CommandTypes.Decompile: | ||
| 176 | command = new DecompileCommand(this.ServiceProvider); | ||
| 177 | break; | ||
| 178 | } | ||
| 179 | } | ||
| 180 | else | ||
| 181 | { | ||
| 182 | foreach (var extension in extensions) | ||
| 183 | { | ||
| 184 | if (extension.TryParseCommand(parser, out command)) | ||
| 185 | { | ||
| 186 | break; | ||
| 187 | } | ||
| 188 | |||
| 189 | command = null; | ||
| 190 | } | ||
| 191 | } | ||
| 192 | } | ||
| 193 | |||
| 194 | return command != null; | ||
| 195 | } | ||
| 196 | |||
| 197 | private static bool TryParseCommandLineArgumentWithExtension(string arg, ICommandLineParser parse, IEnumerable<IExtensionCommandLine> extensions) | ||
| 198 | { | ||
| 199 | foreach (var extension in extensions) | ||
| 200 | { | ||
| 201 | if (extension.TryParseArgument(parse, arg)) | ||
| 202 | { | ||
| 203 | return true; | ||
| 204 | } | ||
| 205 | } | ||
| 206 | |||
| 207 | return false; | ||
| 208 | } | ||
| 209 | } | ||
| 210 | } | ||
diff --git a/src/WixToolset.Core/CommandLine/CommandLineArguments.cs b/src/WixToolset.Core/CommandLine/CommandLineArguments.cs index 2f8226df..5fa547b4 100644 --- a/src/WixToolset.Core/CommandLine/CommandLineArguments.cs +++ b/src/WixToolset.Core/CommandLine/CommandLineArguments.cs | |||
| @@ -41,11 +41,11 @@ namespace WixToolset.Core.CommandLine | |||
| 41 | this.ProcessArgumentsAndParseExtensions(this.OriginalArguments); | 41 | this.ProcessArgumentsAndParseExtensions(this.OriginalArguments); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | public IParseCommandLine Parse() | 44 | public ICommandLineParser Parse() |
| 45 | { | 45 | { |
| 46 | var messaging = (IMessaging)this.ServiceProvider.GetService(typeof(IMessaging)); | 46 | var messaging = (IMessaging)this.ServiceProvider.GetService(typeof(IMessaging)); |
| 47 | 47 | ||
| 48 | return new ParseCommandLine(messaging, this.Arguments, this.ErrorArgument); | 48 | return new CommandLineParser(messaging, this.Arguments, this.ErrorArgument); |
| 49 | } | 49 | } |
| 50 | 50 | ||
| 51 | private void FlattenArgumentsWithResponseFilesIntoOriginalArguments(string[] commandLineArguments) | 51 | private void FlattenArgumentsWithResponseFilesIntoOriginalArguments(string[] commandLineArguments) |
diff --git a/src/WixToolset.Core/CommandLine/CommandLineParser.cs b/src/WixToolset.Core/CommandLine/CommandLineParser.cs index d0484e45..11e5751d 100644 --- a/src/WixToolset.Core/CommandLine/CommandLineParser.cs +++ b/src/WixToolset.Core/CommandLine/CommandLineParser.cs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // 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. | 1 | // 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. |
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.CommandLine | 3 | namespace WixToolset.Core.CommandLine |
| 4 | { | 4 | { |
| @@ -6,437 +6,269 @@ namespace WixToolset.Core.CommandLine | |||
| 6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
| 7 | using System.IO; | 7 | using System.IO; |
| 8 | using WixToolset.Data; | 8 | using WixToolset.Data; |
| 9 | using WixToolset.Extensibility; | ||
| 10 | using WixToolset.Extensibility.Data; | ||
| 11 | using WixToolset.Extensibility.Services; | 9 | using WixToolset.Extensibility.Services; |
| 12 | 10 | ||
| 13 | internal enum Commands | ||
| 14 | { | ||
| 15 | Unknown, | ||
| 16 | Build, | ||
| 17 | Preprocess, | ||
| 18 | Compile, | ||
| 19 | Link, | ||
| 20 | Bind, | ||
| 21 | } | ||
| 22 | |||
| 23 | internal class CommandLineParser : ICommandLineParser | 11 | internal class CommandLineParser : ICommandLineParser |
| 24 | { | 12 | { |
| 25 | private static readonly char[] BindPathSplit = { '=' }; | 13 | private const string ExpectedArgument = "expected argument"; |
| 26 | |||
| 27 | public CommandLineParser(IServiceProvider serviceProvider) | ||
| 28 | { | ||
| 29 | this.ServiceProvider = serviceProvider; | ||
| 30 | |||
| 31 | this.Messaging = this.ServiceProvider.GetService<IMessaging>(); | ||
| 32 | } | ||
| 33 | 14 | ||
| 34 | private IServiceProvider ServiceProvider { get; } | 15 | public string ErrorArgument { get; set; } |
| 35 | 16 | ||
| 36 | private IMessaging Messaging { get; set; } | 17 | private Queue<string> RemainingArguments { get; } |
| 37 | 18 | ||
| 38 | public IExtensionManager ExtensionManager { get; set; } | 19 | private IMessaging Messaging { get; } |
| 39 | 20 | ||
| 40 | public ICommandLineArguments Arguments { get; set; } | 21 | public CommandLineParser(IMessaging messaging, string[] arguments, string errorArgument) |
| 41 | 22 | { | |
| 42 | public static string ExpectedArgument { get; } = "expected argument"; | 23 | this.Messaging = messaging; |
| 43 | 24 | this.RemainingArguments = new Queue<string>(arguments); | |
| 44 | public string ActiveCommand { get; private set; } | 25 | this.ErrorArgument = errorArgument; |
| 26 | } | ||
| 45 | 27 | ||
| 46 | public bool ShowHelp { get; private set; } | 28 | public bool IsSwitch(string arg) |
| 29 | { | ||
| 30 | return !String.IsNullOrEmpty(arg) && ('/' == arg[0] || '-' == arg[0]); | ||
| 31 | } | ||
| 47 | 32 | ||
| 48 | public ICommandLineCommand ParseStandardCommandLine() | 33 | public string GetArgumentAsFilePathOrError(string argument, string fileType) |
| 49 | { | 34 | { |
| 50 | var context = this.ServiceProvider.GetService<ICommandLineContext>(); | 35 | if (!File.Exists(argument)) |
| 51 | context.ExtensionManager = this.ExtensionManager ?? this.ServiceProvider.GetService<IExtensionManager>(); | ||
| 52 | context.Arguments = this.Arguments; | ||
| 53 | |||
| 54 | var next = String.Empty; | ||
| 55 | |||
| 56 | var command = Commands.Unknown; | ||
| 57 | var showLogo = true; | ||
| 58 | var showVersion = false; | ||
| 59 | var outputFolder = String.Empty; | ||
| 60 | var outputFile = String.Empty; | ||
| 61 | var outputType = String.Empty; | ||
| 62 | var platformType = String.Empty; | ||
| 63 | var verbose = false; | ||
| 64 | var files = new List<string>(); | ||
| 65 | var defines = new List<string>(); | ||
| 66 | var includePaths = new List<string>(); | ||
| 67 | var locFiles = new List<string>(); | ||
| 68 | var libraryFiles = new List<string>(); | ||
| 69 | var suppressedWarnings = new List<int>(); | ||
| 70 | |||
| 71 | var bindFiles = false; | ||
| 72 | var bindPaths = new List<string>(); | ||
| 73 | |||
| 74 | var intermediateFolder = String.Empty; | ||
| 75 | |||
| 76 | var cabCachePath = String.Empty; | ||
| 77 | var cultures = new List<string>(); | ||
| 78 | var contentsFile = String.Empty; | ||
| 79 | var outputsFile = String.Empty; | ||
| 80 | var builtOutputsFile = String.Empty; | ||
| 81 | |||
| 82 | this.Parse(context, (cmdline, arg) => Enum.TryParse(arg, true, out command), (cmdline, parser, arg) => | ||
| 83 | { | 36 | { |
| 84 | if (parser.IsSwitch(arg)) | 37 | this.Messaging.Write(ErrorMessages.FileNotFound(null, argument, fileType)); |
| 85 | { | 38 | return null; |
| 86 | var parameter = arg.Substring(1); | 39 | } |
| 87 | switch (parameter.ToLowerInvariant()) | ||
| 88 | { | ||
| 89 | case "?": | ||
| 90 | case "h": | ||
| 91 | case "help": | ||
| 92 | cmdline.ShowHelp = true; | ||
| 93 | return true; | ||
| 94 | |||
| 95 | case "arch": | ||
| 96 | case "platform": | ||
| 97 | platformType = parser.GetNextArgumentOrError(arg); | ||
| 98 | return true; | ||
| 99 | |||
| 100 | case "bindfiles": | ||
| 101 | bindFiles = true; | ||
| 102 | return true; | ||
| 103 | |||
| 104 | case "bindpath": | ||
| 105 | parser.GetNextArgumentOrError(arg, bindPaths); | ||
| 106 | return true; | ||
| 107 | |||
| 108 | case "cc": | ||
| 109 | cabCachePath = parser.GetNextArgumentOrError(arg); | ||
| 110 | return true; | ||
| 111 | |||
| 112 | case "culture": | ||
| 113 | parser.GetNextArgumentOrError(arg, cultures); | ||
| 114 | return true; | ||
| 115 | case "contentsfile": | ||
| 116 | contentsFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 117 | return true; | ||
| 118 | case "outputsfile": | ||
| 119 | outputsFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 120 | return true; | ||
| 121 | case "builtoutputsfile": | ||
| 122 | builtOutputsFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 123 | return true; | ||
| 124 | |||
| 125 | case "d": | ||
| 126 | case "define": | ||
| 127 | parser.GetNextArgumentOrError(arg, defines); | ||
| 128 | return true; | ||
| 129 | |||
| 130 | case "i": | ||
| 131 | case "includepath": | ||
| 132 | parser.GetNextArgumentOrError(arg, includePaths); | ||
| 133 | return true; | ||
| 134 | |||
| 135 | case "intermediatefolder": | ||
| 136 | intermediateFolder = parser.GetNextArgumentAsDirectoryOrError(arg); | ||
| 137 | return true; | ||
| 138 | |||
| 139 | case "loc": | ||
| 140 | parser.GetNextArgumentAsFilePathOrError(arg, "localization files", locFiles); | ||
| 141 | return true; | ||
| 142 | |||
| 143 | case "lib": | ||
| 144 | parser.GetNextArgumentAsFilePathOrError(arg, "library files", libraryFiles); | ||
| 145 | return true; | ||
| 146 | |||
| 147 | case "o": | ||
| 148 | case "out": | ||
| 149 | outputFile = parser.GetNextArgumentAsFilePathOrError(arg); | ||
| 150 | return true; | ||
| 151 | |||
| 152 | case "outputtype": | ||
| 153 | outputType = parser.GetNextArgumentOrError(arg); | ||
| 154 | return true; | ||
| 155 | |||
| 156 | case "nologo": | ||
| 157 | showLogo = false; | ||
| 158 | return true; | ||
| 159 | |||
| 160 | case "v": | ||
| 161 | case "verbose": | ||
| 162 | verbose = true; | ||
| 163 | return true; | ||
| 164 | |||
| 165 | case "version": | ||
| 166 | case "-version": | ||
| 167 | showVersion = true; | ||
| 168 | return true; | ||
| 169 | |||
| 170 | case "sval": | ||
| 171 | // todo: implement | ||
| 172 | return true; | ||
| 173 | |||
| 174 | case "sw": | ||
| 175 | case "suppresswarning": | ||
| 176 | var warning = parser.GetNextArgumentOrError(arg); | ||
| 177 | if (!String.IsNullOrEmpty(warning)) | ||
| 178 | { | ||
| 179 | var warningNumber = Convert.ToInt32(warning); | ||
| 180 | this.Messaging.SuppressWarningMessage(warningNumber); | ||
| 181 | } | ||
| 182 | return true; | ||
| 183 | } | ||
| 184 | |||
| 185 | return false; | ||
| 186 | } | ||
| 187 | else | ||
| 188 | { | ||
| 189 | parser.GetArgumentAsFilePathOrError(arg, "source code", files); | ||
| 190 | return true; | ||
| 191 | } | ||
| 192 | }); | ||
| 193 | 40 | ||
| 194 | this.Messaging.ShowVerboseMessages = verbose; | 41 | return argument; |
| 42 | } | ||
| 195 | 43 | ||
| 196 | if (showVersion) | 44 | public void GetArgumentAsFilePathOrError(string argument, string fileType, IList<string> paths) |
| 45 | { | ||
| 46 | foreach (var path in this.GetFiles(argument, fileType)) | ||
| 197 | { | 47 | { |
| 198 | return new VersionCommand(); | 48 | paths.Add(path); |
| 199 | } | 49 | } |
| 50 | } | ||
| 200 | 51 | ||
| 201 | if (showLogo) | 52 | public string GetNextArgumentOrError(string commandLineSwitch) |
| 53 | { | ||
| 54 | if (this.TryGetNextNonSwitchArgumentOrError(out var argument)) | ||
| 202 | { | 55 | { |
| 203 | AppCommon.DisplayToolHeader(); | 56 | return argument; |
| 204 | } | 57 | } |
| 205 | 58 | ||
| 206 | if (this.ShowHelp) | 59 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); |
| 207 | { | 60 | return null; |
| 208 | return new HelpCommand(command); | 61 | } |
| 209 | } | ||
| 210 | 62 | ||
| 211 | switch (command) | 63 | public bool GetNextArgumentOrError(string commandLineSwitch, IList<string> args) |
| 212 | { | 64 | { |
| 213 | case Commands.Build: | 65 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg)) |
| 214 | { | 66 | { |
| 215 | var sourceFiles = GatherSourceFiles(files, outputFolder); | 67 | args.Add(arg); |
| 216 | var variables = this.GatherPreprocessorVariables(defines); | 68 | return true; |
| 217 | var bindPathList = this.GatherBindPaths(bindPaths); | ||
| 218 | var filterCultures = CalculateFilterCultures(cultures); | ||
| 219 | var type = CalculateOutputType(outputType, outputFile); | ||
| 220 | var platform = CalculatePlatform(platformType); | ||
| 221 | return new BuildCommand(this.ServiceProvider, sourceFiles, variables, locFiles, libraryFiles, filterCultures, outputFile, type, platform, cabCachePath, bindFiles, bindPathList, includePaths, intermediateFolder, contentsFile, outputsFile, builtOutputsFile); | ||
| 222 | } | 69 | } |
| 223 | 70 | ||
| 224 | case Commands.Compile: | 71 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); |
| 72 | return false; | ||
| 73 | } | ||
| 74 | |||
| 75 | public string GetNextArgumentAsDirectoryOrError(string commandLineSwitch) | ||
| 76 | { | ||
| 77 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetDirectory(commandLineSwitch, this.Messaging, arg, out var directory)) | ||
| 225 | { | 78 | { |
| 226 | var sourceFiles = GatherSourceFiles(files, outputFolder); | 79 | return directory; |
| 227 | var variables = this.GatherPreprocessorVariables(defines); | ||
| 228 | var platform = CalculatePlatform(platformType); | ||
| 229 | return new CompileCommand(this.ServiceProvider, sourceFiles, variables, platform); | ||
| 230 | } | ||
| 231 | } | 80 | } |
| 232 | 81 | ||
| 82 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); | ||
| 233 | return null; | 83 | return null; |
| 234 | } | 84 | } |
| 235 | 85 | ||
| 236 | private static IEnumerable<string> CalculateFilterCultures(List<string> cultures) | 86 | public bool GetNextArgumentAsDirectoryOrError(string commandLineSwitch, IList<string> directories) |
| 237 | { | 87 | { |
| 238 | var result = new List<string>(); | 88 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetDirectory(commandLineSwitch, this.Messaging, arg, out var directory)) |
| 239 | |||
| 240 | if (cultures == null) | ||
| 241 | { | ||
| 242 | } | ||
| 243 | else if (cultures.Count == 1 && cultures[0].Equals("null", StringComparison.OrdinalIgnoreCase)) | ||
| 244 | { | 89 | { |
| 245 | // When null is used treat it as if cultures wasn't specified. This is | 90 | directories.Add(directory); |
| 246 | // needed for batching in the MSBuild task since MSBuild doesn't support | 91 | return true; |
| 247 | // empty items. | ||
| 248 | } | ||
| 249 | else | ||
| 250 | { | ||
| 251 | foreach (var culture in cultures) | ||
| 252 | { | ||
| 253 | // Neutral is different from null. For neutral we still want to do culture filtering. | ||
| 254 | // Set the culture to the empty string = identifier for the invariant culture. | ||
| 255 | var filter = (culture.Equals("neutral", StringComparison.OrdinalIgnoreCase)) ? String.Empty : culture; | ||
| 256 | result.Add(filter); | ||
| 257 | } | ||
| 258 | } | 92 | } |
| 259 | 93 | ||
| 260 | return result; | 94 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); |
| 95 | return false; | ||
| 261 | } | 96 | } |
| 262 | 97 | ||
| 263 | private static OutputType CalculateOutputType(string outputType, string outputFile) | 98 | public string GetNextArgumentAsFilePathOrError(string commandLineSwitch) |
| 264 | { | 99 | { |
| 265 | if (String.IsNullOrEmpty(outputType)) | 100 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetFile(commandLineSwitch, arg, out var path)) |
| 266 | { | 101 | { |
| 267 | outputType = Path.GetExtension(outputFile); | 102 | return path; |
| 268 | } | 103 | } |
| 269 | 104 | ||
| 270 | switch (outputType.ToLowerInvariant()) | 105 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); |
| 271 | { | 106 | return null; |
| 272 | case "bundle": | 107 | } |
| 273 | case ".exe": | ||
| 274 | return OutputType.Bundle; | ||
| 275 | |||
| 276 | case "library": | ||
| 277 | case ".wixlib": | ||
| 278 | return OutputType.Library; | ||
| 279 | |||
| 280 | case "module": | ||
| 281 | case ".msm": | ||
| 282 | return OutputType.Module; | ||
| 283 | |||
| 284 | case "patch": | ||
| 285 | case ".msp": | ||
| 286 | return OutputType.Patch; | ||
| 287 | |||
| 288 | case ".pcp": | ||
| 289 | return OutputType.PatchCreation; | ||
| 290 | |||
| 291 | case "product": | ||
| 292 | case "package": | ||
| 293 | case ".msi": | ||
| 294 | return OutputType.Product; | ||
| 295 | 108 | ||
| 296 | case "transform": | 109 | public bool GetNextArgumentAsFilePathOrError(string commandLineSwitch, string fileType, IList<string> paths) |
| 297 | case ".mst": | 110 | { |
| 298 | return OutputType.Transform; | 111 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg)) |
| 112 | { | ||
| 113 | foreach (var path in this.GetFiles(arg, fileType)) | ||
| 114 | { | ||
| 115 | paths.Add(path); | ||
| 116 | } | ||
| 299 | 117 | ||
| 300 | case "intermediatepostlink": | 118 | return true; |
| 301 | case ".wixipl": | ||
| 302 | return OutputType.IntermediatePostLink; | ||
| 303 | } | 119 | } |
| 304 | 120 | ||
| 305 | return OutputType.Unknown; | 121 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); |
| 122 | return false; | ||
| 306 | } | 123 | } |
| 307 | 124 | ||
| 308 | private static Platform CalculatePlatform(string platformType) | 125 | public bool TryGetNextSwitchOrArgument(out string arg) |
| 309 | { | 126 | { |
| 310 | return Enum.TryParse(platformType, true, out Platform platform) ? platform : Platform.X86; | 127 | return TryDequeue(this.RemainingArguments, out arg); |
| 311 | } | 128 | } |
| 312 | 129 | ||
| 313 | private ICommandLineParser Parse(ICommandLineContext context, Func<CommandLineParser, string, bool> parseCommand, Func<CommandLineParser, IParseCommandLine, string, bool> parseArgument) | 130 | private bool TryGetNextNonSwitchArgumentOrError(out string arg) |
| 314 | { | 131 | { |
| 315 | var extensions = this.ExtensionManager.Create<IExtensionCommandLine>(); | 132 | var result = this.TryGetNextSwitchOrArgument(out arg); |
| 316 | 133 | ||
| 317 | foreach (var extension in extensions) | 134 | if (!result && !this.IsSwitch(arg)) |
| 318 | { | 135 | { |
| 319 | extension.PreParse(context); | 136 | this.ErrorArgument = arg ?? CommandLineParser.ExpectedArgument; |
| 320 | } | 137 | } |
| 321 | 138 | ||
| 322 | var parser = context.Arguments.Parse(); | 139 | return result; |
| 323 | 140 | } | |
| 324 | while (!this.ShowHelp && | ||
| 325 | String.IsNullOrEmpty(parser.ErrorArgument) && | ||
| 326 | parser.TryGetNextSwitchOrArgument(out var arg)) | ||
| 327 | { | ||
| 328 | if (String.IsNullOrWhiteSpace(arg)) // skip blank arguments. | ||
| 329 | { | ||
| 330 | continue; | ||
| 331 | } | ||
| 332 | 141 | ||
| 333 | if (parser.IsSwitch(arg)) | 142 | private static bool IsValidArg(string arg) |
| 334 | { | 143 | { |
| 335 | if (!parseArgument(this, parser, arg) && | 144 | return !(String.IsNullOrEmpty(arg) || '/' == arg[0] || '-' == arg[0]); |
| 336 | !this.TryParseCommandLineArgumentWithExtension(arg, parser, extensions)) | 145 | } |
| 337 | { | ||
| 338 | parser.ErrorArgument = arg; | ||
| 339 | } | ||
| 340 | } | ||
| 341 | else if (String.IsNullOrEmpty(this.ActiveCommand) && parseCommand != null) // First non-switch must be the command, if commands are supported. | ||
| 342 | { | ||
| 343 | if (parseCommand(this, arg)) | ||
| 344 | { | ||
| 345 | this.ActiveCommand = arg; | ||
| 346 | } | ||
| 347 | else | ||
| 348 | { | ||
| 349 | parser.ErrorArgument = arg; | ||
| 350 | } | ||
| 351 | } | ||
| 352 | else if (!this.TryParseCommandLineArgumentWithExtension(arg, parser, extensions) && | ||
| 353 | !parseArgument(this, parser, arg)) | ||
| 354 | { | ||
| 355 | parser.ErrorArgument = arg; | ||
| 356 | } | ||
| 357 | } | ||
| 358 | 146 | ||
| 359 | foreach (var extension in extensions) | 147 | private static bool TryDequeue(Queue<string> q, out string arg) |
| 148 | { | ||
| 149 | if (q.Count > 0) | ||
| 360 | { | 150 | { |
| 361 | extension.PostParse(); | 151 | arg = q.Dequeue(); |
| 152 | return true; | ||
| 362 | } | 153 | } |
| 363 | 154 | ||
| 364 | return this; | 155 | arg = null; |
| 156 | return false; | ||
| 365 | } | 157 | } |
| 366 | 158 | ||
| 367 | private static IEnumerable<SourceFile> GatherSourceFiles(IEnumerable<string> sourceFiles, string intermediateDirectory) | 159 | private bool TryGetDirectory(string commandlineSwitch, IMessaging messageHandler, string arg, out string directory) |
| 368 | { | 160 | { |
| 369 | var files = new List<SourceFile>(); | 161 | directory = null; |
| 370 | 162 | ||
| 371 | foreach (var item in sourceFiles) | 163 | if (File.Exists(arg)) |
| 372 | { | 164 | { |
| 373 | var sourcePath = item; | 165 | this.Messaging.Write(ErrorMessages.ExpectedDirectoryGotFile(commandlineSwitch, arg)); |
| 374 | var outputPath = Path.Combine(intermediateDirectory, Path.GetFileNameWithoutExtension(sourcePath) + ".wir"); | 166 | return false; |
| 375 | |||
| 376 | files.Add(new SourceFile(sourcePath, outputPath)); | ||
| 377 | } | 167 | } |
| 378 | 168 | ||
| 379 | return files; | 169 | directory = this.VerifyPath(arg); |
| 170 | return directory != null; | ||
| 380 | } | 171 | } |
| 381 | 172 | ||
| 382 | private IDictionary<string, string> GatherPreprocessorVariables(IEnumerable<string> defineConstants) | 173 | private bool TryGetFile(string commandlineSwitch, string arg, out string path) |
| 383 | { | 174 | { |
| 384 | var variables = new Dictionary<string, string>(); | 175 | path = null; |
| 385 | 176 | ||
| 386 | foreach (var pair in defineConstants) | 177 | if (!IsValidArg(arg)) |
| 387 | { | 178 | { |
| 388 | var value = pair.Split(new[] { '=' }, 2); | 179 | this.Messaging.Write(ErrorMessages.FilePathRequired(commandlineSwitch)); |
| 389 | 180 | } | |
| 390 | if (variables.ContainsKey(value[0])) | 181 | else if (Directory.Exists(arg)) |
| 391 | { | 182 | { |
| 392 | this.Messaging.Write(ErrorMessages.DuplicateVariableDefinition(value[0], (1 == value.Length) ? String.Empty : value[1], variables[value[0]])); | 183 | this.Messaging.Write(ErrorMessages.ExpectedFileGotDirectory(commandlineSwitch, arg)); |
| 393 | continue; | 184 | } |
| 394 | } | 185 | else |
| 395 | 186 | { | |
| 396 | variables.Add(value[0], (1 == value.Length) ? String.Empty : value[1]); | 187 | path = this.VerifyPath(arg); |
| 397 | } | 188 | } |
| 398 | 189 | ||
| 399 | return variables; | 190 | return path != null; |
| 400 | } | 191 | } |
| 401 | 192 | ||
| 402 | private IEnumerable<BindPath> GatherBindPaths(IEnumerable<string> bindPaths) | 193 | /// <summary> |
| 194 | /// Get a set of files that possibly have a search pattern in the path (such as '*'). | ||
| 195 | /// </summary> | ||
| 196 | /// <param name="searchPath">Search path to find files in.</param> | ||
| 197 | /// <param name="fileType">Type of file; typically "Source".</param> | ||
| 198 | /// <returns>An array of files matching the search path.</returns> | ||
| 199 | /// <remarks> | ||
| 200 | /// This method is written in this verbose way because it needs to support ".." in the path. | ||
| 201 | /// It needs the directory path isolated from the file name in order to use Directory.GetFiles | ||
| 202 | /// or DirectoryInfo.GetFiles. The only way to get this directory path is manually since | ||
| 203 | /// Path.GetDirectoryName does not support ".." in the path. | ||
| 204 | /// </remarks> | ||
| 205 | /// <exception cref="WixFileNotFoundException">Throws WixFileNotFoundException if no file matching the pattern can be found.</exception> | ||
| 206 | private string[] GetFiles(string searchPath, string fileType) | ||
| 403 | { | 207 | { |
| 404 | var result = new List<BindPath>(); | 208 | if (null == searchPath) |
| 405 | |||
| 406 | foreach (var bindPath in bindPaths) | ||
| 407 | { | 209 | { |
| 408 | var bp = ParseBindPath(bindPath); | 210 | throw new ArgumentNullException(nameof(searchPath)); |
| 211 | } | ||
| 409 | 212 | ||
| 410 | if (File.Exists(bp.Path)) | 213 | // Convert alternate directory separators to the standard one. |
| 214 | var filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); | ||
| 215 | var lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar); | ||
| 216 | var files = new string[0]; | ||
| 217 | |||
| 218 | try | ||
| 219 | { | ||
| 220 | if (0 > lastSeparator) | ||
| 411 | { | 221 | { |
| 412 | this.Messaging.Write(ErrorMessages.ExpectedDirectoryGotFile("-bindpath", bp.Path)); | 222 | files = Directory.GetFiles(".", filePath); |
| 413 | } | 223 | } |
| 414 | else | 224 | else // found directory separator |
| 415 | { | 225 | { |
| 416 | result.Add(bp); | 226 | files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), filePath.Substring(lastSeparator + 1)); |
| 417 | } | 227 | } |
| 418 | } | 228 | } |
| 229 | catch (DirectoryNotFoundException) | ||
| 230 | { | ||
| 231 | // Don't let this function throw the DirectoryNotFoundException. This exception | ||
| 232 | // occurs for non-existant directories and invalid characters in the searchPattern. | ||
| 233 | } | ||
| 234 | catch (ArgumentException) | ||
| 235 | { | ||
| 236 | // Don't let this function throw the ArgumentException. This exception | ||
| 237 | // occurs in certain situations such as when passing a malformed UNC path. | ||
| 238 | } | ||
| 239 | catch (IOException) | ||
| 240 | { | ||
| 241 | } | ||
| 419 | 242 | ||
| 420 | return result; | 243 | if (0 == files.Length) |
| 244 | { | ||
| 245 | this.Messaging.Write(ErrorMessages.FileNotFound(null, searchPath, fileType)); | ||
| 246 | } | ||
| 247 | |||
| 248 | return files; | ||
| 421 | } | 249 | } |
| 422 | 250 | ||
| 423 | private bool TryParseCommandLineArgumentWithExtension(string arg, IParseCommandLine parse, IEnumerable<IExtensionCommandLine> extensions) | 251 | private string VerifyPath(string path) |
| 424 | { | 252 | { |
| 425 | foreach (var extension in extensions) | 253 | string fullPath; |
| 254 | |||
| 255 | if (0 <= path.IndexOf('\"')) | ||
| 426 | { | 256 | { |
| 427 | if (extension.TryParseArgument(parse, arg)) | 257 | this.Messaging.Write(ErrorMessages.PathCannotContainQuote(path)); |
| 428 | { | 258 | return null; |
| 429 | return true; | ||
| 430 | } | ||
| 431 | } | 259 | } |
| 432 | 260 | ||
| 433 | return false; | 261 | try |
| 434 | } | 262 | { |
| 263 | fullPath = Path.GetFullPath(path); | ||
| 264 | } | ||
| 265 | catch (Exception e) | ||
| 266 | { | ||
| 267 | this.Messaging.Write(ErrorMessages.InvalidCommandLineFileName(path, e.Message)); | ||
| 268 | return null; | ||
| 269 | } | ||
| 435 | 270 | ||
| 436 | public static BindPath ParseBindPath(string bindPath) | 271 | return fullPath; |
| 437 | { | ||
| 438 | var namedPath = bindPath.Split(BindPathSplit, 2); | ||
| 439 | return (1 == namedPath.Length) ? new BindPath(namedPath[0]) : new BindPath(namedPath[0], namedPath[1]); | ||
| 440 | } | 272 | } |
| 441 | } | 273 | } |
| 442 | } | 274 | } |
diff --git a/src/WixToolset.Core/CommandLine/CompileCommand.cs b/src/WixToolset.Core/CommandLine/CompileCommand.cs index 4007c263..69e35cab 100644 --- a/src/WixToolset.Core/CommandLine/CompileCommand.cs +++ b/src/WixToolset.Core/CommandLine/CompileCommand.cs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // 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. | 1 | // 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. |
| 2 | 2 | ||
| 3 | namespace WixToolset.Core.CommandLine | 3 | namespace WixToolset.Core.CommandLine |
| 4 | { | 4 | { |
| @@ -12,6 +12,13 @@ namespace WixToolset.Core.CommandLine | |||
| 12 | 12 | ||
| 13 | internal class CompileCommand : ICommandLineCommand | 13 | internal class CompileCommand : ICommandLineCommand |
| 14 | { | 14 | { |
| 15 | public CompileCommand(IServiceProvider serviceProvider) | ||
| 16 | { | ||
| 17 | this.ServiceProvider = serviceProvider; | ||
| 18 | this.Messaging = serviceProvider.GetService<IMessaging>(); | ||
| 19 | this.ExtensionManager = serviceProvider.GetService<IExtensionManager>(); | ||
| 20 | } | ||
| 21 | |||
| 15 | public CompileCommand(IServiceProvider serviceProvider, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, Platform platform) | 22 | public CompileCommand(IServiceProvider serviceProvider, IEnumerable<SourceFile> sources, IDictionary<string, string> preprocessorVariables, Platform platform) |
| 16 | { | 23 | { |
| 17 | this.ServiceProvider = serviceProvider; | 24 | this.ServiceProvider = serviceProvider; |
| @@ -36,6 +43,15 @@ namespace WixToolset.Core.CommandLine | |||
| 36 | 43 | ||
| 37 | public IEnumerable<string> IncludeSearchPaths { get; } | 44 | public IEnumerable<string> IncludeSearchPaths { get; } |
| 38 | 45 | ||
| 46 | public bool ShowLogo => throw new NotImplementedException(); | ||
| 47 | |||
| 48 | public bool StopParsing => throw new NotImplementedException(); | ||
| 49 | |||
| 50 | public bool TryParseArgument(ICommandLineParser parseHelper, string argument) | ||
| 51 | { | ||
| 52 | throw new NotImplementedException(); | ||
| 53 | } | ||
| 54 | |||
| 39 | public int Execute() | 55 | public int Execute() |
| 40 | { | 56 | { |
| 41 | foreach (var sourceFile in this.SourceFiles) | 57 | foreach (var sourceFile in this.SourceFiles) |
diff --git a/src/WixToolset.Core/CommandLine/HelpCommand.cs b/src/WixToolset.Core/CommandLine/HelpCommand.cs index b1298e46..224b154c 100644 --- a/src/WixToolset.Core/CommandLine/HelpCommand.cs +++ b/src/WixToolset.Core/CommandLine/HelpCommand.cs | |||
| @@ -4,28 +4,24 @@ namespace WixToolset.Core.CommandLine | |||
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using WixToolset.Extensibility.Data; | 6 | using WixToolset.Extensibility.Data; |
| 7 | using WixToolset.Extensibility.Services; | ||
| 7 | 8 | ||
| 8 | internal class HelpCommand : ICommandLineCommand | 9 | internal class HelpCommand : ICommandLineCommand |
| 9 | { | 10 | { |
| 10 | public HelpCommand(Commands command) | 11 | public bool ShowLogo => true; |
| 11 | { | ||
| 12 | this.Command = command; | ||
| 13 | } | ||
| 14 | 12 | ||
| 15 | public Commands Command { get; } | 13 | public bool StopParsing => true; |
| 16 | 14 | ||
| 17 | public int Execute() | 15 | public int Execute() |
| 18 | { | 16 | { |
| 19 | if (this.Command == Commands.Unknown) | 17 | Console.WriteLine("TODO: Show list of available commands"); |
| 20 | { | ||
| 21 | Console.WriteLine(); | ||
| 22 | } | ||
| 23 | else | ||
| 24 | { | ||
| 25 | Console.WriteLine(); | ||
| 26 | } | ||
| 27 | 18 | ||
| 28 | return -1; | 19 | return -1; |
| 29 | } | 20 | } |
| 21 | |||
| 22 | public bool TryParseArgument(ICommandLineParser parseHelper, string argument) | ||
| 23 | { | ||
| 24 | return true; // eat any arguments | ||
| 25 | } | ||
| 30 | } | 26 | } |
| 31 | } | 27 | } |
diff --git a/src/WixToolset.Core/CommandLine/ParseCommandLine.cs b/src/WixToolset.Core/CommandLine/ParseCommandLine.cs deleted file mode 100644 index 3cf6e032..00000000 --- a/src/WixToolset.Core/CommandLine/ParseCommandLine.cs +++ /dev/null | |||
| @@ -1,263 +0,0 @@ | |||
| 1 | // 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. | ||
| 2 | |||
| 3 | namespace WixToolset.Core.CommandLine | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.IO; | ||
| 8 | using WixToolset.Data; | ||
| 9 | using WixToolset.Extensibility.Services; | ||
| 10 | |||
| 11 | internal class ParseCommandLine : IParseCommandLine | ||
| 12 | { | ||
| 13 | private const string ExpectedArgument = "expected argument"; | ||
| 14 | |||
| 15 | public string ErrorArgument { get; set; } | ||
| 16 | |||
| 17 | private Queue<string> RemainingArguments { get; } | ||
| 18 | |||
| 19 | private IMessaging Messaging { get; } | ||
| 20 | |||
| 21 | public ParseCommandLine(IMessaging messaging, string[] arguments, string errorArgument) | ||
| 22 | { | ||
| 23 | this.Messaging = messaging; | ||
| 24 | this.RemainingArguments = new Queue<string>(arguments); | ||
| 25 | this.ErrorArgument = errorArgument; | ||
| 26 | } | ||
| 27 | |||
| 28 | public bool IsSwitch(string arg) | ||
| 29 | { | ||
| 30 | return !String.IsNullOrEmpty(arg) && ('/' == arg[0] || '-' == arg[0]); | ||
| 31 | } | ||
| 32 | |||
| 33 | public void GetArgumentAsFilePathOrError(string argument, string fileType, IList<string> paths) | ||
| 34 | { | ||
| 35 | foreach (var path in this.GetFiles(argument, fileType)) | ||
| 36 | { | ||
| 37 | paths.Add(path); | ||
| 38 | } | ||
| 39 | } | ||
| 40 | |||
| 41 | public string GetNextArgumentOrError(string commandLineSwitch) | ||
| 42 | { | ||
| 43 | if (this.TryGetNextNonSwitchArgumentOrError(out var argument)) | ||
| 44 | { | ||
| 45 | return argument; | ||
| 46 | } | ||
| 47 | |||
| 48 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); | ||
| 49 | return null; | ||
| 50 | } | ||
| 51 | |||
| 52 | public bool GetNextArgumentOrError(string commandLineSwitch, IList<string> args) | ||
| 53 | { | ||
| 54 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg)) | ||
| 55 | { | ||
| 56 | args.Add(arg); | ||
| 57 | return true; | ||
| 58 | } | ||
| 59 | |||
| 60 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); | ||
| 61 | return false; | ||
| 62 | } | ||
| 63 | |||
| 64 | public string GetNextArgumentAsDirectoryOrError(string commandLineSwitch) | ||
| 65 | { | ||
| 66 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetDirectory(commandLineSwitch, this.Messaging, arg, out var directory)) | ||
| 67 | { | ||
| 68 | return directory; | ||
| 69 | } | ||
| 70 | |||
| 71 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); | ||
| 72 | return null; | ||
| 73 | } | ||
| 74 | |||
| 75 | public bool GetNextArgumentAsDirectoryOrError(string commandLineSwitch, IList<string> directories) | ||
| 76 | { | ||
| 77 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetDirectory(commandLineSwitch, this.Messaging, arg, out var directory)) | ||
| 78 | { | ||
| 79 | directories.Add(directory); | ||
| 80 | return true; | ||
| 81 | } | ||
| 82 | |||
| 83 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); | ||
| 84 | return false; | ||
| 85 | } | ||
| 86 | |||
| 87 | public string GetNextArgumentAsFilePathOrError(string commandLineSwitch) | ||
| 88 | { | ||
| 89 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg) && this.TryGetFile(commandLineSwitch, arg, out var path)) | ||
| 90 | { | ||
| 91 | return path; | ||
| 92 | } | ||
| 93 | |||
| 94 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); | ||
| 95 | return null; | ||
| 96 | } | ||
| 97 | |||
| 98 | public bool GetNextArgumentAsFilePathOrError(string commandLineSwitch, string fileType, IList<string> paths) | ||
| 99 | { | ||
| 100 | if (this.TryGetNextNonSwitchArgumentOrError(out var arg)) | ||
| 101 | { | ||
| 102 | foreach (var path in this.GetFiles(arg, fileType)) | ||
| 103 | { | ||
| 104 | paths.Add(path); | ||
| 105 | } | ||
| 106 | |||
| 107 | return true; | ||
| 108 | } | ||
| 109 | |||
| 110 | this.Messaging.Write(ErrorMessages.ExpectedArgument(commandLineSwitch)); | ||
| 111 | return false; | ||
| 112 | } | ||
| 113 | |||
| 114 | public bool TryGetNextSwitchOrArgument(out string arg) | ||
| 115 | { | ||
| 116 | return TryDequeue(this.RemainingArguments, out arg); | ||
| 117 | } | ||
| 118 | |||
| 119 | private bool TryGetNextNonSwitchArgumentOrError(out string arg) | ||
| 120 | { | ||
| 121 | var result = this.TryGetNextSwitchOrArgument(out arg); | ||
| 122 | |||
| 123 | if (!result && !this.IsSwitch(arg)) | ||
| 124 | { | ||
| 125 | this.ErrorArgument = arg ?? ParseCommandLine.ExpectedArgument; | ||
| 126 | } | ||
| 127 | |||
| 128 | return result; | ||
| 129 | } | ||
| 130 | |||
| 131 | private static bool IsValidArg(string arg) | ||
| 132 | { | ||
| 133 | return !(String.IsNullOrEmpty(arg) || '/' == arg[0] || '-' == arg[0]); | ||
| 134 | } | ||
| 135 | |||
| 136 | private static bool TryDequeue(Queue<string> q, out string arg) | ||
| 137 | { | ||
| 138 | if (q.Count > 0) | ||
| 139 | { | ||
| 140 | arg = q.Dequeue(); | ||
| 141 | return true; | ||
| 142 | } | ||
| 143 | |||
| 144 | arg = null; | ||
| 145 | return false; | ||
| 146 | } | ||
| 147 | |||
| 148 | private bool TryGetDirectory(string commandlineSwitch, IMessaging messageHandler, string arg, out string directory) | ||
| 149 | { | ||
| 150 | directory = null; | ||
| 151 | |||
| 152 | if (File.Exists(arg)) | ||
| 153 | { | ||
| 154 | this.Messaging.Write(ErrorMessages.ExpectedDirectoryGotFile(commandlineSwitch, arg)); | ||
| 155 | return false; | ||
| 156 | } | ||
| 157 | |||
| 158 | directory = this.VerifyPath(arg); | ||
| 159 | return directory != null; | ||
| 160 | } | ||
| 161 | |||
| 162 | private bool TryGetFile(string commandlineSwitch, string arg, out string path) | ||
| 163 | { | ||
| 164 | path = null; | ||
| 165 | |||
| 166 | if (!IsValidArg(arg)) | ||
| 167 | { | ||
| 168 | this.Messaging.Write(ErrorMessages.FilePathRequired(commandlineSwitch)); | ||
| 169 | } | ||
| 170 | else if (Directory.Exists(arg)) | ||
| 171 | { | ||
| 172 | this.Messaging.Write(ErrorMessages.ExpectedFileGotDirectory(commandlineSwitch, arg)); | ||
| 173 | } | ||
| 174 | else | ||
| 175 | { | ||
| 176 | path = this.VerifyPath(arg); | ||
| 177 | } | ||
| 178 | |||
| 179 | return path != null; | ||
| 180 | } | ||
| 181 | |||
| 182 | /// <summary> | ||
| 183 | /// Get a set of files that possibly have a search pattern in the path (such as '*'). | ||
| 184 | /// </summary> | ||
| 185 | /// <param name="searchPath">Search path to find files in.</param> | ||
| 186 | /// <param name="fileType">Type of file; typically "Source".</param> | ||
| 187 | /// <returns>An array of files matching the search path.</returns> | ||
| 188 | /// <remarks> | ||
| 189 | /// This method is written in this verbose way because it needs to support ".." in the path. | ||
| 190 | /// It needs the directory path isolated from the file name in order to use Directory.GetFiles | ||
| 191 | /// or DirectoryInfo.GetFiles. The only way to get this directory path is manually since | ||
| 192 | /// Path.GetDirectoryName does not support ".." in the path. | ||
| 193 | /// </remarks> | ||
| 194 | /// <exception cref="WixFileNotFoundException">Throws WixFileNotFoundException if no file matching the pattern can be found.</exception> | ||
| 195 | private string[] GetFiles(string searchPath, string fileType) | ||
| 196 | { | ||
| 197 | if (null == searchPath) | ||
| 198 | { | ||
| 199 | throw new ArgumentNullException(nameof(searchPath)); | ||
| 200 | } | ||
| 201 | |||
| 202 | // Convert alternate directory separators to the standard one. | ||
| 203 | var filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); | ||
| 204 | var lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar); | ||
| 205 | var files = new string[0]; | ||
| 206 | |||
| 207 | try | ||
| 208 | { | ||
| 209 | if (0 > lastSeparator) | ||
| 210 | { | ||
| 211 | files = Directory.GetFiles(".", filePath); | ||
| 212 | } | ||
| 213 | else // found directory separator | ||
| 214 | { | ||
| 215 | files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), filePath.Substring(lastSeparator + 1)); | ||
| 216 | } | ||
| 217 | } | ||
| 218 | catch (DirectoryNotFoundException) | ||
| 219 | { | ||
| 220 | // Don't let this function throw the DirectoryNotFoundException. This exception | ||
| 221 | // occurs for non-existant directories and invalid characters in the searchPattern. | ||
| 222 | } | ||
| 223 | catch (ArgumentException) | ||
| 224 | { | ||
| 225 | // Don't let this function throw the ArgumentException. This exception | ||
| 226 | // occurs in certain situations such as when passing a malformed UNC path. | ||
| 227 | } | ||
| 228 | catch (IOException) | ||
| 229 | { | ||
| 230 | } | ||
| 231 | |||
| 232 | if (0 == files.Length) | ||
| 233 | { | ||
| 234 | this.Messaging.Write(ErrorMessages.FileNotFound(null, searchPath, fileType)); | ||
| 235 | } | ||
| 236 | |||
| 237 | return files; | ||
| 238 | } | ||
| 239 | |||
| 240 | private string VerifyPath(string path) | ||
| 241 | { | ||
| 242 | string fullPath; | ||
| 243 | |||
| 244 | if (0 <= path.IndexOf('\"')) | ||
| 245 | { | ||
| 246 | this.Messaging.Write(ErrorMessages.PathCannotContainQuote(path)); | ||
| 247 | return null; | ||
| 248 | } | ||
| 249 | |||
| 250 | try | ||
| 251 | { | ||
| 252 | fullPath = Path.GetFullPath(path); | ||
| 253 | } | ||
| 254 | catch (Exception e) | ||
| 255 | { | ||
| 256 | this.Messaging.Write(ErrorMessages.InvalidCommandLineFileName(path, e.Message)); | ||
| 257 | return null; | ||
| 258 | } | ||
| 259 | |||
| 260 | return fullPath; | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
diff --git a/src/WixToolset.Core/CommandLine/VersionCommand.cs b/src/WixToolset.Core/CommandLine/VersionCommand.cs index e67aafb8..1baee72d 100644 --- a/src/WixToolset.Core/CommandLine/VersionCommand.cs +++ b/src/WixToolset.Core/CommandLine/VersionCommand.cs | |||
| @@ -4,9 +4,14 @@ namespace WixToolset.Core.CommandLine | |||
| 4 | { | 4 | { |
| 5 | using System; | 5 | using System; |
| 6 | using WixToolset.Extensibility.Data; | 6 | using WixToolset.Extensibility.Data; |
| 7 | using WixToolset.Extensibility.Services; | ||
| 7 | 8 | ||
| 8 | internal class VersionCommand : ICommandLineCommand | 9 | internal class VersionCommand : ICommandLineCommand |
| 9 | { | 10 | { |
| 11 | public bool ShowLogo => true; | ||
| 12 | |||
| 13 | public bool StopParsing => true; | ||
| 14 | |||
| 10 | public int Execute() | 15 | public int Execute() |
| 11 | { | 16 | { |
| 12 | Console.WriteLine("wix version {0}", ThisAssembly.AssemblyInformationalVersion); | 17 | Console.WriteLine("wix version {0}", ThisAssembly.AssemblyInformationalVersion); |
| @@ -14,5 +19,10 @@ namespace WixToolset.Core.CommandLine | |||
| 14 | 19 | ||
| 15 | return 0; | 20 | return 0; |
| 16 | } | 21 | } |
| 22 | |||
| 23 | public bool TryParseArgument(ICommandLineParser parseHelper, string argument) | ||
| 24 | { | ||
| 25 | return true; // eat any arguments | ||
| 26 | } | ||
| 17 | } | 27 | } |
| 18 | } | 28 | } |
diff --git a/src/WixToolset.Core/WixToolsetServiceProvider.cs b/src/WixToolset.Core/WixToolsetServiceProvider.cs index 0337f771..7216ae2a 100644 --- a/src/WixToolset.Core/WixToolsetServiceProvider.cs +++ b/src/WixToolset.Core/WixToolsetServiceProvider.cs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // 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. | 1 | // 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. |
| 2 | 2 | ||
| 3 | namespace WixToolset.Core | 3 | namespace WixToolset.Core |
| 4 | { | 4 | { |
| @@ -29,7 +29,7 @@ namespace WixToolset.Core | |||
| 29 | // Transients. | 29 | // Transients. |
| 30 | this.AddService<ICommandLineArguments>((provider, singletons) => new CommandLineArguments(provider)); | 30 | this.AddService<ICommandLineArguments>((provider, singletons) => new CommandLineArguments(provider)); |
| 31 | this.AddService<ICommandLineContext>((provider, singletons) => new CommandLineContext(provider)); | 31 | this.AddService<ICommandLineContext>((provider, singletons) => new CommandLineContext(provider)); |
| 32 | this.AddService<ICommandLineParser>((provider, singletons) => new CommandLineParser(provider)); | 32 | this.AddService<ICommandLine>((provider, singletons) => new CommandLine.CommandLine(provider)); |
| 33 | this.AddService<IPreprocessContext>((provider, singletons) => new PreprocessContext(provider)); | 33 | this.AddService<IPreprocessContext>((provider, singletons) => new PreprocessContext(provider)); |
| 34 | this.AddService<ICompileContext>((provider, singletons) => new CompileContext(provider)); | 34 | this.AddService<ICompileContext>((provider, singletons) => new CompileContext(provider)); |
| 35 | this.AddService<ILibraryContext>((provider, singletons) => new LibraryContext(provider)); | 35 | this.AddService<ILibraryContext>((provider, singletons) => new LibraryContext(provider)); |
diff --git a/src/test/Example.Extension/ExamplePreprocessorExtensionAndCommandLine.cs b/src/test/Example.Extension/ExamplePreprocessorExtensionAndCommandLine.cs index 8fed7944..eddcf6e4 100644 --- a/src/test/Example.Extension/ExamplePreprocessorExtensionAndCommandLine.cs +++ b/src/test/Example.Extension/ExamplePreprocessorExtensionAndCommandLine.cs | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | // 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. | 1 | // 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. |
| 2 | 2 | ||
| 3 | namespace Example.Extension | 3 | namespace Example.Extension |
| 4 | { | 4 | { |
| @@ -23,17 +23,23 @@ namespace Example.Extension | |||
| 23 | { | 23 | { |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | public bool TryParseArgument(IParseCommandLine parseCommandLine, string arg) | 26 | public bool TryParseArgument(ICommandLineParser parser, string argument) |
| 27 | { | 27 | { |
| 28 | if (parseCommandLine.IsSwitch(arg) && arg.Substring(1).Equals("example", StringComparison.OrdinalIgnoreCase)) | 28 | if (parser.IsSwitch(argument) && argument.Substring(1).Equals("example", StringComparison.OrdinalIgnoreCase)) |
| 29 | { | 29 | { |
| 30 | this.exampleValueFromCommandLine = parseCommandLine.GetNextArgumentOrError(arg); | 30 | this.exampleValueFromCommandLine = parser.GetNextArgumentOrError(argument); |
| 31 | return true; | 31 | return true; |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | return false; | 34 | return false; |
| 35 | } | 35 | } |
| 36 | 36 | ||
| 37 | public bool TryParseCommand(ICommandLineParser parser, out ICommandLineCommand command) | ||
| 38 | { | ||
| 39 | command = null; | ||
| 40 | return false; | ||
| 41 | } | ||
| 42 | |||
| 37 | public void PostParse() | 43 | public void PostParse() |
| 38 | { | 44 | { |
| 39 | } | 45 | } |
