From bc101e0424d627ca79f79b30e9fccf61db722466 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Wed, 23 Feb 2022 15:15:10 -0800 Subject: Fix wixlib, msm, msi incremental build Simplify and improves the tracking of input and intermediate files to fix incremental build issues for wixlibs, merge modules and MSI databases. --- .../BaseLibrarianExtension.cs | 4 +- .../Data/ILibraryResult.cs | 25 +++++ .../ILibrarianExtension.cs | 21 +++- .../WixprojModuleCsprojWinFormsNetFx.wixproj | 10 +- .../Package.ja-jp.wxl | 2 +- .../WixprojPackageVcxprojWindowsApp/Package.wxs | 6 +- .../WixprojPackageVcxprojWindowsApp.wixproj | 2 + src/test/wix/WixE2E/WixE2EFixture.cs | 109 +++++++++++++++++++++ .../Bind/BindDatabaseCommand.cs | 34 ++++++- .../Bind/ExtractMergeModuleFilesCommand.cs | 22 +++-- .../Bind/MergeModulesCommand.cs | 13 ++- .../Bind/ProcessPackageSoftwareTagsCommand.cs | 15 ++- .../Bind/ExtractEmbeddedFilesCommand.cs | 3 +- .../WixToolset.Core/CommandLine/BuildCommand.cs | 50 +++++----- src/wix/WixToolset.Core/ILibrarian.cs | 11 ++- src/wix/WixToolset.Core/Librarian.cs | 26 +++-- src/wix/WixToolset.Core/LibraryResult.cs | 19 ++++ .../WixToolset.Core/WixToolsetServiceProvider.cs | 1 + 18 files changed, 311 insertions(+), 62 deletions(-) create mode 100644 src/api/wix/WixToolset.Extensibility/Data/ILibraryResult.cs create mode 100644 src/wix/WixToolset.Core/LibraryResult.cs diff --git a/src/api/wix/WixToolset.Extensibility/BaseLibrarianExtension.cs b/src/api/wix/WixToolset.Extensibility/BaseLibrarianExtension.cs index cbc9e4ba..ff5edae3 100644 --- a/src/api/wix/WixToolset.Extensibility/BaseLibrarianExtension.cs +++ b/src/api/wix/WixToolset.Extensibility/BaseLibrarianExtension.cs @@ -48,8 +48,8 @@ namespace WixToolset.Extensibility /// /// Called at the end of combining. /// - /// Combined library intermediate. - public virtual void PostCombine(Intermediate library) + /// Combined library result. + public virtual void PostCombine(ILibraryResult result) { } diff --git a/src/api/wix/WixToolset.Extensibility/Data/ILibraryResult.cs b/src/api/wix/WixToolset.Extensibility/Data/ILibraryResult.cs new file mode 100644 index 00000000..6974e265 --- /dev/null +++ b/src/api/wix/WixToolset.Extensibility/Data/ILibraryResult.cs @@ -0,0 +1,25 @@ +// 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.Extensibility.Data +{ + using System; + using System.Collections.Generic; + using System.Threading; + using WixToolset.Data; + + /// + /// Result of a library combine operation. + /// + public interface ILibraryResult + { + /// + /// Collection of files tracked when binding files into the library. + /// + IReadOnlyCollection TrackedFiles { get; set; } + + /// + /// Output of librarian. + /// + Intermediate Library { get; set; } + } +} diff --git a/src/api/wix/WixToolset.Extensibility/ILibrarianExtension.cs b/src/api/wix/WixToolset.Extensibility/ILibrarianExtension.cs index d9b04cd2..d25da5e4 100644 --- a/src/api/wix/WixToolset.Extensibility/ILibrarianExtension.cs +++ b/src/api/wix/WixToolset.Extensibility/ILibrarianExtension.cs @@ -5,13 +5,30 @@ namespace WixToolset.Extensibility using WixToolset.Data; using WixToolset.Extensibility.Data; -#pragma warning disable 1591 // TODO: add documentation + /// + /// Interface all librarian extensions implement. + /// public interface ILibrarianExtension { + /// + /// Called at the beginning of combining. + /// + /// Librarian context. void PreCombine(ILibraryContext context); + /// + /// Resolves a path to a file path on disk. + /// + /// Source line number for the path to resolve. + /// Symbol related to the path to resolve. + /// Path to resolve. + /// Optional resolved file result. IResolveFileResult ResolveFile(SourceLineNumber sourceLineNumber, IntermediateSymbolDefinition symbolDefinition, string path); - void PostCombine(Intermediate library); + /// + /// Called at the end of combining. + /// + /// Combined library result. + void PostCombine(ILibraryResult result); } } diff --git a/src/test/wix/TestData/WixprojModuleCsprojWinFormsNetFx/WixprojModuleCsprojWinFormsNetFx.wixproj b/src/test/wix/TestData/WixprojModuleCsprojWinFormsNetFx/WixprojModuleCsprojWinFormsNetFx.wixproj index 07e42b08..6009460c 100644 --- a/src/test/wix/TestData/WixprojModuleCsprojWinFormsNetFx/WixprojModuleCsprojWinFormsNetFx.wixproj +++ b/src/test/wix/TestData/WixprojModuleCsprojWinFormsNetFx/WixprojModuleCsprojWinFormsNetFx.wixproj @@ -1,19 +1,11 @@ + - Module - - - - diff --git a/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.ja-jp.wxl b/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.ja-jp.wxl index 52e1871e..0f902c8d 100644 --- a/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.ja-jp.wxl +++ b/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.ja-jp.wxl @@ -5,7 +5,7 @@ This file contains the declaration of all the localizable strings. --> - WixprojPackageVcxprojWindowsApp, eh? + WixprojPackageVcxprojWindowsApp-jp The First Feature in my Prooooduct, eh? diff --git a/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs b/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs index fe849608..508d4721 100644 --- a/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs +++ b/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/Package.wxs @@ -1,5 +1,7 @@ - + + @@ -16,5 +18,7 @@ + + diff --git a/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/WixprojPackageVcxprojWindowsApp.wixproj b/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/WixprojPackageVcxprojWindowsApp.wixproj index 7dc26a2d..bbd39870 100644 --- a/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/WixprojPackageVcxprojWindowsApp.wixproj +++ b/src/test/wix/TestData/WixprojPackageVcxprojWindowsApp/WixprojPackageVcxprojWindowsApp.wixproj @@ -5,5 +5,7 @@ + + diff --git a/src/test/wix/WixE2E/WixE2EFixture.cs b/src/test/wix/WixE2E/WixE2EFixture.cs index 89762f72..b1c6b2de 100644 --- a/src/test/wix/WixE2E/WixE2EFixture.cs +++ b/src/test/wix/WixE2E/WixE2EFixture.cs @@ -2,7 +2,12 @@ namespace WixE2E { + using System; using System.IO; + using System.Linq; + using System.Security.Cryptography; + using System.Text; + using System.Threading; using WixBuildTools.TestSupport; using Xunit; @@ -52,6 +57,93 @@ namespace WixE2E result.AssertSuccess(); } + [Fact] + public void CanIncrementalBuildPackageWithNativeWindowsAppWithNoEdits() + { + var projectDirectory = TestData.Get("TestData", "WixprojPackageVcxprojWindowsApp"); + var projectPath = Path.Combine(projectDirectory, "WixprojPackageVcxprojWindowsApp.wixproj"); + var projectBinPath = Path.Combine(projectDirectory, "bin"); + + CleanEverything(); + + var result = RestoreAndBuild(projectPath); + result.AssertSuccess(); + + var firstBuiltFiles = Directory.GetFiles(projectBinPath, "*.*", SearchOption.AllDirectories).ToArray(); + var firstHashes = firstBuiltFiles.Select(s => $"{s.Substring(projectBinPath.Length).TrimStart('\\')} with hash: {GetFileHash(s)}").ToArray(); + + // This should be an incremental build and not do any work. + // + result = RestoreAndBuild(projectPath); + result.AssertSuccess(); + + var secondBuiltFiles = Directory.GetFiles(projectBinPath, "*.*", SearchOption.AllDirectories).ToArray(); + var secondHashes = secondBuiltFiles.Select(s => $"{s.Substring(projectBinPath.Length).TrimStart('\\')} with hash: {GetFileHash(s)}").ToArray(); + + WixAssert.CompareLineByLine(firstHashes, secondHashes); + } + + [Fact] + public void CanIncrementalBuildPackageWithNativeWindowsAppWithEdits() + { + var projectDirectory = TestData.Get("TestData", "WixprojPackageVcxprojWindowsApp"); + var projectPath = Path.Combine(projectDirectory, "WixprojPackageVcxprojWindowsApp.wixproj"); + var projectBinPath = Path.Combine(projectDirectory, "bin"); + + CleanEverything(); + + var result = RestoreAndBuild(projectPath); + result.AssertSuccess(); + + var firstBuiltFiles = Directory.GetFiles(projectBinPath, "*.*", SearchOption.AllDirectories).ToArray(); + var firstRelativePaths = firstBuiltFiles.Select(s => $"{s.Substring(projectBinPath.Length).TrimStart('\\')}").ToArray(); + var firstHashes = firstBuiltFiles.Select(s => $"{s.Substring(projectBinPath.Length).TrimStart('\\')} with hash: {GetFileHash(s)}").ToArray(); + + var packageWxsPath = Path.Combine(projectDirectory, "Package.wxs"); + File.SetLastWriteTime(packageWxsPath, DateTime.Now); + + // This should be an incremental build that does work because a file was updated. + // + result = RestoreAndBuild(projectPath); + result.AssertSuccess(); + + var secondBuiltFiles = Directory.GetFiles(projectBinPath, "*.*", SearchOption.AllDirectories).ToArray(); + var secondRelativePaths = secondBuiltFiles.Select(s => $"{s.Substring(projectBinPath.Length).TrimStart('\\')}").ToArray(); + var secondHashes = secondBuiltFiles.Select(s => $"{s.Substring(projectBinPath.Length).TrimStart('\\')} with hash: {GetFileHash(s)}").ToArray(); + + WixAssert.CompareLineByLine(firstRelativePaths, secondRelativePaths); + Assert.NotEqual(firstHashes, secondHashes); + } + + [Fact(Skip = "Investigate if .NET Core WebApplications can be incrementally built")] + public void CanIncrementalBuildPackageWithNetCoreWebAppWithoutEdits() + { + var projectDirectory = TestData.Get("TestData", "WixprojPackageCsprojWebApplicationNetCore"); + var projectPath = Path.Combine(projectDirectory, "WixprojPackageCsprojWebApplicationNetCore.wixproj"); + var projectBinPath = Path.Combine(projectDirectory, "bin"); + + CleanEverything(); + + var result = RestoreAndBuild(projectPath); + result.AssertSuccess(); + + var firstBuiltFiles = Directory.GetFiles(projectBinPath, "*.*", SearchOption.AllDirectories).ToArray(); + var firstHashes = firstBuiltFiles.Select(s => $"{s.Substring(projectBinPath.Length).TrimStart('\\')} with hash: {GetFileHash(s)}").ToArray(); + + //var packageWxsPath = Path.Combine(projectDirectory, "Package.wxs"); + //File.SetLastWriteTime(packageWxsPath, DateTime.Now); + + // This should be an incremental build that does work because a file was updated. + // + result = RestoreAndBuild(projectPath); + result.AssertSuccess(); + + var secondBuiltFiles = Directory.GetFiles(projectBinPath, "*.*", SearchOption.AllDirectories).ToArray(); + var secondHashes = secondBuiltFiles.Select(s => $"{s.Substring(projectBinPath.Length).TrimStart('\\')} with hash: {GetFileHash(s)}").ToArray(); + + WixAssert.CompareLineByLine(firstHashes, secondHashes); + } + private static void CleanEverything() { var rootFolder = TestData.Get("TestData"); @@ -71,6 +163,23 @@ namespace WixE2E } } + private static string GetFileHash(string path) + { + using (var sha2 = SHA256.Create()) + { + var bytes = File.ReadAllBytes(path); + var hashBytes = sha2.ComputeHash(bytes); + + var sb = new StringBuilder(); + foreach (var hash in hashBytes) + { + sb.AppendFormat("{0:X}", hash); + } + + return sb.ToString(); + } + } + private static MsbuildRunnerResult RestoreAndBuild(string projectPath, bool x64 = true) { return MsbuildRunner.Execute(projectPath, new[] { "-Restore", "-v:m", "-bl" }, x64); diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index ab471702..c3dbcfce 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs @@ -244,6 +244,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind command.Execute(); fileFacades.AddRange(command.MergeModulesFileFacades); + trackedFiles.AddRange(command.TrackedFiles); } } @@ -260,8 +261,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind if (softwareTags.Any()) { - var command = new ProcessPackageSoftwareTagsCommand(section, softwareTags, this.IntermediateFolder); + var command = new ProcessPackageSoftwareTagsCommand(section, this.WindowsInstallerBackendHelper, softwareTags, this.IntermediateFolder); command.Execute(); + + trackedFiles.AddRange(command.TrackedFiles); } } @@ -483,8 +486,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind { this.Messaging.Write(VerboseMessages.MergingModules()); - var command = new MergeModulesCommand(this.Messaging, fileFacades, section, suppressedTableNames, this.OutputPath, this.IntermediateFolder); + var command = new MergeModulesCommand(this.Messaging, this.WindowsInstallerBackendHelper, fileFacades, section, suppressedTableNames, this.OutputPath, this.IntermediateFolder); command.Execute(); + + trackedFiles.AddRange(command.TrackedFiles); } if (this.Messaging.EncounteredError) @@ -508,8 +513,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind trackedFiles.AddRange(command.TrackedFiles); } - // TODO: this is not sufficient to collect all Input files (for example, it misses Binary and Icon tables). - trackedFiles.AddRange(fileFacades.Select(f => this.WindowsInstallerBackendHelper.TrackFile(f.SourcePath, TrackedFileType.Input, f.SourceLineNumber))); + var trackedInputFiles = this.TrackInputFiles(data, trackedFiles); + trackedFiles.AddRange(trackedInputFiles); var result = this.ServiceProvider.GetService(); result.FileTransfers = fileTransfers; @@ -613,5 +618,26 @@ namespace WixToolset.Core.WindowsInstaller.Bind return layout; } + + private IEnumerable TrackInputFiles(WindowsInstallerData data, List trackedFiles) + { + var trackedInputFiles = new List(); + var intermediateAndTemporaryPaths = new HashSet(trackedFiles.Where(t => t.Type == TrackedFileType.Intermediate || t.Type == TrackedFileType.Temporary).Select(t => t.Path), StringComparer.OrdinalIgnoreCase); + + foreach (var row in data.Tables.SelectMany(t => t.Rows)) + { + foreach (var field in row.Fields.Where(f => f.Column.Type == ColumnType.Object)) + { + var path = field.AsString(); + + if (!intermediateAndTemporaryPaths.Contains(path)) + { + trackedInputFiles.Add(this.WindowsInstallerBackendHelper.TrackFile(path, TrackedFileType.Input, row.SourceLineNumbers)); + } + } + } + + return trackedInputFiles; + } } } diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs index aac4dd4f..06168727 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ExtractMergeModuleFilesCommand.cs @@ -49,9 +49,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind public IEnumerable MergeModulesFileFacades { get; private set; } + public IReadOnlyList TrackedFiles { get; private set; } + public void Execute() { var mergeModulesFileFacades = new List(); + var trackedFiles = new List(); var merge = MsmInterop.GetMsmMerge(); @@ -66,21 +69,23 @@ namespace WixToolset.Core.WindowsInstaller.Bind foreach (var wixMergeRow in this.WixMergeSymbols) { - var containsFiles = this.CreateFacadesForMergeModuleFiles(wixMergeRow, mergeModulesFileFacades, indexedFileFacades); + var modulesTrackedFiles = this.CreateFacadesForMergeModuleFiles(wixMergeRow, mergeModulesFileFacades, indexedFileFacades); // If the module has files and creating layout - if (containsFiles && !this.SuppressLayout) + if (modulesTrackedFiles.Count > 0 && !this.SuppressLayout) { this.ExtractFilesFromMergeModule(merge, wixMergeRow); + trackedFiles.AddRange(modulesTrackedFiles); } } this.MergeModulesFileFacades = mergeModulesFileFacades; + this.TrackedFiles = trackedFiles; } - private bool CreateFacadesForMergeModuleFiles(WixMergeSymbol wixMergeRow, List mergeModulesFileFacades, Dictionary indexedFileFacades) + private IReadOnlyCollection CreateFacadesForMergeModuleFiles(WixMergeSymbol wixMergeRow, List mergeModulesFileFacades, Dictionary indexedFileFacades) { - var containsFiles = false; + var trackedFiles = new List(); try { @@ -125,12 +130,13 @@ namespace WixToolset.Core.WindowsInstaller.Bind { mergeModulesFileFacades.Add(mergeModuleFileFacade); - // Keep updating the indexes as new rows are added. + // Keep updating the indexes as new facades are added. indexedFileFacades.Add(mergeModuleFileFacade.Id, mergeModuleFileFacade); uniqueModuleFileIdentifiers.Add(mergeModuleFileFacade.Id, mergeModuleFileFacade); - } - containsFiles = true; + // Track where file will be extracted. + trackedFiles.Add(this.BackendHelper.TrackFile(mergeModuleFileFacade.SourcePath, TrackedFileType.Intermediate, mergeModuleFileFacade.SourceLineNumber)); + } } } } @@ -164,7 +170,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind throw new WixException(ErrorMessages.CannotOpenMergeModule(wixMergeRow.SourceLineNumbers, wixMergeRow.Id.Id, wixMergeRow.SourceFile)); } - return containsFiles; + return trackedFiles; } private void ExtractFilesFromMergeModule(IMsmMerge2 merge, WixMergeSymbol wixMergeRow) diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs index 6446692e..96b7866c 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/MergeModulesCommand.cs @@ -22,9 +22,10 @@ namespace WixToolset.Core.WindowsInstaller.Bind /// internal class MergeModulesCommand { - public MergeModulesCommand(IMessaging messaging, IEnumerable fileFacades, IntermediateSection section, IEnumerable suppressedTableNames, string outputPath, string intermediateFolder) + public MergeModulesCommand(IMessaging messaging, IBackendHelper backendHelper, IEnumerable fileFacades, IntermediateSection section, IEnumerable suppressedTableNames, string outputPath, string intermediateFolder) { this.Messaging = messaging; + this.BackendHelper = backendHelper; this.FileFacades = fileFacades; this.Section = section; this.SuppressedTableNames = suppressedTableNames ?? Array.Empty(); @@ -34,6 +35,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind private IMessaging Messaging { get; } + private IBackendHelper BackendHelper { get; } + private IEnumerable FileFacades { get; } private IntermediateSection Section { get; } @@ -44,8 +47,12 @@ namespace WixToolset.Core.WindowsInstaller.Bind private string IntermediateFolder { get; } + public IReadOnlyList TrackedFiles { get; private set; } + public void Execute() { + var trackedFiles = new List(); + var wixMergeSymbols = this.Section.Symbols.OfType().ToList(); if (!wixMergeSymbols.Any()) { @@ -93,6 +100,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind merge.OpenModule(wixMergeRow.SourceFile, mergeLanguage); moduleOpen = true; + trackedFiles.Add(this.BackendHelper.TrackFile(wixMergeRow.SourceFile, TrackedFileType.Input, wixMergeRow.SourceLineNumbers)); + // If there is merge configuration data, create a callback object to contain it all. ConfigurationCallback callback = null; if (!String.IsNullOrEmpty(wixMergeRow.ConfigurationData)) @@ -326,6 +335,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind db.Commit(); } + + this.TrackedFiles = trackedFiles; } } } diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs index 9a068603..68e11790 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs @@ -9,12 +9,15 @@ namespace WixToolset.Core.WindowsInstaller.Bind using System.Xml; using WixToolset.Data; using WixToolset.Data.Symbols; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; internal class ProcessPackageSoftwareTagsCommand { - public ProcessPackageSoftwareTagsCommand(IntermediateSection section, IEnumerable softwareTags, string intermediateFolder) + public ProcessPackageSoftwareTagsCommand(IntermediateSection section, IBackendHelper backendHelper, IEnumerable softwareTags, string intermediateFolder) { this.Section = section; + this.BackendHelper = backendHelper; this.SoftwareTags = softwareTags; this.IntermediateFolder = intermediateFolder; } @@ -23,10 +26,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind private IntermediateSection Section { get; } + private IBackendHelper BackendHelper { get; } + private IEnumerable SoftwareTags { get; } + public IReadOnlyCollection TrackedFiles { get; private set; } + public void Execute() { + var trackedFiles = new List(); + string productName = null; string productVersion = null; string manufacturer = null; @@ -70,6 +79,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind // Write the tag file. fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(workingFolder, fileSymbol.Name) }; + trackedFiles.Add(this.BackendHelper.TrackFile(fileSymbol.Source.Path, TrackedFileType.Intermediate, tagRow.SourceLineNumbers)); + using (var fs = new FileStream(fileSymbol.Source.Path, FileMode.Create)) { CreateTagFile(fs, uniqueId, productName, productVersion, tagRow.Regid, manufacturer, persistentId); @@ -86,6 +97,8 @@ namespace WixToolset.Core.WindowsInstaller.Bind }); } } + + this.TrackedFiles = trackedFiles; } private static string NormalizeGuid(string guidString) diff --git a/src/wix/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs b/src/wix/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs index ec2d8896..5d984d53 100644 --- a/src/wix/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs +++ b/src/wix/WixToolset.Core/Bind/ExtractEmbeddedFilesCommand.cs @@ -31,6 +31,7 @@ namespace WixToolset.Core.Bind foreach (var expectedEmbeddedFileByUri in group) { var baseUri = expectedEmbeddedFileByUri.Key; + trackedFiles.Add(this.BackendHelper.TrackFile(baseUri.LocalPath, TrackedFileType.Input)); using (var wixout = WixOutput.Read(baseUri)) { @@ -41,7 +42,7 @@ namespace WixToolset.Core.Bind if (uniqueIds.Add(embeddedFile.EmbeddedFileId)) { wixout.ExtractEmbeddedFile(embeddedFile.EmbeddedFileId, embeddedFile.OutputPath); - trackedFiles.Add(this.BackendHelper.TrackFile(embeddedFile.OutputPath, TrackedFileType.Temporary)); + trackedFiles.Add(this.BackendHelper.TrackFile(embeddedFile.OutputPath, TrackedFileType.Intermediate)); } } } diff --git a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs index d289b557..67d2876d 100644 --- a/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs +++ b/src/wix/WixToolset.Core/CommandLine/BuildCommand.cs @@ -132,12 +132,7 @@ namespace WixToolset.Core.CommandLine { using (new IntermediateFieldContext("wix.lib")) { - var wixlib = this.LibraryPhase(wixobjs, wxls, this.commandLine.BindFiles, this.commandLine.BindPaths, cancellationToken); - - if (!this.Messaging.EncounteredError) - { - wixlib.Save(this.OutputFile); - } + this.LibraryPhase(wixobjs, wxls, this.commandLine.BindFiles, this.commandLine.BindPaths, cancellationToken); } } else @@ -260,7 +255,7 @@ namespace WixToolset.Core.CommandLine return intermediates; } - private Intermediate LibraryPhase(IReadOnlyCollection intermediates, IReadOnlyCollection localizations, bool bindFiles, IReadOnlyCollection bindPaths, CancellationToken cancellationToken) + private void LibraryPhase(IReadOnlyCollection intermediates, IReadOnlyCollection localizations, bool bindFiles, IReadOnlyCollection bindPaths, CancellationToken cancellationToken) { var context = this.ServiceProvider.GetService(); context.BindFiles = bindFiles; @@ -270,18 +265,22 @@ namespace WixToolset.Core.CommandLine context.Intermediates = intermediates; context.CancellationToken = cancellationToken; - Intermediate library = null; try { var librarian = this.ServiceProvider.GetService(); - library = librarian.Combine(context); + var result = librarian.Combine(context); + + if (!this.Messaging.EncounteredError) + { + result.Library.Save(this.OutputFile); + + this.LayoutFiles(this.IntermediateFolder, result.TrackedFiles, null, cancellationToken); + } } catch (WixException e) { this.Messaging.Write(e.Error); } - - return library; } private Intermediate LinkPhase(IEnumerable intermediates, IEnumerable libraryFiles, ISymbolDefinitionCreator creator, CancellationToken cancellationToken) @@ -365,19 +364,7 @@ namespace WixToolset.Core.CommandLine return; } - { - var context = this.ServiceProvider.GetService(); - context.Extensions = this.ExtensionManager.GetServices(); - context.TrackedFiles = bindResult.TrackedFiles; - context.FileTransfers = bindResult.FileTransfers; - context.IntermediateFolder = intermediateFolder; - context.TrackingFile = this.TrackingFile; - context.ResetAcls = this.commandLine.ResetAcls; - context.CancellationToken = cancellationToken; - - var layout = this.ServiceProvider.GetService(); - layout.Layout(context); - } + this.LayoutFiles(intermediateFolder, bindResult.TrackedFiles, bindResult.FileTransfers, cancellationToken); } finally { @@ -385,6 +372,21 @@ namespace WixToolset.Core.CommandLine } } + private void LayoutFiles(string intermediateFolder, IReadOnlyCollection trackedFiles, IReadOnlyCollection fileTransfers, CancellationToken cancellationToken) + { + var context = this.ServiceProvider.GetService(); + context.Extensions = this.ExtensionManager.GetServices(); + context.TrackedFiles = trackedFiles; + context.FileTransfers = fileTransfers; + context.IntermediateFolder = intermediateFolder; + context.TrackingFile = this.TrackingFile; + context.ResetAcls = this.commandLine.ResetAcls; + context.CancellationToken = cancellationToken; + + var layout = this.ServiceProvider.GetService(); + layout.Layout(context); + } + private IEnumerable LoadLibraries(IEnumerable libraryFiles, ISymbolDefinitionCreator creator) { try diff --git a/src/wix/WixToolset.Core/ILibrarian.cs b/src/wix/WixToolset.Core/ILibrarian.cs index 0fcedea5..8f57ca67 100644 --- a/src/wix/WixToolset.Core/ILibrarian.cs +++ b/src/wix/WixToolset.Core/ILibrarian.cs @@ -5,9 +5,16 @@ namespace WixToolset.Core using WixToolset.Data; using WixToolset.Extensibility.Data; -#pragma warning disable 1591 // TODO: add documentation + /// + /// Create libraries from input intermediates. + /// public interface ILibrarian { - Intermediate Combine(ILibraryContext context); + /// + /// Combine intermediates into a single result. + /// + /// Library context. + /// Library result. + ILibraryResult Combine(ILibraryContext context); } } diff --git a/src/wix/WixToolset.Core/Librarian.cs b/src/wix/WixToolset.Core/Librarian.cs index 1dd1b44d..2762fb33 100644 --- a/src/wix/WixToolset.Core/Librarian.cs +++ b/src/wix/WixToolset.Core/Librarian.cs @@ -21,17 +21,20 @@ namespace WixToolset.Core this.ServiceProvider = serviceProvider; this.Messaging = this.ServiceProvider.GetService(); + this.LayoutServices = this.ServiceProvider.GetService(); } private IServiceProvider ServiceProvider { get; } private IMessaging Messaging { get; } + private ILayoutServices LayoutServices { get; } + /// /// Create a library by combining several intermediates (objects). /// - /// Returns the new library. - public Intermediate Combine(ILibraryContext context) + /// Returns tracked input files and the new library. + public ILibraryResult Combine(ILibraryContext context) { if (String.IsNullOrEmpty(context.LibraryId)) { @@ -43,7 +46,9 @@ namespace WixToolset.Core extension.PreCombine(context); } + ILibraryResult result = this.ServiceProvider.GetService(); Intermediate library = null; + IReadOnlyCollection trackedFiles = null; try { var sections = context.Intermediates.SelectMany(i => i.Sections).ToList(); @@ -56,7 +61,7 @@ namespace WixToolset.Core return null; } - this.ResolveFilePathsToEmbed(context, sections); + trackedFiles = this.ResolveFilePathsToEmbed(context, sections); foreach (var section in sections) { @@ -71,17 +76,22 @@ namespace WixToolset.Core } finally { + result.Library = library; + result.TrackedFiles = trackedFiles; + foreach (var extension in context.Extensions) { - extension.PostCombine(library); + extension.PostCombine(result); } } - return this.Messaging.EncounteredError ? null : library; + return result; } - private void ResolveFilePathsToEmbed(ILibraryContext context, IEnumerable sections) + private IReadOnlyCollection ResolveFilePathsToEmbed(ILibraryContext context, IEnumerable sections) { + var trackedFiles = new List(); + // Resolve paths to files that are to be embedded in the library. if (context.BindFiles) { @@ -105,6 +115,8 @@ namespace WixToolset.Core { // File was successfully resolved so track the embedded index as the embedded file index. field.Set(new IntermediateFieldPathValue { Embed = true, Path = file }); + + trackedFiles.Add(this.LayoutServices.TrackFile(file, TrackedFileType.Input, symbol.SourceLineNumbers)); } else { @@ -114,6 +126,8 @@ namespace WixToolset.Core } } } + + return trackedFiles; } private void Validate(Intermediate library) diff --git a/src/wix/WixToolset.Core/LibraryResult.cs b/src/wix/WixToolset.Core/LibraryResult.cs new file mode 100644 index 00000000..80db2c3a --- /dev/null +++ b/src/wix/WixToolset.Core/LibraryResult.cs @@ -0,0 +1,19 @@ +// 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.Threading; + using WixToolset.Data; + using WixToolset.Extensibility; + using WixToolset.Extensibility.Data; + using WixToolset.Extensibility.Services; + + internal class LibraryResult : ILibraryResult + { + public IReadOnlyCollection TrackedFiles { get; set; } + + public Intermediate Library { get; set; } + } +} diff --git a/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs b/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs index 7bbd4075..06dbdfae 100644 --- a/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs +++ b/src/wix/WixToolset.Core/WixToolsetServiceProvider.cs @@ -35,6 +35,7 @@ namespace WixToolset.Core this.AddService((provider, singletons) => new PreprocessContext(provider)); this.AddService((provider, singletons) => new CompileContext(provider)); this.AddService((provider, singletons) => new LibraryContext(provider)); + this.AddService((provider, singletons) => new LibraryResult()); this.AddService((provider, singletons) => new LinkContext(provider)); this.AddService((provider, singletons) => new ResolveContext(provider)); this.AddService((provider, singletons) => new BindContext(provider)); -- cgit v1.2.3-55-g6feb