@joebigelow / wix-1 / commits / c76db43a

Resolve container and payload DownloadUrls

Fixes wixtoolset/issues#6405

Rob Mensching committed Apr 19, 2021 at 12:49 UTC c76db43a5ce1da70a980dc5651141c2a6cd94f6b
4 files changed +138 -48
src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+7 -1
@@ -459,12 +459,18 @@ namespace WixToolset.Core.Burn
459 containers = command.Containers;
460 }
461
462 + // Resolve the download URLs now that we have all of the containers and payloads calculated.
463 + {
464 + var command = new ResolveDownloadUrlsCommand(this.Messaging, this.BackendExtensions, containers, payloadSymbols);
465 + command.Execute();
466 + }
467 +
468 // Create the bundle manifest.
469 string manifestPath;
470 {
471 var executableName = Path.GetFileName(this.OutputPath);
472
467 - var command = new CreateBurnManifestCommand(this.Messaging, this.BackendExtensions, executableName, section, bundleSymbol, containers, chainSymbol, orderedFacades, boundaries, uxPayloads, payloadSymbols, packagesPayloads, orderedSearches, this.IntermediateFolder);
473 + var command = new CreateBurnManifestCommand(executableName, section, bundleSymbol, containers, chainSymbol, orderedFacades, boundaries, uxPayloads, payloadSymbols, packagesPayloads, orderedSearches, this.IntermediateFolder);
474 command.Execute();
475
476 manifestPath = command.OutputPath;
src/WixToolset.Core.Burn/Bind/ResolveDownloadUrlsCommand.cs new
+127
@@ -0,0 +1,127 @@
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.Bind
4 +{
5 + using System;
6 + using System.Collections.Generic;
7 + using WixToolset.Data;
8 + using WixToolset.Data.Symbols;
9 + using WixToolset.Extensibility;
10 + using WixToolset.Extensibility.Services;
11 +
12 + internal class ResolveDownloadUrlsCommand
13 + {
14 + public ResolveDownloadUrlsCommand(IMessaging messaging, IEnumerable<IBurnBackendBinderExtension> backendExtensions, IEnumerable<WixBundleContainerSymbol> containers, Dictionary<string, WixBundlePayloadSymbol> payloadsById)
15 + {
16 + this.Messaging = messaging;
17 + this.BackendExtensions = backendExtensions;
18 + this.Containers = containers;
19 + this.PayloadsById = payloadsById;
20 + }
21 +
22 + private IMessaging Messaging { get; }
23 +
24 + private IEnumerable<IBurnBackendBinderExtension> BackendExtensions { get; }
25 +
26 + private IEnumerable<WixBundleContainerSymbol> Containers { get; }
27 +
28 + private Dictionary<string, WixBundlePayloadSymbol> PayloadsById { get; }
29 +
30 + public void Execute()
31 + {
32 + this.ResolveContainerUrls();
33 +
34 + this.ResolvePayloadUrls();
35 + }
36 +
37 + private void ResolveContainerUrls()
38 + {
39 + foreach (var container in this.Containers)
40 + {
41 + if (container.Type == ContainerType.Detached)
42 + {
43 + var resolvedUrl = this.ResolveUrl(container.DownloadUrl, null, null, container.Id.Id, container.Name);
44 + if (!String.IsNullOrEmpty(resolvedUrl))
45 + {
46 + container.DownloadUrl = resolvedUrl;
47 + }
48 + }
49 + else if (container.Type == ContainerType.Attached)
50 + {
51 + if (!String.IsNullOrEmpty(container.DownloadUrl))
52 + {
53 + this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id.Id));
54 + }
55 + }
56 + }
57 + }
58 +
59 + private void ResolvePayloadUrls()
60 + {
61 + foreach (var payload in this.PayloadsById.Values)
62 + {
63 + if (payload.Packaging == PackagingType.External)
64 + {
65 + var packageId = payload.ParentPackagePayloadRef;
66 + var parentUrl = payload.ParentPackagePayloadRef == null ? null : this.PayloadsById[payload.ParentPackagePayloadRef].DownloadUrl;
67 + var resolvedUrl = this.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id.Id, payload.Name);
68 + if (!String.IsNullOrEmpty(resolvedUrl))
69 + {
70 + payload.DownloadUrl = resolvedUrl;
71 + }
72 + }
73 + else if (payload.Packaging == PackagingType.Embedded)
74 + {
75 + if (!String.IsNullOrEmpty(payload.DownloadUrl))
76 + {
77 + this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id.Id));
78 + }
79 + }
80 + }
81 + }
82 +
83 + private string ResolveUrl(string url, string fallbackUrl, string packageId, string payloadId, string fileName)
84 + {
85 + string resolvedUrl = null;
86 +
87 + foreach (var extension in this.BackendExtensions)
88 + {
89 + resolvedUrl = extension.ResolveUrl(url, fallbackUrl, packageId, payloadId, fileName);
90 + if (!String.IsNullOrEmpty(resolvedUrl))
91 + {
92 + break;
93 + }
94 + }
95 +
96 + if (String.IsNullOrEmpty(resolvedUrl))
97 + {
98 + // If a URL was not specified but there is a fallback URL that has a format specifier in it
99 + // then use the fallback URL formatter for this URL.
100 + if (String.IsNullOrEmpty(url) && !String.IsNullOrEmpty(fallbackUrl))
101 + {
102 + var formattedFallbackUrl = String.Format(fallbackUrl, packageId, payloadId, fileName);
103 + if (!String.Equals(fallbackUrl, formattedFallbackUrl, StringComparison.OrdinalIgnoreCase))
104 + {
105 + url = fallbackUrl;
106 + }
107 + }
108 +
109 + if (!String.IsNullOrEmpty(url))
110 + {
111 + var formattedUrl = String.Format(url, packageId, payloadId, fileName);
112 +
113 + if (Uri.TryCreate(formattedUrl, UriKind.Absolute, out var canonicalUri))
114 + {
115 + resolvedUrl = canonicalUri.AbsoluteUri;
116 + }
117 + else
118 + {
119 + resolvedUrl = null;
120 + }
121 + }
122 + }
123 +
124 + return resolvedUrl;
125 + }
126 + }
127 +}
src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+3 -46
@@ -18,10 +18,8 @@ namespace WixToolset.Core.Burn.Bundles
18
19 internal class CreateBurnManifestCommand
20 {
21 - public CreateBurnManifestCommand(IMessaging messaging, IEnumerable<IBurnBackendBinderExtension> backendExtensions, 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, IEnumerable<PackageFacade> orderedPackages, IEnumerable<WixBundleRollbackBoundarySymbol> boundaries, IEnumerable<WixBundlePayloadSymbol> uxPayloads, Dictionary<string, WixBundlePayloadSymbol> allPayloadsById, Dictionary<string, Dictionary<string, WixBundlePayloadSymbol>> packagesPayloads, IEnumerable<ISearchFacade> orderedSearches, string intermediateFolder)
22 {
23 - this.Messaging = messaging;
24 - this.BackendExtensions = backendExtensions;
23 this.ExecutableName = executableName;
24 this.Section = section;
25 this.BundleSymbol = bundleSymbol;
@@ -38,10 +36,6 @@ namespace WixToolset.Core.Burn.Bundles
36
37 public string OutputPath { get; private set; }
38
41 - private IMessaging Messaging { get; }
42 -
43 - private IEnumerable<IBurnBackendBinderExtension> BackendExtensions { get; }
44 -
39 private string ExecutableName { get; }
40
41 private IntermediateSection Section { get; }
@@ -657,12 +651,7 @@ namespace WixToolset.Core.Burn.Bundles
651
652 if (ContainerType.Detached == container.Type)
653 {
660 - string resolvedUrl = this.ResolveUrl(container.DownloadUrl, null, null, container.Id.Id, container.Name);
661 - if (!String.IsNullOrEmpty(resolvedUrl))
662 - {
663 - writer.WriteAttributeString("DownloadUrl", resolvedUrl);
664 - }
665 - else if (!String.IsNullOrEmpty(container.DownloadUrl))
654 + if (!String.IsNullOrEmpty(container.DownloadUrl))
655 {
656 writer.WriteAttributeString("DownloadUrl", container.DownloadUrl);
657 }
@@ -671,11 +660,6 @@ namespace WixToolset.Core.Burn.Bundles
660 }
661 else if (ContainerType.Attached == container.Type)
662 {
674 - if (!String.IsNullOrEmpty(container.DownloadUrl))
675 - {
676 - this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id.Id));
677 - }
678 -
663 writer.WriteAttributeString("FilePath", executableName); // attached containers use the name of the bundle since they are attached to the executable.
664 writer.WriteAttributeString("AttachedIndex", container.AttachedContainerIndex.Value.ToString(CultureInfo.InvariantCulture));
665 writer.WriteAttributeString("Attached", "yes");
@@ -700,11 +684,6 @@ namespace WixToolset.Core.Burn.Bundles
684 switch (payload.Packaging)
685 {
686 case PackagingType.Embedded: // this means it's in a container.
703 - if (!String.IsNullOrEmpty(payload.DownloadUrl))
704 - {
705 - this.Messaging.Write(WarningMessages.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id.Id));
706 - }
707 -
687 writer.WriteAttributeString("Packaging", "embedded");
688 writer.WriteAttributeString("SourcePath", payload.EmbeddedId);
689
@@ -715,14 +694,7 @@ namespace WixToolset.Core.Burn.Bundles
694 break;
695
696 case PackagingType.External:
718 - var packageId = payload.ParentPackagePayloadRef;
719 - var parentUrl = payload.ParentPackagePayloadRef == null ? null : allPayloads[payload.ParentPackagePayloadRef].DownloadUrl;
720 - var resolvedUrl = this.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id.Id, payload.Name);
721 - if (!String.IsNullOrEmpty(resolvedUrl))
722 - {
723 - writer.WriteAttributeString("DownloadUrl", resolvedUrl);
724 - }
725 - else if (!String.IsNullOrEmpty(payload.DownloadUrl))
697 + if (!String.IsNullOrEmpty(payload.DownloadUrl))
698 {
699 writer.WriteAttributeString("DownloadUrl", payload.DownloadUrl);
700 }
@@ -732,20 +704,5 @@ namespace WixToolset.Core.Burn.Bundles
704 break;
705 }
706 }
735 -
736 - private string ResolveUrl(string url, string fallbackUrl, string packageId, string payloadId, string fileName)
737 - {
738 - string resolved = null;
739 - foreach (var extension in this.BackendExtensions)
740 - {
741 - resolved = extension.ResolveUrl(url, fallbackUrl, packageId, payloadId, fileName);
742 - if (!String.IsNullOrEmpty(resolved))
743 - {
744 - break;
745 - }
746 - }
747 -
748 - return resolved;
749 - }
707 }
708 }
src/test/WixToolsetTest.CoreIntegration/PayloadFixture.cs
+1 -1
@@ -143,7 +143,7 @@ namespace WixToolsetTest.CoreIntegration
143 }
144 }
145
146 - [Fact(Skip = "Test demonstrates failure")]
146 + [Fact]
147 public void ReplacesDownloadUrlPlaceholders()
148 {
149 var folder = TestData.Get(@"TestData");