diff options
Diffstat (limited to 'src/WixToolset.Core.Burn')
4 files changed, 155 insertions, 7 deletions
diff --git a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index 93620e1b..c9a111c6 100644 --- a/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs +++ b/src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs | |||
| @@ -380,6 +380,13 @@ namespace WixToolset.Core.Burn | |||
| 380 | // Update the bundle per-machine/per-user scope based on the chained packages. | 380 | // Update the bundle per-machine/per-user scope based on the chained packages. |
| 381 | this.ResolveBundleInstallScope(section, bundleSymbol, orderedFacades); | 381 | this.ResolveBundleInstallScope(section, bundleSymbol, orderedFacades); |
| 382 | 382 | ||
| 383 | var softwareTags = section.Symbols.OfType<WixBundleTagSymbol>().ToList(); | ||
| 384 | if (softwareTags.Any()) | ||
| 385 | { | ||
| 386 | var command = new ProcessBundleSoftwareTagsCommand(section, softwareTags); | ||
| 387 | command.Execute(); | ||
| 388 | } | ||
| 389 | |||
| 383 | // Give the extension one last hook before generating the output files. | 390 | // Give the extension one last hook before generating the output files. |
| 384 | foreach (var extension in this.BackendExtensions) | 391 | foreach (var extension in this.BackendExtensions) |
| 385 | { | 392 | { |
diff --git a/src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs b/src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs index c51d380c..36ced6cf 100644 --- a/src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs +++ b/src/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs | |||
| @@ -82,6 +82,7 @@ namespace WixToolset.Core.Burn.Bind | |||
| 82 | case SymbolDefinitionType.WixBundleRelatedPackage: | 82 | case SymbolDefinitionType.WixBundleRelatedPackage: |
| 83 | case SymbolDefinitionType.WixBundleRollbackBoundary: | 83 | case SymbolDefinitionType.WixBundleRollbackBoundary: |
| 84 | case SymbolDefinitionType.WixBundleSlipstreamMsp: | 84 | case SymbolDefinitionType.WixBundleSlipstreamMsp: |
| 85 | case SymbolDefinitionType.WixBundleTag: | ||
| 85 | case SymbolDefinitionType.WixBundleUpdate: | 86 | case SymbolDefinitionType.WixBundleUpdate: |
| 86 | case SymbolDefinitionType.WixBundleVariable: | 87 | case SymbolDefinitionType.WixBundleVariable: |
| 87 | case SymbolDefinitionType.WixBuildInfo: | 88 | case SymbolDefinitionType.WixBuildInfo: |
diff --git a/src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs b/src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs new file mode 100644 index 00000000..8584d2a4 --- /dev/null +++ b/src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs | |||
| @@ -0,0 +1,142 @@ | |||
| 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 System.IO; | ||
| 8 | using System.Linq; | ||
| 9 | using System.Text; | ||
| 10 | using System.Xml; | ||
| 11 | using WixToolset.Data; | ||
| 12 | using WixToolset.Data.Symbols; | ||
| 13 | using WixToolset.Dtf.WindowsInstaller; | ||
| 14 | |||
| 15 | internal class ProcessBundleSoftwareTagsCommand | ||
| 16 | { | ||
| 17 | public ProcessBundleSoftwareTagsCommand(IntermediateSection section, IEnumerable<WixBundleTagSymbol> softwareTags) | ||
| 18 | { | ||
| 19 | this.Section = section; | ||
| 20 | this.SoftwareTags = softwareTags; | ||
| 21 | } | ||
| 22 | |||
| 23 | private IntermediateSection Section { get; } | ||
| 24 | |||
| 25 | private IEnumerable<WixBundleTagSymbol> SoftwareTags { get; } | ||
| 26 | |||
| 27 | public void Execute() | ||
| 28 | { | ||
| 29 | var bundleInfo = this.Section.Symbols.OfType<WixBundleSymbol>().FirstOrDefault(); | ||
| 30 | var bundleId = NormalizeGuid(bundleInfo.BundleId); | ||
| 31 | var upgradeCode = NormalizeGuid(bundleInfo.UpgradeCode); | ||
| 32 | |||
| 33 | var uniqueId = String.Concat("wix:bundle/", bundleId); | ||
| 34 | var persistentId = String.Concat("wix:bundle.upgrade/", upgradeCode); | ||
| 35 | |||
| 36 | // Try to collect all the software id tags from all the child packages. | ||
| 37 | var containedTags = CollectPackageTags(this.Section); | ||
| 38 | |||
| 39 | foreach (var bundleTag in this.SoftwareTags) | ||
| 40 | { | ||
| 41 | using (var ms = new MemoryStream()) | ||
| 42 | { | ||
| 43 | CreateTagFile(ms, uniqueId, bundleInfo.Name, bundleInfo.Version, bundleTag.Regid, bundleInfo.Manufacturer, persistentId, containedTags); | ||
| 44 | bundleTag.Xml = Encoding.UTF8.GetString(ms.ToArray()); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | private static string NormalizeGuid(string guidString) | ||
| 50 | { | ||
| 51 | if (Guid.TryParse(guidString, out var guid)) | ||
| 52 | { | ||
| 53 | return guid.ToString("D").ToUpperInvariant(); | ||
| 54 | } | ||
| 55 | |||
| 56 | return guidString; | ||
| 57 | } | ||
| 58 | |||
| 59 | private static IEnumerable<SoftwareTag> CollectPackageTags(IntermediateSection section) | ||
| 60 | { | ||
| 61 | var tags = new List<SoftwareTag>(); | ||
| 62 | |||
| 63 | var msiPackages = section.Symbols.OfType<WixBundlePackageSymbol>().Where(s => s.Type == WixBundlePackageType.Msi).ToList(); | ||
| 64 | if (msiPackages.Any()) | ||
| 65 | { | ||
| 66 | var payloadSymbolsById = section.Symbols.OfType<WixBundlePayloadSymbol>().ToDictionary(s => s.Id.Id); | ||
| 67 | |||
| 68 | foreach (var msiPackage in msiPackages) | ||
| 69 | { | ||
| 70 | var payload = payloadSymbolsById[msiPackage.PayloadRef]; | ||
| 71 | |||
| 72 | using (var db = new Database(payload.SourceFile.Path)) | ||
| 73 | { | ||
| 74 | using (var view = db.OpenView("SELECT `Regid`, `TagId` FROM `SoftwareIdentificationTag`")) | ||
| 75 | { | ||
| 76 | view.Execute(); | ||
| 77 | while (true) | ||
| 78 | { | ||
| 79 | using (var record = view.Fetch()) | ||
| 80 | { | ||
| 81 | if (null == record) | ||
| 82 | { | ||
| 83 | break; | ||
| 84 | } | ||
| 85 | |||
| 86 | tags.Add(new SoftwareTag { Regid = record.GetString(1), Id = record.GetString(2) }); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | return tags; | ||
| 95 | } | ||
| 96 | |||
| 97 | private static void CreateTagFile(Stream stream, string uniqueId, string name, string version, string regid, string manufacturer, string persistendId, IEnumerable<SoftwareTag> containedTags) | ||
| 98 | { | ||
| 99 | var versionScheme = Version.TryParse(version, out _) ? "multipartnumeric" : "alphanumeric"; | ||
| 100 | |||
| 101 | using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true})) | ||
| 102 | { | ||
| 103 | writer.WriteStartDocument(); | ||
| 104 | writer.WriteStartElement("SoftwareIdentity", "http://standards.iso.org/iso/19770/-2/2015/schema.xsd"); | ||
| 105 | writer.WriteAttributeString("tagId", uniqueId); | ||
| 106 | writer.WriteAttributeString("name", name); | ||
| 107 | writer.WriteAttributeString("version", version); | ||
| 108 | writer.WriteAttributeString("versionScheme", versionScheme); | ||
| 109 | |||
| 110 | writer.WriteStartElement("Entity"); | ||
| 111 | writer.WriteAttributeString("name", manufacturer); | ||
| 112 | writer.WriteAttributeString("regid", regid); | ||
| 113 | writer.WriteAttributeString("role", "softwareCreator tagCreator"); | ||
| 114 | writer.WriteEndElement(); // </Entity> | ||
| 115 | |||
| 116 | if (!String.IsNullOrEmpty(persistendId)) | ||
| 117 | { | ||
| 118 | writer.WriteStartElement("Meta"); | ||
| 119 | writer.WriteAttributeString("persistentId", persistendId); | ||
| 120 | writer.WriteEndElement(); // </Meta> | ||
| 121 | } | ||
| 122 | |||
| 123 | foreach (var containedTag in containedTags) | ||
| 124 | { | ||
| 125 | writer.WriteStartElement("Link"); | ||
| 126 | writer.WriteAttributeString("rel", "component"); | ||
| 127 | writer.WriteAttributeString("href", String.Concat("swid:", containedTag.Id)); | ||
| 128 | writer.WriteEndElement(); // </Link> | ||
| 129 | } | ||
| 130 | |||
| 131 | writer.WriteEndElement(); // </SoftwareIdentity> | ||
| 132 | } | ||
| 133 | } | ||
| 134 | |||
| 135 | private class SoftwareTag | ||
| 136 | { | ||
| 137 | public string Regid { get; set; } | ||
| 138 | |||
| 139 | public string Id { get; set; } | ||
| 140 | } | ||
| 141 | } | ||
| 142 | } | ||
diff --git a/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs index 71bc0229..3bc6bf1b 100644 --- a/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs +++ b/src/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs | |||
| @@ -295,17 +295,15 @@ namespace WixToolset.Core.Burn.Bundles | |||
| 295 | writer.WriteEndElement(); // </Update> | 295 | writer.WriteEndElement(); // </Update> |
| 296 | } | 296 | } |
| 297 | 297 | ||
| 298 | #if TODO // Handle SWID Tags | 298 | foreach (var bundleTagSymbol in this.Section.Symbols.OfType<WixBundleTagSymbol>()) |
| 299 | var bundleTags = this.Output.Tables["WixBundleTag"].RowsAs<Row>(); | ||
| 300 | foreach (var row in bundleTags) | ||
| 301 | { | 299 | { |
| 302 | writer.WriteStartElement("SoftwareTag"); | 300 | writer.WriteStartElement("SoftwareTag"); |
| 303 | writer.WriteAttributeString("Filename", (string)row[0]); | 301 | writer.WriteAttributeString("Filename", bundleTagSymbol.Filename); |
| 304 | writer.WriteAttributeString("Regid", (string)row[1]); | 302 | writer.WriteAttributeString("Regid", bundleTagSymbol.Regid); |
| 305 | writer.WriteCData((string)row[4]); | 303 | writer.WriteAttributeString("Path", bundleTagSymbol.InstallPath); |
| 304 | writer.WriteCData(bundleTagSymbol.Xml); | ||
| 306 | writer.WriteEndElement(); | 305 | writer.WriteEndElement(); |
| 307 | } | 306 | } |
| 308 | #endif | ||
| 309 | 307 | ||
| 310 | writer.WriteEndElement(); // </Register> | 308 | writer.WriteEndElement(); // </Register> |
| 311 | 309 | ||
