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 --- .../Bind/BindDatabaseCommand.cs | 12 ++ .../Bind/CreateOutputFromIRCommand.cs | 3 +- .../Bind/ProcessPackageSoftwareTagsCommand.cs | 131 +++++++++++++++++++++ .../Bind/UpdateFileFacadesCommand.cs | 2 +- 4 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 src/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs (limited to 'src/WixToolset.Core.WindowsInstaller') diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index 012c7c4c..25a093fd 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs @@ -282,6 +282,18 @@ namespace WixToolset.Core.WindowsInstaller.Bind return null; } + // Process SoftwareTags in MSI packages. + if (SectionType.Product == section.Type) + { + var softwareTags = section.Symbols.OfType().ToList(); + + if (softwareTags.Any()) + { + var command = new ProcessPackageSoftwareTagsCommand(section, softwareTags, this.IntermediateFolder); + command.Execute(); + } + } + // Gather information about files that do not come from merge modules. { var command = new UpdateFileFacadesCommand(this.Messaging, section, fileFacades, fileFacades.Where(f => !f.FromModule), variableCache, overwriteHash: true); diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs index b52ff434..37383caa 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/CreateOutputFromIRCommand.cs @@ -231,6 +231,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind case SymbolDefinitionType.WixPatchRef: case SymbolDefinitionType.WixPatchTarget: case SymbolDefinitionType.WixProperty: + case SymbolDefinitionType.WixProductTag: case SymbolDefinitionType.WixSimpleReference: case SymbolDefinitionType.WixSuppressAction: case SymbolDefinitionType.WixSuppressModularization: @@ -456,7 +457,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind private void AddDirectorySymbol(DirectorySymbol symbol) { - if (String.IsNullOrEmpty(symbol.ShortName) && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !Common.IsValidShortFilename(symbol.Name, false)) + if (String.IsNullOrEmpty(symbol.ShortName) && symbol.Name != null && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !Common.IsValidShortFilename(symbol.Name, false)) { symbol.ShortName = CreateShortName(symbol.Name, false, false, "Directory", symbol.ParentDirectoryRef); } diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs new file mode 100644 index 00000000..9a068603 --- /dev/null +++ b/src/WixToolset.Core.WindowsInstaller/Bind/ProcessPackageSoftwareTagsCommand.cs @@ -0,0 +1,131 @@ +// 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.WindowsInstaller.Bind +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using System.Xml; + using WixToolset.Data; + using WixToolset.Data.Symbols; + + internal class ProcessPackageSoftwareTagsCommand + { + public ProcessPackageSoftwareTagsCommand(IntermediateSection section, IEnumerable softwareTags, string intermediateFolder) + { + this.Section = section; + this.SoftwareTags = softwareTags; + this.IntermediateFolder = intermediateFolder; + } + + private string IntermediateFolder { get; } + + private IntermediateSection Section { get; } + + private IEnumerable SoftwareTags { get; } + + public void Execute() + { + string productName = null; + string productVersion = null; + string manufacturer = null; + string upgradeCode = null; + + var summaryInfo = this.Section.Symbols.OfType().FirstOrDefault(s => s.PropertyId == SummaryInformationType.PackageCode); + var packageCode = NormalizeGuid(summaryInfo?.Value); + + foreach (var property in this.Section.Symbols.OfType()) + { + switch (property.Id.Id) + { + case "ProductName": + productName = property.Value; + break; + case "ProductVersion": + productVersion = property.Value; + break; + case "Manufacturer": + manufacturer = property.Value; + break; + case "UpgradeCode": + upgradeCode = NormalizeGuid(property.Value); + break; + } + } + + var fileSymbolsById = this.Section.Symbols.OfType().Where(f => f.Id != null).ToDictionary(f => f.Id.Id); + + var workingFolder = Path.Combine(this.IntermediateFolder, "_swidtag"); + + Directory.CreateDirectory(workingFolder); + + foreach (var tagRow in this.SoftwareTags) + { + if (fileSymbolsById.TryGetValue(tagRow.FileRef, out var fileSymbol)) + { + var uniqueId = String.Concat("msi:package/", packageCode); + var persistentId = String.IsNullOrEmpty(upgradeCode) ? null : String.Concat("msi:upgrade/", upgradeCode); + + // Write the tag file. + fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(workingFolder, fileSymbol.Name) }; + + using (var fs = new FileStream(fileSymbol.Source.Path, FileMode.Create)) + { + CreateTagFile(fs, uniqueId, productName, productVersion, tagRow.Regid, manufacturer, persistentId); + } + + // Ensure the matching "SoftwareIdentificationTag" row exists and + // is populated correctly. + this.Section.AddSymbol(new SoftwareIdentificationTagSymbol(tagRow.SourceLineNumbers, tagRow.Id) + { + FileRef = fileSymbol.Id.Id, + Regid = tagRow.Regid, + TagId = uniqueId, + PersistentId = persistentId + }); + } + } + } + + private static string NormalizeGuid(string guidString) + { + if (Guid.TryParse(guidString, out var guid)) + { + return guid.ToString("D").ToUpperInvariant(); + } + + return guidString; + } + + private static void CreateTagFile(Stream stream, string uniqueId, string name, string version, string regid, string manufacturer, string persistendId) + { + 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(); // + } + + writer.WriteEndElement(); // + } + } + } +} diff --git a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs index 938627ed..d5bdc797 100644 --- a/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs +++ b/src/WixToolset.Core.WindowsInstaller/Bind/UpdateFileFacadesCommand.cs @@ -45,7 +45,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind { var assemblyNameSymbols = this.Section.Symbols.OfType().ToDictionary(t => t.Id.Id); - foreach (var file in this.UpdateFileFacades) + foreach (var file in this.UpdateFileFacades.Where(f => f.SourcePath != null)) { this.UpdateFileFacade(file, assemblyNameSymbols); } -- cgit v1.2.3-55-g6feb