From 60c9a081d337bf432a61bee6784d4c05da1a049a Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sat, 6 Jun 2020 15:40:38 -0700 Subject: Expose converter as a command-line command for use by wix.exe --- .../WixToolset.Converters.Tupleizer.csproj | 2 +- src/WixToolset.Converters/ConvertCommand.cs | 281 +++++++++++++++++++++ .../ConverterExtensionCommandLine.cs | 39 +++ .../ConverterExtensionFactory.cs | 30 +++ .../WixToolset.Converters.csproj | 2 +- .../WixToolsetCoreServiceProviderExtensions.cs | 17 ++ ...lsetTest.Converters.Tupleizer.v3.ncrunchproject | 9 + 7 files changed, 378 insertions(+), 2 deletions(-) create mode 100644 src/WixToolset.Converters/ConvertCommand.cs create mode 100644 src/WixToolset.Converters/ConverterExtensionCommandLine.cs create mode 100644 src/WixToolset.Converters/ConverterExtensionFactory.cs create mode 100644 src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs create mode 100644 src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.v3.ncrunchproject (limited to 'src') diff --git a/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj b/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj index 3fa1b57d..cafb5feb 100644 --- a/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj +++ b/src/WixToolset.Converters.Tupleizer/WixToolset.Converters.Tupleizer.csproj @@ -28,7 +28,7 @@ - + diff --git a/src/WixToolset.Converters/ConvertCommand.cs b/src/WixToolset.Converters/ConvertCommand.cs new file mode 100644 index 00000000..a684bc95 --- /dev/null +++ b/src/WixToolset.Converters/ConvertCommand.cs @@ -0,0 +1,281 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Xml; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + internal class ConvertCommand : ICommandLineCommand + { + private const string SettingsFileDefault = "wixcop.settings.xml"; + + public ConvertCommand(IWixToolsetServiceProvider serviceProvider) + { + this.Messaging = serviceProvider.GetService(); + + this.IndentationAmount = 4; // default indentation amount + this.ErrorsAsWarnings = new HashSet(); + this.ExemptFiles = new HashSet(); + this.IgnoreErrors = new HashSet(); + this.SearchPatternResults = new HashSet(); + this.SearchPatterns = new List(); + } + + private IMessaging Messaging { get; } + + public bool ShowLogo { get; private set; } + + public bool StopParsing { get; private set; } + + private bool ShowHelp { get; set; } + + private HashSet ErrorsAsWarnings { get; } + + private HashSet ExemptFiles { get; } + + private bool FixErrors { get; set; } + + private int IndentationAmount { get; set; } + + private HashSet IgnoreErrors { get; } + + private HashSet SearchPatternResults { get; } + + private List SearchPatterns { get; } + + private string SettingsFile1 { get; set; } + + private string SettingsFile2 { get; set; } + + private bool SubDirectories { get; set; } + + public bool TryParseArgument(ICommandLineParser parser, string argument) + { + if (!parser.IsSwitch(argument)) + { + this.SearchPatterns.Add(argument); + return true; + } + + var parameter = argument.Substring(1); + switch (parameter.ToLowerInvariant()) + { + case "?": + this.ShowHelp = true; + this.ShowLogo = true; + this.StopParsing = true; + return true; + + case "f": + this.FixErrors = true; + return true; + + case "nologo": + this.ShowLogo = false; + return true; + + case "s": + this.SubDirectories = true; + return true; + + default: // other parameters + if (parameter.StartsWith("set1", StringComparison.Ordinal)) + { + this.SettingsFile1 = parameter.Substring(4); + return true; + } + else if (parameter.StartsWith("set2", StringComparison.Ordinal)) + { + this.SettingsFile2 = parameter.Substring(4); + return true; + } + else if (parameter.StartsWith("indent:", StringComparison.Ordinal)) + { + try + { + this.IndentationAmount = Convert.ToInt32(parameter.Substring(7)); + } + catch + { + parser.ErrorArgument = parameter; // $"Invalid numeric argument: {parameter}"; + } + return true; + } + + return false; + } + } + + public int Execute() + { + if (this.ShowHelp) + { + DisplayHelp(); + return 1; + } + + // parse the settings if any were specified + if (null != this.SettingsFile1 || null != this.SettingsFile2) + { + this.ParseSettingsFiles(this.SettingsFile1, this.SettingsFile2); + } + else + { + if (File.Exists(ConvertCommand.SettingsFileDefault)) + { + this.ParseSettingsFiles(ConvertCommand.SettingsFileDefault, null); + } + } + + var converter = new Wix3Converter(this.Messaging, this.IndentationAmount, this.ErrorsAsWarnings, this.IgnoreErrors); + + var errors = this.InspectSubDirectories(converter, Path.GetFullPath(".")); + + foreach (var searchPattern in this.SearchPatterns) + { + if (!this.SearchPatternResults.Contains(searchPattern)) + { + Console.Error.WriteLine("Could not find file \"{0}\"", searchPattern); + errors++; + } + } + + return errors != 0 ? 2 : 0; + } + + private static void DisplayHelp() + { + Console.WriteLine(" usage: wix.exe convert sourceFile [sourceFile ...]"); + Console.WriteLine(); + Console.WriteLine(" -f fix errors automatically for writable files"); + Console.WriteLine(" -nologo suppress displaying the logo information"); + Console.WriteLine(" -s search for matching files in current dir and subdirs"); + Console.WriteLine(" -set1 primary settings file"); + Console.WriteLine(" -set2 secondary settings file (overrides primary)"); + Console.WriteLine(" -indent: indentation multiple (overrides default of 4)"); + Console.WriteLine(" -? this help information"); + Console.WriteLine(); + Console.WriteLine(" sourceFile may use wildcards like *.wxs"); + } + + /// + /// Get the files that match a search path pattern. + /// + /// The base directory at which to begin the search. + /// The search path pattern. + /// The files matching the pattern. + private static string[] GetFiles(string baseDir, string searchPath) + { + // convert alternate directory separators to the standard one + var filePath = searchPath.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); + var lastSeparator = filePath.LastIndexOf(Path.DirectorySeparatorChar); + string[] files = null; + + try + { + if (0 > lastSeparator) + { + files = Directory.GetFiles(baseDir, filePath); + } + else // found directory separator + { + var searchPattern = filePath.Substring(lastSeparator + 1); + + files = Directory.GetFiles(filePath.Substring(0, lastSeparator + 1), searchPattern); + } + } + catch (DirectoryNotFoundException) + { + // don't let this function throw the DirectoryNotFoundException. (this exception + // occurs for non-existant directories and invalid characters in the searchPattern) + } + + return files; + } + + /// + /// Inspect sub-directories. + /// + /// The directory whose sub-directories will be inspected. + /// The number of errors that were found. + private int InspectSubDirectories(Wix3Converter converter, string directory) + { + var errors = 0; + + foreach (var searchPattern in this.SearchPatterns) + { + foreach (var sourceFilePath in GetFiles(directory, searchPattern)) + { + var file = new FileInfo(sourceFilePath); + + if (!this.ExemptFiles.Contains(file.Name.ToUpperInvariant())) + { + this.SearchPatternResults.Add(searchPattern); + errors += converter.ConvertFile(file.FullName, this.FixErrors); + } + } + } + + if (this.SubDirectories) + { + foreach (var childDirectoryPath in Directory.GetDirectories(directory)) + { + errors += this.InspectSubDirectories(converter, childDirectoryPath); + } + } + + return errors; + } + + /// + /// Parse the primary and secondary settings files. + /// + /// The primary settings file. + /// The secondary settings file. + private void ParseSettingsFiles(string localSettingsFile1, string localSettingsFile2) + { + if (null == localSettingsFile1 && null != localSettingsFile2) + { + throw new ArgumentException("Cannot specify a secondary settings file (set2) without a primary settings file (set1).", nameof(localSettingsFile2)); + } + + var settingsFile = localSettingsFile1; + while (null != settingsFile) + { + var doc = new XmlDocument(); + doc.Load(settingsFile); + + // get the types of tests that will have their errors displayed as warnings + var testsIgnoredElements = doc.SelectNodes("/Settings/IgnoreErrors/Test"); + foreach (XmlElement test in testsIgnoredElements) + { + var key = test.GetAttribute("Id"); + this.IgnoreErrors.Add(key); + } + + // get the types of tests that will have their errors displayed as warnings + var testsAsWarningsElements = doc.SelectNodes("/Settings/ErrorsAsWarnings/Test"); + foreach (XmlElement test in testsAsWarningsElements) + { + var key = test.GetAttribute("Id"); + this.ErrorsAsWarnings.Add(key); + } + + // get the exempt files + var localExemptFiles = doc.SelectNodes("/Settings/ExemptFiles/File"); + foreach (XmlElement file in localExemptFiles) + { + var key = file.GetAttribute("Name").ToUpperInvariant(); + this.ExemptFiles.Add(key); + } + + settingsFile = localSettingsFile2; + localSettingsFile2 = null; + } + } + } +} diff --git a/src/WixToolset.Converters/ConverterExtensionCommandLine.cs b/src/WixToolset.Converters/ConverterExtensionCommandLine.cs new file mode 100644 index 00000000..ed4b613e --- /dev/null +++ b/src/WixToolset.Converters/ConverterExtensionCommandLine.cs @@ -0,0 +1,39 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using System.Collections.Generic; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + /// + /// Parses the "convert" command-line command. See ConvertCommand for + /// the bulk of the command-line processing. + /// + internal class ConverterExtensionCommandLine : BaseExtensionCommandLine + { + public ConverterExtensionCommandLine(IWixToolsetServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + private IWixToolsetServiceProvider ServiceProvider { get; } + + // TODO: Do something with CommandLineSwitches + public override IEnumerable CommandLineSwitches => base.CommandLineSwitches; + + public override bool TryParseCommand(ICommandLineParser parser, string argument, out ICommandLineCommand command) + { + command = null; + + if ("convert".Equals(argument, StringComparison.OrdinalIgnoreCase)) + { + command = new ConvertCommand(this.ServiceProvider); + } + + return command != null; + } + } +} diff --git a/src/WixToolset.Converters/ConverterExtensionFactory.cs b/src/WixToolset.Converters/ConverterExtensionFactory.cs new file mode 100644 index 00000000..51099e67 --- /dev/null +++ b/src/WixToolset.Converters/ConverterExtensionFactory.cs @@ -0,0 +1,30 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using System; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + + internal class ConverterExtensionFactory : IExtensionFactory + { + public ConverterExtensionFactory(IWixToolsetServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + private IWixToolsetServiceProvider ServiceProvider { get; } + + public bool TryCreateExtension(Type extensionType, out object extension) + { + extension = null; + + if (extensionType == typeof(IExtensionCommandLine)) + { + extension = new ConverterExtensionCommandLine(this.ServiceProvider); + } + + return extension != null; + } + } +} diff --git a/src/WixToolset.Converters/WixToolset.Converters.csproj b/src/WixToolset.Converters/WixToolset.Converters.csproj index d223cf44..1e443877 100644 --- a/src/WixToolset.Converters/WixToolset.Converters.csproj +++ b/src/WixToolset.Converters/WixToolset.Converters.csproj @@ -20,7 +20,7 @@ - + diff --git a/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs b/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs new file mode 100644 index 00000000..afc33f62 --- /dev/null +++ b/src/WixToolset.Converters/WixToolsetCoreServiceProviderExtensions.cs @@ -0,0 +1,17 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.Converters +{ + using WixToolset.Extensibility.Services; + + public static class WixToolsetCoreServiceProviderExtensions + { + public static IWixToolsetCoreServiceProvider AddConverter(this IWixToolsetCoreServiceProvider serviceProvider) + { + var extensionManager = serviceProvider.GetService(); + extensionManager.Add(typeof(ConverterExtensionFactory).Assembly); + + return serviceProvider; + } + } +} diff --git a/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.v3.ncrunchproject b/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.v3.ncrunchproject new file mode 100644 index 00000000..bb70cf0f --- /dev/null +++ b/src/test/WixToolsetTest.Converters.Tupleizer/WixToolsetTest.Converters.Tupleizer.v3.ncrunchproject @@ -0,0 +1,9 @@ + + + + + WixToolsetTest.Converters.Tupleizer.ConvertTuplesFixture.CanLoadWixoutAndConvertToIntermediate + + + + \ No newline at end of file -- cgit v1.2.3-55-g6feb