diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2022-04-13 12:17:36 -0500 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2022-04-13 13:13:48 -0500 |
commit | 535e4165e3121a14e5799f575a1010671212c539 (patch) | |
tree | 7b7f5b7da112d7c519a20fd109d2537cdc1152f1 | |
parent | faa9777b7720a935b28c33c3fa1088cd7bcc2f86 (diff) | |
download | wix-535e4165e3121a14e5799f575a1010671212c539.tar.gz wix-535e4165e3121a14e5799f575a1010671212c539.tar.bz2 wix-535e4165e3121a14e5799f575a1010671212c539.zip |
Add bundle support to "burn remotepayload" command.
7 files changed, 379 insertions, 206 deletions
diff --git a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index ffc219dc..1c88fdeb 100644 --- a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs | |||
@@ -182,6 +182,8 @@ namespace WixToolset.Core.Burn | |||
182 | { | 182 | { |
183 | var command = new ProcessBundlePackageCommand(this.ServiceProvider, section, facade, packagesPayloads[facade.PackageId], this.IntermediateFolder); | 183 | var command = new ProcessBundlePackageCommand(this.ServiceProvider, section, facade, packagesPayloads[facade.PackageId], this.IntermediateFolder); |
184 | command.Execute(); | 184 | command.Execute(); |
185 | |||
186 | trackedFiles.AddRange(command.TrackedFiles); | ||
185 | } | 187 | } |
186 | break; | 188 | break; |
187 | 189 | ||
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/HarvestBundlePackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/HarvestBundlePackageCommand.cs new file mode 100644 index 00000000..84ce6051 --- /dev/null +++ b/src/wix/WixToolset.Core.Burn/Bundles/HarvestBundlePackageCommand.cs | |||
@@ -0,0 +1,248 @@ | |||
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; | ||
6 | using System.Collections.Generic; | ||
7 | using System.IO; | ||
8 | using System.Text; | ||
9 | using System.Xml; | ||
10 | using WixToolset.Data; | ||
11 | using WixToolset.Data.Symbols; | ||
12 | using WixToolset.Extensibility.Data; | ||
13 | using WixToolset.Extensibility.Services; | ||
14 | |||
15 | internal class HarvestBundlePackageCommand | ||
16 | { | ||
17 | public HarvestBundlePackageCommand(IServiceProvider serviceProvider, string intermediateFolder, WixBundlePayloadSymbol payloadSymbol) | ||
18 | { | ||
19 | this.Messaging = serviceProvider.GetService<IMessaging>(); | ||
20 | this.BackendHelper = serviceProvider.GetService<IBackendHelper>(); | ||
21 | this.IntermediateFolder = intermediateFolder; | ||
22 | |||
23 | this.PackagePayload = payloadSymbol; | ||
24 | } | ||
25 | |||
26 | private IMessaging Messaging { get; } | ||
27 | |||
28 | private IBackendHelper BackendHelper { get; } | ||
29 | |||
30 | private string IntermediateFolder { get; } | ||
31 | |||
32 | private WixBundlePayloadSymbol PackagePayload { get; } | ||
33 | |||
34 | public WixBundleHarvestedBundlePackageSymbol HarvestedBundlePackage { get; private set; } | ||
35 | |||
36 | public WixBundleHarvestedDependencyProviderSymbol HarvestedDependencyProvider { get; private set; } | ||
37 | |||
38 | public List<WixBundlePackageRelatedBundleSymbol> RelatedBundles { get; } = new List<WixBundlePackageRelatedBundleSymbol>(); | ||
39 | |||
40 | public List<ITrackedFile> TrackedFiles { get; } = new List<ITrackedFile>(); | ||
41 | |||
42 | public void Execute() | ||
43 | { | ||
44 | bool win64; | ||
45 | string bundleId; | ||
46 | string engineVersion; | ||
47 | int protocolVersion; | ||
48 | string manifestNamespace; | ||
49 | bool perMachine; | ||
50 | string version; | ||
51 | string displayName; | ||
52 | long installSize; | ||
53 | |||
54 | var sourcePath = this.PackagePayload.SourceFile.Path; | ||
55 | var sourceLineNumbers = this.PackagePayload.SourceLineNumbers; | ||
56 | |||
57 | using (var burnReader = BurnReader.Open(this.Messaging, sourcePath)) | ||
58 | { | ||
59 | if (burnReader.Invalid) | ||
60 | { | ||
61 | return; | ||
62 | } | ||
63 | |||
64 | var baFolderPath = Path.Combine(this.IntermediateFolder, burnReader.BundleId.ToString()); | ||
65 | |||
66 | if (!burnReader.ExtractUXContainer(baFolderPath, baFolderPath)) | ||
67 | { | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | foreach (var filePath in Directory.EnumerateFiles(baFolderPath, "*.*", SearchOption.AllDirectories)) | ||
72 | { | ||
73 | this.TrackedFiles.Add(this.BackendHelper.TrackFile(filePath, TrackedFileType.Temporary, sourceLineNumbers)); | ||
74 | } | ||
75 | |||
76 | bundleId = burnReader.BundleId.ToString("B").ToUpperInvariant(); | ||
77 | |||
78 | try | ||
79 | { | ||
80 | var document = new XmlDocument(); | ||
81 | document.Load(Path.Combine(baFolderPath, "manifest.xml")); | ||
82 | var namespaceManager = new XmlNamespaceManager(document.NameTable); | ||
83 | |||
84 | if (document.DocumentElement.LocalName != "BurnManifest") | ||
85 | { | ||
86 | this.Messaging.Write(BurnBackendErrors.InvalidBundleManifest(sourceLineNumbers, sourcePath, $"Expected root element to be 'BurnManifest' but was '{document.DocumentElement.LocalName}'.")); | ||
87 | return; | ||
88 | } | ||
89 | |||
90 | engineVersion = document.DocumentElement.GetAttribute("EngineVersion"); | ||
91 | protocolVersion = this.ProcessProtocolVersion(burnReader, document); | ||
92 | win64 = this.ProcessWin64(burnReader, document, sourceLineNumbers, sourcePath); | ||
93 | |||
94 | manifestNamespace = document.DocumentElement.NamespaceURI; | ||
95 | |||
96 | namespaceManager.AddNamespace("burn", document.DocumentElement.NamespaceURI); | ||
97 | var registrationElement = document.SelectSingleNode("/burn:BurnManifest/burn:Registration", namespaceManager) as XmlElement; | ||
98 | var arpElement = document.SelectSingleNode("/burn:BurnManifest/burn:Registration/burn:Arp", namespaceManager) as XmlElement; | ||
99 | |||
100 | perMachine = registrationElement.GetAttribute("PerMachine") == "yes"; | ||
101 | |||
102 | version = registrationElement.GetAttribute("Version"); | ||
103 | |||
104 | var providerKey = registrationElement.GetAttribute("ProviderKey"); | ||
105 | var depId = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", this.PackagePayload.Id.Id, providerKey)); | ||
106 | this.HarvestedDependencyProvider = new WixBundleHarvestedDependencyProviderSymbol(sourceLineNumbers, depId) | ||
107 | { | ||
108 | PackagePayloadRef = this.PackagePayload.Id.Id, | ||
109 | ProviderKey = providerKey, | ||
110 | Version = version, | ||
111 | }; | ||
112 | |||
113 | displayName = arpElement.GetAttribute("DisplayName"); | ||
114 | |||
115 | installSize = this.ProcessPackages(document, namespaceManager); | ||
116 | |||
117 | this.ProcessRelatedBundles(document, namespaceManager, sourcePath); | ||
118 | |||
119 | // TODO: Add payloads? | ||
120 | } | ||
121 | catch (Exception e) | ||
122 | { | ||
123 | this.Messaging.Write(BurnBackendErrors.InvalidBundleManifest(sourceLineNumbers, sourcePath, e.ToString())); | ||
124 | return; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | this.HarvestedBundlePackage = new WixBundleHarvestedBundlePackageSymbol(this.PackagePayload.SourceLineNumbers, this.PackagePayload.Id) | ||
129 | { | ||
130 | Win64 = win64, | ||
131 | BundleId = bundleId, | ||
132 | EngineVersion = engineVersion, | ||
133 | ManifestNamespace = manifestNamespace, | ||
134 | ProtocolVersion = protocolVersion, | ||
135 | PerMachine = perMachine, | ||
136 | Version = version, | ||
137 | DisplayName = displayName, | ||
138 | InstallSize = installSize, | ||
139 | }; | ||
140 | } | ||
141 | |||
142 | private int ProcessProtocolVersion(BurnReader burnReader, XmlDocument document) | ||
143 | { | ||
144 | var protocolVersionValue = document.DocumentElement.GetAttribute("ProtocolVersion"); | ||
145 | |||
146 | if (Int32.TryParse(protocolVersionValue, out var protocolVersion)) | ||
147 | { | ||
148 | return protocolVersion; | ||
149 | } | ||
150 | |||
151 | // Assume that the .wixburn section version will change when the Burn protocol changes. | ||
152 | // This should be a safe assumption since only old bundles should be missing the ProtocolVersion from the manifest. | ||
153 | return burnReader.Version == 2 ? 1 : 0; | ||
154 | } | ||
155 | |||
156 | private bool ProcessWin64(BurnReader burnReader, XmlDocument document, SourceLineNumber sourceLineNumbers, string sourcePath) | ||
157 | { | ||
158 | var win64Value = document.DocumentElement.GetAttribute("Win64"); | ||
159 | |||
160 | switch (win64Value) | ||
161 | { | ||
162 | case "yes": | ||
163 | return true; | ||
164 | case "no": | ||
165 | return false; | ||
166 | } | ||
167 | |||
168 | switch (burnReader.MachineType) | ||
169 | { | ||
170 | case BurnCommon.IMAGE_FILE_MACHINE_ARM: | ||
171 | case BurnCommon.IMAGE_FILE_MACHINE_ARMNT: | ||
172 | case BurnCommon.IMAGE_FILE_MACHINE_I386: | ||
173 | case BurnCommon.IMAGE_FILE_MACHINE_LOONGARCH32: | ||
174 | return false; | ||
175 | case BurnCommon.IMAGE_FILE_MACHINE_AMD64: | ||
176 | case BurnCommon.IMAGE_FILE_MACHINE_ARM64: | ||
177 | case BurnCommon.IMAGE_FILE_MACHINE_IA64: | ||
178 | case BurnCommon.IMAGE_FILE_MACHINE_LOONGARCH64: | ||
179 | return true; | ||
180 | case BurnCommon.IMAGE_FILE_MACHINE_AM33: | ||
181 | case BurnCommon.IMAGE_FILE_MACHINE_EBC: | ||
182 | case BurnCommon.IMAGE_FILE_MACHINE_M32R: | ||
183 | case BurnCommon.IMAGE_FILE_MACHINE_MIPS16: | ||
184 | case BurnCommon.IMAGE_FILE_MACHINE_MIPSFPU: | ||
185 | case BurnCommon.IMAGE_FILE_MACHINE_MIPSFPU16: | ||
186 | case BurnCommon.IMAGE_FILE_MACHINE_POWERPC: | ||
187 | case BurnCommon.IMAGE_FILE_MACHINE_POWERPCFP: | ||
188 | case BurnCommon.IMAGE_FILE_MACHINE_R4000: | ||
189 | case BurnCommon.IMAGE_FILE_MACHINE_RISCV32: | ||
190 | case BurnCommon.IMAGE_FILE_MACHINE_RISCV64: | ||
191 | case BurnCommon.IMAGE_FILE_MACHINE_RISCV128: | ||
192 | case BurnCommon.IMAGE_FILE_MACHINE_SH3: | ||
193 | case BurnCommon.IMAGE_FILE_MACHINE_SH3DSP: | ||
194 | case BurnCommon.IMAGE_FILE_MACHINE_SH4: | ||
195 | case BurnCommon.IMAGE_FILE_MACHINE_SH5: | ||
196 | case BurnCommon.IMAGE_FILE_MACHINE_THUMB: | ||
197 | case BurnCommon.IMAGE_FILE_MACHINE_WCEMIPSV2: | ||
198 | default: | ||
199 | this.Messaging.Write(BurnBackendWarnings.UnknownCoffMachineType(sourceLineNumbers, sourcePath, burnReader.MachineType)); | ||
200 | return false; | ||
201 | } | ||
202 | } | ||
203 | |||
204 | private long ProcessPackages(XmlDocument document, XmlNamespaceManager namespaceManager) | ||
205 | { | ||
206 | long packageInstallSize = 0; | ||
207 | |||
208 | foreach (XmlElement packageElement in document.SelectNodes("/burn:BurnManifest/burn:Chain/*", namespaceManager)) | ||
209 | { | ||
210 | if (!packageElement.Name.EndsWith("Package")) | ||
211 | { | ||
212 | continue; | ||
213 | } | ||
214 | |||
215 | if (Int64.TryParse(packageElement.GetAttribute("InstallSize"), out var installSize)) | ||
216 | { | ||
217 | packageInstallSize += installSize; | ||
218 | } | ||
219 | } | ||
220 | |||
221 | return packageInstallSize; | ||
222 | } | ||
223 | |||
224 | private void ProcessRelatedBundles(XmlDocument document, XmlNamespaceManager namespaceManager, string sourcePath) | ||
225 | { | ||
226 | var sourceLineNumbers = this.PackagePayload.SourceLineNumbers; | ||
227 | |||
228 | foreach (XmlElement relatedBundleElement in document.SelectNodes("/burn:BurnManifest/burn:RelatedBundle", namespaceManager)) | ||
229 | { | ||
230 | var id = relatedBundleElement.GetAttribute("Id"); | ||
231 | var actionValue = relatedBundleElement.GetAttribute("Action"); | ||
232 | |||
233 | if (!Enum.TryParse(actionValue, out RelatedBundleActionType action)) | ||
234 | { | ||
235 | this.Messaging.Write(BurnBackendWarnings.UnknownBundleRelationAction(sourceLineNumbers, sourcePath, actionValue)); | ||
236 | continue; | ||
237 | } | ||
238 | |||
239 | this.RelatedBundles.Add(new WixBundlePackageRelatedBundleSymbol(sourceLineNumbers) | ||
240 | { | ||
241 | PackagePayloadRef = this.PackagePayload.Id.Id, | ||
242 | BundleId = id, | ||
243 | Action = action, | ||
244 | }); | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | } | ||
diff --git a/src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs index c8e6bcf2..af37676c 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/ProcessBundlePackageCommand.cs | |||
@@ -4,10 +4,7 @@ namespace WixToolset.Core.Burn.Bundles | |||
4 | { | 4 | { |
5 | using System; | 5 | using System; |
6 | using System.Collections.Generic; | 6 | using System.Collections.Generic; |
7 | using System.Diagnostics; | ||
8 | using System.IO; | ||
9 | using System.Linq; | 7 | using System.Linq; |
10 | using System.Xml; | ||
11 | using WixToolset.Data; | 8 | using WixToolset.Data; |
12 | using WixToolset.Data.Symbols; | 9 | using WixToolset.Data.Symbols; |
13 | using WixToolset.Extensibility.Data; | 10 | using WixToolset.Extensibility.Data; |
@@ -20,8 +17,8 @@ namespace WixToolset.Core.Burn.Bundles | |||
20 | { | 17 | { |
21 | public ProcessBundlePackageCommand(IServiceProvider serviceProvider, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> packagePayloads, string intermediateFolder) | 18 | public ProcessBundlePackageCommand(IServiceProvider serviceProvider, IntermediateSection section, PackageFacade facade, Dictionary<string, WixBundlePayloadSymbol> packagePayloads, string intermediateFolder) |
22 | { | 19 | { |
20 | this.ServiceProvider = serviceProvider; | ||
23 | this.Messaging = serviceProvider.GetService<IMessaging>(); | 21 | this.Messaging = serviceProvider.GetService<IMessaging>(); |
24 | this.BackendHelper = serviceProvider.GetService<IBackendHelper>(); | ||
25 | this.PackagePayloads = packagePayloads; | 22 | this.PackagePayloads = packagePayloads; |
26 | this.Section = section; | 23 | this.Section = section; |
27 | this.IntermediateFolder = intermediateFolder; | 24 | this.IntermediateFolder = intermediateFolder; |
@@ -31,9 +28,9 @@ namespace WixToolset.Core.Burn.Bundles | |||
31 | this.PackagePayload = packagePayloads[this.ChainPackage.PayloadRef]; | 28 | this.PackagePayload = packagePayloads[this.ChainPackage.PayloadRef]; |
32 | } | 29 | } |
33 | 30 | ||
34 | private IMessaging Messaging { get; } | 31 | private IServiceProvider ServiceProvider { get; } |
35 | 32 | ||
36 | private IBackendHelper BackendHelper { get; } | 33 | private IMessaging Messaging { get; } |
37 | 34 | ||
38 | private Dictionary<string, WixBundlePayloadSymbol> PackagePayloads { get; } | 35 | private Dictionary<string, WixBundlePayloadSymbol> PackagePayloads { get; } |
39 | 36 | ||
@@ -101,210 +98,26 @@ namespace WixToolset.Core.Burn.Bundles | |||
101 | this.ChainPackage.InstallSize = harvestedBundlePackage.InstallSize; | 98 | this.ChainPackage.InstallSize = harvestedBundlePackage.InstallSize; |
102 | } | 99 | } |
103 | 100 | ||
104 | public WixBundleHarvestedBundlePackageSymbol HarvestPackage() | 101 | private WixBundleHarvestedBundlePackageSymbol HarvestPackage() |
105 | { | 102 | { |
106 | bool win64; | 103 | var command = new HarvestBundlePackageCommand(this.ServiceProvider, this.IntermediateFolder, this.PackagePayload); |
107 | string bundleId; | 104 | command.Execute(); |
108 | string engineVersion; | ||
109 | int protocolVersion; | ||
110 | string manifestNamespace; | ||
111 | bool perMachine; | ||
112 | string version; | ||
113 | string displayName; | ||
114 | long installSize; | ||
115 | |||
116 | var sourcePath = this.PackagePayload.SourceFile.Path; | ||
117 | var sourceLineNumbers = this.PackagePayload.SourceLineNumbers; | ||
118 | 105 | ||
119 | using (var burnReader = BurnReader.Open(this.Messaging, sourcePath)) | 106 | this.TrackedFiles.AddRange(command.TrackedFiles); |
107 | if (this.Messaging.EncounteredError) | ||
120 | { | 108 | { |
121 | if (burnReader.Invalid) | 109 | return null; |
122 | { | ||
123 | return null; | ||
124 | } | ||
125 | |||
126 | var baFolderPath = Path.Combine(this.IntermediateFolder, burnReader.BundleId.ToString()); | ||
127 | |||
128 | if (!burnReader.ExtractUXContainer(baFolderPath, baFolderPath)) | ||
129 | { | ||
130 | return null; | ||
131 | } | ||
132 | |||
133 | foreach (var filePath in Directory.EnumerateFiles(baFolderPath, "*.*", SearchOption.AllDirectories)) | ||
134 | { | ||
135 | this.TrackedFiles.Add(this.BackendHelper.TrackFile(filePath, TrackedFileType.Temporary, sourceLineNumbers)); | ||
136 | } | ||
137 | |||
138 | bundleId = burnReader.BundleId.ToString("B").ToUpperInvariant(); | ||
139 | |||
140 | try | ||
141 | { | ||
142 | var document = new XmlDocument(); | ||
143 | document.Load(Path.Combine(baFolderPath, "manifest.xml")); | ||
144 | var namespaceManager = new XmlNamespaceManager(document.NameTable); | ||
145 | |||
146 | if (document.DocumentElement.LocalName != "BurnManifest") | ||
147 | { | ||
148 | this.Messaging.Write(BurnBackendErrors.InvalidBundleManifest(sourceLineNumbers, sourcePath, $"Expected root element to be 'BurnManifest' but was '{document.DocumentElement.LocalName}'.")); | ||
149 | return null; | ||
150 | } | ||
151 | |||
152 | engineVersion = document.DocumentElement.GetAttribute("EngineVersion"); | ||
153 | protocolVersion = this.ProcessProtocolVersion(burnReader, document); | ||
154 | win64 = this.ProcessWin64(burnReader, document, sourceLineNumbers, sourcePath); | ||
155 | |||
156 | manifestNamespace = document.DocumentElement.NamespaceURI; | ||
157 | |||
158 | namespaceManager.AddNamespace("burn", document.DocumentElement.NamespaceURI); | ||
159 | var registrationElement = document.SelectSingleNode("/burn:BurnManifest/burn:Registration", namespaceManager) as XmlElement; | ||
160 | var arpElement = document.SelectSingleNode("/burn:BurnManifest/burn:Registration/burn:Arp", namespaceManager) as XmlElement; | ||
161 | |||
162 | perMachine = registrationElement.GetAttribute("PerMachine") == "yes"; | ||
163 | |||
164 | version = registrationElement.GetAttribute("Version"); | ||
165 | |||
166 | var providerKey = registrationElement.GetAttribute("ProviderKey"); | ||
167 | var depId = new Identifier(AccessModifier.Section, this.BackendHelper.GenerateIdentifier("dep", this.PackagePayload.Id.Id, providerKey)); | ||
168 | this.Section.AddSymbol(new WixBundleHarvestedDependencyProviderSymbol(sourceLineNumbers, depId) | ||
169 | { | ||
170 | PackagePayloadRef = this.PackagePayload.Id.Id, | ||
171 | ProviderKey = providerKey, | ||
172 | Version = version, | ||
173 | }); | ||
174 | |||
175 | displayName = arpElement.GetAttribute("DisplayName"); | ||
176 | |||
177 | installSize = this.ProcessPackages(document, namespaceManager); | ||
178 | |||
179 | this.ProcessRelatedBundles(document, namespaceManager, sourcePath); | ||
180 | |||
181 | // TODO: Add payloads? | ||
182 | } | ||
183 | catch (Exception e) | ||
184 | { | ||
185 | this.Messaging.Write(BurnBackendErrors.InvalidBundleManifest(sourceLineNumbers, sourcePath, e.ToString())); | ||
186 | return null; | ||
187 | } | ||
188 | } | 110 | } |
189 | 111 | ||
190 | return this.Section.AddSymbol(new WixBundleHarvestedBundlePackageSymbol(this.PackagePayload.SourceLineNumbers, this.PackagePayload.Id) | 112 | this.Section.AddSymbol(command.HarvestedBundlePackage); |
191 | { | 113 | this.Section.AddSymbol(command.HarvestedDependencyProvider); |
192 | Win64 = win64, | ||
193 | BundleId = bundleId, | ||
194 | EngineVersion = engineVersion, | ||
195 | ManifestNamespace = manifestNamespace, | ||
196 | ProtocolVersion = protocolVersion, | ||
197 | PerMachine = perMachine, | ||
198 | Version = version, | ||
199 | DisplayName = displayName, | ||
200 | InstallSize = installSize, | ||
201 | }); | ||
202 | } | ||
203 | |||
204 | private int ProcessProtocolVersion(BurnReader burnReader, XmlDocument document) | ||
205 | { | ||
206 | var protocolVersionValue = document.DocumentElement.GetAttribute("ProtocolVersion"); | ||
207 | 114 | ||
208 | if (Int32.TryParse(protocolVersionValue, out var protocolVersion)) | 115 | foreach (var relatedBundle in command.RelatedBundles) |
209 | { | 116 | { |
210 | return protocolVersion; | 117 | this.Section.AddSymbol(relatedBundle); |
211 | } | 118 | } |
212 | 119 | ||
213 | // Assume that the .wixburn section version will change when the Burn protocol changes. | 120 | return command.HarvestedBundlePackage; |
214 | // This should be a safe assumption since only old bundles should be missing the ProtocolVersion from the manifest. | ||
215 | return burnReader.Version == 2 ? 1 : 0; | ||
216 | } | ||
217 | |||
218 | private bool ProcessWin64(BurnReader burnReader, XmlDocument document, SourceLineNumber sourceLineNumbers, string sourcePath) | ||
219 | { | ||
220 | var win64Value = document.DocumentElement.GetAttribute("Win64"); | ||
221 | |||
222 | switch (win64Value) | ||
223 | { | ||
224 | case "yes": | ||
225 | return true; | ||
226 | case "no": | ||
227 | return false; | ||
228 | } | ||
229 | |||
230 | switch (burnReader.MachineType) | ||
231 | { | ||
232 | case BurnCommon.IMAGE_FILE_MACHINE_ARM: | ||
233 | case BurnCommon.IMAGE_FILE_MACHINE_ARMNT: | ||
234 | case BurnCommon.IMAGE_FILE_MACHINE_I386: | ||
235 | case BurnCommon.IMAGE_FILE_MACHINE_LOONGARCH32: | ||
236 | return false; | ||
237 | case BurnCommon.IMAGE_FILE_MACHINE_AMD64: | ||
238 | case BurnCommon.IMAGE_FILE_MACHINE_ARM64: | ||
239 | case BurnCommon.IMAGE_FILE_MACHINE_IA64: | ||
240 | case BurnCommon.IMAGE_FILE_MACHINE_LOONGARCH64: | ||
241 | return true; | ||
242 | case BurnCommon.IMAGE_FILE_MACHINE_AM33: | ||
243 | case BurnCommon.IMAGE_FILE_MACHINE_EBC: | ||
244 | case BurnCommon.IMAGE_FILE_MACHINE_M32R: | ||
245 | case BurnCommon.IMAGE_FILE_MACHINE_MIPS16: | ||
246 | case BurnCommon.IMAGE_FILE_MACHINE_MIPSFPU: | ||
247 | case BurnCommon.IMAGE_FILE_MACHINE_MIPSFPU16: | ||
248 | case BurnCommon.IMAGE_FILE_MACHINE_POWERPC: | ||
249 | case BurnCommon.IMAGE_FILE_MACHINE_POWERPCFP: | ||
250 | case BurnCommon.IMAGE_FILE_MACHINE_R4000: | ||
251 | case BurnCommon.IMAGE_FILE_MACHINE_RISCV32: | ||
252 | case BurnCommon.IMAGE_FILE_MACHINE_RISCV64: | ||
253 | case BurnCommon.IMAGE_FILE_MACHINE_RISCV128: | ||
254 | case BurnCommon.IMAGE_FILE_MACHINE_SH3: | ||
255 | case BurnCommon.IMAGE_FILE_MACHINE_SH3DSP: | ||
256 | case BurnCommon.IMAGE_FILE_MACHINE_SH4: | ||
257 | case BurnCommon.IMAGE_FILE_MACHINE_SH5: | ||
258 | case BurnCommon.IMAGE_FILE_MACHINE_THUMB: | ||
259 | case BurnCommon.IMAGE_FILE_MACHINE_WCEMIPSV2: | ||
260 | default: | ||
261 | this.Messaging.Write(BurnBackendWarnings.UnknownCoffMachineType(sourceLineNumbers, sourcePath, burnReader.MachineType)); | ||
262 | return false; | ||
263 | } | ||
264 | } | ||
265 | |||
266 | private long ProcessPackages(XmlDocument document, XmlNamespaceManager namespaceManager) | ||
267 | { | ||
268 | long packageInstallSize = 0; | ||
269 | |||
270 | foreach (XmlElement packageElement in document.SelectNodes("/burn:BurnManifest/burn:Chain/*", namespaceManager)) | ||
271 | { | ||
272 | if (!packageElement.Name.EndsWith("Package")) | ||
273 | { | ||
274 | continue; | ||
275 | } | ||
276 | |||
277 | if (Int64.TryParse(packageElement.GetAttribute("InstallSize"), out var installSize)) | ||
278 | { | ||
279 | packageInstallSize += installSize; | ||
280 | } | ||
281 | } | ||
282 | |||
283 | return packageInstallSize; | ||
284 | } | ||
285 | |||
286 | private void ProcessRelatedBundles(XmlDocument document, XmlNamespaceManager namespaceManager, string sourcePath) | ||
287 | { | ||
288 | var sourceLineNumbers = this.PackagePayload.SourceLineNumbers; | ||
289 | |||
290 | foreach (XmlElement relatedBundleElement in document.SelectNodes("/burn:BurnManifest/burn:RelatedBundle", namespaceManager)) | ||
291 | { | ||
292 | var id = relatedBundleElement.GetAttribute("Id"); | ||
293 | var actionValue = relatedBundleElement.GetAttribute("Action"); | ||
294 | |||
295 | if (!Enum.TryParse(actionValue, out RelatedBundleActionType action)) | ||
296 | { | ||
297 | this.Messaging.Write(BurnBackendWarnings.UnknownBundleRelationAction(sourceLineNumbers, sourcePath, actionValue)); | ||
298 | continue; | ||
299 | } | ||
300 | |||
301 | this.Section.AddSymbol(new WixBundlePackageRelatedBundleSymbol(sourceLineNumbers) | ||
302 | { | ||
303 | PackagePayloadRef = this.PackagePayload.Id.Id, | ||
304 | BundleId = id, | ||
305 | Action = action, | ||
306 | }); | ||
307 | } | ||
308 | } | 121 | } |
309 | } | 122 | } |
310 | } | 123 | } |
diff --git a/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs b/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs index 7b362485..6eed62eb 100644 --- a/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs +++ b/src/wix/WixToolset.Core.Burn/CommandLine/RemotePayloadSubcommand.cs | |||
@@ -9,6 +9,7 @@ namespace WixToolset.Core.Burn.CommandLine | |||
9 | using System.Threading; | 9 | using System.Threading; |
10 | using System.Threading.Tasks; | 10 | using System.Threading.Tasks; |
11 | using System.Xml.Linq; | 11 | using System.Xml.Linq; |
12 | using WixToolset.Core.Burn.Bundles; | ||
12 | using WixToolset.Core.Burn.Interfaces; | 13 | using WixToolset.Core.Burn.Interfaces; |
13 | using WixToolset.Core.Native; | 14 | using WixToolset.Core.Native; |
14 | using WixToolset.Data; | 15 | using WixToolset.Data; |
@@ -17,16 +18,22 @@ namespace WixToolset.Core.Burn.CommandLine | |||
17 | 18 | ||
18 | internal class RemotePayloadSubcommand : BurnSubcommandBase | 19 | internal class RemotePayloadSubcommand : BurnSubcommandBase |
19 | { | 20 | { |
21 | private static readonly XName BundlePackagePayloadName = "BundlePackagePayload"; | ||
20 | private static readonly XName ExePackagePayloadName = "ExePackagePayload"; | 22 | private static readonly XName ExePackagePayloadName = "ExePackagePayload"; |
21 | private static readonly XName MsuPackagePayloadName = "MsuPackagePayload"; | 23 | private static readonly XName MsuPackagePayloadName = "MsuPackagePayload"; |
22 | private static readonly XName PayloadName = "Payload"; | 24 | private static readonly XName PayloadName = "Payload"; |
25 | private static readonly XName RemoteBundleName = "RemoteBundle"; | ||
26 | private static readonly XName RemoteRelatedBundleName = "RemoteRelatedBundle"; | ||
23 | 27 | ||
24 | public RemotePayloadSubcommand(IServiceProvider serviceProvider) | 28 | public RemotePayloadSubcommand(IServiceProvider serviceProvider) |
25 | { | 29 | { |
30 | this.ServiceProvider = serviceProvider; | ||
26 | this.Messaging = serviceProvider.GetService<IMessaging>(); | 31 | this.Messaging = serviceProvider.GetService<IMessaging>(); |
27 | this.PayloadHarvester = serviceProvider.GetService<IPayloadHarvester>(); | 32 | this.PayloadHarvester = serviceProvider.GetService<IPayloadHarvester>(); |
28 | } | 33 | } |
29 | 34 | ||
35 | private IServiceProvider ServiceProvider { get; } | ||
36 | |||
30 | private IMessaging Messaging { get; } | 37 | private IMessaging Messaging { get; } |
31 | 38 | ||
32 | private IPayloadHarvester PayloadHarvester { get; } | 39 | private IPayloadHarvester PayloadHarvester { get; } |
@@ -37,6 +44,8 @@ namespace WixToolset.Core.Burn.CommandLine | |||
37 | 44 | ||
38 | private List<string> InputPaths { get; } = new List<string>(); | 45 | private List<string> InputPaths { get; } = new List<string>(); |
39 | 46 | ||
47 | private string IntermediateFolder { get; set; } | ||
48 | |||
40 | private string OutputPath { get; set; } | 49 | private string OutputPath { get; set; } |
41 | 50 | ||
42 | private WixBundlePackageType? PackageType { get; set; } | 51 | private WixBundlePackageType? PackageType { get; set; } |
@@ -58,6 +67,11 @@ namespace WixToolset.Core.Burn.CommandLine | |||
58 | this.BasePaths.Sort(); | 67 | this.BasePaths.Sort(); |
59 | this.BasePaths.Reverse(); | 68 | this.BasePaths.Reverse(); |
60 | 69 | ||
70 | if (String.IsNullOrEmpty(this.IntermediateFolder)) | ||
71 | { | ||
72 | this.IntermediateFolder = Path.GetTempPath(); | ||
73 | } | ||
74 | |||
61 | var elements = this.HarvestRemotePayloads(inputPaths); | 75 | var elements = this.HarvestRemotePayloads(inputPaths); |
62 | 76 | ||
63 | if (!this.Messaging.EncounteredError) | 77 | if (!this.Messaging.EncounteredError) |
@@ -98,6 +112,10 @@ namespace WixToolset.Core.Burn.CommandLine | |||
98 | this.DownloadUrl = parser.GetNextArgumentOrError(argument); | 112 | this.DownloadUrl = parser.GetNextArgumentOrError(argument); |
99 | return true; | 113 | return true; |
100 | 114 | ||
115 | case "intermediatefolder": | ||
116 | this.IntermediateFolder = parser.GetNextArgumentAsDirectoryOrError(argument); | ||
117 | return true; | ||
118 | |||
101 | case "packagetype": | 119 | case "packagetype": |
102 | var packageTypeValue = parser.GetNextArgumentOrError(argument); | 120 | var packageTypeValue = parser.GetNextArgumentOrError(argument); |
103 | if (Enum.TryParse<WixBundlePackageType>(packageTypeValue, ignoreCase: true, out var packageType)) | 121 | if (Enum.TryParse<WixBundlePackageType>(packageTypeValue, ignoreCase: true, out var packageType)) |
@@ -174,7 +192,7 @@ namespace WixToolset.Core.Burn.CommandLine | |||
174 | continue; | 192 | continue; |
175 | } | 193 | } |
176 | 194 | ||
177 | var payloadSymbol = new WixBundlePayloadSymbol | 195 | var payloadSymbol = new WixBundlePayloadSymbol(null, new Identifier(AccessModifier.Section, "id")) |
178 | { | 196 | { |
179 | SourceFile = new IntermediateFieldPathValue { Path = path }, | 197 | SourceFile = new IntermediateFieldPathValue { Path = path }, |
180 | }; | 198 | }; |
@@ -225,6 +243,62 @@ namespace WixToolset.Core.Burn.CommandLine | |||
225 | element.Add(new XAttribute("Version", payloadSymbol.Version)); | 243 | element.Add(new XAttribute("Version", payloadSymbol.Version)); |
226 | } | 244 | } |
227 | 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 | } | ||
297 | |||
298 | element.Add(bundleElement); | ||
299 | } | ||
300 | } | ||
301 | |||
228 | yield return element; | 302 | yield return element; |
229 | } | 303 | } |
230 | } | 304 | } |
@@ -237,6 +311,9 @@ namespace WixToolset.Core.Burn.CommandLine | |||
237 | 311 | ||
238 | switch (extension.ToUpperInvariant()) | 312 | switch (extension.ToUpperInvariant()) |
239 | { | 313 | { |
314 | case "BUNDLE": | ||
315 | return new XElement(BundlePackagePayloadName); | ||
316 | |||
240 | case "EXE": | 317 | case "EXE": |
241 | case ".EXE": | 318 | case ".EXE": |
242 | return new XElement(ExePackagePayloadName); | 319 | return new XElement(ExePackagePayloadName); |
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs index 0dd29e38..6387a12a 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundleFixture.cs | |||
@@ -574,7 +574,7 @@ namespace WixToolsetTest.CoreIntegration | |||
574 | } | 574 | } |
575 | 575 | ||
576 | [Fact] | 576 | [Fact] |
577 | public void CantBuildWithSubfolderContainer() | 577 | public void CanBuildWithSubfolderContainer() |
578 | { | 578 | { |
579 | var folder = TestData.Get(@"TestData"); | 579 | var folder = TestData.Get(@"TestData"); |
580 | 580 | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs index 3dead50d..29ea1e7f 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/PackagePayloadFixture.cs | |||
@@ -90,7 +90,7 @@ namespace WixToolsetTest.CoreIntegration | |||
90 | } | 90 | } |
91 | 91 | ||
92 | [Fact] | 92 | [Fact] |
93 | public void CanSpecifyPackagePayloadInPayloadGroup() | 93 | public void CanSpecifyExePackagePayloadInPayloadGroup() |
94 | { | 94 | { |
95 | var folder = TestData.Get(@"TestData"); | 95 | var folder = TestData.Get(@"TestData"); |
96 | 96 | ||
@@ -135,7 +135,7 @@ namespace WixToolsetTest.CoreIntegration | |||
135 | } | 135 | } |
136 | 136 | ||
137 | [Fact] | 137 | [Fact] |
138 | public void CanSpecifyPackagePayloadWithCertificate() | 138 | public void CanSpecifyExePackagePayloadWithCertificate() |
139 | { | 139 | { |
140 | var folder = TestData.Get(@"TestData", "PackagePayload"); | 140 | var folder = TestData.Get(@"TestData", "PackagePayload"); |
141 | 141 | ||
diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs index 434b3621..41791bd0 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs | |||
@@ -11,7 +11,40 @@ namespace WixToolsetTest.CoreIntegration | |||
11 | public class RemotePayloadFixture | 11 | public class RemotePayloadFixture |
12 | { | 12 | { |
13 | [Fact] | 13 | [Fact] |
14 | public void CanGetRemotePayload() | 14 | public void CanGetRemoteV3BundlePayload() |
15 | { | ||
16 | var folder = TestData.Get(@"TestData"); | ||
17 | |||
18 | using (var fs = new DisposableFileSystem()) | ||
19 | { | ||
20 | var outputFolder = fs.GetFolder(); | ||
21 | var outFile = Path.Combine(outputFolder, "out.xml"); | ||
22 | |||
23 | var result = WixRunner.Execute(new[] | ||
24 | { | ||
25 | "burn", "remotepayload", | ||
26 | Path.Combine(folder, ".Data", "v3bundle.exe"), | ||
27 | "-downloadurl", "https://www.example.com/files/{0}", | ||
28 | "-o", outFile, | ||
29 | "-packagetype", "bundle", | ||
30 | }); | ||
31 | |||
32 | result.AssertSuccess(); | ||
33 | |||
34 | var elements = File.ReadAllLines(outFile); | ||
35 | elements = elements.Select(s => s.Replace("\"", "'")).ToArray(); | ||
36 | |||
37 | WixAssert.CompareLineByLine(new[] | ||
38 | { | ||
39 | "<BundlePackagePayload Name='v3bundle.exe' ProductName='CustomV3Theme' Description='CustomV3Theme' DownloadUrl='https://www.example.com/files/v3bundle.exe' Hash='80739E7B8C31D75B4CDC48D60D74F5E481CB904212A3AE3FB0920365A163FBF32B0C5C175AB516D4124F107923E96200605DE1D560D362FEB47350FA727823B4' Size='648397' Version='1.0.0.0'>", | ||
40 | " <RemoteBundle BundleId='{215A70DB-AB35-48C7-BE51-D66EAAC87177}' DisplayName='CustomV3Theme' InstallSize='1135' ManifestNamespace='http://schemas.microsoft.com/wix/2008/Burn' PerMachine='yes' ProviderKey='{215a70db-ab35-48c7-be51-d66eaac87177}' ProtocolVersion='1' Version='1.0.0.0' Win64='no' UpgradeCode='{2BF4C01F-C132-4E70-97AB-2BC68C7CCD10}' />", | ||
41 | "</BundlePackagePayload>", | ||
42 | }, elements); | ||
43 | } | ||
44 | } | ||
45 | |||
46 | [Fact] | ||
47 | public void CanGetRemoteExePayload() | ||
15 | { | 48 | { |
16 | var folder = TestData.Get(@"TestData"); | 49 | var folder = TestData.Get(@"TestData"); |
17 | 50 | ||