From 39c7e2bb0399802e65a3025c4a73db211e730479 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Sun, 1 Oct 2017 14:25:33 -0700 Subject: Add support for BindPaths and building .wixlibs --- src/WixToolset.Core/CommandLine/BuildCommand.cs | 196 +++++++++++++++++++++--- src/WixToolset.Core/CommandLine/CommandLine.cs | 115 +++++++++++--- 2 files changed, 266 insertions(+), 45 deletions(-) (limited to 'src/WixToolset.Core/CommandLine') diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs index ffb48305..d8954cb7 100644 --- a/src/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs @@ -7,17 +7,24 @@ namespace WixToolset.Core using System.IO; using System.Linq; using WixToolset.Data; + using WixToolset.Extensibility; internal class BuildCommand : ICommand { - public BuildCommand(IEnumerable sources, IDictionary preprocessorVariables, IEnumerable locFiles, string outputPath, IEnumerable cultures, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile) + public BuildCommand(IEnumerable sources, IDictionary preprocessorVariables, IEnumerable locFiles, IEnumerable libraryFiles, string outputPath, OutputType outputType, IEnumerable cultures, bool bindFiles, IEnumerable bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile, string wixProjectFile) { this.LocFiles = locFiles; + this.LibraryFiles = libraryFiles; this.PreprocessorVariables = preprocessorVariables; this.SourceFiles = sources; this.OutputPath = outputPath; + this.OutputType = outputType; this.Cultures = cultures; + this.BindFiles = bindFiles; + this.BindPaths = bindPaths; + + this.IntermediateFolder = intermediateFolder ?? Path.GetTempPath(); this.ContentsFile = contentsFile; this.OutputsFile = outputsFile; this.BuiltOutputsFile = builtOutputsFile; @@ -26,14 +33,24 @@ namespace WixToolset.Core public IEnumerable LocFiles { get; } + public IEnumerable LibraryFiles { get; } + private IEnumerable SourceFiles { get; } private IDictionary PreprocessorVariables { get; } private string OutputPath { get; } + private OutputType OutputType { get; } + public IEnumerable Cultures { get; } + public bool BindFiles { get; } + + public IEnumerable BindPaths { get; } + + public string IntermediateFolder { get; } + public string ContentsFile { get; } public string OutputsFile { get; } @@ -44,21 +61,135 @@ namespace WixToolset.Core public int Execute() { - var intermediates = CompilePhase(); + var intermediates = this.CompilePhase(); + + var tableDefinitions = new TableDefinitionCollection(WindowsInstallerStandard.GetTableDefinitions()); + + if (this.OutputType == OutputType.Library) + { + this.LibraryPhase(intermediates, tableDefinitions); + } + else + { + var output = this.LinkPhase(intermediates, tableDefinitions); + + if (!Messaging.Instance.EncounteredError) + { + this.BindPhase(output, tableDefinitions); + } + } + + return Messaging.Instance.LastErrorNumber; + } + + private IEnumerable CompilePhase() + { + var intermediates = new List(); + + var preprocessor = new Preprocessor(); + + var compiler = new Compiler(); + + foreach (var sourceFile in this.SourceFiles) + { + var document = preprocessor.Process(sourceFile.SourcePath, this.PreprocessorVariables); + + var intermediate = compiler.Compile(document); + + intermediates.Add(intermediate); + } + + return intermediates; + } + + private void LibraryPhase(IEnumerable intermediates, TableDefinitionCollection tableDefinitions) + { + var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList(); + + // If there was an error adding localization files, then bail. + if (Messaging.Instance.EncounteredError) + { + return; + } var sections = intermediates.SelectMany(i => i.Sections).ToList(); + LibraryBinaryFileResolver resolver = null; + + if (this.BindFiles) + { + resolver = new LibraryBinaryFileResolver(); + resolver.FileManagers = new List { new BinderFileManager() }; ; + resolver.VariableResolver = new WixVariableResolver(); + + BinderFileManagerCore core = new BinderFileManagerCore(); + core.AddBindPaths(this.BindPaths, BindStage.Normal); + + foreach (var fileManager in resolver.FileManagers) + { + fileManager.Core = core; + } + } + + var librarian = new Librarian(); + + var library = librarian.Combine(sections, localizations, resolver); + + library?.Save(this.OutputPath); + } + + private Output LinkPhase(IEnumerable intermediates, TableDefinitionCollection tableDefinitions) + { + var sections = intermediates.SelectMany(i => i.Sections).ToList(); + + sections.AddRange(SectionsFromLibraries(tableDefinitions)); + var linker = new Linker(); - var output = linker.Link(sections, OutputType.Product); + var output = linker.Link(sections, this.OutputType); + + return output; + } + + private IEnumerable
SectionsFromLibraries(TableDefinitionCollection tableDefinitions) + { + var sections = new List
(); + + if (this.LibraryFiles != null) + { + foreach (var libraryFile in this.LibraryFiles) + { + try + { + var library = Library.Load(libraryFile, tableDefinitions, false); + + sections.AddRange(library.Sections); + } + catch (WixCorruptFileException e) + { + Messaging.Instance.OnMessage(e.Error); + } + catch (WixUnexpectedFileFormatException e) + { + Messaging.Instance.OnMessage(e.Error); + } + } + } - var localizer = new Localizer(); + return sections; + } + + private void BindPhase(Output output, TableDefinitionCollection tableDefinitions) + { + var localizations = this.LoadLocalizationFiles(tableDefinitions).ToList(); + + var localizer = new Localizer(localizations); + + var resolver = new WixVariableResolver(localizer); var binder = new Binder(); - binder.TempFilesLocation = Path.GetTempPath(); - binder.WixVariableResolver = new WixVariableResolver(); - binder.WixVariableResolver.Localizer = localizer; - binder.AddExtension(new BinderFileManager()); + binder.TempFilesLocation = this.IntermediateFolder; + binder.WixVariableResolver = resolver; binder.SuppressValidation = true; binder.ContentsFile = this.ContentsFile; @@ -66,35 +197,50 @@ namespace WixToolset.Core binder.BuiltOutputsFile = this.BuiltOutputsFile; binder.WixprojectFile = this.WixProjectFile; - foreach (var loc in this.LocFiles) + if (this.BindPaths != null) { - var localization = Localizer.ParseLocalizationFile(loc, linker.TableDefinitions); - binder.WixVariableResolver.Localizer.AddLocalization(localization); + binder.BindPaths.AddRange(this.BindPaths); } - binder.Bind(output, this.OutputPath); + binder.AddExtension(new BinderFileManager()); - return 0; + binder.Bind(output, this.OutputPath); } - private IEnumerable CompilePhase() + private IEnumerable LoadLocalizationFiles(TableDefinitionCollection tableDefinitions) { - var intermediates = new List(); - - var preprocessor = new Preprocessor(); + foreach (var loc in this.LocFiles) + { + var localization = Localizer.ParseLocalizationFile(loc, tableDefinitions); - var compiler = new Compiler(); + yield return localization; + } + } - foreach (var sourceFile in this.SourceFiles) - { - var document = preprocessor.Process(sourceFile.SourcePath, this.PreprocessorVariables); + /// + /// File resolution mechanism to create binary library. + /// + private class LibraryBinaryFileResolver : ILibraryBinaryFileResolver + { + public IEnumerable FileManagers { get; set; } - var intermediate = compiler.Compile(document); + public WixVariableResolver VariableResolver { get; set; } - intermediates.Add(intermediate); + public string Resolve(SourceLineNumber sourceLineNumber, string table, string path) + { + string resolvedPath = this.VariableResolver.ResolveVariables(sourceLineNumber, path, false); + + foreach (IBinderFileManager fileManager in this.FileManagers) + { + string finalPath = fileManager.ResolveFile(resolvedPath, table, sourceLineNumber, BindStage.Normal); + if (!String.IsNullOrEmpty(finalPath)) + { + return finalPath; + } + } + + return null; } - - return intermediates; } } } diff --git a/src/WixToolset.Core/CommandLine/CommandLine.cs b/src/WixToolset.Core/CommandLine/CommandLine.cs index 440ae9ef..cac54091 100644 --- a/src/WixToolset.Core/CommandLine/CommandLine.cs +++ b/src/WixToolset.Core/CommandLine/CommandLine.cs @@ -57,14 +57,20 @@ namespace WixToolset.Core var showVersion = false; var outputFolder = String.Empty; var outputFile = String.Empty; - var sourceFile = String.Empty; + var outputType = String.Empty; var verbose = false; var files = new List(); var defines = new List(); var includePaths = new List(); var locFiles = new List(); + var libraryFiles = new List(); var suppressedWarnings = new List(); + var bindFiles = false; + var bindPaths = new List(); + + var intermediateFolder = String.Empty; + var cultures = new List(); var contentsFile = String.Empty; var outputsFile = String.Empty; @@ -84,6 +90,14 @@ namespace WixToolset.Core cmdline.ShowHelp = true; return true; + case "bindfiles": + bindFiles = true; + return true; + + case "bindpath": + cmdline.GetNextArgumentOrError(bindPaths); + return true; + case "cultures": cmdline.GetNextArgumentOrError(cultures); return true; @@ -110,15 +124,27 @@ namespace WixToolset.Core cmdline.GetNextArgumentOrError(includePaths); return true; + case "intermediatefolder": + cmdline.GetNextArgumentOrError(ref intermediateFolder); + return true; + case "loc": cmdline.GetNextArgumentAsFilePathOrError(locFiles, "localization files"); return true; + case "lib": + cmdline.GetNextArgumentAsFilePathOrError(libraryFiles, "library files"); + return true; + case "o": case "out": cmdline.GetNextArgumentOrError(ref outputFile); return true; + case "outputtype": + cmdline.GetNextArgumentOrError(ref outputType); + return true; + case "nologo": showLogo = false; return true; @@ -143,6 +169,8 @@ namespace WixToolset.Core } }); + Messaging.Instance.ShowVerboseMessages = verbose; + if (showVersion) { return new VersionCommand(); @@ -164,8 +192,10 @@ namespace WixToolset.Core { var sourceFiles = GatherSourceFiles(files, outputFolder); var variables = GatherPreprocessorVariables(defines); + var bindPathList = GatherBindPaths(bindPaths); var extensions = cli.ExtensionManager; - return new BuildCommand(sourceFiles, variables, locFiles, outputFile, cultures, contentsFile, outputsFile, builtOutputsFile, wixProjectFile); + var type = CalculateOutputType(outputType, outputFile); + return new BuildCommand(sourceFiles, variables, locFiles, libraryFiles, outputFile, type, cultures, bindFiles, bindPathList, intermediateFolder, contentsFile, outputsFile, builtOutputsFile, wixProjectFile); } case Commands.Compile: @@ -179,6 +209,46 @@ namespace WixToolset.Core return null; } + private static OutputType CalculateOutputType(string outputType, string outputFile) + { + if (String.IsNullOrEmpty(outputType)) + { + outputType = Path.GetExtension(outputFile); + } + + switch (outputType.ToLowerInvariant()) + { + case "bundle": + case ".exe": + return OutputType.Bundle; + + case "library": + case ".wixlib": + return OutputType.Library; + + case "module": + case ".msm": + return OutputType.Module; + + case "patch": + case ".msp": + return OutputType.Patch; + + case ".pcp": + return OutputType.PatchCreation; + + case "product": + case ".msi": + return OutputType.Product; + + case "transform": + case ".mst": + return OutputType.Transform; + } + + return OutputType.Unknown; + } + private static CommandLine Parse(string commandLineString, Func parseArgument) { var arguments = CommandLine.ParseArgumentsToArray(commandLineString).ToArray(); @@ -239,6 +309,26 @@ namespace WixToolset.Core return variables; } + private static IEnumerable GatherBindPaths(IEnumerable bindPaths) + { + var result = new List(); + + foreach (var bindPath in bindPaths) + { + BindPath bp = BindPath.Parse(bindPath); + + if (Directory.Exists(bp.Path)) + { + result.Add(bp); + } + else if (File.Exists(bp.Path)) + { + Messaging.Instance.OnMessage(WixErrors.ExpectedDirectoryGotFile("-bindpath", bp.Path)); + } + } + + return result; + } /// /// Get a set of files that possibly have a search pattern in the path (such as '*'). @@ -361,7 +451,7 @@ namespace WixToolset.Core private static bool TryDequeue(Queue q, out string arg) { - if (q.Count> 0) + if (q.Count > 0) { arg = q.Dequeue(); return true; @@ -469,11 +559,6 @@ namespace WixToolset.Core return false; } - /// - /// Parses a response file. - /// - /// The file to parse. - /// The array of arguments. private static List ParseResponseFile(string responseFile) { string arguments; @@ -486,11 +571,6 @@ namespace WixToolset.Core return CommandLine.ParseArgumentsToArray(arguments); } - /// - /// Parses an argument string into an argument array based on whitespace and quoting. - /// - /// Argument string. - /// Argument array. private static List ParseArgumentsToArray(string arguments) { // Scan and parse the arguments string, dividing up the arguments based on whitespace. @@ -526,7 +606,7 @@ namespace WixToolset.Core // Add the argument to the list if it's not empty. if (arg.Length > 0) { - argsList.Add(CommandLine.ExpandEnvVars(arg.ToString())); + argsList.Add(CommandLine.ExpandEnvironmentVariables(arg.ToString())); arg.Length = 0; } } @@ -557,12 +637,7 @@ namespace WixToolset.Core return argsList; } - /// - /// Expand enxironment variables contained in the passed string - /// - /// - /// - private static string ExpandEnvVars(string arguments) + private static string ExpandEnvironmentVariables(string arguments) { var id = Environment.GetEnvironmentVariables(); -- cgit v1.2.3-55-g6feb