diff options
Diffstat (limited to 'src')
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 | ||
