From 860676fa5b40a1904478151e9b4934c004e7db63 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Mon, 7 Oct 2019 11:18:13 -0700 Subject: Implement Bundle build --- src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs | 860 ++++++--------------- 1 file changed, 242 insertions(+), 618 deletions(-) (limited to 'src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs') diff --git a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index 61aa5189..6b4b9d68 100644 --- a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs +++ b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs @@ -8,78 +8,51 @@ namespace WixToolset.Core.Burn using System.Globalization; using System.IO; using System.Linq; - using System.Reflection; using WixToolset.Core.Bind; + using WixToolset.Core.Burn.Bind; using WixToolset.Core.Burn.Bundles; using WixToolset.Data; - using WixToolset.Data.Bind; + using WixToolset.Data.Burn; + using WixToolset.Data.Tuples; using WixToolset.Extensibility; using WixToolset.Extensibility.Data; using WixToolset.Extensibility.Services; - // TODO: (4.0) Refactor so that these don't need to be copied. - // Copied verbatim from ext\UtilExtension\wixext\UtilCompiler.cs - [Flags] - internal enum WixFileSearchAttributes - { - Default = 0x001, - MinVersionInclusive = 0x002, - MaxVersionInclusive = 0x004, - MinSizeInclusive = 0x008, - MaxSizeInclusive = 0x010, - MinDateInclusive = 0x020, - MaxDateInclusive = 0x040, - WantVersion = 0x080, - WantExists = 0x100, - IsDirectory = 0x200, - } - - [Flags] - internal enum WixRegistrySearchAttributes - { - Raw = 0x01, - Compatible = 0x02, - ExpandEnvironmentVariables = 0x04, - WantValue = 0x08, - WantExists = 0x10, - Win64 = 0x20, - } - - internal enum WixComponentSearchAttributes - { - KeyPath = 0x1, - State = 0x2, - WantDirectory = 0x4, - } - - [Flags] - internal enum WixProductSearchAttributes - { - Version = 0x1, - Language = 0x2, - State = 0x4, - Assignment = 0x8, - UpgradeCode = 0x10, - } - /// /// Binds a this.bundle. /// internal class BindBundleCommand { - public BindBundleCommand(IBindContext context) + public BindBundleCommand(IBindContext context, IEnumerable backedExtensions) { - //this.TableDefinitions = WindowsInstallerStandard.GetTableDefinitions(); + this.ServiceProvider = context.ServiceProvider; + + this.Messaging = context.ServiceProvider.GetService(); + + this.BackendHelper = context.ServiceProvider.GetService(); + this.BurnStubPath = context.BurnStubPath; + this.DefaultCompressionLevel = context.DefaultCompressionLevel; this.DelayedFields = context.DelayedFields; this.ExpectedEmbeddedFiles = context.ExpectedEmbeddedFiles; + this.IntermediateFolder = context.IntermediateFolder; + this.Output = context.IntermediateRepresentation; + this.OutputPath = context.OutputPath; + this.OutputPdbPath = context.OutputPdbPath; + //this.VariableResolver = context.VariableResolver; - var extensionManager = context.ServiceProvider.GetService(); - - this.BackendExtensions = extensionManager.GetServices(); + this.BackendExtensions = backedExtensions; } - public CompressionLevel DefaultCompressionLevel { private get; set; } + private IServiceProvider ServiceProvider { get; } + + private IMessaging Messaging { get; } + + private IBackendHelper BackendHelper { get; } + + private string BurnStubPath { get; } + + private CompressionLevel? DefaultCompressionLevel { get; } public IEnumerable DelayedFields { get; } @@ -87,17 +60,15 @@ namespace WixToolset.Core.Burn private IEnumerable BackendExtensions { get; } - public Intermediate Output { private get; set; } - - public string OutputPath { private get; set; } + private Intermediate Output { get; } - public string PdbFile { private get; set; } + private string OutputPath { get; } - //public TableDefinitionCollection TableDefinitions { private get; set; } + private string OutputPdbPath { get; } - public string IntermediateFolder { private get; set; } + private string IntermediateFolder { get; } - public IVariableResolver VariableResolver { private get; set; } + private IVariableResolver VariableResolver { get; } public IEnumerable FileTransfers { get; private set; } @@ -105,196 +76,177 @@ namespace WixToolset.Core.Burn public void Execute() { - throw new NotImplementedException(); -#if TODO - this.FileTransfers = Enumerable.Empty(); - this.ContentFilePaths = Enumerable.Empty(); + var section = this.Output.Sections.Single(); + + var fileTransfers = new List(); + var trackedFiles = new List(); // First look for data we expect to find... Chain, WixGroups, etc. // We shouldn't really get past the linker phase if there are // no group items... that means that there's no UX, no Chain, // *and* no Containers! - Table chainPackageTable = this.GetRequiredTable("WixBundlePackage"); + var chainPackageTuples = this.GetRequiredTuples(); - Table wixGroupTable = this.GetRequiredTable("WixGroup"); + var wixGroupTuples = this.GetRequiredTuples(); // Ensure there is one and only one row in the WixBundle table. // The compiler and linker behavior should have colluded to get // this behavior. - WixBundleRow bundleRow = (WixBundleRow)this.GetSingleRowTable("WixBundle"); + var bundleTuple = this.GetSingleTuple(); + + bundleTuple.BundleId = Guid.NewGuid().ToString("B").ToUpperInvariant(); - bundleRow.PerMachine = true; // default to per-machine but the first-per user package wil flip the bundle per-user. + bundleTuple.Attributes |= WixBundleAttributes.PerMachine; // default to per-machine but the first-per user package wil flip the bundle per-user. // Ensure there is one and only one row in the WixBootstrapperApplication table. // The compiler and linker behavior should have colluded to get // this behavior. - Row baRow = this.GetSingleRowTable("WixBootstrapperApplication"); + var bundleApplicationTuple = this.GetSingleTuple(); // Ensure there is one and only one row in the WixChain table. // The compiler and linker behavior should have colluded to get // this behavior. - WixChainRow chainRow = (WixChainRow)this.GetSingleRowTable("WixChain"); + var chainTuple = this.GetSingleTuple(); - if (Messaging.Instance.EncounteredError) + if (this.Messaging.EncounteredError) { return; } // If there are any fields to resolve later, create the cache to populate during bind. - IDictionary variableCache = null; - if (this.DelayedFields.Any()) - { - variableCache = new Dictionary(StringComparer.InvariantCultureIgnoreCase); - } + var variableCache = this.DelayedFields.Any() ? new Dictionary(StringComparer.InvariantCultureIgnoreCase) : null; // TODO: Although the WixSearch tables are defined in the Util extension, // the Bundle Binder has to know all about them. We hope to revisit all // of this in the 4.0 timeframe. - IEnumerable orderedSearches = this.OrderSearches(); + var orderedSearches = this.OrderSearches(section); +#if THIS_SHOULD_BE_DELETED_SINCE_RESOLVE_DOES_THIS_NOW // Extract files that come from cabinet files (this does not extract files from merge modules). { var extractEmbeddedFilesCommand = new ExtractEmbeddedFilesCommand(); extractEmbeddedFilesCommand.FilesWithEmbeddedFiles = ExpectedEmbeddedFiles; extractEmbeddedFilesCommand.Execute(); } +#endif // Get the explicit payloads. - RowDictionary payloads = new RowDictionary(this.Output.Tables["WixBundlePayload"]); + var payloadTuples = section.Tuples.OfType().ToDictionary(t => t.Id.Id); // Update explicitly authored payloads with their parent package and container (as appropriate) // to make it easier to gather the payloads later. - foreach (WixGroupRow row in wixGroupTable.RowsAs()) + foreach (var groupTuple in wixGroupTuples) { - if (ComplexReferenceChildType.Payload == row.ChildType) + if (ComplexReferenceChildType.Payload == groupTuple.ChildType) { - WixBundlePayloadRow payload = payloads.Get(row.ChildId); + var payloadTuple = payloadTuples[groupTuple.ChildId]; - if (ComplexReferenceParentType.Package == row.ParentType) + if (ComplexReferenceParentType.Package == groupTuple.ParentType) { - Debug.Assert(String.IsNullOrEmpty(payload.Package)); - payload.Package = row.ParentId; + Debug.Assert(String.IsNullOrEmpty(payloadTuple.PackageRef)); + payloadTuple.PackageRef = groupTuple.ParentId; } - else if (ComplexReferenceParentType.Container == row.ParentType) + else if (ComplexReferenceParentType.Container == groupTuple.ParentType) { - Debug.Assert(String.IsNullOrEmpty(payload.Container)); - payload.Container = row.ParentId; + Debug.Assert(String.IsNullOrEmpty(payloadTuple.ContainerRef)); + payloadTuple.ContainerRef = groupTuple.ParentId; } - else if (ComplexReferenceParentType.Layout == row.ParentType) + else if (ComplexReferenceParentType.Layout == groupTuple.ParentType) { - payload.LayoutOnly = true; + payloadTuple.LayoutOnly = true; } } } - List fileTransfers = new List(); - string layoutDirectory = Path.GetDirectoryName(this.OutputPath); + var layoutDirectory = Path.GetDirectoryName(this.OutputPath); // Process the explicitly authored payloads. ISet processedPayloads; { - ProcessPayloadsCommand command = new ProcessPayloadsCommand(); - command.Payloads = payloads.Values; - command.DefaultPackaging = bundleRow.DefaultPackagingType; - command.LayoutDirectory = layoutDirectory; + var command = new ProcessPayloadsCommand(this.ServiceProvider, this.BackendHelper, payloadTuples.Values, bundleTuple.DefaultPackagingType, layoutDirectory); command.Execute(); fileTransfers.AddRange(command.FileTransfers); - processedPayloads = new HashSet(payloads.Keys); + processedPayloads = new HashSet(payloadTuples.Keys); } IDictionary facades; { - GetPackageFacadesCommand command = new GetPackageFacadesCommand(); - command.PackageTable = chainPackageTable; - command.ExePackageTable = this.Output.Tables["WixBundleExePackage"]; - command.MsiPackageTable = this.Output.Tables["WixBundleMsiPackage"]; - command.MspPackageTable = this.Output.Tables["WixBundleMspPackage"]; - command.MsuPackageTable = this.Output.Tables["WixBundleMsuPackage"]; + var command = new GetPackageFacadesCommand(chainPackageTuples, section); command.Execute(); facades = command.PackageFacades; } - // Process each package facade. Note this is likely to add payloads and other rows to tables so + // Process each package facade. Note this is likely to add payloads and other tuples so // note that any indexes created above may be out of date now. - foreach (PackageFacade facade in facades.Values) + foreach (var facade in facades.Values) { - switch (facade.Package.Type) + switch (facade.PackageTuple.Type) { - case WixBundlePackageType.Exe: - { - ProcessExePackageCommand command = new ProcessExePackageCommand(); - command.AuthoredPayloads = payloads; - command.Facade = facade; - command.Execute(); - - // ? variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.ExePackage.Manufacturer); - } - break; + case WixBundlePackageType.Exe: + { + var command = new ProcessExePackageCommand(facade, payloadTuples); + command.Execute(); + } + break; - case WixBundlePackageType.Msi: - { - var command = new ProcessMsiPackageCommand(); - command.AuthoredPayloads = payloads; - command.Facade = facade; - command.BackendExtensions = this.BackendExtensions; - command.MsiFeatureTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiFeature"]); - command.MsiPropertyTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiProperty"]); - command.PayloadTable = this.Output.Tables["WixBundlePayload"]; - command.RelatedPackageTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleRelatedPackage"]); - command.Execute(); - - if (null != variableCache) - { - variableCache.Add(String.Concat("packageLanguage.", facade.Package.WixChainItemId), facade.MsiPackage.ProductLanguage.ToString()); - - if (null != facade.MsiPackage.Manufacturer) - { - variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.MsiPackage.Manufacturer); - } - } + case WixBundlePackageType.Msi: + { + var command = new ProcessMsiPackageCommand(this.ServiceProvider, this.BackendExtensions, section, facade, payloadTuples); + command.Execute(); - } - break; + if (null != variableCache) + { + var msiPackage = (WixBundleMsiPackageTuple)facade.SpecificPackageTuple; + variableCache.Add(String.Concat("packageLanguage.", facade.PackageId), msiPackage.ProductLanguage.ToString()); - case WixBundlePackageType.Msp: + if (null != msiPackage.Manufacturer) { - ProcessMspPackageCommand command = new ProcessMspPackageCommand(); - command.AuthoredPayloads = payloads; - command.Facade = facade; - command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]); - command.Execute(); + variableCache.Add(String.Concat("packageManufacturer.", facade.PackageId), msiPackage.Manufacturer); } - break; + } - case WixBundlePackageType.Msu: - { - ProcessMsuPackageCommand command = new ProcessMsuPackageCommand(); - command.Facade = facade; - command.Execute(); - } - break; + } + break; + + case WixBundlePackageType.Msp: + { + var command = new ProcessMspPackageCommand(this.Messaging, section, facade, payloadTuples); + command.Execute(); + } + break; + + case WixBundlePackageType.Msu: + { + var command = new ProcessMsuPackageCommand(facade, payloadTuples); + command.Execute(); + } + break; } if (null != variableCache) { - BindBundleCommand.PopulatePackageVariableCache(facade.Package, variableCache); + BindBundleCommand.PopulatePackageVariableCache(facade.PackageTuple, variableCache); } } + if (this.Messaging.EncounteredError) + { + return; + } + // Reindex the payloads now that all the payloads (minus the manifest payloads that will be created later) // are present. - payloads = new RowDictionary(this.Output.Tables["WixBundlePayload"]); + payloadTuples = section.Tuples.OfType().ToDictionary(t => t.Id.Id); // Process the payloads that were added by processing the packages. { - ProcessPayloadsCommand command = new ProcessPayloadsCommand(); - command.Payloads = payloads.Values.Where(r => !processedPayloads.Contains(r.Id)).ToList(); - command.DefaultPackaging = bundleRow.DefaultPackagingType; - command.LayoutDirectory = layoutDirectory; + var toProcess = payloadTuples.Values.Where(r => !processedPayloads.Contains(r.Id.Id)).ToList(); + + var command = new ProcessPayloadsCommand(this.ServiceProvider, this.BackendHelper, toProcess, bundleTuple.DefaultPackagingType, layoutDirectory); command.Execute(); fileTransfers.AddRange(command.FileTransfers); @@ -303,45 +255,43 @@ namespace WixToolset.Core.Burn } // Set the package metadata from the payloads now that we have the complete payload information. - ILookup payloadsByPackage = payloads.Values.ToLookup(p => p.Package); - { - foreach (PackageFacade facade in facades.Values) + var payloadsByPackageId = payloadTuples.Values.ToLookup(p => p.PackageRef); + + foreach (var facade in facades.Values) { - facade.Package.Size = 0; + facade.PackageTuple.Size = 0; - IEnumerable packagePayloads = payloadsByPackage[facade.Package.WixChainItemId]; + var packagePayloads = payloadsByPackageId[facade.PackageId]; - foreach (WixBundlePayloadRow payload in packagePayloads) + foreach (var payload in packagePayloads) { - facade.Package.Size += payload.FileSize; + facade.PackageTuple.Size += payload.FileSize; } - if (!facade.Package.InstallSize.HasValue) + if (!facade.PackageTuple.InstallSize.HasValue) { - facade.Package.InstallSize = facade.Package.Size; - + facade.PackageTuple.InstallSize = facade.PackageTuple.Size; } - WixBundlePayloadRow packagePayload = payloads[facade.Package.PackagePayload]; + var packagePayload = payloadTuples[facade.PackageTuple.PayloadRef]; - if (String.IsNullOrEmpty(facade.Package.Description)) + if (String.IsNullOrEmpty(facade.PackageTuple.Description)) { - facade.Package.Description = packagePayload.Description; + facade.PackageTuple.Description = packagePayload.Description; } - if (String.IsNullOrEmpty(facade.Package.DisplayName)) + if (String.IsNullOrEmpty(facade.PackageTuple.DisplayName)) { - facade.Package.DisplayName = packagePayload.DisplayName; + facade.PackageTuple.DisplayName = packagePayload.DisplayName; } } } - // Give the UX payloads their embedded IDs... - int uxPayloadIndex = 0; + var uxPayloadIndex = 0; { - foreach (WixBundlePayloadRow payload in payloads.Values.Where(p => Compiler.BurnUXContainerId == p.Container)) + foreach (var payload in payloadTuples.Values.Where(p => BurnConstants.BurnUXContainerName == p.ContainerRef)) { // In theory, UX payloads could be embedded in the UX CAB, external to the bundle EXE, or even // downloaded. The current engine requires the UX to be fully present before any downloading starts, @@ -349,7 +299,7 @@ namespace WixToolset.Core.Burn // into the temporary UX directory correctly, so we don't allow external either. if (PackagingType.Embedded != payload.Packaging) { - Messaging.Instance.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.FullFileName)); + this.Messaging.Write(WarningMessages.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.SourceFile.Path)); payload.Packaging = PackagingType.Embedded; } @@ -360,12 +310,12 @@ namespace WixToolset.Core.Burn if (0 == uxPayloadIndex) { // If we didn't get any UX payloads, it's an error! - throw new WixException(WixErrors.MissingBundleInformation("BootstrapperApplication")); + throw new WixException(ErrorMessages.MissingBundleInformation("BootstrapperApplication")); } // Give the embedded payloads without an embedded id yet an embedded id. - int payloadIndex = 0; - foreach (WixBundlePayloadRow payload in payloads.Values) + var payloadIndex = 0; + foreach (var payload in payloadTuples.Values) { Debug.Assert(PackagingType.Unknown != payload.Packaging); @@ -377,38 +327,38 @@ namespace WixToolset.Core.Burn } } + if (this.Messaging.EncounteredError) + { + return; + } + // Determine patches to automatically slipstream. { - AutomaticallySlipstreamPatchesCommand command = new AutomaticallySlipstreamPatchesCommand(); - command.PackageFacades = facades.Values; - command.SlipstreamMspTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleSlipstreamMsp"]); - command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]); + var command = new AutomaticallySlipstreamPatchesCommand(section, facades.Values); command.Execute(); } // If catalog files exist, non-embedded payloads should validate with the catalogs. - IEnumerable catalogs = this.Output.Tables["WixBundleCatalog"].RowsAs(); + var catalogs = section.Tuples.OfType().ToList(); - if (catalogs.Any()) + if (catalogs.Count > 0) { - VerifyPayloadsWithCatalogCommand command = new VerifyPayloadsWithCatalogCommand(); - command.Catalogs = catalogs; - command.Payloads = payloads.Values; + var command = new VerifyPayloadsWithCatalogCommand(this.Messaging, catalogs, payloadTuples.Values); command.Execute(); } - if (Messaging.Instance.EncounteredError) + if (this.Messaging.EncounteredError) { return; } IEnumerable orderedFacades; - IEnumerable boundaries; + IEnumerable boundaries; { - OrderPackagesAndRollbackBoundariesCommand command = new OrderPackagesAndRollbackBoundariesCommand(); - command.Boundaries = new RowDictionary(this.Output.Tables["WixBundleRollbackBoundary"]); - command.PackageFacades = facades; - command.WixGroupTable = wixGroupTable; + var groupTuples = section.Tuples.OfType(); + var boundaryTuplesById = section.Tuples.OfType().ToDictionary(b => b.Id.Id); + + var command = new OrderPackagesAndRollbackBoundariesCommand(this.Messaging, groupTuples, boundaryTuplesById, facades); command.Execute(); orderedFacades = command.OrderedPackageFacades; @@ -418,280 +368,122 @@ namespace WixToolset.Core.Burn // Resolve any delayed fields before generating the manifest. if (this.DelayedFields.Any()) { - var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand(); - resolveDelayedFieldsCommand.OutputType = this.Output.Type; - resolveDelayedFieldsCommand.DelayedFields = this.DelayedFields; - resolveDelayedFieldsCommand.ModularizationGuid = null; - resolveDelayedFieldsCommand.VariableCache = variableCache; + var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand(this.Messaging, this.DelayedFields, variableCache); resolveDelayedFieldsCommand.Execute(); } - // Set the overridable bundle provider key. - this.SetBundleProviderKey(this.Output, bundleRow); + Dictionary dependencyTuplesByKey; + { + var command = new ProcessDependencyProvidersCommand(this.Messaging, section, facades); + command.Execute(); - // Import or generate dependency providers for packages in the manifest. - this.ProcessDependencyProviders(this.Output, facades); + bundleTuple.ProviderKey = command.BundleProviderKey; // set the overridable bundle provider key. + dependencyTuplesByKey = command.DependencyTuplesByKey; + } // Update the bundle per-machine/per-user scope based on the chained packages. - this.ResolveBundleInstallScope(bundleRow, orderedFacades); + this.ResolveBundleInstallScope(section, bundleTuple, orderedFacades); // Generate the core-defined BA manifest tables... { - CreateBootstrapperApplicationManifestCommand command = new CreateBootstrapperApplicationManifestCommand(); - command.BundleRow = bundleRow; - command.ChainPackages = orderedFacades; - command.LastUXPayloadIndex = uxPayloadIndex; - command.MsiFeatures = this.Output.Tables["WixBundleMsiFeature"].RowsAs(); - command.Output = this.Output; - command.Payloads = payloads; - command.TableDefinitions = this.TableDefinitions; - command.TempFilesLocation = this.IntermediateFolder; + var command = new CreateBootstrapperApplicationManifestCommand(section, bundleTuple, orderedFacades, uxPayloadIndex, payloadTuples, this.IntermediateFolder); command.Execute(); - WixBundlePayloadRow baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; - payloads.Add(baManifestPayload); + var baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; + payloadTuples.Add(baManifestPayload.Id.Id, baManifestPayload); } - //foreach (BinderExtension extension in this.Extensions) - //{ - // extension.PostBind(this.Context); - //} +#if TODO + foreach (BinderExtension extension in this.Extensions) + { + extension.PostBind(this.Context); + } +#endif // Create all the containers except the UX container first so the manifest (that goes in the UX container) // can contain all size and hash information about the non-UX containers. - RowDictionary containers = new RowDictionary(this.Output.Tables["WixBundleContainer"]); - - ILookup payloadsByContainer = payloads.Values.ToLookup(p => p.Container); - - int attachedContainerIndex = 1; // count starts at one because UX container is "0". - - IEnumerable uxContainerPayloads = Enumerable.Empty(); - - foreach (WixBundleContainerRow container in containers.Values) + WixBundleContainerTuple uxContainer; + IEnumerable uxPayloads; + IEnumerable containers; { - IEnumerable containerPayloads = payloadsByContainer[container.Id]; - - if (!containerPayloads.Any()) - { - if (container.Id != Compiler.BurnDefaultAttachedContainerId) - { - // TODO: display warning that we're ignoring container that ended up with no paylods in it. - } - } - else if (Compiler.BurnUXContainerId == container.Id) - { - container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name); - container.AttachedContainerIndex = 0; - - // Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first - // in the list since that is the Payload that Burn attempts to load. - List uxPayloads = new List(); - - string baPayloadId = baRow.FieldAsString(0); - - foreach (WixBundlePayloadRow uxPayload in containerPayloads) - { - if (uxPayload.Id == baPayloadId) - { - uxPayloads.Insert(0, uxPayload); - } - else - { - uxPayloads.Add(uxPayload); - } - } + var command = new CreateNonUXContainers(this.BackendHelper, section, bundleApplicationTuple, payloadTuples, this.IntermediateFolder, layoutDirectory, this.DefaultCompressionLevel); + command.Execute(); - uxContainerPayloads = uxPayloads; - } - else - { - container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name); + fileTransfers.AddRange(command.FileTransfers); - // Add detached containers to the list of file transfers. - if (ContainerType.Detached == container.Type) - { - FileTransfer transfer; - if (FileTransfer.TryCreate(container.WorkingPath, Path.Combine(layoutDirectory, container.Name), true, "Container", container.SourceLineNumbers, out transfer)) - { - transfer.Built = true; - fileTransfers.Add(transfer); - } - } - else // update the attached container index. - { - Debug.Assert(ContainerType.Attached == container.Type); + uxContainer = command.UXContainer; + uxPayloads = command.UXContainerPayloads; + containers = command.Containers; + } + + // Create the bundle manifest. + string manifestPath; + { + var executableName = Path.GetFileName(this.OutputPath); - container.AttachedContainerIndex = attachedContainerIndex; - ++attachedContainerIndex; - } + var command = new CreateBurnManifestCommand(this.Messaging, this.BackendExtensions, executableName, section, bundleTuple, containers, chainTuple, orderedFacades, boundaries, uxPayloads, payloadTuples, orderedSearches, catalogs, this.IntermediateFolder); + command.Execute(); - this.CreateContainer(container, containerPayloads, null); - } + manifestPath = command.OutputPath; } - // Create the bundle manifest then UX container. - string manifestPath = Path.Combine(this.IntermediateFolder, "bundle-manifest.xml"); + // Create the UX container. { - var command = new CreateBurnManifestCommand(); - command.BackendExtensions = this.BackendExtensions; - command.Output = this.Output; - - command.BundleInfo = bundleRow; - command.Chain = chainRow; - command.Containers = containers; - command.Catalogs = catalogs; - command.ExecutableName = Path.GetFileName(this.OutputPath); - command.OrderedPackages = orderedFacades; - command.OutputPath = manifestPath; - command.RollbackBoundaries = boundaries; - command.OrderedSearches = orderedSearches; - command.Payloads = payloads; - command.UXContainerPayloads = uxContainerPayloads; + var command = new CreateContainerCommand(manifestPath, uxPayloads, uxContainer.WorkingPath, this.DefaultCompressionLevel); command.Execute(); - } - - WixBundleContainerRow uxContainer = containers[Compiler.BurnUXContainerId]; - this.CreateContainer(uxContainer, uxContainerPayloads, manifestPath); - - // Copy the burn.exe to a writable location then mark it to be moved to its final build location. Note - // that today, the x64 Burn uses the x86 stub. - string stubPlatform = (Platform.X64 == bundleRow.Platform) ? "x86" : bundleRow.Platform.ToString(); - - string stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe"); - string bundleTempPath = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath)); - - Messaging.Instance.OnMessage(WixVerboses.GeneratingBundle(bundleTempPath, stubFile)); - string bundleFilename = Path.GetFileName(this.OutputPath); - if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase)) - { - Messaging.Instance.OnMessage(WixErrors.InsecureBundleFilename(bundleFilename)); + uxContainer.Hash = command.Hash; + uxContainer.Size = command.Size; } - FileTransfer bundleTransfer; - if (FileTransfer.TryCreate(bundleTempPath, this.OutputPath, true, "Bundle", bundleRow.SourceLineNumbers, out bundleTransfer)) { - bundleTransfer.Built = true; - fileTransfers.Add(bundleTransfer); - } + var command = new CreateBundleExeCommand(this.Messaging, this.BackendHelper, this.IntermediateFolder, this.OutputPath, bundleTuple, uxContainer, containers, this.BurnStubPath); + command.Execute(); - File.Copy(stubFile, bundleTempPath, true); - File.SetAttributes(bundleTempPath, FileAttributes.Normal); + fileTransfers.Add(command.Transfer); + } - this.UpdateBurnResources(bundleTempPath, this.OutputPath, bundleRow); +#if TODO + this.Pdb = new Pdb { Output = output }; - // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers - // if they should be attached. - using (BurnWriter writer = BurnWriter.Open(bundleTempPath)) + if (!String.IsNullOrEmpty(this.OutputPdbPath)) { - FileInfo burnStubFile = new FileInfo(bundleTempPath); - writer.InitializeBundleSectionData(burnStubFile.Length, bundleRow.BundleId); - - // Always attach the UX container first - writer.AppendContainer(uxContainer.WorkingPath, BurnWriter.Container.UX); + var trackPdb = this.BackendHelper.TrackFile(this.OutputPdbPath, TrackedFileType.Final); + trackedFiles.Add(trackPdb); - // Now append all other attached containers - foreach (WixBundleContainerRow container in containers.Values) - { - if (ContainerType.Attached == container.Type) - { - // The container was only created if it had payloads. - if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id) - { - writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached); - } - } - } - } - - if (null != this.PdbFile) - { - Pdb pdb = new Pdb(); - pdb.Output = Output; - pdb.Save(this.PdbFile); + this.Pdb.Save(trackPdb.Path); } +#endif +#if TODO // does this need to come back, or do they only need to be in TrackedFiles? + this.ContentFilePaths = payloadTuples.Values.Where(p => p.ContentFile).Select(p => p.FullFileName).ToList(); +#endif this.FileTransfers = fileTransfers; - this.ContentFilePaths = payloads.Values.Where(p => p.ContentFile).Select(p => p.FullFileName).ToList(); - } - - private Table GetRequiredTable(string tableName) - { - Table table = this.Output.Tables[tableName]; - if (null == table || 0 == table.Rows.Count) - { - throw new WixException(WixErrors.MissingBundleInformation(tableName)); - } - - return table; - } - - private Row GetSingleRowTable(string tableName) - { - Table table = this.Output.Tables[tableName]; - if (null == table || 1 != table.Rows.Count) - { - throw new WixException(WixErrors.MissingBundleInformation(tableName)); - } + this.TrackedFiles = trackedFiles; - return table.Rows[0]; + // TODO: Eventually this gets removed + var intermediate = new Intermediate(this.Output.Id, new[] { section }, this.Output.Localizations.ToDictionary(l => l.Culture, StringComparer.OrdinalIgnoreCase), this.Output.EmbedFilePaths); + var trackIntermediate = this.BackendHelper.TrackFile(Path.Combine(this.IntermediateFolder, Path.GetFileName(Path.ChangeExtension(this.OutputPath, "wir"))), TrackedFileType.Intermediate); + intermediate.Save(trackIntermediate.Path); + trackedFiles.Add(trackIntermediate); } - private List OrderSearches() + private IEnumerable OrderSearches(IntermediateSection section) { - Dictionary allSearches = new Dictionary(); - Table wixFileSearchTable = this.Output.Tables["WixFileSearch"]; - if (null != wixFileSearchTable && 0 < wixFileSearchTable.Rows.Count) - { - foreach (Row row in wixFileSearchTable.Rows) - { - WixFileSearchInfo fileSearchInfo = new WixFileSearchInfo(row); - allSearches.Add(fileSearchInfo.Id, fileSearchInfo); - } - } - - Table wixRegistrySearchTable = this.Output.Tables["WixRegistrySearch"]; - if (null != wixRegistrySearchTable && 0 < wixRegistrySearchTable.Rows.Count) - { - foreach (Row row in wixRegistrySearchTable.Rows) - { - WixRegistrySearchInfo registrySearchInfo = new WixRegistrySearchInfo(row); - allSearches.Add(registrySearchInfo.Id, registrySearchInfo); - } - } - - Table wixComponentSearchTable = this.Output.Tables["WixComponentSearch"]; - if (null != wixComponentSearchTable && 0 < wixComponentSearchTable.Rows.Count) - { - foreach (Row row in wixComponentSearchTable.Rows) - { - WixComponentSearchInfo componentSearchInfo = new WixComponentSearchInfo(row); - allSearches.Add(componentSearchInfo.Id, componentSearchInfo); - } - } + var searchesById = section.Tuples + .Where(t => t.Definition.Type == TupleDefinitionType.WixComponentSearch || + t.Definition.Type == TupleDefinitionType.WixFileSearch || + t.Definition.Type == TupleDefinitionType.WixProductSearch || + t.Definition.Type == TupleDefinitionType.WixRegistrySearch) + .ToDictionary(t => t.Id.Id); - Table wixProductSearchTable = this.Output.Tables["WixProductSearch"]; - if (null != wixProductSearchTable && 0 < wixProductSearchTable.Rows.Count) - { - foreach (Row row in wixProductSearchTable.Rows) - { - WixProductSearchInfo productSearchInfo = new WixProductSearchInfo(row); - allSearches.Add(productSearchInfo.Id, productSearchInfo); - } - } + var orderedSearches = new List(searchesById.Keys.Count); - // Merge in the variable/condition info and get the canonical ordering for - // the searches. - List orderedSearches = new List(); - Table wixSearchTable = this.Output.Tables["WixSearch"]; - if (null != wixSearchTable && 0 < wixSearchTable.Rows.Count) + foreach (var searchTuple in section.Tuples.OfType()) { - orderedSearches.Capacity = wixSearchTable.Rows.Count; - foreach (Row row in wixSearchTable.Rows) + if (searchesById.TryGetValue(searchTuple.Id.Id, out var specificSearchTuple)) { - WixSearchInfo searchInfo = allSearches[(string)row[0]]; - searchInfo.AddWixSearchRowInfo(row); - orderedSearches.Add(searchInfo); + orderedSearches.Add(new SearchFacade(searchTuple, specificSearchTuple)); } } @@ -703,9 +495,9 @@ namespace WixToolset.Core.Burn /// /// The package with properties to cache. /// The property cache. - private static void PopulatePackageVariableCache(WixBundlePackageRow package, IDictionary variableCache) + private static void PopulatePackageVariableCache(WixBundlePackageTuple package, IDictionary variableCache) { - string id = package.WixChainItemId; + var id = package.Id.Id; variableCache.Add(String.Concat("packageDescription.", id), package.Description); //variableCache.Add(String.Concat("packageLanguage.", id), package.Language); @@ -714,231 +506,63 @@ namespace WixToolset.Core.Burn variableCache.Add(String.Concat("packageVersion.", id), package.Version); } - private void CreateContainer(WixBundleContainerRow container, IEnumerable containerPayloads, string manifestFile) + private void ResolveBundleInstallScope(IntermediateSection section, WixBundleTuple bundleTuple, IEnumerable facades) { - CreateContainerCommand command = new CreateContainerCommand(); - command.DefaultCompressionLevel = this.DefaultCompressionLevel; - command.Payloads = containerPayloads; - command.ManifestFile = manifestFile; - command.OutputPath = container.WorkingPath; - command.Execute(); - - container.Hash = command.Hash; - container.Size = command.Size; - } + var dependencyTuplesById = section.Tuples.OfType().ToDictionary(t => t.Id.Id); - private void ResolveBundleInstallScope(WixBundleRow bundleInfo, IEnumerable facades) - { - foreach (PackageFacade facade in facades) + foreach (var facade in facades) { - if (bundleInfo.PerMachine && YesNoDefaultType.No == facade.Package.PerMachine) + if (bundleTuple.PerMachine && YesNoDefaultType.No == facade.PackageTuple.PerMachine) { - Messaging.Instance.OnMessage(WixVerboses.SwitchingToPerUserPackage(facade.Package.SourceLineNumbers, facade.Package.WixChainItemId)); + this.Messaging.Write(VerboseMessages.SwitchingToPerUserPackage(facade.PackageTuple.SourceLineNumbers, facade.PackageId)); - bundleInfo.PerMachine = false; + bundleTuple.Attributes &= ~WixBundleAttributes.PerMachine; break; } } - foreach (PackageFacade facade in facades) + foreach (var facade in facades) { // Update package scope from bundle scope if default. - if (YesNoDefaultType.Default == facade.Package.PerMachine) + if (YesNoDefaultType.Default == facade.PackageTuple.PerMachine) { - facade.Package.PerMachine = bundleInfo.PerMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No; + facade.PackageTuple.PerMachine = bundleTuple.PerMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No; } // We will only register packages in the same scope as the bundle. Warn if any packages with providers // are in a different scope and not permanent (permanents typically don't need a ref-count). - if (!bundleInfo.PerMachine && YesNoDefaultType.Yes == facade.Package.PerMachine && !facade.Package.Permanent && 0 < facade.Provides.Count) + if (!bundleTuple.PerMachine && + YesNoDefaultType.Yes == facade.PackageTuple.PerMachine && + !facade.PackageTuple.Permanent && + dependencyTuplesById.ContainsKey(facade.PackageId)) { - Messaging.Instance.OnMessage(WixWarnings.NoPerMachineDependencies(facade.Package.SourceLineNumbers, facade.Package.WixChainItemId)); + this.Messaging.Write(WarningMessages.NoPerMachineDependencies(facade.PackageTuple.SourceLineNumbers, facade.PackageId)); } } } - private void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleRow bundleInfo) + private IEnumerable GetRequiredTuples() where T : IntermediateTuple { - WixToolset.Dtf.Resources.ResourceCollection resources = new WixToolset.Dtf.Resources.ResourceCollection(); - WixToolset.Dtf.Resources.VersionResource version = new WixToolset.Dtf.Resources.VersionResource("#1", 1033); + var tuples = this.Output.Sections.Single().Tuples.OfType().ToList(); - version.Load(bundleTempPath); - resources.Add(version); - - // Ensure the bundle info provides a full four part version. - Version fourPartVersion = new Version(bundleInfo.Version); - int major = (fourPartVersion.Major < 0) ? 0 : fourPartVersion.Major; - int minor = (fourPartVersion.Minor < 0) ? 0 : fourPartVersion.Minor; - int build = (fourPartVersion.Build < 0) ? 0 : fourPartVersion.Build; - int revision = (fourPartVersion.Revision < 0) ? 0 : fourPartVersion.Revision; - - if (UInt16.MaxValue < major || UInt16.MaxValue < minor || UInt16.MaxValue < build || UInt16.MaxValue < revision) - { - throw new WixException(WixErrors.InvalidModuleOrBundleVersion(bundleInfo.SourceLineNumbers, "Bundle", bundleInfo.Version)); - } - - fourPartVersion = new Version(major, minor, build, revision); - version.FileVersion = fourPartVersion; - version.ProductVersion = fourPartVersion; - - WixToolset.Dtf.Resources.VersionStringTable strings = version[1033]; - strings["LegalCopyright"] = bundleInfo.Copyright; - strings["OriginalFilename"] = Path.GetFileName(outputPath); - strings["FileVersion"] = bundleInfo.Version; // string versions do not have to be four parts. - strings["ProductVersion"] = bundleInfo.Version; // string versions do not have to be four parts. - - if (!String.IsNullOrEmpty(bundleInfo.Name)) + if (0 == tuples.Count) { - strings["ProductName"] = bundleInfo.Name; - strings["FileDescription"] = bundleInfo.Name; + throw new WixException(ErrorMessages.MissingBundleInformation(nameof(T))); } - if (!String.IsNullOrEmpty(bundleInfo.Publisher)) - { - strings["CompanyName"] = bundleInfo.Publisher; - } - else - { - strings["CompanyName"] = String.Empty; - } - - if (!String.IsNullOrEmpty(bundleInfo.IconPath)) - { - Dtf.Resources.GroupIconResource iconGroup = new Dtf.Resources.GroupIconResource("#1", 1033); - iconGroup.ReadFromFile(bundleInfo.IconPath); - resources.Add(iconGroup); - - foreach (Dtf.Resources.Resource icon in iconGroup.Icons) - { - resources.Add(icon); - } - } - - if (!String.IsNullOrEmpty(bundleInfo.SplashScreenBitmapPath)) - { - Dtf.Resources.BitmapResource bitmap = new Dtf.Resources.BitmapResource("#1", 1033); - bitmap.ReadFromFile(bundleInfo.SplashScreenBitmapPath); - resources.Add(bitmap); - } - - resources.Save(bundleTempPath); + return tuples; } -//#region DependencyExtension - /// - /// Imports authored dependency providers for each package in the manifest, - /// and generates dependency providers for certain package types that do not - /// have a provider defined. - /// - /// The object for the bundle. - /// An indexed collection of chained packages. - private void ProcessDependencyProviders(Output bundle, IDictionary facades) + private T GetSingleTuple() where T : IntermediateTuple { - // First import any authored dependencies. These may merge with imported provides from MSI packages. - Table wixDependencyProviderTable = bundle.Tables["WixDependencyProvider"]; - if (null != wixDependencyProviderTable && 0 < wixDependencyProviderTable.Rows.Count) - { - // Add package information for each dependency provider authored into the manifest. - foreach (Row wixDependencyProviderRow in wixDependencyProviderTable.Rows) - { - string packageId = (string)wixDependencyProviderRow[1]; - - PackageFacade facade = null; - if (facades.TryGetValue(packageId, out facade)) - { - ProvidesDependency dependency = new ProvidesDependency(wixDependencyProviderRow); - - if (String.IsNullOrEmpty(dependency.Key)) - { - switch (facade.Package.Type) - { - // The WixDependencyExtension allows an empty Key for MSIs and MSPs. - case WixBundlePackageType.Msi: - dependency.Key = facade.MsiPackage.ProductCode; - break; - case WixBundlePackageType.Msp: - dependency.Key = facade.MspPackage.PatchCode; - break; - } - } - - if (String.IsNullOrEmpty(dependency.Version)) - { - dependency.Version = facade.Package.Version; - } - - // If the version is still missing, a version could not be harvested from the package and was not authored. - if (String.IsNullOrEmpty(dependency.Version)) - { - Messaging.Instance.OnMessage(WixErrors.MissingDependencyVersion(facade.Package.WixChainItemId)); - } - - if (String.IsNullOrEmpty(dependency.DisplayName)) - { - dependency.DisplayName = facade.Package.DisplayName; - } + var tuples = this.Output.Sections.Single().Tuples.OfType().ToList(); - if (!facade.Provides.Merge(dependency)) - { - Messaging.Instance.OnMessage(WixErrors.DuplicateProviderDependencyKey(dependency.Key, facade.Package.WixChainItemId)); - } - } - } - } - - // Generate providers for MSI packages that still do not have providers. - foreach (PackageFacade facade in facades.Values) + if (1 != tuples.Count) { - string key = null; - - if (WixBundlePackageType.Msi == facade.Package.Type && 0 == facade.Provides.Count) - { - key = facade.MsiPackage.ProductCode; - } - else if (WixBundlePackageType.Msp == facade.Package.Type && 0 == facade.Provides.Count) - { - key = facade.MspPackage.PatchCode; - } - - if (!String.IsNullOrEmpty(key)) - { - ProvidesDependency dependency = new ProvidesDependency(key, facade.Package.Version, facade.Package.DisplayName, 0); - - if (!facade.Provides.Merge(dependency)) - { - Messaging.Instance.OnMessage(WixErrors.DuplicateProviderDependencyKey(dependency.Key, facade.Package.WixChainItemId)); - } - } + throw new WixException(ErrorMessages.MissingBundleInformation(nameof(T))); } - } - /// - /// Sets the provider key for the bundle. - /// - /// The object for the bundle. - /// The containing the provider key and other information for the bundle. - private void SetBundleProviderKey(Output bundle, WixBundleRow bundleInfo) - { - // From DependencyCommon.cs in the WixDependencyExtension. - const int ProvidesAttributesBundle = 0x10000; - - Table wixDependencyProviderTable = bundle.Tables["WixDependencyProvider"]; - if (null != wixDependencyProviderTable && 0 < wixDependencyProviderTable.Rows.Count) - { - // Search the WixDependencyProvider table for the single bundle provider key. - foreach (Row wixDependencyProviderRow in wixDependencyProviderTable.Rows) - { - object attributes = wixDependencyProviderRow[5]; - if (null != attributes && 0 != (ProvidesAttributesBundle & (int)attributes)) - { - bundleInfo.ProviderKey = (string)wixDependencyProviderRow[2]; - break; - } - } - } - - // Defaults to the bundle ID as the provider key. -#endif + return tuples[0]; } } } -- cgit v1.2.3-55-g6feb