@joebigelow / wix / commits / 3704a554

Change harvested symbols to ref the package payload for remote support.

Sean Hall committed Apr 13, 2022 at 10:14 UTC 3704a5547766581b15690b6535d03568afcfc2a0
22 files changed +461 -161
src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs
+4
@@ -131,6 +131,7 @@ namespace WixToolset.Data
131 WixBundleExePackagePayload,
132 WixBundleExtension,
133 WixBundleHarvestedBundlePackage,
134 + WixBundleHarvestedDependencyProvider,
135 WixBundleHarvestedMsiPackage,
136 WixBundleHarvestedMspPackage,
137 WixBundleMsiFeature,
@@ -589,6 +590,9 @@ namespace WixToolset.Data
590 case SymbolDefinitionType.WixBundleHarvestedBundlePackage:
591 return SymbolDefinitions.WixBundleHarvestedBundlePackage;
592
593 + case SymbolDefinitionType.WixBundleHarvestedDependencyProvider:
594 + return SymbolDefinitions.WixBundleHarvestedDependencyProvider;
595 +
596 case SymbolDefinitionType.WixBundleHarvestedMsiPackage:
597 return SymbolDefinitions.WixBundleHarvestedMsiPackage;
598
src/api/wix/WixToolset.Data/Symbols/WixBundleHarvestedDependencyProviderSymbol.cs new
+93
@@ -0,0 +1,93 @@
1 +// 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.
2 +
3 +namespace WixToolset.Data
4 +{
5 + using WixToolset.Data.Symbols;
6 +
7 + public static partial class SymbolDefinitions
8 + {
9 + public static readonly IntermediateSymbolDefinition WixBundleHarvestedDependencyProvider = new IntermediateSymbolDefinition(
10 + SymbolDefinitionType.WixBundleHarvestedDependencyProvider,
11 + new[]
12 + {
13 + new IntermediateFieldDefinition(nameof(WixBundleHarvestedDependencyProviderSymbolFields.PackagePayloadRef), IntermediateFieldType.String),
14 + new IntermediateFieldDefinition(nameof(WixBundleHarvestedDependencyProviderSymbolFields.Attributes), IntermediateFieldType.Number),
15 + new IntermediateFieldDefinition(nameof(WixBundleHarvestedDependencyProviderSymbolFields.ProviderKey), IntermediateFieldType.String),
16 + new IntermediateFieldDefinition(nameof(WixBundleHarvestedDependencyProviderSymbolFields.Version), IntermediateFieldType.String),
17 + new IntermediateFieldDefinition(nameof(WixBundleHarvestedDependencyProviderSymbolFields.DisplayName), IntermediateFieldType.String),
18 + new IntermediateFieldDefinition(nameof(WixBundleHarvestedDependencyProviderSymbolFields.ProviderAttributes), IntermediateFieldType.Number),
19 + },
20 + typeof(WixDependencyProviderSymbol));
21 + }
22 +}
23 +
24 +namespace WixToolset.Data.Symbols
25 +{
26 + using System;
27 + using WixToolset.Data;
28 +
29 + public enum WixBundleHarvestedDependencyProviderSymbolFields
30 + {
31 + PackagePayloadRef,
32 + Attributes,
33 + ProviderKey,
34 + Version,
35 + DisplayName,
36 + ProviderAttributes,
37 + }
38 +
39 + [Flags]
40 + public enum WixBundleHarvestedDependencyProviderAttributes
41 + {
42 + None = 0x0,
43 + }
44 +
45 + public class WixBundleHarvestedDependencyProviderSymbol : IntermediateSymbol
46 + {
47 + public WixBundleHarvestedDependencyProviderSymbol() : base(SymbolDefinitions.WixBundleHarvestedDependencyProvider, null, null)
48 + {
49 + }
50 +
51 + public WixBundleHarvestedDependencyProviderSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(SymbolDefinitions.WixBundleHarvestedDependencyProvider, sourceLineNumber, id)
52 + {
53 + }
54 +
55 + public IntermediateField this[WixBundleHarvestedDependencyProviderSymbolFields index] => this.Fields[(int)index];
56 +
57 + public string PackagePayloadRef
58 + {
59 + get => this.Fields[(int)WixBundleHarvestedDependencyProviderSymbolFields.PackagePayloadRef].AsString();
60 + set => this.Set((int)WixBundleHarvestedDependencyProviderSymbolFields.PackagePayloadRef, value);
61 + }
62 +
63 + public WixBundleHarvestedDependencyProviderAttributes Attributes
64 + {
65 + get => (WixBundleHarvestedDependencyProviderAttributes)this.Fields[(int)WixBundleHarvestedDependencyProviderSymbolFields.Attributes].AsNumber();
66 + set => this.Set((int)WixBundleHarvestedDependencyProviderSymbolFields.Attributes, (int)value);
67 + }
68 +
69 + public string ProviderKey
70 + {
71 + get => this.Fields[(int)WixBundleHarvestedDependencyProviderSymbolFields.ProviderKey].AsString();
72 + set => this.Set((int)WixBundleHarvestedDependencyProviderSymbolFields.ProviderKey, value);
73 + }
74 +
75 + public string Version
76 + {
77 + get => this.Fields[(int)WixBundleHarvestedDependencyProviderSymbolFields.Version].AsString();
78 + set => this.Set((int)WixBundleHarvestedDependencyProviderSymbolFields.Version, value);
79 + }
80 +
81 + public string DisplayName
82 + {
83 + get => this.Fields[(int)WixBundleHarvestedDependencyProviderSymbolFields.DisplayName].AsString();
84 + set => this.Set((int)WixBundleHarvestedDependencyProviderSymbolFields.DisplayName, value);
85 + }
86 +
87 + public int ProviderAttributes
88 + {
89 + get => this.Fields[(int)WixBundleHarvestedDependencyProviderSymbolFields.ProviderAttributes].AsNumber();
90 + set => this.Set((int)WixBundleHarvestedDependencyProviderSymbolFields.ProviderAttributes, value);
91 + }
92 + }
93 +}
src/api/wix/WixToolset.Data/Symbols/WixBundleMsiFeatureSymbol.cs
+5 -5
@@ -10,7 +10,7 @@ namespace WixToolset.Data
10 SymbolDefinitionType.WixBundleMsiFeature,
11 new[]
12 {
13 - new IntermediateFieldDefinition(nameof(WixBundleMsiFeatureSymbolFields.PackageRef), IntermediateFieldType.String),
13 + new IntermediateFieldDefinition(nameof(WixBundleMsiFeatureSymbolFields.PackagePayloadRef), IntermediateFieldType.String),
14 new IntermediateFieldDefinition(nameof(WixBundleMsiFeatureSymbolFields.Name), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixBundleMsiFeatureSymbolFields.Size), IntermediateFieldType.LargeNumber),
16 new IntermediateFieldDefinition(nameof(WixBundleMsiFeatureSymbolFields.Parent), IntermediateFieldType.String),
@@ -29,7 +29,7 @@ namespace WixToolset.Data.Symbols
29 {
30 public enum WixBundleMsiFeatureSymbolFields
31 {
32 - PackageRef,
32 + PackagePayloadRef,
33 Name,
34 Size,
35 Parent,
@@ -53,10 +53,10 @@ namespace WixToolset.Data.Symbols
53
54 public IntermediateField this[WixBundleMsiFeatureSymbolFields index] => this.Fields[(int)index];
55
56 - public string PackageRef
56 + public string PackagePayloadRef
57 {
58 - get => (string)this.Fields[(int)WixBundleMsiFeatureSymbolFields.PackageRef];
59 - set => this.Set((int)WixBundleMsiFeatureSymbolFields.PackageRef, value);
58 + get => (string)this.Fields[(int)WixBundleMsiFeatureSymbolFields.PackagePayloadRef];
59 + set => this.Set((int)WixBundleMsiFeatureSymbolFields.PackagePayloadRef, value);
60 }
61
62 public string Name
src/api/wix/WixToolset.Data/Symbols/WixBundlePackageRelatedBundleSymbol.cs
+5 -5
@@ -10,7 +10,7 @@ namespace WixToolset.Data
10 SymbolDefinitionType.WixBundlePackageRelatedBundle,
11 new[]
12 {
13 - new IntermediateFieldDefinition(nameof(WixBundlePackageRelatedBundleSymbolFields.PackageRef), IntermediateFieldType.String),
13 + new IntermediateFieldDefinition(nameof(WixBundlePackageRelatedBundleSymbolFields.PackagePayloadRef), IntermediateFieldType.String),
14 new IntermediateFieldDefinition(nameof(WixBundlePackageRelatedBundleSymbolFields.BundleId), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixBundlePackageRelatedBundleSymbolFields.Action), IntermediateFieldType.Number),
16 },
@@ -22,7 +22,7 @@ namespace WixToolset.Data.Symbols
22 {
23 public enum WixBundlePackageRelatedBundleSymbolFields
24 {
25 - PackageRef,
25 + PackagePayloadRef,
26 BundleId,
27 Action,
28 }
@@ -39,10 +39,10 @@ namespace WixToolset.Data.Symbols
39
40 public IntermediateField this[WixBundlePackageRelatedBundleSymbolFields index] => this.Fields[(int)index];
41
42 - public string PackageRef
42 + public string PackagePayloadRef
43 {
44 - get => (string)this.Fields[(int)WixBundlePackageRelatedBundleSymbolFields.PackageRef];
45 - set => this.Set((int)WixBundlePackageRelatedBundleSymbolFields.PackageRef, value);
44 + get => (string)this.Fields[(int)WixBundlePackageRelatedBundleSymbolFields.PackagePayloadRef];
45 + set => this.Set((int)WixBundlePackageRelatedBundleSymbolFields.PackagePayloadRef, value);
46 }
47
48 public string BundleId
src/api/wix/WixToolset.Data/Symbols/WixBundlePatchTargetCodeSymbol.cs
+5 -5
@@ -10,7 +10,7 @@ namespace WixToolset.Data
10 SymbolDefinitionType.WixBundlePatchTargetCode,
11 new[]
12 {
13 - new IntermediateFieldDefinition(nameof(WixBundlePatchTargetCodeSymbolFields.PackageRef), IntermediateFieldType.String),
13 + new IntermediateFieldDefinition(nameof(WixBundlePatchTargetCodeSymbolFields.PackagePayloadRef), IntermediateFieldType.String),
14 new IntermediateFieldDefinition(nameof(WixBundlePatchTargetCodeSymbolFields.TargetCode), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixBundlePatchTargetCodeSymbolFields.Attributes), IntermediateFieldType.Number),
16 new IntermediateFieldDefinition(nameof(WixBundlePatchTargetCodeSymbolFields.Type), IntermediateFieldType.Number),
@@ -25,7 +25,7 @@ namespace WixToolset.Data.Symbols
25
26 public enum WixBundlePatchTargetCodeSymbolFields
27 {
28 - PackageRef,
28 + PackagePayloadRef,
29 TargetCode,
30 Attributes,
31 Type,
@@ -67,10 +67,10 @@ namespace WixToolset.Data.Symbols
67
68 public IntermediateField this[WixBundlePatchTargetCodeSymbolFields index] => this.Fields[(int)index];
69
70 - public string PackageRef
70 + public string PackagePayloadRef
71 {
72 - get => (string)this.Fields[(int)WixBundlePatchTargetCodeSymbolFields.PackageRef];
73 - set => this.Set((int)WixBundlePatchTargetCodeSymbolFields.PackageRef, value);
72 + get => (string)this.Fields[(int)WixBundlePatchTargetCodeSymbolFields.PackagePayloadRef];
73 + set => this.Set((int)WixBundlePatchTargetCodeSymbolFields.PackagePayloadRef, value);
74 }
75
76 public string TargetCode
src/api/wix/WixToolset.Data/Symbols/WixBundleRelatedPackageSymbol.cs
+5 -5
@@ -10,7 +10,7 @@ namespace WixToolset.Data
10 SymbolDefinitionType.WixBundleRelatedPackage,
11 new[]
12 {
13 - new IntermediateFieldDefinition(nameof(WixBundleRelatedPackageSymbolFields.PackageRef), IntermediateFieldType.String),
13 + new IntermediateFieldDefinition(nameof(WixBundleRelatedPackageSymbolFields.PackagePayloadRef), IntermediateFieldType.String),
14 new IntermediateFieldDefinition(nameof(WixBundleRelatedPackageSymbolFields.RelatedId), IntermediateFieldType.String),
15 new IntermediateFieldDefinition(nameof(WixBundleRelatedPackageSymbolFields.MinVersion), IntermediateFieldType.String),
16 new IntermediateFieldDefinition(nameof(WixBundleRelatedPackageSymbolFields.MaxVersion), IntermediateFieldType.String),
@@ -27,7 +27,7 @@ namespace WixToolset.Data.Symbols
27
28 public enum WixBundleRelatedPackageSymbolFields
29 {
30 - PackageRef,
30 + PackagePayloadRef,
31 RelatedId,
32 MinVersion,
33 MaxVersion,
@@ -57,10 +57,10 @@ namespace WixToolset.Data.Symbols
57
58 public IntermediateField this[WixBundleRelatedPackageSymbolFields index] => this.Fields[(int)index];
59
60 - public string PackageRef
60 + public string PackagePayloadRef
61 {
62 - get => (string)this.Fields[(int)WixBundleRelatedPackageSymbolFields.PackageRef];
63 - set => this.Set((int)WixBundleRelatedPackageSymbolFields.PackageRef, value);
62 + get => (string)this.Fields[(int)WixBundleRelatedPackageSymbolFields.PackagePayloadRef];
63 + set => this.Set((int)WixBundleRelatedPackageSymbolFields.PackagePayloadRef, value);
64 }
65
66 public string RelatedId
src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+9 -11
@@ -159,7 +159,7 @@ namespace WixToolset.Core.Burn
159 processedPayloads = new HashSet<string>(payloadSymbols.Keys);
160 }
161
162 - IDictionary<string, PackageFacade> facades;
162 + PackageFacades facades;
163 {
164 var command = new GetPackageFacadesCommand(this.Messaging, chainPackageSymbols, section);
165 command.Execute();
@@ -325,7 +325,7 @@ namespace WixToolset.Core.Burn
325
326 // Determine patches to automatically slipstream.
327 {
328 - var command = new AutomaticallySlipstreamPatchesCommand(section, facades.Values);
328 + var command = new AutomaticallySlipstreamPatchesCommand(this.Messaging, section, facades);
329 command.Execute();
330 }
331
@@ -334,13 +334,11 @@ namespace WixToolset.Core.Burn
334 return;
335 }
336
337 - IEnumerable<PackageFacade> orderedFacades;
337 IEnumerable<WixBundleRollbackBoundarySymbol> boundaries;
338 {
339 var command = new OrderPackagesAndRollbackBoundariesCommand(this.Messaging, section, facades);
340 command.Execute();
341
343 - orderedFacades = command.OrderedPackageFacades;
342 boundaries = command.UsedRollbackBoundaries;
343 }
344
@@ -351,7 +349,7 @@ namespace WixToolset.Core.Burn
349 }
350
351 {
354 - var command = new ProcessDependencyProvidersCommand(this.Messaging, section, facades);
352 + var command = new ProcessDependencyProvidersCommand(this.ServiceProvider, section, facades);
353 command.Execute();
354
355 if (!String.IsNullOrEmpty(command.BundleProviderKey))
@@ -361,7 +359,7 @@ namespace WixToolset.Core.Burn
359 }
360
361 // Update the bundle per-machine/per-user scope based on the chained packages.
364 - this.ResolveBundleInstallScope(section, bundleSymbol, orderedFacades);
362 + this.ResolveBundleInstallScope(section, bundleSymbol, facades.OrderedValues);
363
364 var softwareTags = section.Symbols.OfType<WixBundleTagSymbol>().ToList();
365 if (softwareTags.Any())
@@ -370,7 +368,7 @@ namespace WixToolset.Core.Burn
368 command.Execute();
369 }
370
373 - this.DetectDuplicateCacheIds(facades);
371 + this.DetectDuplicateCacheIds(facades.Values);
372
373 if (this.Messaging.EncounteredError)
374 {
@@ -413,7 +411,7 @@ namespace WixToolset.Core.Burn
411 // Generate the core-defined BA manifest tables...
412 string baManifestPath;
413 {
416 - var command = new CreateBootstrapperApplicationManifestCommand(section, bundleSymbol, boundaries, orderedFacades, uxPayloadIndex, payloadSymbols, packagesPayloads, this.IntermediateFolder, this.InternalBurnBackendHelper);
414 + var command = new CreateBootstrapperApplicationManifestCommand(section, bundleSymbol, boundaries, facades, uxPayloadIndex, payloadSymbols, packagesPayloads, this.IntermediateFolder, this.InternalBurnBackendHelper);
415 command.Execute();
416
417 var baManifestPayload = command.BootstrapperApplicationManifestPayloadRow;
@@ -480,7 +478,7 @@ namespace WixToolset.Core.Burn
478 {
479 var executableName = Path.GetFileName(this.OutputPath);
480
483 - var command = new CreateBurnManifestCommand(executableName, section, bundleSymbol, containers.Values, chainSymbol, orderedFacades, boundaries, uxPayloads, payloadSymbols, packagesPayloads, orderedSearches, this.IntermediateFolder);
481 + var command = new CreateBurnManifestCommand(executableName, section, bundleSymbol, containers.Values, chainSymbol, facades, boundaries, uxPayloads, payloadSymbols, packagesPayloads, orderedSearches, this.IntermediateFolder);
482 command.Execute();
483
484 manifestPath = command.OutputPath;
@@ -637,11 +635,11 @@ namespace WixToolset.Core.Burn
635 }
636 }
637
640 - private void DetectDuplicateCacheIds(IDictionary<string, PackageFacade> facades)
638 + private void DetectDuplicateCacheIds(IEnumerable<PackageFacade> facades)
639 {
640 var duplicateCacheIdDetector = new Dictionary<string, WixBundlePackageSymbol>();
641
644 - foreach (var facade in facades.Values)
642 + foreach (var facade in facades)
643 {
644 if (duplicateCacheIdDetector.TryGetValue(facade.PackageSymbol.CacheId, out var collisionPackage))
645 {
src/wix/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs
+1
@@ -71,6 +71,7 @@ namespace WixToolset.Core.Burn.Bind
71 case SymbolDefinitionType.WixBundleExePackagePayload:
72 case SymbolDefinitionType.WixBundleExtension:
73 case SymbolDefinitionType.WixBundleHarvestedBundlePackage:
74 + case SymbolDefinitionType.WixBundleHarvestedDependencyProvider:
75 case SymbolDefinitionType.WixBundleHarvestedMsiPackage:
76 case SymbolDefinitionType.WixBundleHarvestedMspPackage:
77 case SymbolDefinitionType.WixBundleMsiFeature:
src/wix/WixToolset.Core.Burn/Bind/ProcessDependencyProvidersCommand.cs
+42 -7
@@ -12,11 +12,12 @@ namespace WixToolset.Core.Burn.Bind
12
13 internal class ProcessDependencyProvidersCommand
14 {
15 - public ProcessDependencyProvidersCommand(IMessaging messaging, IntermediateSection section, IDictionary<string, PackageFacade> facades)
15 + public ProcessDependencyProvidersCommand(IServiceProvider serviceProvider, IntermediateSection section, PackageFacades facades)
16 {
17 - this.Messaging = messaging;
18 - this.Section = section;
17 + this.Messaging = serviceProvider.GetService<IMessaging>();
18 + this.BackendHelper = serviceProvider.GetService<IBackendHelper>();
19
20 + this.Section = section;
21 this.Facades = facades;
22 }
23
@@ -24,9 +25,11 @@ namespace WixToolset.Core.Burn.Bind
25
26 private IMessaging Messaging { get; }
27
28 + private IBackendHelper BackendHelper { get; }
29 +
30 private IntermediateSection Section { get; }
31
29 - private IDictionary<string, PackageFacade> Facades { get; }
32 + private PackageFacades Facades { get; }
33
34 /// <summary>
35 /// Sets the explicitly provided bundle provider key, if provided. And...
@@ -36,23 +39,29 @@ namespace WixToolset.Core.Burn.Bind
39 /// </summary>
40 public void Execute()
41 {
42 + this.ProcessHarvestedProviders();
43 +
44 var dependencySymbols = this.Section.Symbols.OfType<WixDependencyProviderSymbol>();
45
46 foreach (var dependency in dependencySymbols)
47 {
48 // Sets the provider key for the bundle, if it is not set already.
44 - if (String.IsNullOrEmpty(this.BundleProviderKey))
49 + if (dependency.Bundle)
50 {
46 - if (dependency.Bundle)
51 + if (String.IsNullOrEmpty(this.BundleProviderKey))
52 {
53 this.BundleProviderKey = dependency.ProviderKey;
54 }
55 + else
56 + {
57 + this.Messaging.Write(BurnBackendErrors.BundleMultipleProviders(dependency.SourceLineNumbers, dependency.ProviderKey, this.BundleProviderKey));
58 + }
59 }
60
61 // Import any authored dependencies. These may merge with imported provides from MSI packages.
62 var packageId = dependency.ParentRef;
63
55 - if (this.Facades.TryGetValue(packageId, out var facade))
64 + if (this.Facades.TryGetFacadeByPackageId(packageId, out var facade))
65 {
66 if (String.IsNullOrEmpty(dependency.ProviderKey))
67 {
@@ -142,5 +151,31 @@ namespace WixToolset.Core.Burn.Bind
151
152 return dependencySymbolsByPackageId;
153 }
154 +
155 + private void ProcessHarvestedProviders()
156 + {
157 + var harvestedDependencies = this.Section.Symbols.OfType<WixBundleHarvestedDependencyProviderSymbol>().ToList();
158 + foreach (var harvestedDependency in harvestedDependencies)
159 + {
160 + if (!this.Facades.TryGetFacadesByPackagePayloadId(harvestedDependency.PackagePayloadRef, out var facades))
161 + {
162 + this.Messaging.Write(ErrorMessages.IdentifierNotFound("Package.PayloadRef", harvestedDependency.PackagePayloadRef));
163 + continue;
164 + }
165 +
166 + foreach (var facade in facades)
167 + {
168 + var depId = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", facade.PackageId, harvestedDependency.Id.Id));
169 + this.Section.AddSymbol(new WixDependencyProviderSymbol(harvestedDependency.SourceLineNumbers, depId)
170 + {
171 + ParentRef = facade.PackageId,
172 + ProviderKey = harvestedDependency.ProviderKey,
173 + Version = harvestedDependency.Version,
174 + DisplayName = harvestedDependency.DisplayName,
175 + Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported | (WixDependencyProviderAttributes)harvestedDependency.ProviderAttributes,
176 + });
177 + }
178 + }
179 + }
180 }
181 }
src/wix/WixToolset.Core.Burn/Bundles/AutomaticallySlipstreamPatchesCommand.cs
+24 -15
@@ -7,18 +7,22 @@ namespace WixToolset.Core.Burn.Bundles
7 using System.Linq;
8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
10 + using WixToolset.Extensibility.Services;
11
12 internal class AutomaticallySlipstreamPatchesCommand
13 {
13 - public AutomaticallySlipstreamPatchesCommand(IntermediateSection section, ICollection<PackageFacade> packageFacades)
14 + public AutomaticallySlipstreamPatchesCommand(IMessaging messaging, IntermediateSection section, PackageFacades packageFacades)
15 {
16 + this.Messaging = messaging;
17 this.Section = section;
18 this.PackageFacades = packageFacades;
19 }
20
21 + private IMessaging Messaging { get; }
22 +
23 private IntermediateSection Section { get; }
24
21 - private IEnumerable<PackageFacade> PackageFacades { get; }
25 + private PackageFacades PackageFacades { get; }
26
27 public void Execute()
28 {
@@ -26,7 +30,7 @@ namespace WixToolset.Core.Burn.Bundles
30 var targetsProductCode = new Dictionary<string, List<WixBundlePatchTargetCodeSymbol>>();
31 var targetsUpgradeCode = new Dictionary<string, List<WixBundlePatchTargetCodeSymbol>>();
32
29 - foreach (var facade in this.PackageFacades)
33 + foreach (var facade in this.PackageFacades.Values)
34 {
35 // Keep track of all MSI packages.
36 if (facade.SpecificPackageSymbol is WixBundleMsiPackageSymbol msiPackage)
@@ -37,7 +41,7 @@ namespace WixToolset.Core.Burn.Bundles
41 {
42 var patchTargetCodeSymbols = this.Section.Symbols
43 .OfType<WixBundlePatchTargetCodeSymbol>()
40 - .Where(r => r.PackageRef == facade.PackageId);
44 + .Where(r => r.PackagePayloadRef == facade.PackageSymbol.PayloadRef);
45
46 // Index target ProductCodes and UpgradeCodes for slipstreamed MSPs.
47 foreach (var symbol in patchTargetCodeSymbols)
@@ -89,22 +93,27 @@ namespace WixToolset.Core.Burn.Bundles
93 }
94 }
95
92 - private bool TryAddSlipstreamSymbol(HashSet<string> slipstreamMspIds, WixBundleMsiPackageSymbol msiPackage, WixBundlePatchTargetCodeSymbol patchTargetCode)
96 + private void TryAddSlipstreamSymbol(HashSet<string> slipstreamMspIds, WixBundleMsiPackageSymbol msiPackage, WixBundlePatchTargetCodeSymbol patchTargetCode)
97 {
94 - var id = new Identifier(AccessModifier.Section, msiPackage.Id.Id, patchTargetCode.PackageRef);
98 + if (!this.PackageFacades.TryGetFacadesByPackagePayloadId(patchTargetCode.PackagePayloadRef, out var packageFacades))
99 + {
100 + this.Messaging.Write(ErrorMessages.IdentifierNotFound("Package.PayloadRef", patchTargetCode.PackagePayloadRef));
101 + return;
102 + }
103
96 - if (slipstreamMspIds.Add(id.Id))
104 + foreach (var packageFacade in packageFacades)
105 {
98 - this.Section.AddSymbol(new WixBundleSlipstreamMspSymbol(patchTargetCode.SourceLineNumbers)
99 - {
100 - TargetPackageRef = msiPackage.Id.Id,
101 - MspPackageRef = patchTargetCode.PackageRef,
102 - });
106 + var id = new Identifier(AccessModifier.Section, msiPackage.Id.Id, packageFacade.PackageId);
107
104 - return true;
108 + if (slipstreamMspIds.Add(id.Id))
109 + {
110 + this.Section.AddSymbol(new WixBundleSlipstreamMspSymbol(patchTargetCode.SourceLineNumbers)
111 + {
112 + TargetPackageRef = msiPackage.Id.Id,
113 + MspPackageRef = packageFacade.PackageId,
114 + });
115 + }
116 }
106 -
107 - return false;
117 }
118 }
119 }
src/wix/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
+37 -24
@@ -15,12 +15,12 @@ namespace WixToolset.Core.Burn.Bundles
15
16 internal class CreateBootstrapperApplicationManifestCommand
17 {
18 - public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable<WixBundleRollbackBoundarySymbol> boundaries, IEnumerable<PackageFacade> chainPackages, int lastUXPayloadIndex, Dictionary<string, WixBundlePayloadSymbol> payloadSymbols, Dictionary<string, Dictionary<string, WixBundlePayloadSymbol>> packagesPayloads, string intermediateFolder, IInternalBurnBackendHelper internalBurnBackendHelper)
18 + public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable<WixBundleRollbackBoundarySymbol> boundaries, PackageFacades packageFacades, int lastUXPayloadIndex, Dictionary<string, WixBundlePayloadSymbol> payloadSymbols, Dictionary<string, Dictionary<string, WixBundlePayloadSymbol>> packagesPayloads, string intermediateFolder, IInternalBurnBackendHelper internalBurnBackendHelper)
19 {
20 this.Section = section;
21 this.BundleSymbol = bundleSymbol;
22 this.RollbackBoundaries = boundaries;
23 - this.ChainPackages = chainPackages;
23 + this.PackagesFacades = packageFacades;
24 this.LastUXPayloadIndex = lastUXPayloadIndex;
25 this.Payloads = payloadSymbols;
26 this.PackagesPayloads = packagesPayloads;
@@ -34,7 +34,7 @@ namespace WixToolset.Core.Burn.Bundles
34
35 private IEnumerable<WixBundleRollbackBoundarySymbol> RollbackBoundaries { get; }
36
37 - private IEnumerable<PackageFacade> ChainPackages { get; }
37 + private PackageFacades PackagesFacades { get; }
38
39 private IInternalBurnBackendHelper InternalBurnBackendHelper { get; }
40
@@ -141,7 +141,7 @@ namespace WixToolset.Core.Burn.Bundles
141
142 private void WritePackageInfo(XmlTextWriter writer)
143 {
144 - foreach (var package in this.ChainPackages)
144 + foreach (var package in this.PackagesFacades.OrderedValues)
145 {
146 if (!this.PackagesPayloads.TryGetValue(package.PackageId, out var payloads))
147 {
@@ -229,33 +229,46 @@ namespace WixToolset.Core.Burn.Bundles
229
230 foreach (var featureSymbol in featureSymbols)
231 {
232 - writer.WriteStartElement("WixPackageFeatureInfo");
233 -
234 - writer.WriteAttributeString("Package", featureSymbol.PackageRef);
235 - writer.WriteAttributeString("Feature", featureSymbol.Name);
236 - writer.WriteAttributeString("Size", featureSymbol.Size.ToString(CultureInfo.InvariantCulture));
237 -
238 - if (!String.IsNullOrEmpty(featureSymbol.Parent))
232 + if (!this.PackagesFacades.TryGetFacadesByPackagePayloadId(featureSymbol.PackagePayloadRef, out var facades))
233 {
240 - writer.WriteAttributeString("Parent", featureSymbol.Parent);
234 + continue;
235 }
236
243 - if (!String.IsNullOrEmpty(featureSymbol.Title))
237 + foreach (var facade in facades)
238 {
245 - writer.WriteAttributeString("Title", featureSymbol.Title);
246 - }
239 + if (!(facade.SpecificPackageSymbol is WixBundleMsiPackageSymbol msiPackage) || !msiPackage.EnableFeatureSelection)
240 + {
241 + continue;
242 + }
243
248 - if (!String.IsNullOrEmpty(featureSymbol.Description))
249 - {
250 - writer.WriteAttributeString("Description", featureSymbol.Description);
251 - }
244 + writer.WriteStartElement("WixPackageFeatureInfo");
245
253 - writer.WriteAttributeString("Display", featureSymbol.Display.ToString(CultureInfo.InvariantCulture));
254 - writer.WriteAttributeString("Level", featureSymbol.Level.ToString(CultureInfo.InvariantCulture));
255 - writer.WriteAttributeString("Directory", featureSymbol.Directory);
256 - writer.WriteAttributeString("Attributes", featureSymbol.Attributes.ToString(CultureInfo.InvariantCulture));
246 + writer.WriteAttributeString("Package", facade.PackageId);
247 + writer.WriteAttributeString("Feature", featureSymbol.Name);
248 + writer.WriteAttributeString("Size", featureSymbol.Size.ToString(CultureInfo.InvariantCulture));
249
258 - writer.WriteEndElement();
250 + if (!String.IsNullOrEmpty(featureSymbol.Parent))
251 + {
252 + writer.WriteAttributeString("Parent", featureSymbol.Parent);
253 + }
254 +
255 + if (!String.IsNullOrEmpty(featureSymbol.Title))
256 + {
257 + writer.WriteAttributeString("Title", featureSymbol.Title);
258 + }
259 +
260 + if (!String.IsNullOrEmpty(featureSymbol.Description))
261 + {
262 + writer.WriteAttributeString("Description", featureSymbol.Description);
263 + }
264 +
265 + writer.WriteAttributeString("Display", featureSymbol.Display.ToString(CultureInfo.InvariantCulture));
266 + writer.WriteAttributeString("Level", featureSymbol.Level.ToString(CultureInfo.InvariantCulture));
267 + writer.WriteAttributeString("Directory", featureSymbol.Directory);
268 + writer.WriteAttributeString("Attributes", featureSymbol.Attributes.ToString(CultureInfo.InvariantCulture));
269 +
270 + writer.WriteEndElement();
271 + }
272 }
273 }
274
src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+27 -22
@@ -18,14 +18,14 @@ namespace WixToolset.Core.Burn.Bundles
18
19 internal class CreateBurnManifestCommand
20 {
21 - public CreateBurnManifestCommand(string executableName, IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable<WixBundleContainerSymbol> containers, WixChainSymbol chainSymbol, IEnumerable<PackageFacade> orderedPackages, IEnumerable<WixBundleRollbackBoundarySymbol> boundaries, IEnumerable<WixBundlePayloadSymbol> uxPayloads, Dictionary<string, WixBundlePayloadSymbol> allPayloadsById, Dictionary<string, Dictionary<string, WixBundlePayloadSymbol>> packagesPayloads, IEnumerable<ISearchFacade> orderedSearches, string intermediateFolder)
21 + public CreateBurnManifestCommand(string executableName, IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable<WixBundleContainerSymbol> containers, WixChainSymbol chainSymbol, PackageFacades packageFacades, IEnumerable<WixBundleRollbackBoundarySymbol> boundaries, IEnumerable<WixBundlePayloadSymbol> uxPayloads, Dictionary<string, WixBundlePayloadSymbol> allPayloadsById, Dictionary<string, Dictionary<string, WixBundlePayloadSymbol>> packagesPayloads, IEnumerable<ISearchFacade> orderedSearches, string intermediateFolder)
22 {
23 this.ExecutableName = executableName;
24 this.Section = section;
25 this.BundleSymbol = bundleSymbol;
26 this.Chain = chainSymbol;
27 this.Containers = containers;
28 - this.OrderedPackages = orderedPackages;
28 + this.PackageFacades = packageFacades;
29 this.RollbackBoundaries = boundaries;
30 this.UXContainerPayloads = uxPayloads;
31 this.Payloads = allPayloadsById;
@@ -46,7 +46,7 @@ namespace WixToolset.Core.Burn.Bundles
46
47 private IEnumerable<WixBundleRollbackBoundarySymbol> RollbackBoundaries { get; }
48
49 - private IEnumerable<PackageFacade> OrderedPackages { get; }
49 + private PackageFacades PackageFacades { get; }
50
51 private IEnumerable<ISearchFacade> OrderedSearches { get; }
52
@@ -316,11 +316,11 @@ namespace WixToolset.Core.Burn.Bundles
316 }
317
318 // Index a few tables by package.
319 - var targetCodesByPatch = this.Section.Symbols.OfType<WixBundlePatchTargetCodeSymbol>().ToLookup(r => r.PackageRef);
320 - var msiFeaturesByPackage = this.Section.Symbols.OfType<WixBundleMsiFeatureSymbol>().ToLookup(r => r.PackageRef);
319 + var targetCodesByPackagePayload = this.Section.Symbols.OfType<WixBundlePatchTargetCodeSymbol>().ToLookup(r => r.PackagePayloadRef);
320 + var msiFeaturesByPackagePayload = this.Section.Symbols.OfType<WixBundleMsiFeatureSymbol>().ToLookup(r => r.PackagePayloadRef);
321 var msiPropertiesByPackage = this.Section.Symbols.OfType<WixBundleMsiPropertySymbol>().ToLookup(r => r.PackageRef);
322 - var relatedBundlesByPackage = this.Section.Symbols.OfType<WixBundlePackageRelatedBundleSymbol>().ToLookup(r => r.PackageRef);
323 - var relatedPackagesByPackage = this.Section.Symbols.OfType<WixBundleRelatedPackageSymbol>().ToLookup(r => r.PackageRef);
322 + var relatedBundlesByPackagePayload = this.Section.Symbols.OfType<WixBundlePackageRelatedBundleSymbol>().ToLookup(r => r.PackagePayloadRef);
323 + var relatedPackagesByPackagePayload = this.Section.Symbols.OfType<WixBundleRelatedPackageSymbol>().ToLookup(r => r.PackagePayloadRef);
324 var slipstreamMspsByPackage = this.Section.Symbols.OfType<WixBundleSlipstreamMspSymbol>().ToLookup(r => r.TargetPackageRef);
325 var exitCodesByPackage = this.Section.Symbols.OfType<WixBundlePackageExitCodeSymbol>().ToLookup(r => r.ChainPackageId);
326 var commandLinesByPackage = this.Section.Symbols.OfType<WixBundlePackageCommandLineSymbol>().ToLookup(r => r.WixBundlePackageRef);
@@ -331,8 +331,10 @@ namespace WixToolset.Core.Burn.Bundles
331 // Build up the list of target codes from all the MSPs in the chain.
332 var targetCodes = new List<WixBundlePatchTargetCodeSymbol>();
333
334 - foreach (var package in this.OrderedPackages)
334 + foreach (var package in this.PackageFacades.OrderedValues)
335 {
336 + var packagePayloadId = package.PackageSymbol.PayloadRef;
337 +
338 writer.WriteStartElement(String.Format(CultureInfo.InvariantCulture, "{0}Package", package.PackageSymbol.Type));
339
340 writer.WriteAttributeString("Id", package.PackageId);
@@ -425,6 +427,19 @@ namespace WixToolset.Core.Burn.Bundles
427 {
428 writer.WriteAttributeString("UpgradeCode", msiPackage.UpgradeCode);
429 }
430 +
431 + // If feature selection is enabled, represent the Feature table in the manifest.
432 + if (msiPackage.EnableFeatureSelection)
433 + {
434 + var packageMsiFeatures = msiFeaturesByPackagePayload[packagePayloadId];
435 +
436 + foreach (var feature in packageMsiFeatures)
437 + {
438 + writer.WriteStartElement("MsiFeature");
439 + writer.WriteAttributeString("Id", feature.Name);
440 + writer.WriteEndElement();
441 + }
442 + }
443 }
444 else if (package.SpecificPackageSymbol is WixBundleMspPackageSymbol mspPackage) // MSP
445 {
@@ -435,7 +450,7 @@ namespace WixToolset.Core.Burn.Bundles
450 // product codes, add the patch list to the overall list.
451 if (null != targetCodes)
452 {
438 - foreach (var patchTargetCode in targetCodesByPatch[mspPackage.Id.Id])
453 + foreach (var patchTargetCode in targetCodesByPackagePayload[packagePayloadId])
454 {
455 if (patchTargetCode.Type == WixBundlePatchTargetCodeType.Unspecified)
456 {
@@ -453,15 +468,6 @@ namespace WixToolset.Core.Burn.Bundles
468 writer.WriteAttributeString("KB", msuPackage.MsuKB);
469 }
470
456 - var packageMsiFeatures = msiFeaturesByPackage[package.PackageId];
457 -
458 - foreach (var feature in packageMsiFeatures)
459 - {
460 - writer.WriteStartElement("MsiFeature");
461 - writer.WriteAttributeString("Id", feature.Name);
462 - writer.WriteEndElement();
463 - }
464 -
471 var packageMsiProperties = msiPropertiesByPackage[package.PackageId];
472
473 foreach (var msiProperty in packageMsiProperties)
@@ -536,14 +542,14 @@ namespace WixToolset.Core.Burn.Bundles
542
543 if (dependency.Imported)
544 {
539 - // The package dependency was explicitly authored into the manifest.
545 + // The package dependency was harvested from the package.
546 writer.WriteAttributeString("Imported", "yes");
547 }
548
549 writer.WriteEndElement();
550 }
551
546 - var packageRelatedBundles = relatedBundlesByPackage[package.PackageId];
552 + var packageRelatedBundles = relatedBundlesByPackagePayload[packagePayloadId];
553
554 foreach (var relatedBundle in packageRelatedBundles)
555 {
@@ -553,7 +559,7 @@ namespace WixToolset.Core.Burn.Bundles
559 writer.WriteEndElement();
560 }
561
556 - var packageRelatedPackages = relatedPackagesByPackage[package.PackageId];
562 + var packageRelatedPackages = relatedPackagesByPackagePayload[packagePayloadId];
563
564 foreach (var related in packageRelatedPackages)
565 {
@@ -587,7 +593,6 @@ namespace WixToolset.Core.Burn.Bundles
593 }
594
595 // Write any contained Payloads with the PackagePayload being first
590 - var packagePayloadId = package.PackageSymbol.PayloadRef;
596 writer.WriteStartElement("PayloadRef");
597 writer.WriteAttributeString("Id", packagePayloadId);
598 writer.WriteEndElement();
src/wix/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs
+8 -7
@@ -23,7 +23,7 @@ namespace WixToolset.Core.Burn.Bundles
23
24 private IntermediateSection Section { get; }
25
26 - public IDictionary<string, PackageFacade> PackageFacades { get; private set; }
26 + public PackageFacades PackageFacades { get; private set; }
27
28 public void Execute()
29 {
@@ -39,7 +39,7 @@ namespace WixToolset.Core.Burn.Bundles
39 var mspPackagePayloads = this.Section.Symbols.OfType<WixBundleMspPackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
40 var msuPackagePayloads = this.Section.Symbols.OfType<WixBundleMsuPackagePayloadSymbol>().ToDictionary(t => t.Id.Id);
41
42 - var facades = new Dictionary<string, PackageFacade>();
42 + var facades = new PackageFacades();
43
44 foreach (var package in this.ChainPackageSymbols)
45 {
@@ -135,6 +135,7 @@ namespace WixToolset.Core.Burn.Bundles
135 if (packagePayload == null)
136 {
137 this.Messaging.Write(ErrorMessages.MissingPackagePayload(package.SourceLineNumbers, id, package.Type.ToString()));
138 + continue;
139 }
140 else
141 {
@@ -146,7 +147,7 @@ namespace WixToolset.Core.Burn.Bundles
147 case WixBundlePackageType.Bundle:
148 if (bundlePackages.TryGetValue(id, out var bundlePackage))
149 {
149 - facades.Add(id, new PackageFacade(package, bundlePackage));
150 + facades.Add(new PackageFacade(package, bundlePackage));
151 }
152 else
153 {
@@ -157,7 +158,7 @@ namespace WixToolset.Core.Burn.Bundles
158 case WixBundlePackageType.Exe:
159 if (exePackages.TryGetValue(id, out var exePackage))
160 {
160 - facades.Add(id, new PackageFacade(package, exePackage));
161 + facades.Add(new PackageFacade(package, exePackage));
162 }
163 else
164 {
@@ -168,7 +169,7 @@ namespace WixToolset.Core.Burn.Bundles
169 case WixBundlePackageType.Msi:
170 if (msiPackages.TryGetValue(id, out var msiPackage))
171 {
171 - facades.Add(id, new PackageFacade(package, msiPackage));
172 + facades.Add(new PackageFacade(package, msiPackage));
173 }
174 else
175 {
@@ -179,7 +180,7 @@ namespace WixToolset.Core.Burn.Bundles
180 case WixBundlePackageType.Msp:
181 if (mspPackages.TryGetValue(id, out var mspPackage))
182 {
182 - facades.Add(id, new PackageFacade(package, mspPackage));
183 + facades.Add(new PackageFacade(package, mspPackage));
184 }
185 else
186 {
@@ -190,7 +191,7 @@ namespace WixToolset.Core.Burn.Bundles
191 case WixBundlePackageType.Msu:
192 if (msuPackages.TryGetValue(id, out var msuPackage))
193 {
193 - facades.Add(id, new PackageFacade(package, msuPackage));
194 + facades.Add(new PackageFacade(package, msuPackage));
195 }
196 else
197 {
src/wix/WixToolset.Core.Burn/Bundles/OrderPackagesAndRollbackBoundariesCommand.cs
+5 -9
@@ -12,7 +12,7 @@ namespace WixToolset.Core.Burn.Bundles
12
13 internal class OrderPackagesAndRollbackBoundariesCommand
14 {
15 - public OrderPackagesAndRollbackBoundariesCommand(IMessaging messaging, IntermediateSection section, IDictionary<string, PackageFacade> packageFacades)
15 + public OrderPackagesAndRollbackBoundariesCommand(IMessaging messaging, IntermediateSection section, PackageFacades packageFacades)
16 {
17 this.Messaging = messaging;
18 this.Section = section;
@@ -23,9 +23,7 @@ namespace WixToolset.Core.Burn.Bundles
23
24 private IntermediateSection Section { get; }
25
26 - private IDictionary<string, PackageFacade> PackageFacades { get; }
27 -
28 - public IEnumerable<PackageFacade> OrderedPackageFacades { get; private set; }
26 + private PackageFacades PackageFacades { get; }
27
28 public IEnumerable<WixBundleRollbackBoundarySymbol> UsedRollbackBoundaries { get; private set; }
29
@@ -34,7 +32,6 @@ namespace WixToolset.Core.Burn.Bundles
32 var groupSymbols = this.Section.Symbols.OfType<WixGroupSymbol>().ToList();
33 var boundariesById = this.Section.Symbols.OfType<WixBundleRollbackBoundarySymbol>().ToDictionary(b => b.Id.Id);
34
37 - var orderedFacades = new List<PackageFacade>();
35 var usedBoundaries = new List<WixBundleRollbackBoundarySymbol>();
36
37 // Process the chain of packages to add them in the correct order
@@ -55,7 +52,7 @@ namespace WixToolset.Core.Burn.Bundles
52 {
53 if (ComplexReferenceChildType.Package == groupSymbol.ChildType && ComplexReferenceParentType.PackageGroup == groupSymbol.ParentType && BurnConstants.BundleChainPackageGroupId == groupSymbol.ParentId)
54 {
58 - if (this.PackageFacades.TryGetValue(groupSymbol.ChildId, out var facade))
55 + if (this.PackageFacades.TryGetFacadeByPackageId(groupSymbol.ChildId, out var facade))
56 {
57 var insideMsiTransaction = lastRollbackBoundary.Transaction;
58
@@ -102,7 +99,7 @@ namespace WixToolset.Core.Burn.Bundles
99 }
100 }
101
105 - orderedFacades.Add(facade);
102 + this.PackageFacades.AddOrdered(facade);
103 }
104 else // must be a rollback boundary.
105 {
@@ -158,7 +155,7 @@ namespace WixToolset.Core.Burn.Bundles
155 string previousRollbackBoundaryId = null;
156 PackageFacade previousFacade = null;
157
161 - foreach (var package in orderedFacades)
158 + foreach (var package in this.PackageFacades.OrderedValues)
159 {
160 if (null != package.PackageSymbol.RollbackBoundaryRef)
161 {
@@ -178,7 +175,6 @@ namespace WixToolset.Core.Burn.Bundles
175 previousFacade.PackageSymbol.RollbackBoundaryBackwardRef = previousRollbackBoundaryId;
176 }
177
181 - this.OrderedPackageFacades = orderedFacades;
178 this.UsedRollbackBoundaries = usedBoundaries;
179 }
180 }
src/wix/WixToolset.Core.Burn/Bundles/PackageFacades.cs new
+54
@@ -0,0 +1,54 @@
1 +// 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.
2 +
3 +namespace WixToolset.Core.Burn.Bundles
4 +{
5 + using System.Collections.Generic;
6 + using System.Linq;
7 + using WixToolset.Data;
8 +
9 + internal class PackageFacades
10 + {
11 + private Dictionary<string, PackageFacade> FacadesByPackageId { get; } = new Dictionary<string, PackageFacade>();
12 +
13 + private Dictionary<string, List<PackageFacade>> FacadesByPackagePayloadId { get; } = new Dictionary<string, List<PackageFacade>>();
14 +
15 + private List<PackageFacade> OrderedFacades { get; } = new List<PackageFacade>();
16 +
17 + public void Add(PackageFacade item)
18 + {
19 + this.FacadesByPackageId.Add(item.PackageId, item);
20 +
21 + if (!this.FacadesByPackagePayloadId.TryGetValue(item.PackageSymbol.PayloadRef, out var facades))
22 + {
23 + facades = new List<PackageFacade>();
24 + this.FacadesByPackagePayloadId.Add(item.PackageSymbol.PayloadRef, facades);
25 + }
26 +
27 + facades.Add(item);
28 + }
29 +
30 + public void AddOrdered(PackageFacade item)
31 + {
32 + if (!this.FacadesByPackageId.ContainsKey(item.PackageId))
33 + {
34 + throw new WixException("Ordered PackageFacade must already exist");
35 + }
36 +
37 + this.OrderedFacades.Add(item);
38 + }
39 +
40 + public IReadOnlyCollection<PackageFacade> OrderedValues => this.OrderedFacades.AsReadOnly();
41 +
42 + public IEnumerable<PackageFacade> Values => this.FacadesByPackageId.Values;
43 +
44 + public bool TryGetFacadeByPackageId(string packageId, out PackageFacade facade)
45 + {
46 + return this.FacadesByPackageId.TryGetValue(packageId, out facade);
47 + }
48 +
49 + public bool TryGetFacadesByPackagePayloadId(string packagePayloadId, out List<PackageFacade> facades)
50 + {
51 + return this.FacadesByPackagePayloadId.TryGetValue(packagePayloadId, out facades);
52 + }
53 + }
54 +}
src/wix/WixToolset.Core.Burn/Bundles/PerformBundleBackendValidationCommand.cs
+4 -5
@@ -3,7 +3,6 @@
3 namespace WixToolset.Core.Burn.Bundles
4 {
5 using System;
6 - using System.Collections.Generic;
6 using WixToolset.Data;
7 using WixToolset.Data.Symbols;
8 using WixToolset.Extensibility.Data;
@@ -11,12 +10,12 @@ namespace WixToolset.Core.Burn.Bundles
10
11 internal class PerformBundleBackendValidationCommand
12 {
14 - public PerformBundleBackendValidationCommand(IMessaging messaging, IBurnBackendHelper burnBackendHelper, IntermediateSection section, IDictionary<string, PackageFacade> packageFacadesById)
13 + public PerformBundleBackendValidationCommand(IMessaging messaging, IBurnBackendHelper burnBackendHelper, IntermediateSection section, PackageFacades packageFacades)
14 {
15 this.Messaging = messaging;
16 this.BackendHelper = burnBackendHelper;
17 this.Section = section;
19 - this.PackageFacadesById = packageFacadesById;
18 + this.PackageFacades = packageFacades;
19 }
20
21 private IMessaging Messaging { get; }
@@ -25,7 +24,7 @@ namespace WixToolset.Core.Burn.Bundles
24
25 private IntermediateSection Section { get; }
26
28 - private IDictionary<string, PackageFacade> PackageFacadesById { get; }
27 + private PackageFacades PackageFacades { get; }
28
29 public void Execute()
30 {
@@ -53,7 +52,7 @@ namespace WixToolset.Core.Burn.Bundles
52 }
53 }
54
56 - foreach (var packageFacade in this.PackageFacadesById.Values)
55 + foreach (var packageFacade in this.PackageFacades.Values)
56 {
57 if (packageFacade.SpecificPackageSymbol is WixBundleBundlePackageSymbol wixBundleBundlePackageSymbol)
58 {
src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs
+7 -8
@@ -57,8 +57,8 @@ namespace WixToolset.Core.Burn.Bundles
57 public void Execute()
58 {
59 var harvestedBundlePackage = this.Section.Symbols.OfType<WixBundleHarvestedBundlePackageSymbol>()
60 - .Where(h => h.Id == this.ChainPackage.Id)
61 - .SingleOrDefault();
60 + .Where(h => h.Id == this.PackagePayload.Id)
61 + .SingleOrDefault();
62
63 if (harvestedBundlePackage == null)
64 {
@@ -200,13 +200,12 @@ namespace WixToolset.Core.Burn.Bundles
200 version = registrationElement.GetAttribute("Version");
201
202 var providerKey = registrationElement.GetAttribute("ProviderKey");
203 - var depId = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", this.PackageId, providerKey));
204 - this.Section.AddSymbol(new WixDependencyProviderSymbol(sourceLineNumbers, depId)
203 + var depId = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", this.PackagePayload.Id.Id, providerKey));
204 + this.Section.AddSymbol(new WixBundleHarvestedDependencyProviderSymbol(sourceLineNumbers, depId)
205 {
206 - ParentRef = this.PackageId,
206 + PackagePayloadRef = this.PackagePayload.Id.Id,
207 ProviderKey = providerKey,
208 Version = version,
209 - Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported,
209 });
210
211 displayName = arpElement.GetAttribute("DisplayName");
@@ -224,7 +223,7 @@ namespace WixToolset.Core.Burn.Bundles
223 }
224 }
225
227 - return this.Section.AddSymbol(new WixBundleHarvestedBundlePackageSymbol(this.PackagePayload.SourceLineNumbers, this.ChainPackage.Id)
226 + return this.Section.AddSymbol(new WixBundleHarvestedBundlePackageSymbol(this.PackagePayload.SourceLineNumbers, this.PackagePayload.Id)
227 {
228 Win64 = win64,
229 BundleId = bundleId,
@@ -274,7 +273,7 @@ namespace WixToolset.Core.Burn.Bundles
273
274 this.Section.AddSymbol(new WixBundlePackageRelatedBundleSymbol(sourceLineNumbers)
275 {
277 - PackageRef = this.PackageId,
276 + PackagePayloadRef = this.PackagePayload.Id.Id,
277 BundleId = id,
278 Action = action,
279 });
src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
+21 -30
@@ -65,7 +65,7 @@ namespace WixToolset.Core.Burn.Bundles
65 public void Execute()
66 {
67 var harvestedMsiPackage = this.Section.Symbols.OfType<WixBundleHarvestedMsiPackageSymbol>()
68 - .Where(h => h.Id == this.ChainPackage.Id)
68 + .Where(h => h.Id == this.PackagePayload.Id)
69 .SingleOrDefault();
70
71 if (harvestedMsiPackage == null)
@@ -78,6 +78,17 @@ namespace WixToolset.Core.Burn.Bundles
78 }
79 }
80
81 + foreach (var childPayload in this.Section.Symbols.OfType<WixBundlePayloadSymbol>().Where(p => p.ParentPackagePayloadRef == this.PackagePayload.Id.Id).ToList())
82 + {
83 + this.Section.AddSymbol(new WixGroupSymbol(childPayload.SourceLineNumbers)
84 + {
85 + ParentType = ComplexReferenceParentType.Package,
86 + ParentId = this.PackageId,
87 + ChildType = ComplexReferenceChildType.Payload,
88 + ChildId = childPayload.Id.Id,
89 + });
90 + }
91 +
92 this.ChainPackage.PerMachine = harvestedMsiPackage.PerMachine;
93 this.ChainPackage.Win64 = harvestedMsiPackage.Win64;
94
@@ -218,11 +229,7 @@ namespace WixToolset.Core.Burn.Bundles
229
230 this.CreateRelatedPackages(db);
231
221 - // If feature selection is enabled, represent the Feature table in the manifest.
222 - if (this.MsiPackage.EnableFeatureSelection)
223 - {
224 - this.CreateMsiFeatures(db);
225 - }
232 + this.CreateMsiFeatures(db);
233
234 // Add all external cabinets as package payloads.
235 this.ImportExternalCabinetAsPayloads(db, payloadNames);
@@ -241,7 +248,7 @@ namespace WixToolset.Core.Burn.Bundles
248 return null;
249 }
250
244 - return this.Section.AddSymbol(new WixBundleHarvestedMsiPackageSymbol(this.PackagePayload.SourceLineNumbers, this.ChainPackage.Id)
251 + return this.Section.AddSymbol(new WixBundleHarvestedMsiPackageSymbol(this.PackagePayload.SourceLineNumbers, this.PackagePayload.Id)
252 {
253 PerMachine = perMachine,
254 Win64 = win64,
@@ -379,7 +386,7 @@ namespace WixToolset.Core.Burn.Bundles
386
387 this.Section.AddSymbol(new WixBundleRelatedPackageSymbol(this.PackagePayload.SourceLineNumbers)
388 {
382 - PackageRef = this.PackageId,
389 + PackagePayloadRef = this.PackagePayload.Id.Id,
390 RelatedId = record.GetString(1),
391 MinVersion = record.GetString(2),
392 MaxVersion = record.GetString(3),
@@ -425,9 +432,9 @@ namespace WixToolset.Core.Burn.Bundles
432 }
433 }
434
428 - this.Section.AddSymbol(new WixBundleMsiFeatureSymbol(this.PackagePayload.SourceLineNumbers, new Identifier(AccessModifier.Section, this.PackageId, featureName))
435 + this.Section.AddSymbol(new WixBundleMsiFeatureSymbol(this.PackagePayload.SourceLineNumbers, new Identifier(AccessModifier.Section, this.PackagePayload.Id.Id, featureName))
436 {
430 - PackageRef = this.PackageId,
437 + PackagePayloadRef = this.PackagePayload.Id.Id,
438 Name = featureName,
439 Parent = allFeaturesResultRecord.GetString(2),
440 Title = allFeaturesResultRecord.GetString(3),
@@ -468,14 +475,6 @@ namespace WixToolset.Core.Burn.Bundles
475 var generatedId = this.BackendHelper.GenerateIdentifier("cab", this.PackagePayload.Id.Id, cabinet);
476 var payloadSourceFile = this.ResolveRelatedFile(this.PackagePayload.SourceFile.Path, this.PackagePayload.UnresolvedSourceFile, cabinet, "Cabinet", sourceLineNumbers);
477
471 - this.Section.AddSymbol(new WixGroupSymbol(sourceLineNumbers)
472 - {
473 - ParentType = ComplexReferenceParentType.Package,
474 - ParentId = this.PackageId,
475 - ChildType = ComplexReferenceChildType.Payload,
476 - ChildId = generatedId
477 - });
478 -
478 this.Section.AddSymbol(new WixBundlePayloadSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
479 {
480 Name = cabinetName,
@@ -540,14 +539,6 @@ namespace WixToolset.Core.Burn.Bundles
539 var generatedId = this.BackendHelper.GenerateIdentifier("f", this.PackagePayload.Id.Id, record.GetString(2));
540 var payloadSourceFile = this.ResolveRelatedFile(this.PackagePayload.SourceFile.Path, this.PackagePayload.UnresolvedSourceFile, fileSourcePath, "File", sourceLineNumbers);
541
543 - this.Section.AddSymbol(new WixGroupSymbol(sourceLineNumbers)
544 - {
545 - ParentType = ComplexReferenceParentType.Package,
546 - ParentId = this.PackageId,
547 - ChildType = ComplexReferenceChildType.Payload,
548 - ChildId = generatedId
549 - });
550 -
542 this.Section.AddSymbol(new WixBundlePayloadSymbol(sourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
543 {
544 Name = name,
@@ -594,16 +585,16 @@ namespace WixToolset.Core.Burn.Bundles
585 {
586 foreach (var record in view.Records)
587 {
597 - var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", this.PackageId, record.GetString(1)));
588 + var id = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", this.PackagePayload.Id.Id, record.GetString(1)));
589
590 // Import the provider key and attributes.
600 - this.Section.AddSymbol(new WixDependencyProviderSymbol(this.PackagePayload.SourceLineNumbers, id)
591 + this.Section.AddSymbol(new WixBundleHarvestedDependencyProviderSymbol(this.PackagePayload.SourceLineNumbers, id)
592 {
602 - ParentRef = this.PackageId,
593 + PackagePayloadRef = this.PackagePayload.Id.Id,
594 ProviderKey = record.GetString(2),
595 Version = record.GetString(3) ?? this.MsiPackage.ProductVersion,
596 DisplayName = record.GetString(4) ?? this.ChainPackage.DisplayName,
606 - Attributes = WixDependencyProviderAttributes.ProvidesAttributesImported | (WixDependencyProviderAttributes)record.GetInteger(5),
597 + ProviderAttributes = record.GetInteger(5),
598 });
599 }
600 }
src/wix/WixToolset.Core.Burn/Bundles/ProcessMspPackageCommand.cs
+3 -3
@@ -53,7 +53,7 @@ namespace WixToolset.Core.Burn.Bundles
53 public void Execute()
54 {
55 var harvestedMspPackage = this.Section.Symbols.OfType<WixBundleHarvestedMspPackageSymbol>()
56 - .Where(h => h.Id == this.ChainPackage.Id)
56 + .Where(h => h.Id == this.PackagePayload.Id)
57 .SingleOrDefault();
58
59 if (harvestedMspPackage == null)
@@ -123,7 +123,7 @@ namespace WixToolset.Core.Burn.Bundles
123 return null;
124 }
125
126 - return this.Section.AddSymbol(new WixBundleHarvestedMspPackageSymbol(this.PackagePayload.SourceLineNumbers, this.ChainPackage.Id)
126 + return this.Section.AddSymbol(new WixBundleHarvestedMspPackageSymbol(this.PackagePayload.SourceLineNumbers, this.PackagePayload.Id)
127 {
128 PatchCode = patchCode,
129 DisplayName = displayName,
@@ -175,7 +175,7 @@ namespace WixToolset.Core.Burn.Bundles
175 {
176 var symbol = section.AddSymbol(new WixBundlePatchTargetCodeSymbol(sourceLineNumbers)
177 {
178 - PackageRef = id.Id,
178 + PackagePayloadRef = id.Id,
179 TargetCode = targetCode,
180 Attributes = 0,
181 Type = type,
src/wix/WixToolset.Core.Burn/BurnBackendErrors.cs
+6
@@ -17,6 +17,11 @@ namespace WixToolset.Core.Burn
17 return Message(sourceLineNumbers, Ids.BAContainerPayloadCollision2, "The location of the payload related to the previous error.");
18 }
19
20 + public static Message BundleMultipleProviders(SourceLineNumber sourceLineNumbers, string extraProviderKey, string originalProviderKey)
21 + {
22 + return Message(sourceLineNumbers, Ids.BundleMultipleProviders, "The bundle can only have a single dependency provider, but it has '{0}' and '{1}'.", originalProviderKey, extraProviderKey);
23 + }
24 +
25 public static Message DuplicateCacheIds(SourceLineNumber originalLineNumber, string cacheId, string packageId)
26 {
27 return Message(originalLineNumber, Ids.DuplicateCacheIds, "The CacheId '{0}' for package '{1}' is duplicated. Each package must have a unique CacheId.", cacheId, packageId);
@@ -110,6 +115,7 @@ namespace WixToolset.Core.Burn
115 UnsupportedRemotePackagePayload = 8010,
116 FailedToAddIconOrSplashScreenToBundle = 8011,
117 InvalidBundleManifest = 8012,
118 + BundleMultipleProviders = 8013,
119 } // last available is 8499. 8500 is BurnBackendWarnings.
120 }
121 }
src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs
+78
@@ -5,12 +5,90 @@ namespace WixToolsetTest.CoreIntegration
5 using System.Collections.Generic;
6 using System.IO;
7 using System.Linq;
8 + using System.Xml;
9 using WixBuildTools.TestSupport;
10 using WixToolset.Core.TestPackage;
11 using Xunit;
12
13 public class PackagePayloadFixture
14 {
15 + [Fact]
16 + public void CanSpecifyMsiPackagePayloadInPayloadGroup()
17 + {
18 + var folder = TestData.Get(@"TestData");
19 +
20 + using (var fs = new DisposableFileSystem())
21 + {
22 + var baseFolder = fs.GetFolder();
23 + var intermediateFolder = Path.Combine(baseFolder, "obj");
24 + var bundlePath = Path.Combine(baseFolder, @"bin\test.exe");
25 + var baFolderPath = Path.Combine(baseFolder, "ba");
26 + var extractFolderPath = Path.Combine(baseFolder, "extract");
27 +
28 + var result = WixRunner.Execute(new[]
29 + {
30 + "build",
31 + Path.Combine(folder, "PackagePayload", "MsiPackagePayloadInPayloadGroup.wxs"),
32 + Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
33 + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
34 + "-bindpath", Path.Combine(folder, ".Data"),
35 + "-intermediateFolder", intermediateFolder,
36 + "-o", bundlePath,
37 + });
38 +
39 + result.AssertSuccess();
40 +
41 + Assert.True(File.Exists(bundlePath));
42 +
43 + var extractResult = BundleExtractor.ExtractBAContainer(null, bundlePath, baFolderPath, extractFolderPath);
44 + extractResult.AssertSuccess();
45 +
46 + var ignoreAttributesByElementName = new Dictionary<string, List<string>>
47 + {
48 + { "ExePackage", new List<string> { "CacheId", "InstallSize", "Size" } },
49 + };
50 + var msiPackageElements = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Chain/burn:MsiPackage")
51 + .Cast<XmlElement>()
52 + .Select(e => e.GetTestXml(ignoreAttributesByElementName))
53 + .ToArray();
54 + WixAssert.CompareLineByLine(new[]
55 + {
56 + "<MsiPackage Id='MsiWithFeatures' Cache='keep' CacheId='{040011E1-F84C-4927-AD62-50A5EC19CA32}v1.0.0.0_1' InstallSize='34' Size='32803' PerMachine='yes' Permanent='no' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' LogPathVariable='WixBundleLog_MsiWithFeatures' RollbackLogPathVariable='WixBundleRollbackLog_MsiWithFeatures' ProductCode='{040011E1-F84C-4927-AD62-50A5EC19CA32}' Language='1033' Version='1.0.0.0' UpgradeCode='{047730A5-30FE-4A62-A520-DA9381B8226A}'>" +
57 + "<MsiFeature Id='ProductFeature' /><MsiProperty Id='ARPSYSTEMCOMPONENT' Value='1' /><MsiProperty Id='MSIFASTINSTALL' Value='7' /><Provides Key='{040011E1-F84C-4927-AD62-50A5EC19CA32}_v1.0.0.0' Version='1.0.0.0' DisplayName='MsiPackage' />" +
58 + "<RelatedPackage Id='{047730A5-30FE-4A62-A520-DA9381B8226A}' MaxVersion='1.0.0.0' MaxInclusive='no' OnlyDetect='no' LangInclusive='yes'><Language Id='1033' /></RelatedPackage>" +
59 + "<RelatedPackage Id='{047730A5-30FE-4A62-A520-DA9381B8226A}' MinVersion='1.0.0.0' MinInclusive='no' OnlyDetect='yes' LangInclusive='yes'><Language Id='1033' /></RelatedPackage>" +
60 + "<PayloadRef Id='test.msi' /><PayloadRef Id='fhuZsOcBDTuIX8rF96kswqI6SnuI' /><PayloadRef Id='faf_OZ741BG7SJ6ZkcIvivZ2Yzo8' />" +
61 + "</MsiPackage>",
62 +
63 + "<MsiPackage Id='MsiWithoutFeatures' Cache='keep' CacheId='{040011E1-F84C-4927-AD62-50A5EC19CA32}v1.0.0.0_2' InstallSize='34' Size='32803' PerMachine='yes' Permanent='no' Vital='yes' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_MsiWithoutFeatures' RollbackLogPathVariable='WixBundleRollbackLog_MsiWithoutFeatures' ProductCode='{040011E1-F84C-4927-AD62-50A5EC19CA32}' Language='1033' Version='1.0.0.0' UpgradeCode='{047730A5-30FE-4A62-A520-DA9381B8226A}'>" +
64 + "<MsiProperty Id='ARPSYSTEMCOMPONENT' Value='1' /><MsiProperty Id='MSIFASTINSTALL' Value='7' /><Provides Key='{040011E1-F84C-4927-AD62-50A5EC19CA32}_v1.0.0.0' Version='1.0.0.0' DisplayName='MsiPackage' />" +
65 + "<RelatedPackage Id='{047730A5-30FE-4A62-A520-DA9381B8226A}' MaxVersion='1.0.0.0' MaxInclusive='no' OnlyDetect='no' LangInclusive='yes'><Language Id='1033' /></RelatedPackage>" +
66 + "<RelatedPackage Id='{047730A5-30FE-4A62-A520-DA9381B8226A}' MinVersion='1.0.0.0' MinInclusive='no' OnlyDetect='yes' LangInclusive='yes'><Language Id='1033' /></RelatedPackage>" +
67 + "<PayloadRef Id='test.msi' /><PayloadRef Id='fhuZsOcBDTuIX8rF96kswqI6SnuI' /><PayloadRef Id='faf_OZ741BG7SJ6ZkcIvivZ2Yzo8' />" +
68 + "</MsiPackage>",
69 + }, msiPackageElements);
70 +
71 + var packageElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixPackageProperties")
72 + .Cast<XmlElement>()
73 + .Select(e => e.GetTestXml())
74 + .ToArray();
75 + WixAssert.CompareLineByLine(new []
76 + {
77 + "<WixPackageProperties Package='MsiWithFeatures' Vital='yes' DisplayName='MsiPackage' DownloadSize='32803' PackageSize='32803' InstalledSize='34' PackageType='Msi' Permanent='no' LogPathVariable='WixBundleLog_MsiWithFeatures' RollbackLogPathVariable='WixBundleRollbackLog_MsiWithFeatures' Compressed='yes' ProductCode='{040011E1-F84C-4927-AD62-50A5EC19CA32}' UpgradeCode='{047730A5-30FE-4A62-A520-DA9381B8226A}' Version='1.0.0.0' Cache='keep' />",
78 + "<WixPackageProperties Package='MsiWithoutFeatures' Vital='yes' DisplayName='MsiPackage' DownloadSize='32803' PackageSize='32803' InstalledSize='34' PackageType='Msi' Permanent='no' LogPathVariable='WixBundleLog_MsiWithoutFeatures' RollbackLogPathVariable='WixBundleRollbackLog_MsiWithoutFeatures' Compressed='yes' ProductCode='{040011E1-F84C-4927-AD62-50A5EC19CA32}' UpgradeCode='{047730A5-30FE-4A62-A520-DA9381B8226A}' Version='1.0.0.0' Cache='keep' />",
79 + }, packageElements);
80 +
81 + var featureElements = extractResult.SelectBADataNodes("/ba:BootstrapperApplicationData/ba:WixPackageFeatureInfo")
82 + .Cast<XmlElement>()
83 + .Select(e => e.GetTestXml())
84 + .ToArray();
85 + WixAssert.CompareLineByLine(new[]
86 + {
87 + "<WixPackageFeatureInfo Package='MsiWithFeatures' Feature='ProductFeature' Size='34' Display='2' Level='1' Directory='' Attributes='0' />",
88 + }, featureElements);
89 + }
90 + }
91 +
92 [Fact]
93 public void CanSpecifyPackagePayloadInPayloadGroup()
94 {
src/wix/test/WixToolsetTest.CoreIntegration/TestData/PackagePayload/MsiPackagePayloadInPayloadGroup.wxs new
+18
@@ -0,0 +1,18 @@
1 +<?xml version="1.0" encoding="utf-8"?>
2 +<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3 + <Fragment>
4 + <PackageGroup Id="BundlePackages">
5 + <MsiPackage Id="MsiWithFeatures" CacheId="{040011E1-F84C-4927-AD62-50A5EC19CA32}v1.0.0.0_1" EnableFeatureSelection="yes">
6 + <PayloadGroupRef Id="PackagePayloadGroup" />
7 + </MsiPackage>
8 + <MsiPackage Id="MsiWithoutFeatures" CacheId="{040011E1-F84C-4927-AD62-50A5EC19CA32}v1.0.0.0_2">
9 + <PayloadGroupRef Id="PackagePayloadGroup" />
10 + </MsiPackage>
11 + </PackageGroup>
12 + </Fragment>
13 + <Fragment>
14 + <PayloadGroup Id="PackagePayloadGroup">
15 + <MsiPackagePayload SourceFile="test.msi" />
16 + </PayloadGroup>
17 + </Fragment>
18 +</Wix>