Harvest BundlePackage payloads.
Fixes 6757
Sean Hall committed
May 5, 2022 at 18:08 UTC
d5744da0117199f23bf72f5c2ba7cd1c6f52e173
18 files changed
+752
-187
src/api/wix/WixToolset.Data/Symbols/WixBundleBundlePackagePayloadSymbol.cs
+16
@@ -10,6 +10,7 @@ namespace WixToolset.Data
10
SymbolDefinitionType.WixBundleBundlePackagePayload,
11
new IntermediateFieldDefinition[]
12
{
13
+ new IntermediateFieldDefinition(nameof(WixBundleBundlePackagePayloadSymbolFields.PayloadGeneration), IntermediateFieldType.Number),
14
},
15
typeof(WixBundleBundlePackagePayloadSymbol));
16
}
@@ -19,6 +20,15 @@ namespace WixToolset.Data.Symbols
20
{
21
public enum WixBundleBundlePackagePayloadSymbolFields
22
{
23
+ PayloadGeneration,
24
+ }
25
+
26
+ public enum BundlePackagePayloadGenerationType
27
+ {
28
+ None,
29
+ ExternalWithoutDownloadUrl,
30
+ External,
31
+ All,
32
}
33
34
public class WixBundleBundlePackagePayloadSymbol : IntermediateSymbol
@@ -32,5 +42,11 @@ namespace WixToolset.Data.Symbols
42
}
43
44
public IntermediateField this[WixBundleBundlePackagePayloadSymbolFields index] => this.Fields[(int)index];
45
+
46
+ public BundlePackagePayloadGenerationType PayloadGeneration
47
+ {
48
+ get => (BundlePackagePayloadGenerationType)this.Fields[(int)WixBundleBundlePackagePayloadSymbolFields.PayloadGeneration].AsNumber();
49
+ set => this.Set((int)WixBundleBundlePackagePayloadSymbolFields.PayloadGeneration, (int)value);
50
+ }
51
}
52
}
src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+1
-1
@@ -180,7 +180,7 @@ namespace WixToolset.Core.Burn
180
{
181
case WixBundlePackageType.Bundle:
182
{
183
- var command = new ProcessBundlePackageCommand(this.ServiceProvider, section, facade, packagesPayloads[facade.PackageId], this.IntermediateFolder);
183
+ var command = new ProcessBundlePackageCommand(this.ServiceProvider, this.BackendExtensions, section, facade, packagesPayloads[facade.PackageId], this.IntermediateFolder);
184
command.Execute();
185
186
trackedFiles.AddRange(command.TrackedFiles);
src/wix/WixToolset.Core.Burn/Bundles/GetPackageFacadesCommand.cs
+9
-5
@@ -2,6 +2,7 @@
2
3
namespace WixToolset.Core.Burn.Bundles
4
{
5
+ using System;
6
using System.Collections.Generic;
7
using System.Linq;
8
using WixToolset.Data;
@@ -147,7 +148,7 @@ namespace WixToolset.Core.Burn.Bundles
148
case WixBundlePackageType.Bundle:
149
if (bundlePackages.TryGetValue(id, out var bundlePackage))
150
{
150
- facades.Add(new PackageFacade(package, bundlePackage));
151
+ facades.Add(new PackageFacade(package, bundlePackage, packagePayload));
152
}
153
else
154
{
@@ -158,7 +159,7 @@ namespace WixToolset.Core.Burn.Bundles
159
case WixBundlePackageType.Exe:
160
if (exePackages.TryGetValue(id, out var exePackage))
161
{
161
- facades.Add(new PackageFacade(package, exePackage));
162
+ facades.Add(new PackageFacade(package, exePackage, packagePayload));
163
}
164
else
165
{
@@ -169,7 +170,7 @@ namespace WixToolset.Core.Burn.Bundles
170
case WixBundlePackageType.Msi:
171
if (msiPackages.TryGetValue(id, out var msiPackage))
172
{
172
- facades.Add(new PackageFacade(package, msiPackage));
173
+ facades.Add(new PackageFacade(package, msiPackage, packagePayload));
174
}
175
else
176
{
@@ -180,7 +181,7 @@ namespace WixToolset.Core.Burn.Bundles
181
case WixBundlePackageType.Msp:
182
if (mspPackages.TryGetValue(id, out var mspPackage))
183
{
183
- facades.Add(new PackageFacade(package, mspPackage));
184
+ facades.Add(new PackageFacade(package, mspPackage, packagePayload));
185
}
186
else
187
{
@@ -191,13 +192,16 @@ namespace WixToolset.Core.Burn.Bundles
192
case WixBundlePackageType.Msu:
193
if (msuPackages.TryGetValue(id, out var msuPackage))
194
{
194
- facades.Add(new PackageFacade(package, msuPackage));
195
+ facades.Add(new PackageFacade(package, msuPackage, packagePayload));
196
}
197
else
198
{
199
this.Messaging.Write(ErrorMessages.IdentifierNotFound("WixBundleMsuPackage", id));
200
}
201
break;
202
+
203
+ default:
204
+ throw new NotImplementedException();
205
}
206
}
207
src/wix/WixToolset.Core.Burn/Bundles/HarvestBundlePackageCommand.cs
+186
-4
@@ -5,36 +5,48 @@ namespace WixToolset.Core.Burn.Bundles
5
using System;
6
using System.Collections.Generic;
7
using System.IO;
8
- using System.Text;
8
+ using System.Linq;
9
using System.Xml;
10
using WixToolset.Data;
11
using WixToolset.Data.Symbols;
12
+ using WixToolset.Extensibility;
13
using WixToolset.Extensibility.Data;
14
using WixToolset.Extensibility.Services;
15
16
internal class HarvestBundlePackageCommand
17
{
17
- public HarvestBundlePackageCommand(IServiceProvider serviceProvider, string intermediateFolder, WixBundlePayloadSymbol payloadSymbol)
18
+ public HarvestBundlePackageCommand(IServiceProvider serviceProvider, IEnumerable<IBurnBackendBinderExtension> backendExtensions, string intermediateFolder, WixBundlePayloadSymbol payloadSymbol, WixBundleBundlePackagePayloadSymbol packagePayloadSymbol, Dictionary<string, WixBundlePayloadSymbol> packagePayloadsById)
19
{
20
this.Messaging = serviceProvider.GetService<IMessaging>();
21
this.BackendHelper = serviceProvider.GetService<IBackendHelper>();
22
+ this.BackendExtensions = backendExtensions;
23
this.IntermediateFolder = intermediateFolder;
24
25
this.PackagePayload = payloadSymbol;
26
+ this.BundlePackagePayload = packagePayloadSymbol;
27
+ this.PackagePayloadsById = packagePayloadsById;
28
}
29
30
private IMessaging Messaging { get; }
31
32
private IBackendHelper BackendHelper { get; }
33
34
+ private IEnumerable<IBurnBackendBinderExtension> BackendExtensions { get; }
35
+
36
private string IntermediateFolder { get; }
37
38
private WixBundlePayloadSymbol PackagePayload { get; }
39
40
+ private WixBundleBundlePackagePayloadSymbol BundlePackagePayload { get; }
41
+
42
+ private Dictionary<string, WixBundlePayloadSymbol> PackagePayloadsById { get; }
43
+
44
public WixBundleHarvestedBundlePackageSymbol HarvestedBundlePackage { get; private set; }
45
46
public WixBundleHarvestedDependencyProviderSymbol HarvestedDependencyProvider { get; private set; }
47
48
+ public List<WixBundlePayloadSymbol> Payloads { get; } = new List<WixBundlePayloadSymbol>();
49
+
50
public List<WixBundlePackageRelatedBundleSymbol> RelatedBundles { get; } = new List<WixBundlePackageRelatedBundleSymbol>();
51
52
public List<ITrackedFile> TrackedFiles { get; } = new List<ITrackedFile>();
@@ -114,9 +126,9 @@ namespace WixToolset.Core.Burn.Bundles
126
127
installSize = this.ProcessPackages(document, namespaceManager);
128
117
- this.ProcessRelatedBundles(document, namespaceManager, sourcePath);
129
+ this.ProcessPayloads(document, namespaceManager, this.BundlePackagePayload.PayloadGeneration);
130
119
- // TODO: Add payloads?
131
+ this.ProcessRelatedBundles(document, namespaceManager, sourcePath);
132
}
133
catch (Exception e)
134
{
@@ -221,6 +233,158 @@ namespace WixToolset.Core.Burn.Bundles
233
return packageInstallSize;
234
}
235
236
+ private void ProcessPayloads(XmlDocument document, XmlNamespaceManager namespaceManager, BundlePackagePayloadGenerationType payloadGenerationType)
237
+ {
238
+ if (payloadGenerationType == BundlePackagePayloadGenerationType.None)
239
+ {
240
+ return;
241
+ }
242
+
243
+ var payloadNames = new HashSet<string>(this.PackagePayloadsById.Values.Select(p => p.Name), StringComparer.OrdinalIgnoreCase);
244
+
245
+ var containersById = new Dictionary<string, ManifestContainer>();
246
+
247
+ foreach (XmlElement containerElement in document.SelectNodes("/burn:BurnManifest/burn:Container", namespaceManager))
248
+ {
249
+ var container = new ManifestContainer();
250
+ container.Attached = containerElement.GetAttribute("Attached") == "yes";
251
+ container.DownloadUrl = containerElement.GetAttribute("DownloadUrl");
252
+ container.FilePath = containerElement.GetAttribute("FilePath");
253
+ container.Id = containerElement.GetAttribute("Id");
254
+ containersById.Add(container.Id, container);
255
+
256
+ if (container.Attached)
257
+ {
258
+ continue;
259
+ }
260
+
261
+ switch (payloadGenerationType)
262
+ {
263
+ case BundlePackagePayloadGenerationType.ExternalWithoutDownloadUrl:
264
+ if (!String.IsNullOrEmpty(container.DownloadUrl))
265
+ {
266
+ continue;
267
+ }
268
+ break;
269
+ }
270
+
271
+ // If we didn't find the Payload as an existing child of the package, we need to
272
+ // add it. We expect the file to exist on-disk in the same relative location as
273
+ // the bundle expects to find it...
274
+ container.IncludedAsPayload = true;
275
+ var containerName = container.FilePath;
276
+ var containerFullName = Path.Combine(Path.GetDirectoryName(this.PackagePayload.Name), containerName);
277
+
278
+ if (!payloadNames.Contains(containerFullName))
279
+ {
280
+ var generatedId = this.BackendHelper.GenerateIdentifier("hcp", this.PackagePayload.Id.Id, containerName);
281
+ var payloadSourceFile = this.ResolveRelatedFile(this.PackagePayload.SourceFile.Path, this.PackagePayload.UnresolvedSourceFile, containerName, "Container", this.PackagePayload.SourceLineNumbers);
282
+
283
+ this.Payloads.Add(new WixBundlePayloadSymbol(this.PackagePayload.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
284
+ {
285
+ Name = containerFullName,
286
+ SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
287
+ Compressed = this.PackagePayload.Compressed,
288
+ UnresolvedSourceFile = containerFullName,
289
+ ContainerRef = this.PackagePayload.ContainerRef,
290
+ DownloadUrl = this.PackagePayload.DownloadUrl,
291
+ Packaging = this.PackagePayload.Packaging,
292
+ ParentPackagePayloadRef = this.PackagePayload.Id.Id,
293
+ });
294
+ }
295
+ }
296
+
297
+ foreach (XmlElement payloadElement in document.SelectNodes("/burn:BurnManifest/burn:Payload", namespaceManager))
298
+ {
299
+ var payload = new ManifestPayload();
300
+ payload.Container = payloadElement.GetAttribute("Container");
301
+ payload.DownloadUrl = payloadElement.GetAttribute("DownloadUrl");
302
+ payload.FilePath = payloadElement.GetAttribute("FilePath");
303
+ payload.Id = payloadElement.GetAttribute("Id");
304
+
305
+ if (payload.Container == null || !containersById.TryGetValue(payload.Container, out var container))
306
+ {
307
+ container = null;
308
+ }
309
+
310
+ if (container != null && container.IncludedAsPayload)
311
+ {
312
+ // Don't include payload if it's in a container that's already included.
313
+ continue;
314
+ }
315
+
316
+ switch (payloadGenerationType)
317
+ {
318
+ case BundlePackagePayloadGenerationType.ExternalWithoutDownloadUrl:
319
+ if (container != null || !String.IsNullOrEmpty(payload.DownloadUrl))
320
+ {
321
+ continue;
322
+ }
323
+ break;
324
+ case BundlePackagePayloadGenerationType.External:
325
+ if (container != null)
326
+ {
327
+ continue;
328
+ }
329
+ break;
330
+ }
331
+
332
+ // If we didn't find the Payload as an existing child of the package, we need to
333
+ // add it. We expect the file to exist on-disk in the same relative location as
334
+ // the bundle expects to find it...
335
+ var payloadName = payload.FilePath;
336
+ var payloadFullName = Path.Combine(Path.GetDirectoryName(this.PackagePayload.Name), payloadName);
337
+
338
+ if (!payloadNames.Contains(payloadFullName))
339
+ {
340
+ var generatedId = this.BackendHelper.GenerateIdentifier("hpp", this.PackagePayload.Id.Id, payloadName);
341
+ var payloadSourceFile = this.ResolveRelatedFile(this.PackagePayload.SourceFile.Path, this.PackagePayload.UnresolvedSourceFile, payloadName, "Payload", this.PackagePayload.SourceLineNumbers);
342
+
343
+ this.Payloads.Add(new WixBundlePayloadSymbol(this.PackagePayload.SourceLineNumbers, new Identifier(AccessModifier.Section, generatedId))
344
+ {
345
+ Name = payloadFullName,
346
+ SourceFile = new IntermediateFieldPathValue { Path = payloadSourceFile },
347
+ Compressed = this.PackagePayload.Compressed,
348
+ UnresolvedSourceFile = payloadFullName,
349
+ ContainerRef = this.PackagePayload.ContainerRef,
350
+ DownloadUrl = this.PackagePayload.DownloadUrl,
351
+ Packaging = this.PackagePayload.Packaging,
352
+ ParentPackagePayloadRef = this.PackagePayload.Id.Id,
353
+ });
354
+ }
355
+ }
356
+ }
357
+
358
+ private string ResolveRelatedFile(string resolvedSource, string unresolvedSource, string relatedSource, string type, SourceLineNumber sourceLineNumbers)
359
+ {
360
+ var checkedPaths = new List<string>();
361
+
362
+ foreach (var extension in this.BackendExtensions)
363
+ {
364
+ var resolved = extension.ResolveRelatedFile(unresolvedSource, relatedSource, type, sourceLineNumbers);
365
+
366
+ if (resolved?.CheckedPaths != null)
367
+ {
368
+ checkedPaths.AddRange(resolved.CheckedPaths);
369
+ }
370
+
371
+ if (!String.IsNullOrEmpty(resolved?.Path))
372
+ {
373
+ return resolved?.Path;
374
+ }
375
+ }
376
+
377
+ var resolvedPath = Path.Combine(Path.GetDirectoryName(resolvedSource), relatedSource);
378
+
379
+ if (!File.Exists(resolvedPath))
380
+ {
381
+ checkedPaths.Add(resolvedPath);
382
+ this.Messaging.Write(ErrorMessages.FileNotFound(sourceLineNumbers, resolvedPath, type, checkedPaths));
383
+ }
384
+
385
+ return resolvedPath;
386
+ }
387
+
388
private void ProcessRelatedBundles(XmlDocument document, XmlNamespaceManager namespaceManager, string sourcePath)
389
{
390
var sourceLineNumbers = this.PackagePayload.SourceLineNumbers;
@@ -244,5 +408,23 @@ namespace WixToolset.Core.Burn.Bundles
408
});
409
}
410
}
411
+
412
+ private class ManifestContainer
413
+ {
414
+ public bool Attached { get; set; }
415
+ public string DownloadUrl { get; set; }
416
+ public string FilePath { get; set; }
417
+ public string Id { get; set; }
418
+
419
+ public bool IncludedAsPayload { get; set; }
420
+ }
421
+
422
+ private class ManifestPayload
423
+ {
424
+ public string Container { get; set; }
425
+ public string DownloadUrl { get; set; }
426
+ public string FilePath { get; set; }
427
+ public string Id { get; set; }
428
+ }
429
}
430
}
src/wix/WixToolset.Core.Burn/Bundles/PackageFacade.cs
+4
-1
@@ -8,12 +8,13 @@ namespace WixToolset.Core.Burn.Bundles
8
9
internal class PackageFacade
10
{
11
- public PackageFacade(WixBundlePackageSymbol packageSymbol, IntermediateSymbol specificPackageSymbol)
11
+ public PackageFacade(WixBundlePackageSymbol packageSymbol, IntermediateSymbol specificPackageSymbol, IntermediateSymbol specificPackagePayloadSymbol)
12
{
13
Debug.Assert(packageSymbol.Id.Id == specificPackageSymbol.Id.Id);
14
15
this.PackageSymbol = packageSymbol;
16
this.SpecificPackageSymbol = specificPackageSymbol;
17
+ this.SpecificPackagePayloadSymbol = specificPackagePayloadSymbol;
18
}
19
20
public string PackageId => this.PackageSymbol.Id.Id;
@@ -21,5 +22,7 @@ namespace WixToolset.Core.Burn.Bundles
22
public WixBundlePackageSymbol PackageSymbol { get; }
23
24
public IntermediateSymbol SpecificPackageSymbol { get; }
25
+
26
+ public IntermediateSymbol SpecificPackagePayloadSymbol { get; }
27
}
28
}
src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs
+14
-2
@@ -7,6 +7,7 @@ namespace WixToolset.Core.Burn.Bundles
7
using System.Linq;
8
using WixToolset.Data;
9
using WixToolset.Data.Symbols;
10
+ using WixToolset.Extensibility;
11
using WixToolset.Extensibility.Data;
12
using WixToolset.Extensibility.Services;
13
@@ -15,16 +16,18 @@ namespace WixToolset.Core.Burn.Bundles
16
/// </summary>
17
internal class ProcessBundlePackageCommand
18
{
18
- public ProcessBundlePackageCommand(IServiceProvider serviceProvider, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> packagePayloads, string intermediateFolder)
19
+ public ProcessBundlePackageCommand(IServiceProvider serviceProvider, IEnumerable<IBurnBackendBinderExtension> backendExtensions, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> packagePayloads, string intermediateFolder)
20
{
21
this.ServiceProvider = serviceProvider;
22
this.Messaging = serviceProvider.GetService<IMessaging>();
23
+ this.BackendExtensions = backendExtensions;
24
this.PackagePayloads = packagePayloads;
25
this.Section = section;
26
this.IntermediateFolder = intermediateFolder;
27
28
this.ChainPackage = facade.PackageSymbol;
29
this.BundlePackage = (WixBundleBundlePackageSymbol)facade.SpecificPackageSymbol;
30
+ this.BundlePackagePayload = (WixBundleBundlePackagePayloadSymbol)facade.SpecificPackagePayloadSymbol;
31
this.PackagePayload = packagePayloads[this.ChainPackage.PayloadRef];
32
}
33
@@ -32,12 +35,16 @@ namespace WixToolset.Core.Burn.Bundles
35
36
private IMessaging Messaging { get; }
37
38
+ private IEnumerable<IBurnBackendBinderExtension> BackendExtensions { get; }
39
+
40
private Dictionary<string, WixBundlePayloadSymbol> PackagePayloads { get; }
41
42
private WixBundlePackageSymbol ChainPackage { get; }
43
44
private WixBundleBundlePackageSymbol BundlePackage { get; }
45
46
+ private WixBundleBundlePackagePayloadSymbol BundlePackagePayload { get; }
47
+
48
private string PackageId => this.ChainPackage.Id.Id;
49
50
private WixBundlePayloadSymbol PackagePayload { get; }
@@ -100,7 +107,7 @@ namespace WixToolset.Core.Burn.Bundles
107
108
private WixBundleHarvestedBundlePackageSymbol HarvestPackage()
109
{
103
- var command = new HarvestBundlePackageCommand(this.ServiceProvider, this.IntermediateFolder, this.PackagePayload);
110
+ var command = new HarvestBundlePackageCommand(this.ServiceProvider, this.BackendExtensions, this.IntermediateFolder, this.PackagePayload, this.BundlePackagePayload, this.PackagePayloads);
111
command.Execute();
112
113
this.TrackedFiles.AddRange(command.TrackedFiles);
@@ -112,6 +119,11 @@ namespace WixToolset.Core.Burn.Bundles
119
this.Section.AddSymbol(command.HarvestedBundlePackage);
120
this.Section.AddSymbol(command.HarvestedDependencyProvider);
121
122
+ foreach (var payload in command.Payloads)
123
+ {
124
+ this.Section.AddSymbol(payload);
125
+ }
126
+
127
foreach (var relatedBundle in command.RelatedBundles)
128
{
129
this.Section.AddSymbol(relatedBundle);
src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs
+190
-114
@@ -14,6 +14,7 @@ namespace WixToolset.Core.Burn.CommandLine
14
using WixToolset.Core.Native;
15
using WixToolset.Data;
16
using WixToolset.Data.Symbols;
17
+ using WixToolset.Extensibility;
18
using WixToolset.Extensibility.Services;
19
20
internal class RemotePayloadSubcommand : BurnSubcommandBase
@@ -30,6 +31,9 @@ namespace WixToolset.Core.Burn.CommandLine
31
this.ServiceProvider = serviceProvider;
32
this.Messaging = serviceProvider.GetService<IMessaging>();
33
this.PayloadHarvester = serviceProvider.GetService<IPayloadHarvester>();
34
+ var extensionManager = serviceProvider.GetService<IExtensionManager>();
35
+
36
+ this.BackendExtensions = extensionManager.GetServices<IBurnBackendBinderExtension>();
37
}
38
39
private IServiceProvider ServiceProvider { get; }
@@ -38,6 +42,8 @@ namespace WixToolset.Core.Burn.CommandLine
42
43
private IPayloadHarvester PayloadHarvester { get; }
44
45
+ private IReadOnlyCollection<IBurnBackendBinderExtension> BackendExtensions { get; }
46
+
47
private List<string> BasePaths { get; } = new List<string>();
48
49
private string DownloadUrl { get; set; }
@@ -50,6 +56,8 @@ namespace WixToolset.Core.Burn.CommandLine
56
57
private WixBundlePackageType? PackageType { get; set; }
58
59
+ private BundlePackagePayloadGenerationType BundlePayloadGeneration { get; set; } = BundlePackagePayloadGenerationType.ExternalWithoutDownloadUrl;
60
+
61
private bool Recurse { get; set; }
62
63
private bool UseCertificate { get; set; }
@@ -107,6 +115,15 @@ namespace WixToolset.Core.Burn.CommandLine
115
this.BasePaths.Add(parser.GetNextArgumentAsDirectoryOrError(argument));
116
return true;
117
118
+ case "bundlepayloadgeneration":
119
+ var bundlePayloadGenerationValue = parser.GetNextArgumentOrError(argument);
120
+ if (Enum.TryParse<BundlePackagePayloadGenerationType>(bundlePayloadGenerationValue, ignoreCase: true, out var bundlePayloadGeneration))
121
+ {
122
+ this.BundlePayloadGeneration = bundlePayloadGeneration;
123
+ return true;
124
+ }
125
+ break;
126
+
127
case "du":
128
case "downloadurl":
129
this.DownloadUrl = parser.GetNextArgumentOrError(argument);
@@ -175,152 +192,74 @@ namespace WixToolset.Core.Burn.CommandLine
192
private IEnumerable<XElement> HarvestRemotePayloads(IEnumerable<string> paths)
193
{
194
var first = true;
178
- var hashes = new Dictionary<string, CertificateHashes>();
179
-
180
- if (this.UseCertificate)
181
- {
182
- hashes = CertificateHashes.Read(paths).Where(c => !String.IsNullOrEmpty(c.PublicKey) && !String.IsNullOrEmpty(c.Thumbprint) && c.Exception is null).ToDictionary(c => c.Path);
183
- }
195
+ var hashes = this.GetHashes(paths);
196
197
foreach (var path in paths)
198
{
187
- var element = this.CreateRemotePayloadElement(path, first);
199
+ var harvestedFile = this.HarvestFile(path, first, hashes);
200
first = false;
201
190
- if (element == null)
202
+ if (harvestedFile == null)
203
{
204
continue;
205
}
206
195
- var payloadSymbol = new WixBundlePayloadSymbol(null, new Identifier(AccessModifier.Section, "id"))
207
+ if (harvestedFile.PackagePayloads.Any())
208
{
197
- SourceFile = new IntermediateFieldPathValue { Path = path },
198
- };
199
-
200
- this.PayloadHarvester.HarvestStandardInformation(payloadSymbol);
201
-
202
- element.Add(new XAttribute("Name", Path.GetFileName(path)));
203
-
204
- if (!String.IsNullOrEmpty(payloadSymbol.DisplayName))
205
- {
206
- element.Add(new XAttribute("ProductName", payloadSymbol.DisplayName));
207
- }
209
+ var packageHashes = this.GetHashes(harvestedFile.PackagePayloads.Select(x => x.SourceFile.Path));
210
209
- if (!String.IsNullOrEmpty(payloadSymbol.Description))
210
- {
211
- element.Add(new XAttribute("Description", payloadSymbol.Description));
212
- }
213
-
214
- if (!String.IsNullOrEmpty(this.DownloadUrl))
215
- {
216
- var filename = this.GetRelativeFileName(payloadSymbol.SourceFile.Path);
217
- var formattedUrl = String.Format(this.DownloadUrl, filename);
218
-
219
- if (Uri.TryCreate(formattedUrl, UriKind.Absolute, out var url))
211
+ foreach (var payloadSymbol in harvestedFile.PackagePayloads)
212
{
221
- element.Add(new XAttribute("DownloadUrl", url.AbsoluteUri));
213
+ var harvestedPackageFile = this.HarvestFile(payloadSymbol.SourceFile.Path, false, packageHashes);
214
+ yield return harvestedPackageFile.Element;
215
}
216
}
217
225
- if (hashes.TryGetValue(path, out var certificateHashes))
226
- {
227
- element.Add(new XAttribute("CertificatePublicKey", certificateHashes.PublicKey));
228
- element.Add(new XAttribute("CertificateThumbprint", certificateHashes.Thumbprint));
229
- }
230
-
231
- if (!String.IsNullOrEmpty(payloadSymbol.Hash))
232
- {
233
- element.Add(new XAttribute("Hash", payloadSymbol.Hash));
234
- }
235
-
236
- if (payloadSymbol.FileSize.HasValue)
237
- {
238
- element.Add(new XAttribute("Size", payloadSymbol.FileSize.Value));
239
- }
240
-
241
- if (!String.IsNullOrEmpty(payloadSymbol.Version))
242
- {
243
- element.Add(new XAttribute("Version", payloadSymbol.Version));
244
- }
245
-
246
- if (element.Name == BundlePackagePayloadName)
247
- {
248
- var command = new HarvestBundlePackageCommand(this.ServiceProvider, this.IntermediateFolder, payloadSymbol);
249
- command.Execute();
250
-
251
- if (!this.Messaging.EncounteredError)
252
- {
253
- var bundleElement = new XElement(RemoteBundleName);
254
-
255
- bundleElement.Add(new XAttribute("BundleId", command.HarvestedBundlePackage.BundleId));
256
-
257
- if (!String.IsNullOrEmpty(command.HarvestedBundlePackage.DisplayName))
258
- {
259
- bundleElement.Add(new XAttribute("DisplayName", command.HarvestedBundlePackage.DisplayName));
260
- }
261
-
262
- if (!String.IsNullOrEmpty(command.HarvestedBundlePackage.EngineVersion))
263
- {
264
- bundleElement.Add(new XAttribute("EngineVersion", command.HarvestedBundlePackage.EngineVersion));
265
- }
266
-
267
- bundleElement.Add(new XAttribute("InstallSize", command.HarvestedBundlePackage.InstallSize));
268
- bundleElement.Add(new XAttribute("ManifestNamespace", command.HarvestedBundlePackage.ManifestNamespace));
269
- bundleElement.Add(new XAttribute("PerMachine", command.HarvestedBundlePackage.PerMachine ? "yes" : "no"));
270
- bundleElement.Add(new XAttribute("ProviderKey", command.HarvestedDependencyProvider.ProviderKey));
271
- bundleElement.Add(new XAttribute("ProtocolVersion", command.HarvestedBundlePackage.ProtocolVersion));
272
-
273
- if (!String.IsNullOrEmpty(command.HarvestedBundlePackage.Version))
274
- {
275
- bundleElement.Add(new XAttribute("Version", command.HarvestedBundlePackage.Version));
276
- }
277
-
278
- bundleElement.Add(new XAttribute("Win64", command.HarvestedBundlePackage.Win64 ? "yes" : "no"));
279
-
280
- var setUpgradeCode = false;
281
- foreach (var relatedBundle in command.RelatedBundles)
282
- {
283
- if (!setUpgradeCode && relatedBundle.Action == RelatedBundleActionType.Upgrade)
284
- {
285
- setUpgradeCode = true;
286
- bundleElement.Add(new XAttribute("UpgradeCode", relatedBundle.BundleId));
287
- continue;
288
- }
289
-
290
- var relatedBundleElement = new XElement(RemoteRelatedBundleName);
291
-
292
- relatedBundleElement.Add(new XAttribute("Id", relatedBundle.BundleId));
293
- relatedBundleElement.Add(new XAttribute("Action", relatedBundle.Action.ToString()));
294
-
295
- bundleElement.Add(relatedBundleElement);
296
- }
218
+ yield return harvestedFile.Element;
219
+ }
220
+ }
221
298
- element.Add(bundleElement);
299
- }
300
- }
222
+ private Dictionary<string, CertificateHashes> GetHashes(IEnumerable<string> paths)
223
+ {
224
+ var hashes = new Dictionary<string, CertificateHashes>();
225
302
- yield return element;
226
+ if (this.UseCertificate)
227
+ {
228
+ hashes = CertificateHashes.Read(paths)
229
+ .Where(c => !String.IsNullOrEmpty(c.PublicKey) && !String.IsNullOrEmpty(c.Thumbprint) && c.Exception is null)
230
+ .ToDictionary(c => c.Path);
231
}
232
+
233
+ return hashes;
234
}
235
306
- private XElement CreateRemotePayloadElement(string path, bool firstHarvest)
236
+ private HarvestedFile HarvestFile(string path, bool isPackage, Dictionary<string, CertificateHashes> hashes)
237
{
308
- if (firstHarvest)
238
+ XElement element;
239
+ WixBundlePackageType? packageType = null;
240
+
241
+ if (isPackage)
242
{
243
var extension = this.PackageType.HasValue ? this.PackageType.ToString() : Path.GetExtension(path);
244
245
switch (extension.ToUpperInvariant())
246
{
247
case "BUNDLE":
315
- return new XElement(BundlePackagePayloadName);
248
+ packageType = WixBundlePackageType.Bundle;
249
+ element = new XElement(BundlePackagePayloadName);
250
+ break;
251
252
case "EXE":
253
case ".EXE":
319
- return new XElement(ExePackagePayloadName);
254
+ packageType = WixBundlePackageType.Exe;
255
+ element = new XElement(ExePackagePayloadName);
256
+ break;
257
258
case "MSU":
259
case ".MSU":
323
- return new XElement(MsuPackagePayloadName);
260
+ packageType = WixBundlePackageType.Msu;
261
+ element = new XElement(MsuPackagePayloadName);
262
+ break;
263
264
default:
265
this.Messaging.Write(BurnBackendErrors.UnsupportedRemotePackagePayload(extension, path));
@@ -329,8 +268,75 @@ namespace WixToolset.Core.Burn.CommandLine
268
}
269
else
270
{
332
- return new XElement(PayloadName);
271
+ element = new XElement(PayloadName);
272
}
273
+
274
+ var payloadSymbol = new WixBundlePayloadSymbol(null, new Identifier(AccessModifier.Section, "id"))
275
+ {
276
+ SourceFile = new IntermediateFieldPathValue { Path = path },
277
+ Name = Path.GetFileName(path),
278
+ };
279
+
280
+ this.PayloadHarvester.HarvestStandardInformation(payloadSymbol);
281
+
282
+ element.Add(new XAttribute("Name", payloadSymbol.Name));
283
+
284
+ if (!String.IsNullOrEmpty(payloadSymbol.DisplayName))
285
+ {
286
+ element.Add(new XAttribute("ProductName", payloadSymbol.DisplayName));
287
+ }
288
+
289
+ if (!String.IsNullOrEmpty(payloadSymbol.Description))
290
+ {
291
+ element.Add(new XAttribute("Description", payloadSymbol.Description));
292
+ }
293
+
294
+ if (!String.IsNullOrEmpty(this.DownloadUrl))
295
+ {
296
+ var filename = this.GetRelativeFileName(payloadSymbol.SourceFile.Path);
297
+ var formattedUrl = String.Format(this.DownloadUrl, filename);
298
+
299
+ if (Uri.TryCreate(formattedUrl, UriKind.Absolute, out var url))
300
+ {
301
+ element.Add(new XAttribute("DownloadUrl", url.AbsoluteUri));
302
+ }
303
+ }
304
+
305
+ if (hashes.TryGetValue(path, out var certificateHashes))
306
+ {
307
+ element.Add(new XAttribute("CertificatePublicKey", certificateHashes.PublicKey));
308
+ element.Add(new XAttribute("CertificateThumbprint", certificateHashes.Thumbprint));
309
+ }
310
+
311
+ if (!String.IsNullOrEmpty(payloadSymbol.Hash))
312
+ {
313
+ element.Add(new XAttribute("Hash", payloadSymbol.Hash));
314
+ }
315
+
316
+ if (payloadSymbol.FileSize.HasValue)
317
+ {
318
+ element.Add(new XAttribute("Size", payloadSymbol.FileSize.Value));
319
+ }
320
+
321
+ if (!String.IsNullOrEmpty(payloadSymbol.Version))
322
+ {
323
+ element.Add(new XAttribute("Version", payloadSymbol.Version));
324
+ }
325
+
326
+ var harvestedFile = new HarvestedFile
327
+ {
328
+ Element = element,
329
+ PayloadSymbol = payloadSymbol,
330
+ };
331
+
332
+ switch (packageType)
333
+ {
334
+ case WixBundlePackageType.Bundle:
335
+ this.HarvestBundle(harvestedFile);
336
+ break;
337
+ }
338
+
339
+ return harvestedFile;
340
}
341
342
private string GetRelativeFileName(string path)
@@ -345,5 +351,75 @@ namespace WixToolset.Core.Burn.CommandLine
351
352
return Path.GetFileName(path);
353
}
354
+
355
+ private void HarvestBundle(HarvestedFile harvestedFile)
356
+ {
357
+ var packagePayloadSymbol = new WixBundleBundlePackagePayloadSymbol(null, new Identifier(AccessModifier.Section, harvestedFile.PayloadSymbol.Id.Id))
358
+ {
359
+ PayloadGeneration = this.BundlePayloadGeneration,
360
+ };
361
+
362
+ var command = new HarvestBundlePackageCommand(this.ServiceProvider, this.BackendExtensions, this.IntermediateFolder, harvestedFile.PayloadSymbol, packagePayloadSymbol, new Dictionary<string, WixBundlePayloadSymbol>());
363
+ command.Execute();
364
+
365
+ if (!this.Messaging.EncounteredError)
366
+ {
367
+ var bundleElement = new XElement(RemoteBundleName);
368
+
369
+ bundleElement.Add(new XAttribute("BundleId", command.HarvestedBundlePackage.BundleId));
370
+
371
+ if (!String.IsNullOrEmpty(command.HarvestedBundlePackage.DisplayName))
372
+ {
373
+ bundleElement.Add(new XAttribute("DisplayName", command.HarvestedBundlePackage.DisplayName));
374
+ }
375
+
376
+ if (!String.IsNullOrEmpty(command.HarvestedBundlePackage.EngineVersion))
377
+ {
378
+ bundleElement.Add(new XAttribute("EngineVersion", command.HarvestedBundlePackage.EngineVersion));
379
+ }
380
+
381
+ bundleElement.Add(new XAttribute("InstallSize", command.HarvestedBundlePackage.InstallSize));
382
+ bundleElement.Add(new XAttribute("ManifestNamespace", command.HarvestedBundlePackage.ManifestNamespace));
383
+ bundleElement.Add(new XAttribute("PerMachine", command.HarvestedBundlePackage.PerMachine ? "yes" : "no"));
384
+ bundleElement.Add(new XAttribute("ProviderKey", command.HarvestedDependencyProvider.ProviderKey));
385
+ bundleElement.Add(new XAttribute("ProtocolVersion", command.HarvestedBundlePackage.ProtocolVersion));
386
+
387
+ if (!String.IsNullOrEmpty(command.HarvestedBundlePackage.Version))
388
+ {
389
+ bundleElement.Add(new XAttribute("Version", command.HarvestedBundlePackage.Version));
390
+ }
391
+
392
+ bundleElement.Add(new XAttribute("Win64", command.HarvestedBundlePackage.Win64 ? "yes" : "no"));
393
+
394
+ var setUpgradeCode = false;
395
+ foreach (var relatedBundle in command.RelatedBundles)
396
+ {
397
+ if (!setUpgradeCode && relatedBundle.Action == RelatedBundleActionType.Upgrade)
398
+ {
399
+ setUpgradeCode = true;
400
+ bundleElement.Add(new XAttribute("UpgradeCode", relatedBundle.BundleId));
401
+ continue;
402
+ }
403
+
404
+ var relatedBundleElement = new XElement(RemoteRelatedBundleName);
405
+
406
+ relatedBundleElement.Add(new XAttribute("Id", relatedBundle.BundleId));
407
+ relatedBundleElement.Add(new XAttribute("Action", relatedBundle.Action.ToString()));
408
+
409
+ bundleElement.Add(relatedBundleElement);
410
+ }
411
+
412
+ harvestedFile.PackagePayloads.AddRange(command.Payloads);
413
+
414
+ harvestedFile.Element.Add(bundleElement);
415
+ }
416
+ }
417
+
418
+ private class HarvestedFile
419
+ {
420
+ public XElement Element { get; set; }
421
+ public WixBundlePayloadSymbol PayloadSymbol { get; set; }
422
+ public List<WixBundlePayloadSymbol> PackagePayloads { get; } = new List<WixBundlePayloadSymbol>();
423
+ }
424
}
425
}
src/wix/WixToolset.Core.TestPackage/XmlNodeExtensions.cs
+11
@@ -12,6 +12,17 @@ namespace WixToolset.Core.TestPackage
12
/// </summary>
13
public static class XmlNodeExtensions
14
{
15
+ /// <summary>
16
+ /// Adds root element around XML then returns it using single quotes and stripping all namespaces.
17
+ /// </summary>
18
+ /// <param name="xmlFragment"></param>
19
+ /// <param name="ignoredAttributesByElementName">Attributes for which the value should be set to '*'.</param>
20
+ /// <returns></returns>
21
+ public static string GetFragmentTestXml(this string xmlFragment, Dictionary<string, List<string>> ignoredAttributesByElementName = null)
22
+ {
23
+ return $"<root>{xmlFragment}</root>".GetTestXml(ignoredAttributesByElementName);
24
+ }
25
+
26
/// <summary>
27
/// Returns the node's outer XML using single quotes and stripping all namespaces.
28
/// </summary>
src/wix/WixToolset.Core/Compile/CompilerPackagePayload.cs
new
+108
@@ -0,0 +1,108 @@
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
4
+{
5
+ using System;
6
+ using System.Collections.Generic;
7
+ using System.Text;
8
+ using System.Xml.Linq;
9
+ using WixToolset.Data;
10
+ using WixToolset.Data.Symbols;
11
+
12
+ internal class CompilerPackagePayload
13
+ {
14
+ public CompilerPackagePayload(CompilerPayload compilerPayload, WixBundlePackageType packageType)
15
+ {
16
+ this.CompilerPayload = compilerPayload;
17
+ this.PackageType = packageType;
18
+ }
19
+
20
+ private CompilerCore Core => this.CompilerPayload.Core;
21
+
22
+ private XElement Element => this.CompilerPayload.Element;
23
+
24
+ private SourceLineNumber SourceLineNumbers => this.CompilerPayload.SourceLineNumbers;
25
+
26
+ public CompilerPayload CompilerPayload { get; }
27
+
28
+ private WixBundlePackageType PackageType { get; }
29
+
30
+ public BundlePackagePayloadGenerationType? PayloadGenerationType { get; set; }
31
+
32
+ public IntermediateSymbol CreatePackagePayloadSymbol(ComplexReferenceParentType parentType, string parentId)
33
+ {
34
+ var payload = this.CompilerPayload.CreatePayloadSymbol(parentType, parentId);
35
+ if (payload == null)
36
+ {
37
+ return null;
38
+ }
39
+
40
+ IntermediateSymbol packagePayload;
41
+
42
+ switch (this.PackageType)
43
+ {
44
+ case WixBundlePackageType.Bundle:
45
+ packagePayload = this.Core.AddSymbol(new WixBundleBundlePackagePayloadSymbol(payload.SourceLineNumbers, payload.Id)
46
+ {
47
+ PayloadGeneration = this.PayloadGenerationType ?? BundlePackagePayloadGenerationType.ExternalWithoutDownloadUrl,
48
+ });
49
+ break;
50
+
51
+ case WixBundlePackageType.Exe:
52
+ packagePayload = this.Core.AddSymbol(new WixBundleExePackagePayloadSymbol(payload.SourceLineNumbers, payload.Id));
53
+ break;
54
+
55
+ case WixBundlePackageType.Msi:
56
+ packagePayload = this.Core.AddSymbol(new WixBundleMsiPackagePayloadSymbol(payload.SourceLineNumbers, payload.Id));
57
+ break;
58
+
59
+ case WixBundlePackageType.Msp:
60
+ packagePayload = this.Core.AddSymbol(new WixBundleMspPackagePayloadSymbol(payload.SourceLineNumbers, payload.Id));
61
+ break;
62
+
63
+ case WixBundlePackageType.Msu:
64
+ packagePayload = this.Core.AddSymbol(new WixBundleMsuPackagePayloadSymbol(payload.SourceLineNumbers, payload.Id));
65
+ break;
66
+
67
+ default:
68
+ throw new NotImplementedException();
69
+ }
70
+
71
+ this.Core.CreateGroupAndOrderingRows(payload.SourceLineNumbers, parentType, parentId, ComplexReferenceChildType.PackagePayload, payload.Id?.Id, ComplexReferenceChildType.Unknown, null);
72
+
73
+ return packagePayload;
74
+ }
75
+
76
+ public bool ParsePayloadGeneration(XAttribute attrib)
77
+ {
78
+ if (this.PackageType != WixBundlePackageType.Bundle)
79
+ {
80
+ return false;
81
+ }
82
+
83
+ var value = this.Core.GetAttributeValue(this.SourceLineNumbers, attrib);
84
+ switch (value)
85
+ {
86
+ case "none":
87
+ this.PayloadGenerationType = BundlePackagePayloadGenerationType.None;
88
+ break;
89
+ case "externalWithoutDownloadUrl":
90
+ this.PayloadGenerationType = BundlePackagePayloadGenerationType.ExternalWithoutDownloadUrl;
91
+ break;
92
+ case "external":
93
+ this.PayloadGenerationType = BundlePackagePayloadGenerationType.External;
94
+ break;
95
+ case "all":
96
+ this.PayloadGenerationType = BundlePackagePayloadGenerationType.All;
97
+ break;
98
+ case "":
99
+ break;
100
+ default:
101
+ this.Core.Write(ErrorMessages.IllegalAttributeValue(this.SourceLineNumbers, this.Element.Name.LocalName, attrib.Name.LocalName, value, "none", "externalWithoutDownloadUrl", "external", "all"));
102
+ break;
103
+ }
104
+
105
+ return true;
106
+ }
107
+ }
108
+}
src/wix/WixToolset.Core/Compile/CompilerPayload.cs
+5
-5
@@ -11,8 +11,6 @@ namespace WixToolset.Core
11
12
internal class CompilerPayload
13
{
14
- public string Version { get; set; }
15
-
14
public CompilerPayload(CompilerCore core, SourceLineNumber sourceLineNumbers, XElement element)
15
{
16
this.Core = core;
@@ -20,11 +18,11 @@ namespace WixToolset.Core
18
this.SourceLineNumbers = sourceLineNumbers;
19
}
20
23
- private CompilerCore Core { get; }
21
+ public CompilerCore Core { get; }
22
25
- private XElement Element { get; }
23
+ public XElement Element { get; }
24
27
- private SourceLineNumber SourceLineNumbers { get; }
25
+ public SourceLineNumber SourceLineNumbers { get; }
26
27
public YesNoDefaultType Compressed { get; set; } = YesNoDefaultType.Default;
28
@@ -52,6 +50,8 @@ namespace WixToolset.Core
50
51
public string SourceFile { get; set; }
52
53
+ public string Version { get; set; }
54
+
55
private void CalculateAndVerifyFields()
56
{
57
var isRemote = this.IsRemoteAllowed && (!String.IsNullOrEmpty(this.CertificatePublicKey) || !String.IsNullOrEmpty(this.CertificateThumbprint) || !String.IsNullOrEmpty(this.Hash));
src/wix/WixToolset.Core/Compiler_Bundle.cs
+22
-48
@@ -1555,12 +1555,8 @@ namespace WixToolset.Core
1555
1556
if (packageType.HasValue)
1557
{
1558
- var compilerPayload = this.ParsePackagePayloadElement(null, child, packageType.Value, null);
1559
- var payloadSymbol = compilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.PayloadGroup, id?.Id);
1560
- if (payloadSymbol != null)
1561
- {
1562
- this.CreatePackagePayloadSymbol(payloadSymbol.SourceLineNumbers, packageType.Value, payloadSymbol.Id, ComplexReferenceParentType.PayloadGroup, id);
1563
- }
1558
+ var compilerPackagePayload = this.ParsePackagePayloadElement(null, child, packageType.Value, null);
1559
+ compilerPackagePayload.CreatePackagePayloadSymbol(ComplexReferenceParentType.PayloadGroup, id?.Id);
1560
}
1561
}
1562
else
@@ -2030,7 +2026,7 @@ namespace WixToolset.Core
2026
string msuKB = null;
2027
var enableFeatureSelection = YesNoType.NotSet;
2028
var forcePerMachine = YesNoType.NotSet;
2033
- CompilerPayload childPackageCompilerPayload = null;
2029
+ CompilerPackagePayload childCompilerPackagePayload = null;
2030
var bundle = YesNoType.NotSet;
2031
var slipstream = YesNoType.NotSet;
2032
var hasPayloadInfo = false;
@@ -2192,7 +2188,7 @@ namespace WixToolset.Core
2188
{
2189
var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
2190
2195
- if (childPackageCompilerPayload != null)
2191
+ if (childCompilerPackagePayload != null)
2192
{
2193
this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, child.Name.LocalName));
2194
}
@@ -2201,12 +2197,12 @@ namespace WixToolset.Core
2197
this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(sourceLineNumbers, node.Name.LocalName, child.Name.LocalName, "SourceFile", "Name", "DownloadUrl", "Compressed"));
2198
}
2199
2204
- childPackageCompilerPayload = this.ParsePackagePayloadElement(childSourceLineNumbers, child, packageType, compilerPayload.Id);
2200
+ childCompilerPackagePayload = this.ParsePackagePayloadElement(childSourceLineNumbers, child, packageType, compilerPayload.Id);
2201
}
2202
2207
- if (compilerPayload.Id == null && childPackageCompilerPayload != null)
2203
+ if (compilerPayload.Id == null && childCompilerPackagePayload != null)
2204
{
2209
- compilerPayload.Id = childPackageCompilerPayload.Id;
2205
+ compilerPayload.Id = childCompilerPackagePayload.CompilerPayload.Id;
2206
}
2207
2208
compilerPayload.FinishCompilingPackage();
@@ -2427,13 +2423,8 @@ namespace WixToolset.Core
2423
2424
if (!this.Core.EncounteredError)
2425
{
2430
- var packageCompilerPayload = childPackageCompilerPayload ?? (hasPayloadInfo ? compilerPayload : null);
2431
- if (packageCompilerPayload != null)
2432
- {
2433
- var payload = packageCompilerPayload.CreatePayloadSymbol(ComplexReferenceParentType.Package, id.Id);
2434
-
2435
- this.CreatePackagePayloadSymbol(sourceLineNumbers, packageType, payload.Id, ComplexReferenceParentType.Package, id);
2436
- }
2426
+ var compilerPackagePayload = childCompilerPackagePayload ?? (hasPayloadInfo ? new CompilerPackagePayload(compilerPayload, packageType) : null);
2427
+ compilerPackagePayload?.CreatePackagePayloadSymbol(ComplexReferenceParentType.Package, id.Id);
2428
2429
this.Core.AddSymbol(new WixChainItemSymbol(sourceLineNumbers, id));
2430
@@ -2536,35 +2527,7 @@ namespace WixToolset.Core
2527
return id.Id;
2528
}
2529
2539
- private void CreatePackagePayloadSymbol(SourceLineNumber sourceLineNumbers, WixBundlePackageType packageType, Identifier payloadId, ComplexReferenceParentType parentType, Identifier parentId)
2540
- {
2541
- switch (packageType)
2542
- {
2543
- case WixBundlePackageType.Bundle:
2544
- this.Core.AddSymbol(new WixBundleBundlePackagePayloadSymbol(sourceLineNumbers, payloadId));
2545
- break;
2546
-
2547
- case WixBundlePackageType.Exe:
2548
- this.Core.AddSymbol(new WixBundleExePackagePayloadSymbol(sourceLineNumbers, payloadId));
2549
- break;
2550
-
2551
- case WixBundlePackageType.Msi:
2552
- this.Core.AddSymbol(new WixBundleMsiPackagePayloadSymbol(sourceLineNumbers, payloadId));
2553
- break;
2554
-
2555
- case WixBundlePackageType.Msp:
2556
- this.Core.AddSymbol(new WixBundleMspPackagePayloadSymbol(sourceLineNumbers, payloadId));
2557
- break;
2558
-
2559
- case WixBundlePackageType.Msu:
2560
- this.Core.AddSymbol(new WixBundleMsuPackagePayloadSymbol(sourceLineNumbers, payloadId));
2561
- break;
2562
- }
2563
-
2564
- this.Core.CreateGroupAndOrderingRows(sourceLineNumbers, parentType, parentId?.Id, ComplexReferenceChildType.PackagePayload, payloadId?.Id, ComplexReferenceChildType.Unknown, null);
2565
- }
2566
-
2567
- private CompilerPayload ParsePackagePayloadElement(SourceLineNumber sourceLineNumbers, XElement node, WixBundlePackageType packageType, Identifier defaultId)
2530
+ private CompilerPackagePayload ParsePackagePayloadElement(SourceLineNumber sourceLineNumbers, XElement node, WixBundlePackageType packageType, Identifier defaultId)
2531
{
2532
sourceLineNumbers = sourceLineNumbers ?? Preprocessor.GetSourceLineNumbers(node);
2533
var compilerPayload = new CompilerPayload(this.Core, sourceLineNumbers, node)
@@ -2572,6 +2535,7 @@ namespace WixToolset.Core
2535
Id = defaultId,
2536
IsRemoteAllowed = packageType == WixBundlePackageType.Bundle || packageType == WixBundlePackageType.Exe || packageType == WixBundlePackageType.Msu,
2537
};
2538
+ var compilerPackagePayload = new CompilerPackagePayload(compilerPayload, packageType);
2539
2540
// This list lets us evaluate extension attributes *after* all core attributes
2541
// have been parsed and dealt with, regardless of authoring order.
@@ -2627,6 +2591,9 @@ namespace WixToolset.Core
2591
compilerPayload.ParseHash(attrib);
2592
}
2593
break;
2594
+ case "PayloadGeneration":
2595
+ allowed = compilerPackagePayload.ParsePayloadGeneration(attrib);
2596
+ break;
2597
case "ProductName":
2598
allowed = compilerPayload.IsRemoteAllowed;
2599
if (allowed)
@@ -2691,11 +2658,18 @@ namespace WixToolset.Core
2658
2659
if (allowed)
2660
{
2661
+ if (compilerPackagePayload.PayloadGenerationType.HasValue)
2662
+ {
2663
+ var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
2664
+ this.Core.Write(ErrorMessages.UnexpectedElementWithAttribute(childSourceLineNumbers, node.Name.LocalName, "RemoteBundle", "PayloadGeneration"));
2665
+ }
2666
+
2667
if (remoteBundleSeen)
2668
{
2669
var childSourceLineNumbers = Preprocessor.GetSourceLineNumbers(child);
2670
this.Core.Write(ErrorMessages.TooManyChildren(childSourceLineNumbers, node.Name.LocalName, "RemoteBundle"));
2671
}
2672
+
2673
this.ParseRemoteBundleElement(child, compilerPayload.Id.Id);
2674
remoteBundleSeen = true;
2675
}
@@ -2723,7 +2697,7 @@ namespace WixToolset.Core
2697
this.Core.Write(ErrorMessages.ExpectedElement(sourceLineNumbers, node.Name.LocalName, "RemoteBundle"));
2698
}
2699
2726
- return compilerPayload;
2700
+ return compilerPackagePayload;
2701
}
2702
2703
private void ParseRemoteBundleElement(XElement node, string packagePayloadId)
src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs
+17
-1
@@ -67,6 +67,7 @@ namespace WixToolsetTest.CoreIntegration
67
{
68
"build",
69
Path.Combine(folder, "BundlePackage", "BundlePackage.wxs"),
70
+ "-bindpath", Path.Combine(folder, ".Data"),
71
"-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
72
"-bindpath", binFolder,
73
"-intermediateFolder", parentIntermediateFolder,
@@ -105,6 +106,7 @@ namespace WixToolsetTest.CoreIntegration
106
"<Provides Key='MyProviderKey,v1.0' Version='1.0.0.0' DisplayName='BurnBundle' Imported='yes' />" +
107
"<RelatedBundle Id='{B94478B1-E1F3-4700-9CE8-6AA090854AEC}' Action='Upgrade' />" +
108
"<PayloadRef Id='chain.exe' />" +
109
+ "<PayloadRef Id='payP6wZpeHEAZbDUQPEKeCpQ_9bN.4' />" +
110
"</BundlePackage>",
111
}, bundlePackages);
112
@@ -129,7 +131,7 @@ namespace WixToolsetTest.CoreIntegration
131
.ToArray();
132
WixAssert.CompareLineByLine(new string[]
133
{
132
- "<WixPackageProperties Package='chain.exe' Vital='yes' DisplayName='BurnBundle' Description='BurnBundle' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='yes' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' Compressed='yes' Version='1.0.0.0' Cache='keep' />",
134
+ "<WixPackageProperties Package='chain.exe' Vital='yes' DisplayName='BurnBundle' Description='BurnBundle' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='yes' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' Compressed='no' Version='1.0.0.0' Cache='keep' />",
135
}, packageElements);
136
137
// grandparent.exe
@@ -178,6 +180,20 @@ namespace WixToolsetTest.CoreIntegration
180
"</BundlePackage>",
181
}, bundlePackages);
182
183
+ ignoreAttributesByElementName = new Dictionary<string, List<string>>
184
+ {
185
+ { "Payload", new List<string> { "FileSize", "Hash" } },
186
+ };
187
+ var payloads = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Payload")
188
+ .Cast<XmlElement>()
189
+ .Select(e => e.GetTestXml(ignoreAttributesByElementName))
190
+ .ToArray();
191
+ WixAssert.CompareLineByLine(new string[]
192
+ {
193
+ "<Payload Id='payP6wZpeHEAZbDUQPEKeCpQ_9bN.4' FilePath='signed_cab1.cab' FileSize='*' Hash='*' Packaging='external' SourcePath='signed_cab1.cab' />",
194
+ "<Payload Id='chain.exe' FilePath='chain.exe' FileSize='*' Hash='*' Packaging='external' SourcePath='chain.exe' />",
195
+ }, payloads);
196
+
197
registrations = grandparentExtractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration")
198
.Cast<XmlElement>()
199
.Select(e => e.GetTestXml())
src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs
+141
-4
@@ -2,6 +2,7 @@
2
3
namespace WixToolsetTest.CoreIntegration
4
{
5
+ using System.Collections.Generic;
6
using System.IO;
7
using System.Linq;
8
using WixBuildTools.TestSupport;
@@ -10,6 +11,142 @@ namespace WixToolsetTest.CoreIntegration
11
12
public class RemotePayloadFixture
13
{
14
+ [Fact]
15
+ public void CanGetRemoteBundlePayload()
16
+ {
17
+ var folder = TestData.Get(@"TestData");
18
+
19
+ using (var fs = new DisposableFileSystem())
20
+ {
21
+ var outputFolder = fs.GetFolder();
22
+ var intermediateFolder = Path.Combine(outputFolder, "obj");
23
+ var exePath = Path.Combine(outputFolder, @"bin\test.exe");
24
+
25
+ var result = WixRunner.Execute(new[]
26
+ {
27
+ "build",
28
+ Path.Combine(folder, "RemotePayload", "DiversePayloadsBundle.wxs"),
29
+ "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
30
+ "-bindpath", Path.Combine(folder, ".Data"),
31
+ "-intermediateFolder", intermediateFolder,
32
+ "-o", exePath,
33
+ });
34
+
35
+ result.AssertSuccess();
36
+
37
+ File.Copy(Path.Combine(folder, ".Data", "signed_bundle_engine.exe"), Path.Combine(outputFolder, "bin", "signed_bundle_engine.exe"));
38
+
39
+ // None
40
+ var noneOutFile = Path.Combine(outputFolder, "none_out.xml");
41
+
42
+ result = WixRunner.Execute(new[]
43
+ {
44
+ "burn", "remotepayload",
45
+ exePath,
46
+ "-o", noneOutFile,
47
+ "-packagetype", "bundle",
48
+ "-bundlepayloadgeneration", "none",
49
+ });
50
+
51
+ result.AssertSuccess();
52
+
53
+ var xml = File.ReadAllText(noneOutFile);
54
+ var ignoreAttributesByElementName = new Dictionary<string, List<string>>
55
+ {
56
+ { "BundlePackagePayload", new List<string> { "Size", "Hash" } },
57
+ { "RemoteBundle", new List<string> { "BundleId", "EngineVersion", "ProviderKey" } },
58
+ { "Payload", new List<string> { "Size", "Hash" } },
59
+ };
60
+ WixAssert.StringEqual(
61
+ "<root>" +
62
+ "<BundlePackagePayload Name='test.exe' ProductName='DiversePayloadsBundle' Description='DiversePayloadsBundle' Hash='*' Size='*' Version='1.0.0.0'>" +
63
+ "<RemoteBundle BundleId='*' DisplayName='DiversePayloadsBundle' EngineVersion='*' InstallSize='3790116' ManifestNamespace='http://wixtoolset.org/schemas/v4/2008/Burn' PerMachine='yes' ProviderKey='*' ProtocolVersion='1' Version='1.0.0.0' Win64='no' UpgradeCode='{FEF1D2B8-4737-4A2A-9F91-77F7294FB55B}' />" +
64
+ "</BundlePackagePayload>" +
65
+ "</root>", xml.GetFragmentTestXml(ignoreAttributesByElementName));
66
+
67
+ // ExternalWithoutDownloadUrl
68
+ var externalWithoutDownloadUrlOutFile = Path.Combine(outputFolder, "externalWithoutDownloadUrl_out.xml");
69
+
70
+ result = WixRunner.Execute(new[]
71
+ {
72
+ "burn", "remotepayload",
73
+ exePath,
74
+ "-o", externalWithoutDownloadUrlOutFile,
75
+ "-packagetype", "bundle",
76
+ "-bundlepayloadgeneration", "externalWithoutDownloadUrl",
77
+ });
78
+
79
+ result.AssertSuccess();
80
+
81
+ xml = File.ReadAllText(externalWithoutDownloadUrlOutFile);
82
+ WixAssert.StringEqual(
83
+ "<root>" +
84
+ "<Payload Name='External.cab' Hash='*' Size='*' />" +
85
+ "<Payload Name='test.msi' Hash='*' Size='*' />" +
86
+ "<Payload Name='test.txt' Hash='*' Size='*' />" +
87
+ "<Payload Name='Shared.dll' Hash='*' Size='*' />" +
88
+ "<BundlePackagePayload Name='test.exe' ProductName='DiversePayloadsBundle' Description='DiversePayloadsBundle' Hash='*' Size='*' Version='1.0.0.0'>" +
89
+ "<RemoteBundle BundleId='*' DisplayName='DiversePayloadsBundle' EngineVersion='*' InstallSize='3790116' ManifestNamespace='http://wixtoolset.org/schemas/v4/2008/Burn' PerMachine='yes' ProviderKey='*' ProtocolVersion='1' Version='1.0.0.0' Win64='no' UpgradeCode='{FEF1D2B8-4737-4A2A-9F91-77F7294FB55B}' />" +
90
+ "</BundlePackagePayload>" +
91
+ "</root>", xml.GetFragmentTestXml(ignoreAttributesByElementName));
92
+
93
+ // External
94
+ var externalOutFile = Path.Combine(outputFolder, "external_out.xml");
95
+
96
+ result = WixRunner.Execute(new[]
97
+ {
98
+ "burn", "remotepayload",
99
+ exePath,
100
+ "-o", externalOutFile,
101
+ "-packagetype", "bundle",
102
+ "-bundlepayloadgeneration", "external",
103
+ });
104
+
105
+ result.AssertSuccess();
106
+
107
+ xml = File.ReadAllText(externalOutFile);
108
+ WixAssert.StringEqual(
109
+ "<root>" +
110
+ "<Payload Name='External.cab' Hash='*' Size='*' />" +
111
+ "<Payload Name='Windows8.1-KB2937592-x86.msu' Hash='*' Size='*' />" +
112
+ "<Payload Name='test.msi' Hash='*' Size='*' />" +
113
+ "<Payload Name='test.txt' Hash='*' Size='*' />" +
114
+ "<Payload Name='Shared.dll' Hash='*' Size='*' />" +
115
+ "<BundlePackagePayload Name='test.exe' ProductName='DiversePayloadsBundle' Description='DiversePayloadsBundle' Hash='*' Size='*' Version='1.0.0.0'>" +
116
+ "<RemoteBundle BundleId='*' DisplayName='DiversePayloadsBundle' EngineVersion='*' InstallSize='3790116' ManifestNamespace='http://wixtoolset.org/schemas/v4/2008/Burn' PerMachine='yes' ProviderKey='*' ProtocolVersion='1' Version='1.0.0.0' Win64='no' UpgradeCode='{FEF1D2B8-4737-4A2A-9F91-77F7294FB55B}' />" +
117
+ "</BundlePackagePayload>" +
118
+ "</root>", xml.GetFragmentTestXml(ignoreAttributesByElementName));
119
+
120
+ // All
121
+ var allOutFile = Path.Combine(outputFolder, "all_out.xml");
122
+
123
+ result = WixRunner.Execute(new[]
124
+ {
125
+ "burn", "remotepayload",
126
+ exePath,
127
+ "-o", allOutFile,
128
+ "-packagetype", "bundle",
129
+ "-bundlepayloadgeneration", "all",
130
+ });
131
+
132
+ result.AssertSuccess();
133
+
134
+ xml = File.ReadAllText(allOutFile);
135
+ WixAssert.StringEqual(
136
+ "<root>" +
137
+ "<Payload Name='External.cab' Hash='*' Size='*' />" +
138
+ "<Payload Name='signed_bundle_engine.exe' ProductName='~TestBundle' Description='~TestBundle' Hash='*' Size='*' Version='1.0.0.0' />" +
139
+ "<Payload Name='Windows8.1-KB2937592-x86.msu' Hash='*' Size='*' />" +
140
+ "<Payload Name='test.msi' Hash='*' Size='*' />" +
141
+ "<Payload Name='test.txt' Hash='*' Size='*' />" +
142
+ "<Payload Name='Shared.dll' Hash='*' Size='*' />" +
143
+ "<BundlePackagePayload Name='test.exe' ProductName='DiversePayloadsBundle' Description='DiversePayloadsBundle' Hash='*' Size='*' Version='1.0.0.0'>" +
144
+ "<RemoteBundle BundleId='*' DisplayName='DiversePayloadsBundle' EngineVersion='*' InstallSize='3790116' ManifestNamespace='http://wixtoolset.org/schemas/v4/2008/Burn' PerMachine='yes' ProviderKey='*' ProtocolVersion='1' Version='1.0.0.0' Win64='no' UpgradeCode='{FEF1D2B8-4737-4A2A-9F91-77F7294FB55B}' />" +
145
+ "</BundlePackagePayload>" +
146
+ "</root>", xml.GetFragmentTestXml(ignoreAttributesByElementName));
147
+ }
148
+ }
149
+
150
[Fact]
151
public void CanGetRemoteV3BundlePayload()
152
{
@@ -181,7 +318,7 @@ namespace WixToolsetTest.CoreIntegration
318
"-recurse",
319
"-du", "https://www.example.com/files/{0}",
320
Path.Combine(folder, ".Data", "burn.exe"),
184
- Path.Combine(folder, "RemotePayload", "*"),
321
+ Path.Combine(folder, "RemotePayload", "recurse", "*"),
322
"-basepath", folder,
323
"-bp", Path.Combine(folder, ".Data"),
324
"-o", outFile
@@ -195,9 +332,9 @@ namespace WixToolsetTest.CoreIntegration
332
WixAssert.CompareLineByLine(new[]
333
{
334
@"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' DownloadUrl='https://www.example.com/files/burn.exe' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />",
198
- @"<Payload Name='a.dat' DownloadUrl='https://www.example.com/files/RemotePayload/a.dat' Hash='D13926E5CBE5ED8B46133F9199FAF2FF25B25981C67A31AE2BC3F6C20390FACBFADCD89BD22D3445D95B989C8EACFB1E68DB634BECB5C9624865BA453BCE362A' Size='16' />",
199
- @"<Payload Name='b.dat' DownloadUrl='https://www.example.com/files/RemotePayload/subfolder/b.dat' Hash='5F94707BC29ADFE3B9615E6753388707FD0B8F5FD9EEEC2B17E21E72F1635FF7D7A101E7D14F614E111F263CB9AC4D0940BE1247881A7844F226D6C400293D8E' Size='37' />",
200
- @"<Payload Name='c.dat' DownloadUrl='https://www.example.com/files/RemotePayload/subfolder/c.dat' Hash='97D6209A5571E05E4F72F9C6BF0987651FA03E63F971F9B53C2B3D798A666D9864F232D4E2D6442E47D9D72B282309B6EEFF4EE017B43B706FA92A0F5EF74734' Size='42' />",
335
+ @"<Payload Name='a.dat' DownloadUrl='https://www.example.com/files/RemotePayload/recurse/a.dat' Hash='D13926E5CBE5ED8B46133F9199FAF2FF25B25981C67A31AE2BC3F6C20390FACBFADCD89BD22D3445D95B989C8EACFB1E68DB634BECB5C9624865BA453BCE362A' Size='16' />",
336
+ @"<Payload Name='b.dat' DownloadUrl='https://www.example.com/files/RemotePayload/recurse/subfolder/b.dat' Hash='5F94707BC29ADFE3B9615E6753388707FD0B8F5FD9EEEC2B17E21E72F1635FF7D7A101E7D14F614E111F263CB9AC4D0940BE1247881A7844F226D6C400293D8E' Size='37' />",
337
+ @"<Payload Name='c.dat' DownloadUrl='https://www.example.com/files/RemotePayload/recurse/subfolder/c.dat' Hash='97D6209A5571E05E4F72F9C6BF0987651FA03E63F971F9B53C2B3D798A666D9864F232D4E2D6442E47D9D72B282309B6EEFF4EE017B43B706FA92A0F5EF74734' Size='42' />",
338
}, elements);
339
}
340
}
src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/BundlePackage.wxs
+4
-2
@@ -1,10 +1,12 @@
1
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
- <Bundle Name="BundlePackageBundle" Version="1.0.1.0" Manufacturer="Example Corporation" UpgradeCode="{4BE34BEE-CA23-488E-96A0-B15878E3654B}">
2
+ <Bundle Name="BundlePackageBundle" Version="1.0.1.0" Manufacturer="Example Corporation" UpgradeCode="{4BE34BEE-CA23-488E-96A0-B15878E3654B}" Compressed="no">
3
<BootstrapperApplication>
4
<BootstrapperApplicationDll SourceFile="fakeba.dll" />
5
</BootstrapperApplication>
6
<Chain>
7
- <BundlePackage SourceFile="chain.exe" Visible="no" Permanent="yes" />
7
+ <BundlePackage SourceFile="chain.exe" Visible="no" Permanent="yes">
8
+ <Payload SourceFile="signed_cab1.cab" />
9
+ </BundlePackage>
10
</Chain>
11
</Bundle>
12
</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/RemotePayload/DiversePayloadsBundle.wxs
new
+24
@@ -0,0 +1,24 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Bundle Name="DiversePayloadsBundle" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="{FEF1D2B8-4737-4A2A-9F91-77F7294FB55B}">
3
+ <BootstrapperApplication>
4
+ <BootstrapperApplicationDll SourceFile="fakeba.dll" />
5
+ </BootstrapperApplication>
6
+ <Chain>
7
+ <PackageGroupRef Id="ExternalContainerPackages" />
8
+ <ExePackage SourceFile="signed_bundle_engine.exe" DetectCondition="none" Permanent="yes" />
9
+ <MsuPackage SourceFile="Windows8.1-KB2937592-x86.msu" DetectCondition="none" Permanent="yes" Compressed="no" DownloadUrl="http://example.com/test.msu" />
10
+ <MsiPackage SourceFile="test.msi" Compressed="no" />
11
+ </Chain>
12
+ <Container Name="External.cab">
13
+ <PackageGroupRef Id="ExternalContainerPackages" />
14
+ </Container>
15
+ </Bundle>
16
+
17
+ <Fragment>
18
+ <PackageGroup Id="ExternalContainerPackages">
19
+ <ExePackage SourceFile="burn.exe" DetectCondition="none" Permanent="yes">
20
+ <Payload SourceFile="signed_cab1.cab" />
21
+ </ExePackage>
22
+ </PackageGroup>
23
+ </Fragment>
24
+</Wix>