From dc9f4c329e6f55ce7595970463e0caf148096f4b Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 21 Dec 2017 13:42:52 -0800 Subject: Support wixout and extract Resolve and Layout from Binder --- src/WixToolset.Core/Bind/FileResolver.cs | 92 +---- src/WixToolset.Core/Bind/FileSystem.cs | 87 +++++ src/WixToolset.Core/Bind/ResolveFieldsCommand.cs | 17 +- src/WixToolset.Core/Bind/ResolveResult.cs | 14 - src/WixToolset.Core/Bind/ResolvedDirectory.cs | 31 -- src/WixToolset.Core/Bind/TransferFilesCommand.cs | 22 +- src/WixToolset.Core/BindContext.cs | 4 +- src/WixToolset.Core/Binder.cs | 451 +++-------------------- src/WixToolset.Core/BinderFileManager.cs | 2 +- src/WixToolset.Core/BinderFileManagerCore.cs | 2 + src/WixToolset.Core/CommandLine/BuildCommand.cs | 122 +++--- src/WixToolset.Core/CommandLine/CommandLine.cs | 4 + src/WixToolset.Core/Compiler.cs | 53 +-- src/WixToolset.Core/Layout.cs | 188 ++++++++++ src/WixToolset.Core/LayoutContext.cs | 40 ++ src/WixToolset.Core/Librarian.cs | 30 +- src/WixToolset.Core/LibraryContext.cs | 2 - src/WixToolset.Core/Linker.cs | 6 +- src/WixToolset.Core/PreprocessContext.cs | 3 - src/WixToolset.Core/ResolveContext.cs | 32 ++ src/WixToolset.Core/Resolver.cs | 234 ++++++++++++ src/WixToolset.Core/WixToolsetServiceProvider.cs | 10 + src/WixToolset.Core/WixVariableResolver.cs | 77 +--- 23 files changed, 825 insertions(+), 698 deletions(-) create mode 100644 src/WixToolset.Core/Bind/FileSystem.cs delete mode 100644 src/WixToolset.Core/Bind/ResolveResult.cs delete mode 100644 src/WixToolset.Core/Bind/ResolvedDirectory.cs create mode 100644 src/WixToolset.Core/Layout.cs create mode 100644 src/WixToolset.Core/LayoutContext.cs create mode 100644 src/WixToolset.Core/ResolveContext.cs create mode 100644 src/WixToolset.Core/Resolver.cs (limited to 'src/WixToolset.Core') diff --git a/src/WixToolset.Core/Bind/FileResolver.cs b/src/WixToolset.Core/Bind/FileResolver.cs index 2142d261..a20d3f34 100644 --- a/src/WixToolset.Core/Bind/FileResolver.cs +++ b/src/WixToolset.Core/Bind/FileResolver.cs @@ -6,7 +6,6 @@ namespace WixToolset.Core.Bind using System.Collections.Generic; using System.IO; using System.Linq; - using System.Runtime.InteropServices; using WixToolset.Data; using WixToolset.Data.Bind; using WixToolset.Extensibility; @@ -22,9 +21,9 @@ namespace WixToolset.Core.Bind this.RebaseUpdated = this.BindPaths[BindStage.Updated].Any(); } - public FileResolver(IEnumerable bindPaths, IEnumerable extensions) : this(bindPaths) + public FileResolver(IEnumerable bindPaths, IEnumerable extensions) : this(bindPaths) { - this.BinderExtensions = extensions ?? Array.Empty(); + this.ResolverExtensions = extensions ?? Array.Empty(); } public FileResolver(IEnumerable bindPaths, IEnumerable extensions) : this(bindPaths) @@ -38,79 +37,15 @@ namespace WixToolset.Core.Bind public bool RebaseUpdated { get; } - private IEnumerable BinderExtensions { get; } + private IEnumerable ResolverExtensions { get; } private IEnumerable LibrarianExtensions { get; } - /// - /// Copies a file. - /// - /// The file to copy. - /// The destination file. - /// true if the destination file can be overwritten; otherwise, false. - public bool CopyFile(string source, string destination, bool overwrite) - { - foreach (var extension in this.BinderExtensions) - { - if (extension.CopyFile(source, destination, overwrite)) - { - return true; - } - } - - if (overwrite && File.Exists(destination)) - { - File.Delete(destination); - } - - if (!CreateHardLink(destination, source, IntPtr.Zero)) - { -#if DEBUG - int er = Marshal.GetLastWin32Error(); -#endif - - File.Copy(source, destination, overwrite); - } - - return true; - } - - /// - /// Moves a file. - /// - /// The file to move. - /// The destination file. - public bool MoveFile(string source, string destination, bool overwrite) - { - foreach (var extension in this.BinderExtensions) - { - if (extension.MoveFile(source, destination, overwrite)) - { - return true; - } - } - - if (overwrite && File.Exists(destination)) - { - File.Delete(destination); - } - - var directory = Path.GetDirectoryName(destination); - if (!String.IsNullOrEmpty(directory)) - { - Directory.CreateDirectory(directory); - } - - File.Move(source, destination); - - return true; - } - - public string Resolve(SourceLineNumber sourceLineNumbers, string table, string path) + public string Resolve(SourceLineNumber sourceLineNumbers, IntermediateTupleDefinition tupleDefinition, string source) { foreach (var extension in this.LibrarianExtensions) { - var resolved = extension.Resolve(sourceLineNumbers, table, path); + var resolved = extension.Resolve(sourceLineNumbers, tupleDefinition, source); if (null != resolved) { @@ -118,7 +53,7 @@ namespace WixToolset.Core.Bind } } - return this.ResolveUsingBindPaths(path, table, sourceLineNumbers, BindStage.Normal); + return this.ResolveUsingBindPaths(source, tupleDefinition, sourceLineNumbers, BindStage.Normal); } /// @@ -129,11 +64,11 @@ namespace WixToolset.Core.Bind /// Optional source line of source file being resolved. /// The binding stage used to determine what collection of bind paths will be used /// Should return a valid path for the stream to be imported. - public string ResolveFile(string source, string type, SourceLineNumber sourceLineNumbers, BindStage bindStage) + public string ResolveFile(string source, IntermediateTupleDefinition tupleDefinition, SourceLineNumber sourceLineNumbers, BindStage bindStage) { - foreach (var extension in this.BinderExtensions) + foreach (var extension in this.ResolverExtensions) { - var resolved = extension.ResolveFile(source, type, sourceLineNumbers, bindStage); + var resolved = extension.ResolveFile(source, tupleDefinition, sourceLineNumbers, bindStage); if (null != resolved) { @@ -141,10 +76,10 @@ namespace WixToolset.Core.Bind } } - return this.ResolveUsingBindPaths(source, type, sourceLineNumbers, bindStage); + return this.ResolveUsingBindPaths(source, tupleDefinition, sourceLineNumbers, bindStage); } - private string ResolveUsingBindPaths(string source, string type, SourceLineNumber sourceLineNumbers, BindStage bindStage) + private string ResolveUsingBindPaths(string source, IntermediateTupleDefinition tupleDefinition, SourceLineNumber sourceLineNumbers, BindStage bindStage) { string resolved = null; @@ -206,7 +141,7 @@ namespace WixToolset.Core.Bind if (null == resolved) { - throw new WixFileNotFoundException(sourceLineNumbers, source, type); + throw new WixFileNotFoundException(sourceLineNumbers, source, tupleDefinition.Name); } // Didn't find the file. @@ -224,8 +159,5 @@ namespace WixToolset.Core.Bind throw new WixException(ErrorMessages.IllegalCharactersInPath(path)); } } - - [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); } } diff --git a/src/WixToolset.Core/Bind/FileSystem.cs b/src/WixToolset.Core/Bind/FileSystem.cs new file mode 100644 index 00000000..7d1b223e --- /dev/null +++ b/src/WixToolset.Core/Bind/FileSystem.cs @@ -0,0 +1,87 @@ +// 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.Bind +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Runtime.InteropServices; + using WixToolset.Extensibility; + + internal class FileSystem + { + public FileSystem(IEnumerable extensions) + { + this.Extensions = extensions ?? Array.Empty(); + } + + private IEnumerable Extensions { get; } + + /// + /// Copies a file. + /// + /// The file to copy. + /// The destination file. + /// true if the destination file can be overwritten; otherwise, false. + public bool CopyFile(string source, string destination, bool overwrite) + { + foreach (var extension in this.Extensions) + { + if (extension.CopyFile(source, destination, overwrite)) + { + return true; + } + } + + if (overwrite && File.Exists(destination)) + { + File.Delete(destination); + } + + if (!CreateHardLink(destination, source, IntPtr.Zero)) + { +#if DEBUG + int er = Marshal.GetLastWin32Error(); +#endif + + File.Copy(source, destination, overwrite); + } + + return true; + } + + /// + /// Moves a file. + /// + /// The file to move. + /// The destination file. + public bool MoveFile(string source, string destination, bool overwrite) + { + foreach (var extension in this.Extensions) + { + if (extension.MoveFile(source, destination, overwrite)) + { + return true; + } + } + + if (overwrite && File.Exists(destination)) + { + File.Delete(destination); + } + + var directory = Path.GetDirectoryName(destination); + if (!String.IsNullOrEmpty(directory)) + { + Directory.CreateDirectory(directory); + } + + File.Move(source, destination); + + return true; + } + + [DllImport("Kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern bool CreateHardLink(string lpFileName, string lpExistingFileName, IntPtr lpSecurityAttributes); + } +} diff --git a/src/WixToolset.Core/Bind/ResolveFieldsCommand.cs b/src/WixToolset.Core/Bind/ResolveFieldsCommand.cs index e8c90956..824eb9a5 100644 --- a/src/WixToolset.Core/Bind/ResolveFieldsCommand.cs +++ b/src/WixToolset.Core/Bind/ResolveFieldsCommand.cs @@ -22,7 +22,7 @@ namespace WixToolset.Core.Bind public IEnumerable BindPaths { private get; set; } - public IEnumerable Extensions { private get; set; } + public IEnumerable Extensions { private get; set; } public ExtractEmbeddedFiles FilesWithEmbeddedFiles { private get; set; } @@ -52,7 +52,6 @@ namespace WixToolset.Core.Bind } var isDefault = true; - var delayedResolve = false; // Check to make sure we're in a scenario where we can handle variable resolution. if (null != delayedFields) @@ -63,16 +62,18 @@ namespace WixToolset.Core.Bind var original = field.AsString(); if (!String.IsNullOrEmpty(original)) { - var value = this.BindVariableResolver.ResolveVariables(row.SourceLineNumbers, original, false, out isDefault, out delayedResolve); - if (original != value) + var resolution = this.BindVariableResolver.ResolveVariables(row.SourceLineNumbers, original, false); + if (resolution.UpdatedValue) { - field.Set(value); + field.Set(resolution.Value); } - if (delayedResolve) + if (resolution.DelayedResolve) { delayedFields.Add(new DelayedField(row, field)); } + + isDefault = resolution.IsDefault; } } } @@ -119,13 +120,13 @@ namespace WixToolset.Core.Bind #endif // resolve the path to the file - var value = fileResolver.ResolveFile(objectField.Path, row.Definition.Name, row.SourceLineNumbers, BindStage.Normal); + var value = fileResolver.ResolveFile(objectField.Path, row.Definition, row.SourceLineNumbers, BindStage.Normal); field.Set(value); } else if (!fileResolver.RebaseTarget && !fileResolver.RebaseUpdated) // Normal binding for Patch Scenario (normal patch, no re-basing logic) { // resolve the path to the file - var value = fileResolver.ResolveFile(objectField.Path, row.Definition.Name, row.SourceLineNumbers, BindStage.Normal); + var value = fileResolver.ResolveFile(objectField.Path, row.Definition, row.SourceLineNumbers, BindStage.Normal); field.Set(value); } #if REVISIT_FOR_PATCHING diff --git a/src/WixToolset.Core/Bind/ResolveResult.cs b/src/WixToolset.Core/Bind/ResolveResult.cs deleted file mode 100644 index 13f25054..00000000 --- a/src/WixToolset.Core/Bind/ResolveResult.cs +++ /dev/null @@ -1,14 +0,0 @@ -// 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.Bind -{ - using System.Collections.Generic; - using WixToolset.Extensibility; - - public class ResolveResult - { - public IEnumerable ExpectedEmbeddedFiles { get; set; } - - public IEnumerable DelayedFields { get; set; } - } -} \ No newline at end of file diff --git a/src/WixToolset.Core/Bind/ResolvedDirectory.cs b/src/WixToolset.Core/Bind/ResolvedDirectory.cs deleted file mode 100644 index 9d07fc93..00000000 --- a/src/WixToolset.Core/Bind/ResolvedDirectory.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Bind -{ - /// - /// Structure used for resolved directory information. - /// - public struct ResolvedDirectory - { - /// - /// Constructor for ResolvedDirectory. - /// - /// Parent directory. - /// The directory name. - public ResolvedDirectory(string directoryParent, string name) - { - this.DirectoryParent = directoryParent; - this.Name = name; - this.Path = null; - } - - /// The directory parent. - public string DirectoryParent { get; set; } - - /// The name of this directory. - public string Name { get; set; } - - /// The path of this directory. - public string Path { get; set; } - } -} diff --git a/src/WixToolset.Core/Bind/TransferFilesCommand.cs b/src/WixToolset.Core/Bind/TransferFilesCommand.cs index 68d8b129..d4e143c3 100644 --- a/src/WixToolset.Core/Bind/TransferFilesCommand.cs +++ b/src/WixToolset.Core/Bind/TransferFilesCommand.cs @@ -13,15 +13,15 @@ namespace WixToolset.Core.Bind internal class TransferFilesCommand { - public TransferFilesCommand(IMessaging messaging, IEnumerable bindPaths, IEnumerable extensions, IEnumerable fileTransfers, bool suppressAclReset) + public TransferFilesCommand(IMessaging messaging, IEnumerable extensions, IEnumerable fileTransfers, bool suppressAclReset) { - this.FileResolver = new FileResolver(bindPaths, extensions); + this.FileSystem = new FileSystem(extensions); this.Messaging = messaging; this.FileTransfers = fileTransfers; this.SuppressAclReset = suppressAclReset; } - private FileResolver FileResolver { get; } + private FileSystem FileSystem { get; } private IMessaging Messaging { get; } @@ -35,10 +35,8 @@ namespace WixToolset.Core.Bind foreach (var fileTransfer in this.FileTransfers) { - string fileSource = this.FileResolver.ResolveFile(fileTransfer.Source, fileTransfer.Type, fileTransfer.SourceLineNumbers, BindStage.Normal); - // If the source and destination are identical, then there's nothing to do here - if (0 == String.Compare(fileSource, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase)) + if (0 == String.Compare(fileTransfer.Source, fileTransfer.Destination, StringComparison.OrdinalIgnoreCase)) { fileTransfer.Redundant = true; continue; @@ -51,13 +49,13 @@ namespace WixToolset.Core.Bind { if (fileTransfer.Move) { - this.Messaging.Write(VerboseMessages.MoveFile(fileSource, fileTransfer.Destination)); - this.TransferFile(true, fileSource, fileTransfer.Destination); + this.Messaging.Write(VerboseMessages.MoveFile(fileTransfer.Source, fileTransfer.Destination)); + this.TransferFile(true, fileTransfer.Source, fileTransfer.Destination); } else { - this.Messaging.Write(VerboseMessages.CopyFile(fileSource, fileTransfer.Destination)); - this.TransferFile(false, fileSource, fileTransfer.Destination); + this.Messaging.Write(VerboseMessages.CopyFile(fileTransfer.Source, fileTransfer.Destination)); + this.TransferFile(false, fileTransfer.Source, fileTransfer.Destination); } retry = false; @@ -183,11 +181,11 @@ namespace WixToolset.Core.Bind if (move) { - complete = this.FileResolver.MoveFile(source, destination, true); + complete = this.FileSystem.MoveFile(source, destination, true); } else { - complete = this.FileResolver.CopyFile(source, destination, true); + complete = this.FileSystem.CopyFile(source, destination, true); } if (!complete) diff --git a/src/WixToolset.Core/BindContext.cs b/src/WixToolset.Core/BindContext.cs index 41d0ddf9..8bdacf75 100644 --- a/src/WixToolset.Core/BindContext.cs +++ b/src/WixToolset.Core/BindContext.cs @@ -35,7 +35,7 @@ namespace WixToolset.Core public IExtensionManager ExtensionManager { get; set; } - public IEnumerable Extensions { get; set; } + public IEnumerable FileSystemExtensions { get; set; } public IEnumerable Ices { get; set; } @@ -47,8 +47,6 @@ namespace WixToolset.Core public string OutputPdbPath { get; set; } - public bool SuppressAclReset { get; set; } - public IEnumerable SuppressIces { get; set; } public bool SuppressValidation { get; set; } diff --git a/src/WixToolset.Core/Binder.cs b/src/WixToolset.Core/Binder.cs index 2369b600..9db27fec 100644 --- a/src/WixToolset.Core/Binder.cs +++ b/src/WixToolset.Core/Binder.cs @@ -3,14 +3,11 @@ namespace WixToolset.Core { using System; - using System.Collections; using System.Collections.Generic; using System.Diagnostics; - using System.Globalization; using System.IO; using System.Linq; using System.Reflection; - using WixToolset.Bind; using WixToolset.Core.Bind; using WixToolset.Data; using WixToolset.Data.Bind; @@ -148,130 +145,72 @@ namespace WixToolset.Core /// The Wix variable resolver. internal WixVariableResolver WixVariableResolver { get; set; } - /// - /// Add a binder extension. - /// - /// New extension. - //public void AddExtension(IBinderExtension extension) - //{ - // this.extensions.Add(extension); - //} - - /// - /// Add a file manager extension. - /// - /// New file manager. - //public void AddExtension(IBinderFileManager extension) - //{ - // this.fileManagers.Add(extension); - //} - - public bool Bind(IBindContext context) + public BindResult Bind(IBindContext context) { this.Context = context; - //if (!String.IsNullOrEmpty(this.Context.FileManagerCore.CabCachePath)) - //{ - // Directory.CreateDirectory(this.Context.FileManagerCore.CabCachePath); - //} - - //this.core = new BinderCore(); - //this.core.FileManagerCore = this.Context.FileManagerCore; - this.WriteBuildInfoTable(this.Context.IntermediateRepresentation, this.Context.OutputPath); - // Prebind. - // - this.Context.Extensions = this.Context.ExtensionManager.Create(); - - foreach (IBinderExtension extension in this.Context.Extensions) - { - extension.PreBind(this.Context); - } - - // Resolve. - // - var resolveResult = this.Resolve(); - - this.Context.DelayedFields = resolveResult.DelayedFields; - - this.Context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; - - // Backend. - // var bindResult = this.BackendBind(); - - if (bindResult != null) - { - // Postbind. - // - foreach (IBinderExtension extension in this.Context.Extensions) - { - extension.PostBind(bindResult); - } - - // Layout. - // - this.Layout(bindResult); - } - - return this.Context.Messaging.EncounteredError; + return bindResult; } - private ResolveResult Resolve() - { - var buildingPatch = this.Context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch); - - var filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); - - IEnumerable delayedFields; - { - var command = new ResolveFieldsCommand(); - command.Messaging = this.Context.Messaging; - command.BuildingPatch = buildingPatch; - command.BindVariableResolver = this.Context.WixVariableResolver; - command.BindPaths = this.Context.BindPaths; - command.Extensions = this.Context.Extensions; - command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; - command.IntermediateFolder = this.Context.IntermediateFolder; - command.Intermediate = this.Context.IntermediateRepresentation; - command.SupportDelayedResolution = true; - command.Execute(); - - delayedFields = command.DelayedFields; - } - -#if REVISIT_FOR_PATCHING - if (this.Context.IntermediateRepresentation.SubStorages != null) - { - foreach (SubStorage transform in this.Context.IntermediateRepresentation.SubStorages) - { - var command = new ResolveFieldsCommand(); - command.BuildingPatch = buildingPatch; - command.BindVariableResolver = this.Context.WixVariableResolver; - command.BindPaths = this.Context.BindPaths; - command.Extensions = this.Context.Extensions; - command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; - command.IntermediateFolder = this.Context.IntermediateFolder; - command.Intermediate = this.Context.IntermediateRepresentation; - command.SupportDelayedResolution = false; - command.Execute(); - } - } -#endif - - var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles(); - - return new ResolveResult - { - ExpectedEmbeddedFiles = expectedEmbeddedFiles, - DelayedFields = delayedFields, - }; - } +//// private ResolveResult Resolve() +//// { +//// var buildingPatch = this.Context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch); + +//// var filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); + +//// IEnumerable delayedFields; +//// { +//// var command = new ResolveFieldsCommand(); +//// command.Messaging = this.Context.Messaging; +//// command.BuildingPatch = buildingPatch; +//// command.BindVariableResolver = this.Context.WixVariableResolver; +//// command.BindPaths = this.Context.BindPaths; +//// command.Extensions = this.Context.Extensions; +//// command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; +//// command.IntermediateFolder = this.Context.IntermediateFolder; +//// command.Intermediate = this.Context.IntermediateRepresentation; +//// command.SupportDelayedResolution = true; +//// command.Execute(); + +//// delayedFields = command.DelayedFields; +//// } + +////#if REVISIT_FOR_PATCHING +//// if (this.Context.IntermediateRepresentation.SubStorages != null) +//// { +//// foreach (SubStorage transform in this.Context.IntermediateRepresentation.SubStorages) +//// { +//// var command = new ResolveFieldsCommand(); +//// command.BuildingPatch = buildingPatch; +//// command.BindVariableResolver = this.Context.WixVariableResolver; +//// command.BindPaths = this.Context.BindPaths; +//// command.Extensions = this.Context.Extensions; +//// command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; +//// command.IntermediateFolder = this.Context.IntermediateFolder; +//// command.Intermediate = this.Context.IntermediateRepresentation; +//// command.SupportDelayedResolution = false; +//// command.Execute(); +//// } +//// } +////#endif + +//// var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles(); + +//// return new ResolveResult +//// { +//// ExpectedEmbeddedFiles = expectedEmbeddedFiles, +//// DelayedFields = delayedFields, +//// }; +//// } private BindResult BackendBind() { - var backendFactories = this.Context.ExtensionManager.Create(); + var extensionManager = this.Context.ServiceProvider.GetService(); + + var backendFactories = extensionManager.Create(); var entrySection = this.Context.IntermediateRepresentation.Sections[0]; @@ -289,31 +228,6 @@ namespace WixToolset.Core return null; } - private void Layout(BindResult result) - { - try - { - this.LayoutMedia(result.FileTransfers); - } - finally - { - if (!String.IsNullOrEmpty(this.Context.ContentsFile) && result.ContentFilePaths != null) - { - this.CreateContentsFile(this.Context.ContentsFile, result.ContentFilePaths); - } - - if (!String.IsNullOrEmpty(this.Context.OutputsFile) && result.FileTransfers != null) - { - this.CreateOutputsFile(this.Context.OutputsFile, result.FileTransfers, this.Context.OutputPdbPath); - } - - if (!String.IsNullOrEmpty(this.Context.BuiltOutputsFile) && result.FileTransfers != null) - { - this.CreateBuiltOutputsFile(this.Context.BuiltOutputsFile, result.FileTransfers, this.Context.OutputPdbPath); - } - } - } - /// /// Binds an output. /// @@ -428,35 +342,6 @@ namespace WixToolset.Core } #endif - /// - /// Does any housekeeping after Bind. - /// - /// Whether or not any actual tidying should be done. - public void Cleanup(bool tidy) - { - if (tidy) - { - if (!this.DeleteTempFiles()) - { - this.Context.Messaging.Write(WarningMessages.FailedToDeleteTempDir(this.TempFilesLocation)); - } - } - else - { - this.Context.Messaging.Write(VerboseMessages.BinderTempDirLocatedAt(this.TempFilesLocation)); - } - } - - /// - /// Cleans up the temp files used by the Binder. - /// - /// True if all files were deleted, false otherwise. - private bool DeleteTempFiles() - { - bool deleted = Common.DeleteTempFiles(this.TempFilesLocation, this.Context.Messaging); - return deleted; - } - /// /// Populates the WixBuildInfo table in an output. /// @@ -585,231 +470,5 @@ namespace WixToolset.Core command.Execute(); } #endif - - /// - /// Final step in binding that transfers (moves/copies) all files generated into the appropriate - /// location in the source image - /// - /// List of files to transfer. - private void LayoutMedia(IEnumerable transfers) - { - if (null != transfers && transfers.Any()) - { - this.Context.Messaging.Write(VerboseMessages.LayingOutMedia()); - - var command = new TransferFilesCommand(this.Context.Messaging, this.Context.BindPaths, this.Context.Extensions, transfers, this.Context.SuppressAclReset); - command.Execute(); - } - } - - /// - /// Get the source path of a directory. - /// - /// All cached directories. - /// Hash table of Component GUID generation seeds indexed by directory id. - /// Directory identifier. - /// Canonicalize the path for standard directories. - /// Source path of a directory. - public static string GetDirectoryPath(Dictionary directories, Dictionary componentIdGenSeeds, string directory, bool canonicalize) - { - if (!directories.ContainsKey(directory)) - { - throw new WixException(ErrorMessages.ExpectedDirectory(directory)); - } - - ResolvedDirectory resolvedDirectory = (ResolvedDirectory)directories[directory]; - - if (null == resolvedDirectory.Path) - { - if (null != componentIdGenSeeds && componentIdGenSeeds.ContainsKey(directory)) - { - resolvedDirectory.Path = (string)componentIdGenSeeds[directory]; - } - else if (canonicalize && WindowsInstallerStandard.IsStandardDirectory(directory)) - { - // when canonicalization is on, standard directories are treated equally - resolvedDirectory.Path = directory; - } - else - { - string name = resolvedDirectory.Name; - - if (canonicalize && null != name) - { - name = name.ToLower(CultureInfo.InvariantCulture); - } - - if (String.IsNullOrEmpty(resolvedDirectory.DirectoryParent)) - { - resolvedDirectory.Path = name; - } - else - { - string parentPath = GetDirectoryPath(directories, componentIdGenSeeds, resolvedDirectory.DirectoryParent, canonicalize); - - if (null != resolvedDirectory.Name) - { - resolvedDirectory.Path = Path.Combine(parentPath, name); - } - else - { - resolvedDirectory.Path = parentPath; - } - } - } - } - - return resolvedDirectory.Path; - } - - /// - /// Gets the source path of a file. - /// - /// All cached directories in . - /// Parent directory identifier. - /// File name (in long|source format). - /// Specifies the package is compressed. - /// Specifies the package uses long file names. - /// Source path of file relative to package directory. - public static string GetFileSourcePath(Dictionary directories, string directoryId, string fileName, bool compressed, bool useLongName) - { - string fileSourcePath = Common.GetName(fileName, true, useLongName); - - if (compressed) - { - // Use just the file name of the file since all uncompressed files must appear - // in the root of the image in a compressed package. - } - else - { - // Get the relative path of where we want the file to be layed out as specified - // in the Directory table. - string directoryPath = Binder.GetDirectoryPath(directories, null, directoryId, false); - fileSourcePath = Path.Combine(directoryPath, fileSourcePath); - } - - // Strip off "SourceDir" if it's still on there. - if (fileSourcePath.StartsWith("SourceDir\\", StringComparison.Ordinal)) - { - fileSourcePath = fileSourcePath.Substring(10); - } - - return fileSourcePath; - } - - /// - /// Writes the paths to the content files included in the package to a text file. - /// - /// Path to write file. - /// Collection of paths to content files that will be written to file. - private void CreateContentsFile(string path, IEnumerable contentFilePaths) - { - string directory = Path.GetDirectoryName(path); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - using (StreamWriter contents = new StreamWriter(path, false)) - { - foreach (string contentPath in contentFilePaths) - { - contents.WriteLine(contentPath); - } - } - } - - /// - /// Writes the paths to the content files included in the bundle to a text file. - /// - /// Path to write file. - /// Collection of payloads whose source will be written to file. - private void CreateContentsFile(string path, IEnumerable payloads) - { - string directory = Path.GetDirectoryName(path); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - using (StreamWriter contents = new StreamWriter(path, false)) - { - foreach (var payload in payloads) - { - if (payload.ContentFile) - { - var fullPath = Path.GetFullPath(payload.SourceFile); - contents.WriteLine(fullPath); - } - } - } - } - - /// - /// Writes the paths to the output files to a text file. - /// - /// Path to write file. - /// Collection of files that were transferred to the output directory. - /// Optional path to created .wixpdb. - private void CreateOutputsFile(string path, IEnumerable fileTransfers, string pdbPath) - { - string directory = Path.GetDirectoryName(path); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - using (StreamWriter outputs = new StreamWriter(path, false)) - { - foreach (FileTransfer fileTransfer in fileTransfers) - { - // Don't list files where the source is the same as the destination since - // that might be the only place the file exists. The outputs file is often - // used to delete stuff and losing the original source would be bad. - if (!fileTransfer.Redundant) - { - outputs.WriteLine(fileTransfer.Destination); - } - } - - if (!String.IsNullOrEmpty(pdbPath)) - { - outputs.WriteLine(Path.GetFullPath(pdbPath)); - } - } - } - - /// - /// Writes the paths to the built output files to a text file. - /// - /// Path to write file. - /// Collection of files that were transferred to the output directory. - /// Optional path to created .wixpdb. - private void CreateBuiltOutputsFile(string path, IEnumerable fileTransfers, string pdbPath) - { - string directory = Path.GetDirectoryName(path); - if (!Directory.Exists(directory)) - { - Directory.CreateDirectory(directory); - } - - using (StreamWriter outputs = new StreamWriter(path, false)) - { - foreach (FileTransfer fileTransfer in fileTransfers) - { - // Only write the built file transfers. Also, skip redundant - // files for the same reason spelled out in this.CreateOutputsFile(). - if (fileTransfer.Built && !fileTransfer.Redundant) - { - outputs.WriteLine(fileTransfer.Destination); - } - } - - if (!String.IsNullOrEmpty(pdbPath)) - { - outputs.WriteLine(Path.GetFullPath(pdbPath)); - } - } - } } } diff --git a/src/WixToolset.Core/BinderFileManager.cs b/src/WixToolset.Core/BinderFileManager.cs index 1527d93d..5e08bc40 100644 --- a/src/WixToolset.Core/BinderFileManager.cs +++ b/src/WixToolset.Core/BinderFileManager.cs @@ -12,7 +12,7 @@ namespace WixToolset using WixToolset.Data.Rows; using WixToolset.Extensibility; -#if false +#if DEAD_CODE /// /// Base class for creating a binder file manager. /// diff --git a/src/WixToolset.Core/BinderFileManagerCore.cs b/src/WixToolset.Core/BinderFileManagerCore.cs index e699f0ce..aa9a45de 100644 --- a/src/WixToolset.Core/BinderFileManagerCore.cs +++ b/src/WixToolset.Core/BinderFileManagerCore.cs @@ -9,6 +9,7 @@ namespace WixToolset using WixToolset.Data.Bind; using WixToolset.Extensibility; +#if DEAD_CODE public class BinderFileManagerCore : IBinderFileManagerCore { private Dictionary>[] bindPaths; @@ -97,4 +98,5 @@ namespace WixToolset return Enumerable.Empty(); } } +#endif } diff --git a/src/WixToolset.Core/CommandLine/BuildCommand.cs b/src/WixToolset.Core/CommandLine/BuildCommand.cs index 43b75f33..92aa3343 100644 --- a/src/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/WixToolset.Core/CommandLine/BuildCommand.cs @@ -7,7 +7,7 @@ namespace WixToolset.Core using System.IO; using System.Linq; using WixToolset.Data; - using WixToolset.Data.Tuples; + using WixToolset.Data.Bind; using WixToolset.Extensibility; using WixToolset.Extensibility.Services; @@ -90,6 +90,12 @@ namespace WixToolset.Core 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); @@ -147,22 +153,20 @@ namespace WixToolset.Core { var localizations = this.LoadLocalizationFiles().ToList(); - // If there was an error adding localization files, then bail. + // If there was an error loading localization files, then bail. if (this.Messaging.EncounteredError) { return null; } - var resolver = CreateWixResolverWithVariables(null, null); - var context = new LibraryContext(); + context.Messaging = this.Messaging; context.BindFiles = this.BindFiles; context.BindPaths = this.BindPaths; context.Extensions = this.ExtensionManager.Create(); context.Localizations = localizations; context.LibraryId = Guid.NewGuid().ToString("N"); context.Intermediates = intermediates; - context.WixVariableResolver = resolver; var librarian = new Librarian(); return librarian.Combine(context); @@ -174,6 +178,11 @@ namespace WixToolset.Core var libraries = this.LoadLibraries(creator); + if (this.Messaging.EncounteredError) + { + return null; + } + var context = this.ServiceProvider.GetService(); context.Messaging = this.Messaging; context.Extensions = this.ExtensionManager.Create(); @@ -183,48 +192,72 @@ namespace WixToolset.Core context.TupleDefinitionCreator = creator; var linker = new Linker(); - var output = linker.Link(context); - return output; + return linker.Link(context); } private void BindPhase(Intermediate output) { var localizations = this.LoadLocalizationFiles().ToList(); - var localizer = new Localizer(this.Messaging, localizations); + // If there was an error loading localization files, then bail. + if (this.Messaging.EncounteredError) + { + return; + } - var resolver = CreateWixResolverWithVariables(localizer, output); + ResolveResult resolveResult; + { + var resolver = new Resolver(this.ServiceProvider, this.BindPaths, output, this.IntermediateFolder, localizations); + resolveResult = resolver.Execute(); + } - var intermediateFolder = this.IntermediateFolder; - if (String.IsNullOrEmpty(intermediateFolder)) + if (this.Messaging.EncounteredError) { - intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + return; } - var context = this.ServiceProvider.GetService(); - context.Messaging = this.Messaging; - context.ExtensionManager = this.ExtensionManager; - context.BindPaths = this.BindPaths ?? Array.Empty(); - //context.CabbingThreadCount = this.CabbingThreadCount; - context.CabCachePath = this.CabCachePath; - context.Codepage = localizer.Codepage; - //context.DefaultCompressionLevel = this.DefaultCompressionLevel; - //context.Ices = this.Ices; - context.IntermediateFolder = intermediateFolder; - context.IntermediateRepresentation = output; - context.OutputPath = this.OutputPath; - context.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb"); - //context.SuppressIces = this.SuppressIces; - context.SuppressValidation = true; - //context.SuppressValidation = this.SuppressValidation; - context.WixVariableResolver = resolver; - context.ContentsFile = this.ContentsFile; - context.OutputsFile = this.OutputsFile; - context.BuiltOutputsFile = this.BuiltOutputsFile; - context.WixprojectFile = this.WixProjectFile; - - var binder = new Binder(); - binder.Bind(context); + BindResult bindResult; + { + var intermediateFolder = this.IntermediateFolder; + if (String.IsNullOrEmpty(intermediateFolder)) + { + intermediateFolder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + } + + var context = this.ServiceProvider.GetService(); + context.Messaging = this.Messaging; + //context.CabbingThreadCount = this.CabbingThreadCount; + context.CabCachePath = this.CabCachePath; + context.Codepage = resolveResult.Codepage; + //context.DefaultCompressionLevel = this.DefaultCompressionLevel; + context.DelayedFields = resolveResult.DelayedFields; + context.ExpectedEmbeddedFiles = resolveResult.ExpectedEmbeddedFiles; + //context.Ices = this.Ices; + context.IntermediateFolder = intermediateFolder; + context.IntermediateRepresentation = resolveResult.IntermediateRepresentation; + context.OutputPath = this.OutputPath; + context.OutputPdbPath = Path.ChangeExtension(this.OutputPath, ".wixpdb"); + //context.SuppressIces = this.SuppressIces; + context.SuppressValidation = true; // TODO: set this correctly + context.ContentsFile = this.ContentsFile; + context.OutputsFile = this.OutputsFile; + context.BuiltOutputsFile = this.BuiltOutputsFile; + context.WixprojectFile = this.WixProjectFile; + + var binder = new Binder(); + bindResult = binder.Bind(context); + } + + if (this.Messaging.EncounteredError) + { + return; + } + + { + // TODO: correctly set SuppressAclReset bool at the end. + var layout = new Layout(this.ServiceProvider, bindResult.FileTransfers, bindResult.ContentFilePaths, this.ContentsFile, this.OutputsFile, this.BuiltOutputsFile, false); + layout.Execute(); + } } private IEnumerable LoadLibraries(ITupleDefinitionCreator creator) @@ -264,22 +297,5 @@ namespace WixToolset.Core yield return localization; } } - - private WixVariableResolver CreateWixResolverWithVariables(Localizer localizer, Intermediate output) - { - var resolver = new WixVariableResolver(this.Messaging, localizer); - - // Gather all the wix variables. - var wixVariables = output?.Sections.SelectMany(s => s.Tuples).OfType(); - if (wixVariables != null) - { - foreach (var wixVariableRow in wixVariables) - { - resolver.AddVariable(wixVariableRow); - } - } - - return resolver; - } } } diff --git a/src/WixToolset.Core/CommandLine/CommandLine.cs b/src/WixToolset.Core/CommandLine/CommandLine.cs index 9db1b2f9..97f79755 100644 --- a/src/WixToolset.Core/CommandLine/CommandLine.cs +++ b/src/WixToolset.Core/CommandLine/CommandLine.cs @@ -260,6 +260,10 @@ namespace WixToolset.Core case "transform": case ".mst": return OutputType.Transform; + + case "wixout": + case ".wixout": + return OutputType.Wixout; } return OutputType.Unknown; diff --git a/src/WixToolset.Core/Compiler.cs b/src/WixToolset.Core/Compiler.cs index 74ca86ac..2dd7da4d 100644 --- a/src/WixToolset.Core/Compiler.cs +++ b/src/WixToolset.Core/Compiler.cs @@ -154,24 +154,40 @@ namespace WixToolset.Core } // Resolve any Component Id placeholders compiled into the intermediate. - if (0 < this.componentIdPlaceholdersResolver.VariableCount) + this.ResolveComponentIdPlaceholders(target); + } + finally + { + foreach (var extension in context.Extensions) { - foreach (var section in target.Sections) + extension.PostCompile(target); + } + + this.Core = null; + } + + return this.Context.Messaging.EncounteredError ? null : target; + } + + private void ResolveComponentIdPlaceholders(Intermediate target) + { + if (0 < this.componentIdPlaceholdersResolver.VariableCount) + { + foreach (var section in target.Sections) + { + foreach (var tuple in section.Tuples) { - foreach (var tuple in section.Tuples) + foreach (var field in tuple.Fields) { - foreach (var field in tuple.Fields) + if (field?.Type == IntermediateFieldType.String) { - if (field != null && field.Type == IntermediateFieldType.String) + var data = field.AsString(); + if (!String.IsNullOrEmpty(data)) { - var data = field.AsString(); - if (!String.IsNullOrEmpty(data)) + var resolved = this.componentIdPlaceholdersResolver.ResolveVariables(tuple.SourceLineNumbers, data, false, false); + if (resolved.UpdatedValue) { - var resolved = this.componentIdPlaceholdersResolver.ResolveVariables(tuple.SourceLineNumbers, data, false, false, out var defaultIgnored, out var delayedIgnored); - if (data != resolved) - { - field.Set(resolved); - } + field.Set(resolved.Value); } } } @@ -179,17 +195,6 @@ namespace WixToolset.Core } } } - finally - { - foreach (var extension in context.Extensions) - { - extension.PostCompile(target); - } - - this.Core = null; - } - - return this.Context.Messaging.EncounteredError ? null : target; } /// @@ -2422,7 +2427,7 @@ namespace WixToolset.Core { if (isGeneratableGuidOk || keyFound && !String.IsNullOrEmpty(keyPath)) { - this.componentIdPlaceholdersResolver.AddVariable(componentIdPlaceholder, keyPath); + this.componentIdPlaceholdersResolver.AddVariable(componentIdPlaceholder, keyPath, false); id = new Identifier(keyPath, AccessModifier.Private); } diff --git a/src/WixToolset.Core/Layout.cs b/src/WixToolset.Core/Layout.cs new file mode 100644 index 00000000..d7322a12 --- /dev/null +++ b/src/WixToolset.Core/Layout.cs @@ -0,0 +1,188 @@ +// 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 +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using WixToolset.Core.Bind; + using WixToolset.Data; + using WixToolset.Data.Bind; + using WixToolset.Data.Tuples; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + + /// + /// Layout for the WiX toolset. + /// + public sealed class Layout + { + public Layout(IServiceProvider serviceProvider, IEnumerable fileTransfers, IEnumerable contentFilePaths, string contentsFile, string outputsFile, string builtOutputsFile, bool suppressAclReset) + { + this.ServiceProvider = serviceProvider; + this.FileTransfers = fileTransfers; + this.ContentFilePaths = contentFilePaths; + this.ContentsFile = contentsFile; + this.OutputsFile = outputsFile; + this.BuiltOutputsFile = builtOutputsFile; + this.SuppressAclReset = suppressAclReset; + this.Messaging = this.ServiceProvider.GetService(); + } + + private IServiceProvider ServiceProvider { get; } + + private IEnumerable FileTransfers { get; } + + private IEnumerable ContentFilePaths { get; } + + private string ContentsFile { get; } + + private string OutputsFile { get; } + + private string BuiltOutputsFile { get; } + + private bool SuppressAclReset { get; } + + private IMessaging Messaging { get; } + + public void Execute() + { + var extensionManager = this.ServiceProvider.GetService(); + + var context = this.ServiceProvider.GetService(); + context.Messaging = this.Messaging; + context.Extensions = extensionManager.Create(); + context.FileSystemExtensions = extensionManager.Create(); + context.FileTransfers = this.FileTransfers; + context.ContentFilePaths = this.ContentFilePaths; + context.ContentsFile = this.ContentsFile; + context.OutputPdbPath = this.OutputsFile; + context.BuiltOutputsFile = this.BuiltOutputsFile; + context.SuppressAclReset = this.SuppressAclReset; + + // Pre-layout. + // + foreach (var extension in context.Extensions) + { + extension.PreLayout(context); + } + + try + { + // Final step in binding that transfers (moves/copies) all files generated into the appropriate + // location in the source image. + if (context.FileTransfers?.Any() == true) + { + this.Messaging.Write(VerboseMessages.LayingOutMedia()); + + var command = new TransferFilesCommand(context.Messaging, context.FileSystemExtensions, context.FileTransfers, context.SuppressAclReset); + command.Execute(); + } + } + finally + { + if (!String.IsNullOrEmpty(context.ContentsFile) && context.ContentFilePaths != null) + { + this.CreateContentsFile(context.ContentsFile, context.ContentFilePaths); + } + + if (!String.IsNullOrEmpty(context.OutputsFile) && context.FileTransfers != null) + { + this.CreateOutputsFile(context.OutputsFile, context.FileTransfers, context.OutputPdbPath); + } + + if (!String.IsNullOrEmpty(context.BuiltOutputsFile) && context.FileTransfers != null) + { + this.CreateBuiltOutputsFile(context.BuiltOutputsFile, context.FileTransfers, context.OutputPdbPath); + } + } + + // Post-layout. + foreach (var extension in context.Extensions) + { + extension.PostLayout(); + } + } + + /// + /// Writes the paths to the content files to a text file. + /// + /// Path to write file. + /// Collection of paths to content files that will be written to file. + private void CreateContentsFile(string path, IEnumerable contentFilePaths) + { + var directory = Path.GetDirectoryName(path); + Directory.CreateDirectory(directory); + + using (var contents = new StreamWriter(path, false)) + { + foreach (string contentPath in contentFilePaths) + { + contents.WriteLine(contentPath); + } + } + } + + /// + /// Writes the paths to the output files to a text file. + /// + /// Path to write file. + /// Collection of files that were transferred to the output directory. + /// Optional path to created .wixpdb. + private void CreateOutputsFile(string path, IEnumerable fileTransfers, string pdbPath) + { + var directory = Path.GetDirectoryName(path); + Directory.CreateDirectory(directory); + + using (var outputs = new StreamWriter(path, false)) + { + foreach (FileTransfer fileTransfer in fileTransfers) + { + // Don't list files where the source is the same as the destination since + // that might be the only place the file exists. The outputs file is often + // used to delete stuff and losing the original source would be bad. + if (!fileTransfer.Redundant) + { + outputs.WriteLine(fileTransfer.Destination); + } + } + + if (!String.IsNullOrEmpty(pdbPath)) + { + outputs.WriteLine(Path.GetFullPath(pdbPath)); + } + } + } + + /// + /// Writes the paths to the built output files to a text file. + /// + /// Path to write file. + /// Collection of files that were transferred to the output directory. + /// Optional path to created .wixpdb. + private void CreateBuiltOutputsFile(string path, IEnumerable fileTransfers, string pdbPath) + { + var directory = Path.GetDirectoryName(path); + Directory.CreateDirectory(directory); + + using (var outputs = new StreamWriter(path, false)) + { + foreach (FileTransfer fileTransfer in fileTransfers) + { + // Only write the built file transfers. Also, skip redundant + // files for the same reason spelled out in this.CreateOutputsFile(). + if (fileTransfer.Built && !fileTransfer.Redundant) + { + outputs.WriteLine(fileTransfer.Destination); + } + } + + if (!String.IsNullOrEmpty(pdbPath)) + { + outputs.WriteLine(Path.GetFullPath(pdbPath)); + } + } + } + } +} diff --git a/src/WixToolset.Core/LayoutContext.cs b/src/WixToolset.Core/LayoutContext.cs new file mode 100644 index 00000000..24f171a9 --- /dev/null +++ b/src/WixToolset.Core/LayoutContext.cs @@ -0,0 +1,40 @@ +// 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 +{ + using System; + using System.Collections.Generic; + using WixToolset.Data.Bind; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + + public class LayoutContext : ILayoutContext + { + internal LayoutContext(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + public IServiceProvider ServiceProvider { get; } + + public IMessaging Messaging { get; set; } + + public IEnumerable Extensions { get; set; } + + public IEnumerable FileSystemExtensions { get; set; } + + public IEnumerable FileTransfers { get; set; } + + public IEnumerable ContentFilePaths { get; set; } + + public string OutputPdbPath { get; set; } + + public string ContentsFile { get; set; } + + public string OutputsFile { get; set; } + + public string BuiltOutputsFile { get; set; } + + public bool SuppressAclReset { get; set; } + } +} diff --git a/src/WixToolset.Core/Librarian.cs b/src/WixToolset.Core/Librarian.cs index a64d77dd..2efb0f9b 100644 --- a/src/WixToolset.Core/Librarian.cs +++ b/src/WixToolset.Core/Librarian.cs @@ -38,11 +38,14 @@ namespace WixToolset.Core var sections = this.Context.Intermediates.SelectMany(i => i.Sections).ToList(); - var fileResolver = new FileResolver(this.Context.BindPaths, this.Context.Extensions); + var embedFilePaths = this.ResolveFilePathsToEmbed(sections); - var embedFilePaths = ResolveFilePathsToEmbed(sections, fileResolver); + var localizationsByCulture = this.CollateLocalizations(this.Context.Localizations); - var localizationsByCulture = CollateLocalizations(this.Context.Localizations); + if (this.Context.Messaging.EncounteredError) + { + return null; + } foreach (var section in sections) { @@ -83,7 +86,7 @@ namespace WixToolset.Core return (this.Context.Messaging.EncounteredError ? null : library); } - private static Dictionary CollateLocalizations(IEnumerable localizations) + private Dictionary CollateLocalizations(IEnumerable localizations) { var localizationsByCulture = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -91,7 +94,14 @@ namespace WixToolset.Core { if (localizationsByCulture.TryGetValue(localization.Culture, out var existingCulture)) { - existingCulture.Merge(localization); + try + { + existingCulture.Merge(localization); + } + catch (WixException e) + { + this.Context.Messaging.Write(e.Error); + } } else { @@ -102,13 +112,17 @@ namespace WixToolset.Core return localizationsByCulture; } - private List ResolveFilePathsToEmbed(IEnumerable sections, FileResolver fileResolver) + private List ResolveFilePathsToEmbed(IEnumerable sections) { var embedFilePaths = new List(); // Resolve paths to files that are to be embedded in the library. if (this.Context.BindFiles) { + var variableResolver = new WixVariableResolver(this.Context.Messaging); + + var fileResolver = new FileResolver(this.Context.BindPaths, this.Context.Extensions); + foreach (var tuple in sections.SelectMany(s => s.Tuples)) { foreach (var field in tuple.Fields.Where(f => f.Type == IntermediateFieldType.Path)) @@ -117,9 +131,9 @@ namespace WixToolset.Core if (pathField != null) { - var resolvedPath = this.Context.WixVariableResolver.ResolveVariables(tuple.SourceLineNumbers, pathField.Path, false); + var resolution = variableResolver.ResolveVariables(tuple.SourceLineNumbers, pathField.Path, false); - var file = fileResolver.Resolve(tuple.SourceLineNumbers, tuple.Definition.Name, resolvedPath); + var file = fileResolver.Resolve(tuple.SourceLineNumbers, tuple.Definition, resolution.Value); if (!String.IsNullOrEmpty(file)) { diff --git a/src/WixToolset.Core/LibraryContext.cs b/src/WixToolset.Core/LibraryContext.cs index c6278482..c1aec5ce 100644 --- a/src/WixToolset.Core/LibraryContext.cs +++ b/src/WixToolset.Core/LibraryContext.cs @@ -25,7 +25,5 @@ namespace WixToolset.Core public IEnumerable Localizations { get; set; } public IEnumerable Intermediates { get; set; } - - public IBindVariableResolver WixVariableResolver { get; set; } } } diff --git a/src/WixToolset.Core/Linker.cs b/src/WixToolset.Core/Linker.cs index d980d79f..93f50efa 100644 --- a/src/WixToolset.Core/Linker.cs +++ b/src/WixToolset.Core/Linker.cs @@ -8,11 +8,11 @@ namespace WixToolset.Core using System.Diagnostics; using System.Globalization; using System.Linq; - using WixToolset.Data; - using WixToolset.Link; using WixToolset.Core.Link; + using WixToolset.Data; using WixToolset.Data.Tuples; - using WixToolset.Extensibility.Services; + using WixToolset.Extensibility; + using WixToolset.Link; /// /// Linker core of the WiX toolset. diff --git a/src/WixToolset.Core/PreprocessContext.cs b/src/WixToolset.Core/PreprocessContext.cs index cb29d1ff..a6085b81 100644 --- a/src/WixToolset.Core/PreprocessContext.cs +++ b/src/WixToolset.Core/PreprocessContext.cs @@ -8,9 +8,6 @@ namespace WixToolset.Core using WixToolset.Extensibility; using WixToolset.Extensibility.Services; - /// - /// The preprocessor core. - /// internal class PreprocessContext : IPreprocessContext { internal PreprocessContext(IServiceProvider serviceProvider) diff --git a/src/WixToolset.Core/ResolveContext.cs b/src/WixToolset.Core/ResolveContext.cs new file mode 100644 index 00000000..6d7b9df1 --- /dev/null +++ b/src/WixToolset.Core/ResolveContext.cs @@ -0,0 +1,32 @@ +// 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 +{ + using System; + using System.Collections.Generic; + using WixToolset.Data; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + + public class ResolveContext : IResolveContext + { + internal ResolveContext(IServiceProvider serviceProvider) + { + this.ServiceProvider = serviceProvider; + } + + public IServiceProvider ServiceProvider { get; } + + public IMessaging Messaging { get; set; } + + public IEnumerable BindPaths { get; set; } + + public IEnumerable Extensions { get; set; } + + public string IntermediateFolder { get; set; } + + public Intermediate IntermediateRepresentation { get; set; } + + public IBindVariableResolver WixVariableResolver { get; set; } + } +} diff --git a/src/WixToolset.Core/Resolver.cs b/src/WixToolset.Core/Resolver.cs new file mode 100644 index 00000000..b0d3a189 --- /dev/null +++ b/src/WixToolset.Core/Resolver.cs @@ -0,0 +1,234 @@ +// 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 +{ + using System; + using System.Collections.Generic; + using System.Linq; + using WixToolset.Core.Bind; + using WixToolset.Data; + using WixToolset.Data.Tuples; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Services; + + /// + /// Resolver for the WiX toolset. + /// + public sealed class Resolver + { + public Resolver(IServiceProvider serviceProvider, IEnumerable bindPaths, Intermediate intermediateRepresentation, string intermediateFolder, IEnumerable localizations) + { + this.ServiceProvider = serviceProvider; + this.BindPaths = bindPaths; + this.IntermediateRepresentation = intermediateRepresentation; + this.IntermediateFolder = intermediateFolder; + this.Localizations = localizations; + + this.Messaging = this.ServiceProvider.GetService(); + } + + private IServiceProvider ServiceProvider { get; } + + private IEnumerable BindPaths { get; } + + private Intermediate IntermediateRepresentation { get; } + + private string IntermediateFolder { get; } + + private IEnumerable Localizations { get; } + + private IMessaging Messaging { get; } + + public ResolveResult Execute() + { + var localizer = new Localizer(this.Messaging, this.Localizations); + + var variableResolver = new WixVariableResolver(this.Messaging, localizer); + + var context = this.ServiceProvider.GetService(); + context.Messaging = this.Messaging; + context.BindPaths = this.BindPaths; + context.Extensions = this.ServiceProvider.GetService().Create(); + context.IntermediateFolder = this.IntermediateFolder; + context.IntermediateRepresentation = this.IntermediateRepresentation; + context.WixVariableResolver = this.PopulateVariableResolver(variableResolver); + + // Preresolve. + // + foreach (IResolverExtension extension in context.Extensions) + { + extension.PreResolve(context); + } + + // Resolve. + // + this.LocalizeUI(context); + + var resolveResult = this.Resolve(localizer.Codepage, context); + + if (resolveResult != null) + { + // Postresolve. + // + foreach (IResolverExtension extension in context.Extensions) + { + extension.PostResolve(resolveResult); + } + } + + return resolveResult; + } + + private ResolveResult Resolve(int codepage, IResolveContext context) + { + var buildingPatch = context.IntermediateRepresentation.Sections.Any(s => s.Type == SectionType.Patch); + + var filesWithEmbeddedFiles = new ExtractEmbeddedFiles(); + + IEnumerable delayedFields; + { + var command = new ResolveFieldsCommand(); + command.Messaging = context.Messaging; + command.BuildingPatch = buildingPatch; + command.BindVariableResolver = context.WixVariableResolver; + command.BindPaths = context.BindPaths; + command.Extensions = context.Extensions; + command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; + command.IntermediateFolder = context.IntermediateFolder; + command.Intermediate = context.IntermediateRepresentation; + command.SupportDelayedResolution = true; + command.Execute(); + + delayedFields = command.DelayedFields; + } + +#if REVISIT_FOR_PATCHING + if (context.IntermediateRepresentation.SubStorages != null) + { + foreach (SubStorage transform in context.IntermediateRepresentation.SubStorages) + { + var command = new ResolveFieldsCommand(); + command.BuildingPatch = buildingPatch; + command.BindVariableResolver = context.WixVariableResolver; + command.BindPaths = context.BindPaths; + command.Extensions = context.Extensions; + command.FilesWithEmbeddedFiles = filesWithEmbeddedFiles; + command.IntermediateFolder = context.IntermediateFolder; + command.Intermediate = context.IntermediateRepresentation; + command.SupportDelayedResolution = false; + command.Execute(); + } + } +#endif + + var expectedEmbeddedFiles = filesWithEmbeddedFiles.GetExpectedEmbeddedFiles(); + + return new ResolveResult + { + Codepage = codepage, + ExpectedEmbeddedFiles = expectedEmbeddedFiles, + DelayedFields = delayedFields, + IntermediateRepresentation = context.IntermediateRepresentation + }; + } + + /// + /// Localize dialogs and controls. + /// + private void LocalizeUI(IResolveContext context) + { + foreach (var section in context.IntermediateRepresentation.Sections) + { + foreach (var row in section.Tuples.OfType()) + { + string dialog = row.Dialog; + + if (context.WixVariableResolver.TryGetLocalizedControl(dialog, null, out LocalizedControl localizedControl)) + { + if (CompilerConstants.IntegerNotSet != localizedControl.X) + { + row.HCentering = localizedControl.X; + } + + if (CompilerConstants.IntegerNotSet != localizedControl.Y) + { + row.VCentering = localizedControl.Y; + } + + if (CompilerConstants.IntegerNotSet != localizedControl.Width) + { + row.Width = localizedControl.Width; + } + + if (CompilerConstants.IntegerNotSet != localizedControl.Height) + { + row.Height = localizedControl.Height; + } + + row.Attributes = row.Attributes | localizedControl.Attributes; + + if (!String.IsNullOrEmpty(localizedControl.Text)) + { + row.Title = localizedControl.Text; + } + } + } + + foreach (var row in section.Tuples.OfType()) + { + string dialog = row.Dialog_; + string control = row.Control; + + if (context.WixVariableResolver.TryGetLocalizedControl(dialog, control, out LocalizedControl localizedControl)) + { + if (CompilerConstants.IntegerNotSet != localizedControl.X) + { + row.X = localizedControl.X; + } + + if (CompilerConstants.IntegerNotSet != localizedControl.Y) + { + row.Y = localizedControl.Y; + } + + if (CompilerConstants.IntegerNotSet != localizedControl.Width) + { + row.Width = localizedControl.Width; + } + + if (CompilerConstants.IntegerNotSet != localizedControl.Height) + { + row.Height = localizedControl.Height; + } + + row.Attributes = row.Attributes | localizedControl.Attributes; + + if (!String.IsNullOrEmpty(localizedControl.Text)) + { + row.Text = localizedControl.Text; + } + } + } + } + } + + private WixVariableResolver PopulateVariableResolver(WixVariableResolver resolver) + { + // Gather all the wix variables. + var wixVariableTuples = this.IntermediateRepresentation.Sections.SelectMany(s => s.Tuples).OfType(); + foreach (var tuple in wixVariableTuples) + { + try + { + resolver.AddVariable(tuple.WixVariable, tuple.Value, tuple.Overridable); + } + catch (ArgumentException) + { + this.Messaging.Write(ErrorMessages.WixVariableCollision(tuple.SourceLineNumbers, tuple.WixVariable)); + } + } + + return resolver; + } + } +} diff --git a/src/WixToolset.Core/WixToolsetServiceProvider.cs b/src/WixToolset.Core/WixToolsetServiceProvider.cs index 995daa89..74b312c6 100644 --- a/src/WixToolset.Core/WixToolsetServiceProvider.cs +++ b/src/WixToolset.Core/WixToolsetServiceProvider.cs @@ -42,6 +42,16 @@ namespace WixToolset.Core return new BindContext(this); } + if (serviceType == typeof(ILayoutContext)) + { + return new LayoutContext(this); + } + + if (serviceType == typeof(IResolveContext)) + { + return new ResolveContext(this); + } + if (serviceType == typeof(IInscribeContext)) { return new InscribeContext(this); diff --git a/src/WixToolset.Core/WixVariableResolver.cs b/src/WixToolset.Core/WixVariableResolver.cs index f8bccef0..7339840e 100644 --- a/src/WixToolset.Core/WixVariableResolver.cs +++ b/src/WixToolset.Core/WixVariableResolver.cs @@ -9,8 +9,6 @@ namespace WixToolset.Core using System.Text; using System.Text.RegularExpressions; using WixToolset.Data; - using WixToolset.Data.Tuples; - using WixToolset.Extensibility; using WixToolset.Extensibility.Services; /// @@ -37,14 +35,15 @@ namespace WixToolset.Core /// /// Gets the count of variables added to the resolver. /// - public int VariableCount => this.wixVariables.Count; + public int VariableCount => this.wixVariables.Count; /// /// Add a variable. /// /// The name of the variable. /// The value of the variable. - public void AddVariable(string name, string value) + /// Indicates whether the variable can be overridden by an existing variable. + public void AddVariable(string name, string value, bool overridable) { try { @@ -52,25 +51,9 @@ namespace WixToolset.Core } catch (ArgumentException) { - this.Messaging.Write(ErrorMessages.WixVariableCollision(null, name)); - } - } - - /// - /// Add a variable. - /// - /// The WixVariableRow to add. - public void AddVariable(WixVariableTuple wixVariableRow) - { - try - { - this.wixVariables.Add(wixVariableRow.WixVariable, wixVariableRow.Value); - } - catch (ArgumentException) - { - if (!wixVariableRow.Overridable) // collision + if (!overridable) { - this.Messaging.Write(ErrorMessages.WixVariableCollision(wixVariableRow.SourceLineNumbers, wixVariableRow.WixVariable)); + throw; } } } @@ -82,37 +65,9 @@ namespace WixToolset.Core /// The value to resolve. /// true to only resolve localization variables; false otherwise. /// The resolved value. - public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly) + public BindVariableResolution ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly) { - return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, out var defaultIgnored, out var delayedIgnored); - } - - /// - /// Resolve the wix variables in a value. - /// - /// The source line information for the value. - /// The value to resolve. - /// true to only resolve localization variables; false otherwise. - /// true if the resolved value was the default. - /// The resolved value. - public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, out bool isDefault) - { - return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, out isDefault, out var ignored); - } - - /// - /// Resolve the wix variables in a value. - /// - /// The source line information for the value. - /// The value to resolve. - /// true to only resolve localization variables; false otherwise. - /// true if unknown variables should throw errors. - /// true if the resolved value was the default. - /// true if the value has variables that cannot yet be resolved. - /// The resolved value. - public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, out bool isDefault, out bool delayedResolve) - { - return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, true, out isDefault, out delayedResolve); + return this.ResolveVariables(sourceLineNumbers, value, localizationOnly, true); } /// @@ -125,13 +80,12 @@ namespace WixToolset.Core /// true if the resolved value was the default. /// true if the value has variables that cannot yet be resolved. /// The resolved value. - public string ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, bool errorOnUnknown, out bool isDefault, out bool delayedResolve) + internal BindVariableResolution ResolveVariables(SourceLineNumber sourceLineNumbers, string value, bool localizationOnly, bool errorOnUnknown) { MatchCollection matches = Common.WixVariableRegex.Matches(value); // the value is the default unless its substituted further down - isDefault = true; - delayedResolve = false; + var result = new BindVariableResolution { IsDefault = true, Value = value }; if (0 < matches.Count) { @@ -172,6 +126,8 @@ namespace WixToolset.Core if (!localizationOnly) { sb.Remove(matches[i].Index - 1, 1); + + result.UpdatedValue = true; } } else @@ -200,7 +156,7 @@ namespace WixToolset.Core if (this.wixVariables.TryGetValue(variableId, out resolvedValue)) { resolvedValue = resolvedValue ?? String.Empty; - isDefault = false; + result.IsDefault = false; } else if (null != variableDefaultValue) // default the resolved value to the inline value if one was specified { @@ -212,16 +168,17 @@ namespace WixToolset.Core if ("bind" == variableNamespace) { // can't resolve these yet, but keep track of where we find them so they can be resolved later with less effort - delayedResolve = true; + result.DelayedResolve = true; } else { - // insert the resolved value if it was found or display an error if (null != resolvedValue) { sb.Remove(matches[i].Index, matches[i].Length); sb.Insert(matches[i].Index, resolvedValue); + + result.UpdatedValue = true; } else if ("loc" == variableNamespace && errorOnUnknown) // unresolved loc variable { @@ -235,10 +192,10 @@ namespace WixToolset.Core } } - value = sb.ToString(); + result.Value = sb.ToString(); } - return value; + return result; } /// -- cgit v1.2.3-55-g6feb