// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. namespace WixToolset.Core.CommandLine { using System; using System.Collections.Generic; using System.IO; using System.Linq; using WixToolset.Data; using WixToolset.Data.Bind; using WixToolset.Extensibility; using WixToolset.Extensibility.Services; internal class BuildCommand : ICommandLineCommand { public BuildCommand(IServiceProvider serviceProvider, IEnumerable sources, IDictionary preprocessorVariables, IEnumerable locFiles, IEnumerable libraryFiles, string outputPath, OutputType outputType, string cabCachePath, IEnumerable cultures, bool bindFiles, IEnumerable bindPaths, string intermediateFolder, string contentsFile, string outputsFile, string builtOutputsFile) { this.ServiceProvider = serviceProvider; this.Messaging = serviceProvider.GetService(); this.ExtensionManager = serviceProvider.GetService(); this.LocFiles = locFiles; this.LibraryFiles = libraryFiles; this.PreprocessorVariables = preprocessorVariables; this.SourceFiles = sources; this.OutputPath = outputPath; this.OutputType = outputType; this.CabCachePath = cabCachePath; this.Cultures = cultures; this.BindFiles = bindFiles; this.BindPaths = bindPaths; this.IntermediateFolder = intermediateFolder ?? Path.GetTempPath(); this.ContentsFile = contentsFile; this.OutputsFile = outputsFile; this.BuiltOutputsFile = builtOutputsFile; } public IServiceProvider ServiceProvider { get; } public IMessaging Messaging { get; } public IExtensionManager ExtensionManager { get; } public IEnumerable IncludeSearchPaths { get; } 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 string CabCachePath { 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; } public string BuiltOutputsFile { get; } public int Execute() { var intermediates = this.CompilePhase(); if (this.Messaging.EncounteredError) { return this.Messaging.LastErrorNumber; } if (!intermediates.Any()) { return 1; } if (this.OutputType == OutputType.Library) { var library = this.LibraryPhase(intermediates); library?.Save(this.OutputPath); } else if (this.OutputType == OutputType.Wixout) { var output = this.LinkPhase(intermediates); output?.Save(this.OutputPath); } else { var output = this.LinkPhase(intermediates); if (!this.Messaging.EncounteredError) { this.BindPhase(output); } } return this.Messaging.LastErrorNumber; } private IEnumerable CompilePhase() { var intermediates = new List(); foreach (var sourceFile in this.SourceFiles) { var preprocessor = new Preprocessor(this.ServiceProvider); preprocessor.IncludeSearchPaths = this.IncludeSearchPaths; preprocessor.Platform = Platform.X86; // TODO: set this correctly preprocessor.SourcePath = sourceFile.SourcePath; preprocessor.Variables = this.PreprocessorVariables; var document = preprocessor.Execute(); if (this.Messaging.EncounteredError) { continue; } var compiler = new Compiler(this.ServiceProvider); compiler.OutputPath = sourceFile.OutputPath; compiler.Platform = Platform.X86; // TODO: set this correctly compiler.SourceDocument = document; var intermediate = compiler.Execute(); if (this.Messaging.EncounteredError) { continue; } intermediates.Add(intermediate); } return intermediates; } private Intermediate LibraryPhase(IEnumerable intermediates) { var localizations = this.LoadLocalizationFiles().ToList(); // If there was an error loading localization files, then bail. if (this.Messaging.EncounteredError) { return null; } var librarian = new Librarian(this.ServiceProvider); librarian.BindFiles = this.BindFiles; librarian.BindPaths = this.BindPaths; librarian.Intermediates = intermediates; librarian.Localizations = localizations; return librarian.Execute(); } private Intermediate LinkPhase(IEnumerable intermediates) { var creator = this.ServiceProvider.GetService(); var libraries = this.LoadLibraries(creator); if (this.Messaging.EncounteredError) { return null; } var linker = new Linker(this.ServiceProvider); linker.OutputType = this.OutputType; linker.Intermediates = intermediates; linker.Libraries = libraries; linker.TupleDefinitionCreator = creator; return linker.Execute(); } private void BindPhase(Intermediate output) { var localizations = this.LoadLocalizationFiles().ToList(); // If there was an error loading localization files, then bail. if (this.Messaging.EncounteredError) { return; } ResolveResult resolveResult; { var resolver = new Resolver(this.ServiceProvider); resolver.BindPaths = this.BindPaths; resolver.IntermediateFolder = this.IntermediateFolder; resolver.IntermediateRepresentation = output; resolver.Localizations = localizations; resolveResult = resolver.Execute(); } if (this.Messaging.EncounteredError) { return; } BindResult bindResult; { var intermediateFolder = this.IntermediateFolder; if (String.IsNullOrEmpty(intermediateFolder)) { intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); } var binder = new Binder(this.ServiceProvider); //binder.CabbingThreadCount = this.CabbingThreadCount; binder.CabCachePath = this.CabCachePath; binder.Codepage = resolveResult.Codepage; //binder.DefaultCompressionLevel = this.DefaultCompressionLevel; binder.DelayedFields = resolveResult.DelayedFields; binder.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; binder.Ices = Array.Empty(); // TODO: set this correctly binder.IntermediateFolder = intermediateFolder; binder.IntermediateRepresentation = resolveResult.IntermediateRepresentation; binder.OutputPath = this.OutputPath; binder.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb"); binder.SuppressIces = Array.Empty(); // TODO: set this correctly binder.SuppressValidation = true; // TODO: set this correctly bindResult = binder.Execute(); } if (this.Messaging.EncounteredError) { return; } { var layout = new Layout(this.ServiceProvider); layout.FileTransfers = bindResult.FileTransfers; layout.ContentFilePaths = bindResult.ContentFilePaths; layout.ContentsFile = this.ContentsFile; layout.OutputsFile = this.OutputsFile; layout.BuiltOutputsFile = this.BuiltOutputsFile; layout.SuppressAclReset = false; // TODO: correctly set SuppressAclReset layout.Execute(); } } private IEnumerable LoadLibraries(ITupleDefinitionCreator creator) { var libraries = new List(); if (this.LibraryFiles != null) { foreach (var libraryFile in this.LibraryFiles) { try { var library = Intermediate.Load(libraryFile, creator); libraries.Add(library); } catch (WixCorruptFileException e) { this.Messaging.Write(e.Error); } catch (WixUnexpectedFileFormatException e) { this.Messaging.Write(e.Error); } } } return libraries; } private IEnumerable LoadLocalizationFiles() { foreach (var loc in this.LocFiles) { var localization = Localizer.ParseLocalizationFile(this.Messaging, loc); yield return localization; } } } }