From 760fb810ba5ecc3c6ce752a9bfa3755f7b7c0f6a Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Thu, 25 Feb 2021 09:58:20 -0800 Subject: Absorb Tag.wixext into Core as SoftwareTag element Resolves wixtoolset/issues#5949 --- src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs | 7 + .../Bind/GenerateManifestDataFromIRCommand.cs | 1 + .../Bind/ProcessBundleSoftwareTagsCommand.cs | 142 +++++++++++++++++++++ .../Bundles/CreateBurnManifestCommand.cs | 12 +- 4 files changed, 155 insertions(+), 7 deletions(-) create mode 100644 src/WixToolset.Core.Burn/Bind/ProcessBundleSoftwareTagsCommand.cs (limited to 'src/WixToolset.Core.Burn') 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 // Update the bundle per-machine/per-user scope based on the chained packages. this.ResolveBundleInstallScope(section, bundleSymbol, orderedFacades); + var softwareTags = section.Symbols.OfType().ToList(); + if (softwareTags.Any()) + { + var command = new ProcessBundleSoftwareTagsCommand(section, softwareTags); + command.Execute(); + } + // Give the extension one last hook before generating the output files. foreach (var extension in this.BackendExtensions) { 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 case SymbolDefinitionType.WixBundleRelatedPackage: case SymbolDefinitionType.WixBundleRollbackBoundary: case SymbolDefinitionType.WixBundleSlipstreamMsp: + case SymbolDefinitionType.WixBundleTag: case SymbolDefinitionType.WixBundleUpdate: case SymbolDefinitionType.WixBundleVariable: 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 @@ +// 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. + +namespace WixToolset.Core.Burn.Bind +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Text; + using System.Xml; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Dtf.WindowsInstaller; + + internal class ProcessBundleSoftwareTagsCommand + { + public ProcessBundleSoftwareTagsCommand(IntermediateSection section, IEnumerable softwareTags) + { + this.Section = section; + this.SoftwareTags = softwareTags; + } + + private IntermediateSection Section { get; } + + private IEnumerable SoftwareTags { get; } + + public void Execute() + { + var bundleInfo = this.Section.Symbols.OfType().FirstOrDefault(); + var bundleId = NormalizeGuid(bundleInfo.BundleId); + var upgradeCode = NormalizeGuid(bundleInfo.UpgradeCode); + + var uniqueId = String.Concat("wix:bundle/", bundleId); + var persistentId = String.Concat("wix:bundle.upgrade/", upgradeCode); + + // Try to collect all the software id tags from all the child packages. + var containedTags = CollectPackageTags(this.Section); + + foreach (var bundleTag in this.SoftwareTags) + { + using (var ms = new MemoryStream()) + { + CreateTagFile(ms, uniqueId, bundleInfo.Name, bundleInfo.Version, bundleTag.Regid, bundleInfo.Manufacturer, persistentId, containedTags); + bundleTag.Xml = Encoding.UTF8.GetString(ms.ToArray()); + } + } + } + + private static string NormalizeGuid(string guidString) + { + if (Guid.TryParse(guidString, out var guid)) + { + return guid.ToString("D").ToUpperInvariant(); + } + + return guidString; + } + + private static IEnumerable CollectPackageTags(IntermediateSection section) + { + var tags = new List(); + + var msiPackages = section.Symbols.OfType().Where(s => s.Type == WixBundlePackageType.Msi).ToList(); + if (msiPackages.Any()) + { + var payloadSymbolsById = section.Symbols.OfType().ToDictionary(s => s.Id.Id); + + foreach (var msiPackage in msiPackages) + { + var payload = payloadSymbolsById[msiPackage.PayloadRef]; + + using (var db = new Database(payload.SourceFile.Path)) + { + using (var view = db.OpenView("SELECT `Regid`, `TagId` FROM `SoftwareIdentificationTag`")) + { + view.Execute(); + while (true) + { + using (var record = view.Fetch()) + { + if (null == record) + { + break; + } + + tags.Add(new SoftwareTag { Regid = record.GetString(1), Id = record.GetString(2) }); + } + } + } + } + } + } + + return tags; + } + + private static void CreateTagFile(Stream stream, string uniqueId, string name, string version, string regid, string manufacturer, string persistendId, IEnumerable containedTags) + { + var versionScheme = Version.TryParse(version, out _) ? "multipartnumeric" : "alphanumeric"; + + using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true})) + { + writer.WriteStartDocument(); + writer.WriteStartElement("SoftwareIdentity", "http://standards.iso.org/iso/19770/-2/2015/schema.xsd"); + writer.WriteAttributeString("tagId", uniqueId); + writer.WriteAttributeString("name", name); + writer.WriteAttributeString("version", version); + writer.WriteAttributeString("versionScheme", versionScheme); + + writer.WriteStartElement("Entity"); + writer.WriteAttributeString("name", manufacturer); + writer.WriteAttributeString("regid", regid); + writer.WriteAttributeString("role", "softwareCreator tagCreator"); + writer.WriteEndElement(); // + + if (!String.IsNullOrEmpty(persistendId)) + { + writer.WriteStartElement("Meta"); + writer.WriteAttributeString("persistentId", persistendId); + writer.WriteEndElement(); // + } + + foreach (var containedTag in containedTags) + { + writer.WriteStartElement("Link"); + writer.WriteAttributeString("rel", "component"); + writer.WriteAttributeString("href", String.Concat("swid:", containedTag.Id)); + writer.WriteEndElement(); // + } + + writer.WriteEndElement(); // + } + } + + private class SoftwareTag + { + public string Regid { get; set; } + + public string Id { get; set; } + } + } +} 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 writer.WriteEndElement(); // } -#if TODO // Handle SWID Tags - var bundleTags = this.Output.Tables["WixBundleTag"].RowsAs(); - foreach (var row in bundleTags) + foreach (var bundleTagSymbol in this.Section.Symbols.OfType()) { writer.WriteStartElement("SoftwareTag"); - writer.WriteAttributeString("Filename", (string)row[0]); - writer.WriteAttributeString("Regid", (string)row[1]); - writer.WriteCData((string)row[4]); + writer.WriteAttributeString("Filename", bundleTagSymbol.Filename); + writer.WriteAttributeString("Regid", bundleTagSymbol.Regid); + writer.WriteAttributeString("Path", bundleTagSymbol.InstallPath); + writer.WriteCData(bundleTagSymbol.Xml); writer.WriteEndElement(); } -#endif writer.WriteEndElement(); // -- cgit v1.2.3-55-g6feb