diff options
| author | Rob Mensching <rob@firegiant.com> | 2021-02-25 09:58:20 -0800 |
|---|---|---|
| committer | Rob Mensching <rob@firegiant.com> | 2021-02-27 07:47:08 -0800 |
| commit | 760fb810ba5ecc3c6ce752a9bfa3755f7b7c0f6a (patch) | |
| tree | 3ad06ffe520f31142e23ce9e752473110d232ec5 /src | |
| parent | 4536440f8d76346bcd120fe9e1410e428f855ee9 (diff) | |
| download | wix-760fb810ba5ecc3c6ce752a9bfa3755f7b7c0f6a.tar.gz wix-760fb810ba5ecc3c6ce752a9bfa3755f7b7c0f6a.tar.bz2 wix-760fb810ba5ecc3c6ce752a9bfa3755f7b7c0f6a.zip | |
Absorb Tag.wixext into Core as SoftwareTag element
Resolves wixtoolset/issues#5949
Diffstat (limited to 'src')
22 files changed, 814 insertions, 11 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 | ||
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 | |||
| 282 | return null; | 282 | return null; |
| 283 | } | 283 | } |
| 284 | 284 | ||
| 285 | // Process SoftwareTags in MSI packages. | ||
| 286 | if (SectionType.Product == section.Type) | ||
| 287 | { | ||
| 288 | var softwareTags = section.Symbols.OfType<WixProductTagSymbol>().ToList(); | ||
| 289 | |||
| 290 | if (softwareTags.Any()) | ||
| 291 | { | ||
| 292 | var command = new ProcessPackageSoftwareTagsCommand(section, softwareTags, this.IntermediateFolder); | ||
| 293 | command.Execute(); | ||
| 294 | } | ||
| 295 | } | ||
| 296 | |||
| 285 | // Gather information about files that do not come from merge modules. | 297 | // Gather information about files that do not come from merge modules. |
| 286 | { | 298 | { |
| 287 | var command = new UpdateFileFacadesCommand(this.Messaging, section, fileFacades, fileFacades.Where(f => !f.FromModule), variableCache, overwriteHash: true); | 299 | 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 | |||
| 231 | case SymbolDefinitionType.WixPatchRef: | 231 | case SymbolDefinitionType.WixPatchRef: |
| 232 | case SymbolDefinitionType.WixPatchTarget: | 232 | case SymbolDefinitionType.WixPatchTarget: |
| 233 | case SymbolDefinitionType.WixProperty: | 233 | case SymbolDefinitionType.WixProperty: |
| 234 | case SymbolDefinitionType.WixProductTag: | ||
| 234 | case SymbolDefinitionType.WixSimpleReference: | 235 | case SymbolDefinitionType.WixSimpleReference: |
| 235 | case SymbolDefinitionType.WixSuppressAction: | 236 | case SymbolDefinitionType.WixSuppressAction: |
| 236 | case SymbolDefinitionType.WixSuppressModularization: | 237 | case SymbolDefinitionType.WixSuppressModularization: |
| @@ -456,7 +457,7 @@ namespace WixToolset.Core.WindowsInstaller.Bind | |||
| 456 | 457 | ||
| 457 | private void AddDirectorySymbol(DirectorySymbol symbol) | 458 | private void AddDirectorySymbol(DirectorySymbol symbol) |
| 458 | { | 459 | { |
| 459 | if (String.IsNullOrEmpty(symbol.ShortName) && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !Common.IsValidShortFilename(symbol.Name, false)) | 460 | if (String.IsNullOrEmpty(symbol.ShortName) && symbol.Name != null && !symbol.Name.Equals(".") && !symbol.Name.Equals("SourceDir") && !Common.IsValidShortFilename(symbol.Name, false)) |
| 460 | { | 461 | { |
| 461 | symbol.ShortName = CreateShortName(symbol.Name, false, false, "Directory", symbol.ParentDirectoryRef); | 462 | symbol.ShortName = CreateShortName(symbol.Name, false, false, "Directory", symbol.ParentDirectoryRef); |
| 462 | } | 463 | } |
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 @@ | |||
| 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.WindowsInstaller.Bind | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Collections.Generic; | ||
| 7 | using System.IO; | ||
| 8 | using System.Linq; | ||
| 9 | using System.Xml; | ||
| 10 | using WixToolset.Data; | ||
| 11 | using WixToolset.Data.Symbols; | ||
| 12 | |||
| 13 | internal class ProcessPackageSoftwareTagsCommand | ||
| 14 | { | ||
| 15 | public ProcessPackageSoftwareTagsCommand(IntermediateSection section, IEnumerable<WixProductTagSymbol> softwareTags, string intermediateFolder) | ||
| 16 | { | ||
| 17 | this.Section = section; | ||
| 18 | this.SoftwareTags = softwareTags; | ||
| 19 | this.IntermediateFolder = intermediateFolder; | ||
| 20 | } | ||
| 21 | |||
| 22 | private string IntermediateFolder { get; } | ||
| 23 | |||
| 24 | private IntermediateSection Section { get; } | ||
| 25 | |||
| 26 | private IEnumerable<WixProductTagSymbol> SoftwareTags { get; } | ||
| 27 | |||
| 28 | public void Execute() | ||
| 29 | { | ||
| 30 | string productName = null; | ||
| 31 | string productVersion = null; | ||
| 32 | string manufacturer = null; | ||
| 33 | string upgradeCode = null; | ||
| 34 | |||
| 35 | var summaryInfo = this.Section.Symbols.OfType<SummaryInformationSymbol>().FirstOrDefault(s => s.PropertyId == SummaryInformationType.PackageCode); | ||
| 36 | var packageCode = NormalizeGuid(summaryInfo?.Value); | ||
| 37 | |||
| 38 | foreach (var property in this.Section.Symbols.OfType<PropertySymbol>()) | ||
| 39 | { | ||
| 40 | switch (property.Id.Id) | ||
| 41 | { | ||
| 42 | case "ProductName": | ||
| 43 | productName = property.Value; | ||
| 44 | break; | ||
| 45 | case "ProductVersion": | ||
| 46 | productVersion = property.Value; | ||
| 47 | break; | ||
| 48 | case "Manufacturer": | ||
| 49 | manufacturer = property.Value; | ||
| 50 | break; | ||
| 51 | case "UpgradeCode": | ||
| 52 | upgradeCode = NormalizeGuid(property.Value); | ||
| 53 | break; | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | var fileSymbolsById = this.Section.Symbols.OfType<FileSymbol>().Where(f => f.Id != null).ToDictionary(f => f.Id.Id); | ||
| 58 | |||
| 59 | var workingFolder = Path.Combine(this.IntermediateFolder, "_swidtag"); | ||
| 60 | |||
| 61 | Directory.CreateDirectory(workingFolder); | ||
| 62 | |||
| 63 | foreach (var tagRow in this.SoftwareTags) | ||
| 64 | { | ||
| 65 | if (fileSymbolsById.TryGetValue(tagRow.FileRef, out var fileSymbol)) | ||
| 66 | { | ||
| 67 | var uniqueId = String.Concat("msi:package/", packageCode); | ||
| 68 | var persistentId = String.IsNullOrEmpty(upgradeCode) ? null : String.Concat("msi:upgrade/", upgradeCode); | ||
| 69 | |||
| 70 | // Write the tag file. | ||
| 71 | fileSymbol.Source = new IntermediateFieldPathValue { Path = Path.Combine(workingFolder, fileSymbol.Name) }; | ||
| 72 | |||
| 73 | using (var fs = new FileStream(fileSymbol.Source.Path, FileMode.Create)) | ||
| 74 | { | ||
| 75 | CreateTagFile(fs, uniqueId, productName, productVersion, tagRow.Regid, manufacturer, persistentId); | ||
| 76 | } | ||
| 77 | |||
| 78 | // Ensure the matching "SoftwareIdentificationTag" row exists and | ||
| 79 | // is populated correctly. | ||
| 80 | this.Section.AddSymbol(new SoftwareIdentificationTagSymbol(tagRow.SourceLineNumbers, tagRow.Id) | ||
| 81 | { | ||
| 82 | FileRef = fileSymbol.Id.Id, | ||
| 83 | Regid = tagRow.Regid, | ||
| 84 | TagId = uniqueId, | ||
| 85 | PersistentId = persistentId | ||
| 86 | }); | ||
| 87 | } | ||
| 88 | } | ||
| 89 | } | ||
| 90 | |||
| 91 | private static string NormalizeGuid(string guidString) | ||
| 92 | { | ||
| 93 | if (Guid.TryParse(guidString, out var guid)) | ||
| 94 | { | ||
| 95 | return guid.ToString("D").ToUpperInvariant(); | ||
| 96 | } | ||
| 97 | |||
| 98 | return guidString; | ||
| 99 | } | ||
| 100 | |||
| 101 | private static void CreateTagFile(Stream stream, string uniqueId, string name, string version, string regid, string manufacturer, string persistendId) | ||
| 102 | { | ||
| 103 | var versionScheme = Version.TryParse(version, out _) ? "multipartnumeric" : "alphanumeric"; | ||
| 104 | |||
| 105 | using (var writer = XmlWriter.Create(stream, new XmlWriterSettings { Indent = true })) | ||
| 106 | { | ||
| 107 | writer.WriteStartDocument(); | ||
| 108 | writer.WriteStartElement("SoftwareIdentity", "http://standards.iso.org/iso/19770/-2/2015/schema.xsd"); | ||
| 109 | writer.WriteAttributeString("tagId", uniqueId); | ||
| 110 | writer.WriteAttributeString("name", name); | ||
| 111 | writer.WriteAttributeString("version", version); | ||
| 112 | writer.WriteAttributeString("versionScheme", versionScheme); | ||
| 113 | |||
| 114 | writer.WriteStartElement("Entity"); | ||
| 115 | writer.WriteAttributeString("name", manufacturer); | ||
| 116 | writer.WriteAttributeString("regid", regid); | ||
| 117 | writer.WriteAttributeString("role", "softwareCreator tagCreator"); | ||
| 118 | writer.WriteEndElement(); // </Entity> | ||
| 119 | |||
| 120 | if (!String.IsNullOrEmpty(persistendId)) | ||
| 121 | { | ||
| 122 | writer.WriteStartElement("Meta"); | ||
| 123 | writer.WriteAttributeString("persistentId", persistendId); | ||
| 124 | writer.WriteEndElement(); // </Meta> | ||
| 125 | } | ||
| 126 | |||
| 127 | writer.WriteEndElement(); // </SoftwareIdentity> | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | } | ||
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 | |||
| 45 | { | 45 | { |
| 46 | var assemblyNameSymbols = this.Section.Symbols.OfType<MsiAssemblyNameSymbol>().ToDictionary(t => t.Id.Id); | 46 | var assemblyNameSymbols = this.Section.Symbols.OfType<MsiAssemblyNameSymbol>().ToDictionary(t => t.Id.Id); |
| 47 | 47 | ||
| 48 | foreach (var file in this.UpdateFileFacades) | 48 | foreach (var file in this.UpdateFileFacades.Where(f => f.SourcePath != null)) |
| 49 | { | 49 | { |
| 50 | this.UpdateFileFacade(file, assemblyNameSymbols); | 50 | this.UpdateFileFacade(file, assemblyNameSymbols); |
| 51 | } | 51 | } |
diff --git a/src/WixToolset.Core/Bind/FileFacade.cs b/src/WixToolset.Core/Bind/FileFacade.cs index ec4e9725..9705cd01 100644 --- a/src/WixToolset.Core/Bind/FileFacade.cs +++ b/src/WixToolset.Core/Bind/FileFacade.cs | |||
| @@ -125,7 +125,7 @@ namespace WixToolset.Core.Bind | |||
| 125 | 125 | ||
| 126 | public SourceLineNumber SourceLineNumber => this.FileRow == null ? this.FileSymbol.SourceLineNumbers : this.FileRow.SourceLineNumbers; | 126 | public SourceLineNumber SourceLineNumber => this.FileRow == null ? this.FileSymbol.SourceLineNumbers : this.FileRow.SourceLineNumbers; |
| 127 | 127 | ||
| 128 | public string SourcePath => this.FileRow == null ? this.FileSymbol.Source.Path : this.FileRow.Source; | 128 | public string SourcePath => this.FileRow == null ? this.FileSymbol.Source?.Path : this.FileRow.Source; |
| 129 | 129 | ||
| 130 | public bool Compressed => this.FileRow == null ? (this.FileSymbol.Attributes & FileSymbolAttributes.Compressed) == FileSymbolAttributes.Compressed : (this.FileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed; | 130 | public bool Compressed => this.FileRow == null ? (this.FileSymbol.Attributes & FileSymbolAttributes.Compressed) == FileSymbolAttributes.Compressed : (this.FileRow.Attributes & WindowsInstallerConstants.MsidbFileAttributesCompressed) == WindowsInstallerConstants.MsidbFileAttributesCompressed; |
| 131 | 131 | ||
diff --git a/src/WixToolset.Core/CompilerCore.cs b/src/WixToolset.Core/CompilerCore.cs index 1f6d6329..53e0f3fc 100644 --- a/src/WixToolset.Core/CompilerCore.cs +++ b/src/WixToolset.Core/CompilerCore.cs | |||
| @@ -6,7 +6,6 @@ namespace WixToolset.Core | |||
| 6 | using System.Collections; | 6 | using System.Collections; |
| 7 | using System.Collections.Generic; | 7 | using System.Collections.Generic; |
| 8 | using System.Diagnostics; | 8 | using System.Diagnostics; |
| 9 | using System.Diagnostics.CodeAnalysis; | ||
| 10 | using System.Globalization; | 9 | using System.Globalization; |
| 11 | using System.Reflection; | 10 | using System.Reflection; |
| 12 | using System.Text; | 11 | using System.Text; |
diff --git a/src/WixToolset.Core/CompilerErrors.cs b/src/WixToolset.Core/CompilerErrors.cs new file mode 100644 index 00000000..da64c376 --- /dev/null +++ b/src/WixToolset.Core/CompilerErrors.cs | |||
| @@ -0,0 +1,30 @@ | |||
| 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 | ||
| 4 | { | ||
| 5 | using WixToolset.Data; | ||
| 6 | |||
| 7 | internal static class CompilerErrors | ||
| 8 | { | ||
| 9 | public static Message IllegalName(SourceLineNumber sourceLineNumbers, string parentElement, string name) | ||
| 10 | { | ||
| 11 | return Message(sourceLineNumbers, Ids.IllegalName, "The Tag/@Name attribute value, '{1}', contains invalid filename identifiers. The Tag/@Name may have defaulted from the {0}/@Name attrbute. If so, use the Tag/@Name attribute to provide a valid filename. Any character except for the follow may be used: \\ ? | > < : / * \".", parentElement, name); | ||
| 12 | } | ||
| 13 | |||
| 14 | public static Message ExampleRegid(SourceLineNumber sourceLineNumbers, string regid) | ||
| 15 | { | ||
| 16 | return Message(sourceLineNumbers, Ids.ExampleRegid, "Regid '{0}' is a placeholder that must be replaced with an appropriate value for your installation. Use the simplified URI for your organization or project.", regid); | ||
| 17 | } | ||
| 18 | |||
| 19 | private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args) | ||
| 20 | { | ||
| 21 | return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args); | ||
| 22 | } | ||
| 23 | |||
| 24 | public enum Ids | ||
| 25 | { | ||
| 26 | IllegalName = 6601, | ||
| 27 | ExampleRegid = 6602, | ||
| 28 | } | ||
| 29 | } | ||
| 30 | } | ||
diff --git a/src/WixToolset.Core/Compiler_2.cs b/src/WixToolset.Core/Compiler_2.cs index 09d56e49..295392c8 100644 --- a/src/WixToolset.Core/Compiler_2.cs +++ b/src/WixToolset.Core/Compiler_2.cs | |||
| @@ -316,6 +316,9 @@ namespace WixToolset.Core | |||
| 316 | string parentName = null; | 316 | string parentName = null; |
| 317 | this.ParseSFPCatalogElement(child, ref parentName); | 317 | this.ParseSFPCatalogElement(child, ref parentName); |
| 318 | break; | 318 | break; |
| 319 | case "SoftwareTag": | ||
| 320 | this.ParsePackageTagElement(child); | ||
| 321 | break; | ||
| 319 | case "SummaryInformation": | 322 | case "SummaryInformation": |
| 320 | this.ParseSummaryInformationElement(child, ref isCodepageSet, ref isPackageNameSet, ref isKeywordsSet, ref isPackageAuthorSet); | 323 | this.ParseSummaryInformationElement(child, ref isCodepageSet, ref isPackageNameSet, ref isKeywordsSet, ref isPackageAuthorSet); |
| 321 | break; | 324 | break; |
diff --git a/src/WixToolset.Core/Compiler_Bundle.cs b/src/WixToolset.Core/Compiler_Bundle.cs index 7a386de7..1ee09166 100644 --- a/src/WixToolset.Core/Compiler_Bundle.cs +++ b/src/WixToolset.Core/Compiler_Bundle.cs | |||
| @@ -346,6 +346,9 @@ namespace WixToolset.Core | |||
| 346 | case "SetVariableRef": | 346 | case "SetVariableRef": |
| 347 | this.ParseSimpleRefElement(child, SymbolDefinitions.WixSetVariable); | 347 | this.ParseSimpleRefElement(child, SymbolDefinitions.WixSetVariable); |
| 348 | break; | 348 | break; |
| 349 | case "SoftwareTag": | ||
| 350 | this.ParseBundleTagElement(child); | ||
| 351 | break; | ||
| 349 | case "Update": | 352 | case "Update": |
| 350 | this.ParseUpdateElement(child); | 353 | this.ParseUpdateElement(child); |
| 351 | break; | 354 | break; |
diff --git a/src/WixToolset.Core/Compiler_Patch.cs b/src/WixToolset.Core/Compiler_Patch.cs index 2fb1affb..83737c43 100644 --- a/src/WixToolset.Core/Compiler_Patch.cs +++ b/src/WixToolset.Core/Compiler_Patch.cs | |||
| @@ -410,6 +410,9 @@ namespace WixToolset.Core | |||
| 410 | case "PropertyRef": | 410 | case "PropertyRef": |
| 411 | this.ParsePatchChildRefElement(child, "Property"); | 411 | this.ParsePatchChildRefElement(child, "Property"); |
| 412 | break; | 412 | break; |
| 413 | case "SoftwareTagRef": | ||
| 414 | this.ParseTagRefElement(child); | ||
| 415 | break; | ||
| 413 | case "UIRef": | 416 | case "UIRef": |
| 414 | this.ParsePatchChildRefElement(child, "WixUI"); | 417 | this.ParsePatchChildRefElement(child, "WixUI"); |
| 415 | break; | 418 | break; |
diff --git a/src/WixToolset.Core/Compiler_Tag.cs b/src/WixToolset.Core/Compiler_Tag.cs new file mode 100644 index 00000000..2b3523c8 --- /dev/null +++ b/src/WixToolset.Core/Compiler_Tag.cs | |||
| @@ -0,0 +1,315 @@ | |||
| 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 | ||
| 4 | { | ||
| 5 | using System; | ||
| 6 | using System.Xml.Linq; | ||
| 7 | using WixToolset.Data; | ||
| 8 | using WixToolset.Data.Symbols; | ||
| 9 | |||
| 10 | /// <summary> | ||
| 11 | /// Compiler of the WiX toolset. | ||
| 12 | /// </summary> | ||
| 13 | internal partial class Compiler : ICompiler | ||
| 14 | { | ||
| 15 | /// <summary> | ||
| 16 | /// Parses a Tag element for Software Id Tag registration under a Bundle element. | ||
| 17 | /// </summary> | ||
| 18 | /// <param name="node">The element to parse.</param> | ||
| 19 | private void ParseBundleTagElement(XElement node) | ||
| 20 | { | ||
| 21 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
| 22 | string name = null; | ||
| 23 | string regid = null; | ||
| 24 | string installPath = null; | ||
| 25 | |||
| 26 | foreach (var attrib in node.Attributes()) | ||
| 27 | { | ||
| 28 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
| 29 | { | ||
| 30 | switch (attrib.Name.LocalName) | ||
| 31 | { | ||
| 32 | case "Name": | ||
| 33 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
| 34 | break; | ||
| 35 | case "Regid": | ||
| 36 | regid = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
| 37 | break; | ||
| 38 | case "InstallDirectory": | ||
| 39 | case "Bitness": | ||
| 40 | this.Core.Write(ErrorMessages.ExpectedParentWithAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Package")); | ||
| 41 | break; | ||
| 42 | case "InstallPath": | ||
| 43 | installPath = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
| 44 | break; | ||
| 45 | default: | ||
| 46 | this.Core.UnexpectedAttribute(node, attrib); | ||
| 47 | break; | ||
| 48 | } | ||
| 49 | } | ||
| 50 | else | ||
| 51 | { | ||
| 52 | this.Core.ParseExtensionAttribute(node, attrib); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | this.Core.ParseForExtensionElements(node); | ||
| 57 | |||
| 58 | if (String.IsNullOrEmpty(name)) | ||
| 59 | { | ||
| 60 | name = node.Parent?.Attribute("Name")?.Value; | ||
| 61 | |||
| 62 | if (String.IsNullOrEmpty(name)) | ||
| 63 | { | ||
| 64 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | if (!String.IsNullOrEmpty(name) && !this.Core.IsValidLongFilename(name)) | ||
| 69 | { | ||
| 70 | this.Core.Write(CompilerErrors.IllegalName(sourceLineNumbers, node.Name.LocalName, name)); | ||
| 71 | } | ||
| 72 | |||
| 73 | if (String.IsNullOrEmpty(regid)) | ||
| 74 | { | ||
| 75 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Regid")); | ||
| 76 | } | ||
| 77 | else if (regid.Equals("example.com", StringComparison.OrdinalIgnoreCase)) | ||
| 78 | { | ||
| 79 | this.Core.Write(CompilerErrors.ExampleRegid(sourceLineNumbers, regid)); | ||
| 80 | } | ||
| 81 | |||
| 82 | if (String.IsNullOrEmpty(installPath)) | ||
| 83 | { | ||
| 84 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "InstallPath")); | ||
| 85 | } | ||
| 86 | |||
| 87 | if (!this.Core.EncounteredError) | ||
| 88 | { | ||
| 89 | this.Core.AddSymbol(new WixBundleTagSymbol(sourceLineNumbers) | ||
| 90 | { | ||
| 91 | Filename = String.Concat(name, ".swidtag"), | ||
| 92 | Regid = regid, | ||
| 93 | Name = name, | ||
| 94 | InstallPath = installPath | ||
| 95 | }); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | /// <summary> | ||
| 100 | /// Parses a Tag element for Software Id Tag registration under a Package element. | ||
| 101 | /// </summary> | ||
| 102 | /// <param name="node">The element to parse.</param> | ||
| 103 | private void ParsePackageTagElement(XElement node) | ||
| 104 | { | ||
| 105 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
| 106 | Identifier id = null; | ||
| 107 | string name = null; | ||
| 108 | string regid = null; | ||
| 109 | string feature = null; | ||
| 110 | string installDirectory = null; | ||
| 111 | var win64 = this.Context.IsCurrentPlatform64Bit; | ||
| 112 | |||
| 113 | foreach (var attrib in node.Attributes()) | ||
| 114 | { | ||
| 115 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
| 116 | { | ||
| 117 | switch (attrib.Name.LocalName) | ||
| 118 | { | ||
| 119 | case "Id": | ||
| 120 | id = this.Core.GetAttributeIdentifier(sourceLineNumbers, attrib); | ||
| 121 | break; | ||
| 122 | case "Name": | ||
| 123 | name = this.Core.GetAttributeLongFilename(sourceLineNumbers, attrib, false); | ||
| 124 | break; | ||
| 125 | case "Regid": | ||
| 126 | regid = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
| 127 | break; | ||
| 128 | case "Feature": | ||
| 129 | feature = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
| 130 | break; | ||
| 131 | case "InstallDirectory": | ||
| 132 | installDirectory = this.Core.GetAttributeIdentifierValue(sourceLineNumbers, attrib); | ||
| 133 | break; | ||
| 134 | case "InstallPath": | ||
| 135 | this.Core.Write(ErrorMessages.ExpectedParentWithAttribute(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, "Bundle")); | ||
| 136 | break; | ||
| 137 | case "Bitness": | ||
| 138 | var bitnessValue = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
| 139 | switch (bitnessValue) | ||
| 140 | { | ||
| 141 | case "always32": | ||
| 142 | win64 = false; | ||
| 143 | break; | ||
| 144 | case "always64": | ||
| 145 | win64 = true; | ||
| 146 | break; | ||
| 147 | case "default": | ||
| 148 | case "": | ||
| 149 | break; | ||
| 150 | default: | ||
| 151 | this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, bitnessValue, "default", "always32", "always64")); | ||
| 152 | break; | ||
| 153 | } | ||
| 154 | break; | ||
| 155 | default: | ||
| 156 | this.Core.UnexpectedAttribute(node, attrib); | ||
| 157 | break; | ||
| 158 | } | ||
| 159 | } | ||
| 160 | else | ||
| 161 | { | ||
| 162 | this.Core.ParseExtensionAttribute(node, attrib); | ||
| 163 | } | ||
| 164 | } | ||
| 165 | |||
| 166 | this.Core.ParseForExtensionElements(node); | ||
| 167 | |||
| 168 | if (String.IsNullOrEmpty(name)) | ||
| 169 | { | ||
| 170 | name = node.Parent?.Attribute("Name")?.Value; | ||
| 171 | |||
| 172 | if (String.IsNullOrEmpty(name)) | ||
| 173 | { | ||
| 174 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Name")); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | if (!String.IsNullOrEmpty(name) && !this.Core.IsValidLongFilename(name)) | ||
| 179 | { | ||
| 180 | this.Core.Write(CompilerErrors.IllegalName(sourceLineNumbers, node.Name.LocalName, name)); | ||
| 181 | } | ||
| 182 | |||
| 183 | if (String.IsNullOrEmpty(regid)) | ||
| 184 | { | ||
| 185 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Regid")); | ||
| 186 | } | ||
| 187 | else if (regid.Equals("example.com", StringComparison.OrdinalIgnoreCase)) | ||
| 188 | { | ||
| 189 | this.Core.Write(CompilerErrors.ExampleRegid(sourceLineNumbers, regid)); | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | else if (id == null) | ||
| 193 | { | ||
| 194 | id = this.CreateTagId(regid); | ||
| 195 | } | ||
| 196 | |||
| 197 | if (String.IsNullOrEmpty(installDirectory)) | ||
| 198 | { | ||
| 199 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "InstallDirectory")); | ||
| 200 | } | ||
| 201 | |||
| 202 | if (!this.Core.EncounteredError) | ||
| 203 | { | ||
| 204 | var fileName = String.Concat(name, ".swidtag"); | ||
| 205 | |||
| 206 | this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, installDirectory); | ||
| 207 | this.Core.AddSymbol(new DirectorySymbol(sourceLineNumbers, id) | ||
| 208 | { | ||
| 209 | Name = "swidtag", | ||
| 210 | ParentDirectoryRef = installDirectory, | ||
| 211 | ComponentGuidGenerationSeed = "4BAD0C8B-3AF0-BFE3-CC83-094749A1C4B1" | ||
| 212 | }); | ||
| 213 | |||
| 214 | this.Core.AddSymbol(new ComponentSymbol(sourceLineNumbers, id) | ||
| 215 | { | ||
| 216 | ComponentId = "*", | ||
| 217 | DirectoryRef = id.Id, | ||
| 218 | KeyPath = id.Id, | ||
| 219 | KeyPathType = ComponentKeyPathType.File, | ||
| 220 | Location = ComponentLocation.LocalOnly, | ||
| 221 | Win64 = win64 | ||
| 222 | }); | ||
| 223 | |||
| 224 | this.Core.AddSymbol(new FileSymbol(sourceLineNumbers, id) | ||
| 225 | { | ||
| 226 | ComponentRef = id.Id, | ||
| 227 | Name = fileName, | ||
| 228 | DiskId = 1, | ||
| 229 | Attributes = FileSymbolAttributes.ReadOnly, | ||
| 230 | }); | ||
| 231 | |||
| 232 | if (!String.IsNullOrEmpty(feature)) | ||
| 233 | { | ||
| 234 | this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Feature, feature); | ||
| 235 | } | ||
| 236 | else | ||
| 237 | { | ||
| 238 | feature = "WixSwidTag"; | ||
| 239 | this.Core.AddSymbol(new FeatureSymbol(sourceLineNumbers, new Identifier(AccessModifier.Private, feature)) | ||
| 240 | { | ||
| 241 | Title = "ISO/IEC 19770-2", | ||
| 242 | Level = 1, | ||
| 243 | InstallDefault = FeatureInstallDefault.Local, | ||
| 244 | Display = 0, | ||
| 245 | DisallowAdvertise = true, | ||
| 246 | DisallowAbsent = true, | ||
| 247 | }); | ||
| 248 | } | ||
| 249 | this.Core.CreateComplexReference(sourceLineNumbers, ComplexReferenceParentType.Feature, feature, null, ComplexReferenceChildType.Component, id.Id, true); | ||
| 250 | |||
| 251 | this.Core.EnsureTable(sourceLineNumbers, "SoftwareIdentificationTag"); | ||
| 252 | this.Core.AddSymbol(new WixProductTagSymbol(sourceLineNumbers, id) | ||
| 253 | { | ||
| 254 | FileRef = id.Id, | ||
| 255 | Regid = regid, | ||
| 256 | Name = name | ||
| 257 | }); | ||
| 258 | } | ||
| 259 | } | ||
| 260 | |||
| 261 | /// <summary> | ||
| 262 | /// Parses a TagRef element for Software Id Tag registration under a PatchFamily element. | ||
| 263 | /// </summary> | ||
| 264 | /// <param name="node">The element to parse.</param> | ||
| 265 | private void ParseTagRefElement(XElement node) | ||
| 266 | { | ||
| 267 | var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); | ||
| 268 | string regid = null; | ||
| 269 | |||
| 270 | foreach (var attrib in node.Attributes()) | ||
| 271 | { | ||
| 272 | if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) | ||
| 273 | { | ||
| 274 | switch (attrib.Name.LocalName) | ||
| 275 | { | ||
| 276 | case "Regid": | ||
| 277 | regid = this.Core.GetAttributeValue(sourceLineNumbers, attrib); | ||
| 278 | break; | ||
| 279 | default: | ||
| 280 | this.Core.UnexpectedAttribute(node, attrib); | ||
| 281 | break; | ||
| 282 | } | ||
| 283 | } | ||
| 284 | else | ||
| 285 | { | ||
| 286 | this.Core.ParseExtensionAttribute(node, attrib); | ||
| 287 | } | ||
| 288 | } | ||
| 289 | |||
| 290 | this.Core.ParseForExtensionElements(node); | ||
| 291 | |||
| 292 | if (String.IsNullOrEmpty(regid)) | ||
| 293 | { | ||
| 294 | this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Regid")); | ||
| 295 | } | ||
| 296 | else if (regid.Equals("example.com", StringComparison.OrdinalIgnoreCase)) | ||
| 297 | { | ||
| 298 | this.Core.Write(CompilerErrors.ExampleRegid(sourceLineNumbers, regid)); | ||
| 299 | } | ||
| 300 | |||
| 301 | if (!this.Core.EncounteredError) | ||
| 302 | { | ||
| 303 | var id = this.CreateTagId(regid); | ||
| 304 | |||
| 305 | this.Core.AddSymbol(new WixPatchRefSymbol(sourceLineNumbers, id) | ||
| 306 | { | ||
| 307 | Table = SymbolDefinitions.Component.Name, | ||
| 308 | PrimaryKeys = id.Id | ||
| 309 | }); | ||
| 310 | } | ||
| 311 | } | ||
| 312 | |||
| 313 | private Identifier CreateTagId(string regid) => this.Core.CreateIdentifier("tag", regid, ".product.tag"); | ||
| 314 | } | ||
| 315 | } | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/SoftwareTagFixture.cs b/src/test/WixToolsetTest.CoreIntegration/SoftwareTagFixture.cs new file mode 100644 index 00000000..15276b18 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/SoftwareTagFixture.cs | |||
| @@ -0,0 +1,100 @@ | |||
| 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 WixToolsetTest.CoreIntegration | ||
| 4 | { | ||
| 5 | using System.IO; | ||
| 6 | using System.Linq; | ||
| 7 | using System.Xml.Linq; | ||
| 8 | using WixBuildTools.TestSupport; | ||
| 9 | using WixToolset.Core.TestPackage; | ||
| 10 | using WixToolset.Data; | ||
| 11 | using Xunit; | ||
| 12 | |||
| 13 | public class SoftwareTagFixture | ||
| 14 | { | ||
| 15 | private static readonly XNamespace BurnManifestNamespace = "http://wixtoolset.org/schemas/v4/2008/Burn"; | ||
| 16 | private static readonly XNamespace SwidTagNamespace = "http://standards.iso.org/iso/19770/-2/2009/schema.xsd"; | ||
| 17 | |||
| 18 | [Fact] | ||
| 19 | public void CanBuildPackageWithTag() | ||
| 20 | { | ||
| 21 | var folder = TestData.Get(@"TestData\ProductTag"); | ||
| 22 | var build = new Builder(folder, null, new[] { folder }); | ||
| 23 | |||
| 24 | var results = build.BuildAndQuery(Build, "File", "SoftwareIdentificationTag"); | ||
| 25 | |||
| 26 | var replacePackageCodeStart = results[2].IndexOf("\tmsi:package/") + "\tmsi:package/".Length; | ||
| 27 | var replacePackageCodeEnd = results[2].IndexOf("\t", replacePackageCodeStart); | ||
| 28 | results[2] = results[2].Substring(0, replacePackageCodeStart) + "???" + results[2].Substring(replacePackageCodeEnd); | ||
| 29 | WixAssert.CompareLineByLine(new[] | ||
| 30 | { | ||
| 31 | "File:filF5_pLhBuF5b4N9XEo52g_hUM5Lo\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\texample.txt\t20\t\t\t512\t1", | ||
| 32 | "File:tagEYRYWwOt95punO7qPPAQ9p1GBpY\ttagEYRYWwOt95punO7qPPAQ9p1GBpY\trdcfonyt.swi|~TagTestPackage.swidtag\t449\t\t\t1\t2", | ||
| 33 | "SoftwareIdentificationTag:tagEYRYWwOt95punO7qPPAQ9p1GBpY\twixtoolset.org\tmsi:package/???\tmsi:upgrade/047730A5-30FE-4A62-A520-DA9381B8226A\t" | ||
| 34 | }, results.ToArray()); | ||
| 35 | } | ||
| 36 | |||
| 37 | [Fact] | ||
| 38 | public void CanBuildBundleWithTag() | ||
| 39 | { | ||
| 40 | var testDataFolder = TestData.Get(@"TestData"); | ||
| 41 | |||
| 42 | using (var fs = new DisposableFileSystem()) | ||
| 43 | { | ||
| 44 | var baseFolder = fs.GetFolder(); | ||
| 45 | var intermediateFolder = Path.Combine(baseFolder, "obj"); | ||
| 46 | |||
| 47 | var result = WixRunner.Execute(new[] | ||
| 48 | { | ||
| 49 | "build", | ||
| 50 | Path.Combine(testDataFolder, "ProductTag", "PackageWithTag.wxs"), | ||
| 51 | Path.Combine(testDataFolder, "ProductTag", "PackageComponents.wxs"), | ||
| 52 | "-loc", Path.Combine(testDataFolder, "ProductTag", "Package.en-us.wxl"), | ||
| 53 | "-bindpath", Path.Combine(testDataFolder, "ProductTag"), | ||
| 54 | "-intermediateFolder", Path.Combine(intermediateFolder, "package"), | ||
| 55 | "-o", Path.Combine(baseFolder, "package", @"test.msi") | ||
| 56 | }); | ||
| 57 | |||
| 58 | result.AssertSuccess(); | ||
| 59 | |||
| 60 | result = WixRunner.Execute(new[] | ||
| 61 | { | ||
| 62 | "build", | ||
| 63 | Path.Combine(testDataFolder, "BundleTag", "BundleWithTag.wxs"), | ||
| 64 | "-bindpath", Path.Combine(testDataFolder, "BundleTag"), | ||
| 65 | "-bindpath", Path.Combine(baseFolder, "package"), | ||
| 66 | "-intermediateFolder", intermediateFolder, | ||
| 67 | "-o", Path.Combine(baseFolder, @"bin\test.exe") | ||
| 68 | }); | ||
| 69 | |||
| 70 | result.AssertSuccess(); | ||
| 71 | |||
| 72 | Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.exe"))); | ||
| 73 | Assert.True(File.Exists(Path.Combine(baseFolder, @"bin\test.wixpdb"))); | ||
| 74 | |||
| 75 | using (var ouput = WixOutput.Read(Path.Combine(baseFolder, @"bin\test.wixpdb"))) | ||
| 76 | { | ||
| 77 | var badata = ouput.GetDataStream("wix-burndata.xml"); | ||
| 78 | var doc = XDocument.Load(badata); | ||
| 79 | |||
| 80 | var swidTag = doc.Root.Element(BurnManifestNamespace + "Registration").Element(BurnManifestNamespace + "SoftwareTag").Value; | ||
| 81 | |||
| 82 | var swidTagPath = Path.Combine(baseFolder, "test.swidtag"); | ||
| 83 | File.WriteAllText(swidTagPath, swidTag); | ||
| 84 | |||
| 85 | var docTag = XDocument.Load(swidTagPath); | ||
| 86 | var title = docTag.Root.Attribute("name").Value; | ||
| 87 | var version = docTag.Root.Attribute("version").Value; | ||
| 88 | Assert.Equal("~TagTestBundle", title); | ||
| 89 | Assert.Equal("4.3.2.1", version); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } | ||
| 93 | |||
| 94 | private static void Build(string[] args) | ||
| 95 | { | ||
| 96 | var result = WixRunner.Execute(args) | ||
| 97 | .AssertSuccess(); | ||
| 98 | } | ||
| 99 | } | ||
| 100 | } | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/BundleTag/BundleWithTag.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/BundleTag/BundleWithTag.wxs new file mode 100644 index 00000000..f44fb7bc --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/BundleTag/BundleWithTag.wxs | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs" > | ||
| 2 | <Bundle Name="~TagTestBundle" Version="4.3.2.1" Manufacturer="Example Corporation" UpgradeCode="047730A5-30FE-4A62-A520-DA9381B8226A"> | ||
| 3 | <BootstrapperApplication> | ||
| 4 | <BootstrapperApplicationDll SourceFile="fakeba.dll" /> | ||
| 5 | </BootstrapperApplication> | ||
| 6 | |||
| 7 | <SoftwareTag Regid="wixtoolset.org" InstallPath="[ProgramFiles6432Folder]\Test\swidtag" /> | ||
| 8 | |||
| 9 | <Chain> | ||
| 10 | <MsiPackage SourceFile="test.msi"> | ||
| 11 | <MsiProperty Name="TEST" Value="1" /> | ||
| 12 | </MsiPackage> | ||
| 13 | </Chain> | ||
| 14 | </Bundle> | ||
| 15 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/BundleTag/fakeba.dll b/src/test/WixToolsetTest.CoreIntegration/TestData/BundleTag/fakeba.dll new file mode 100644 index 00000000..64061ea0 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/BundleTag/fakeba.dll | |||
| @@ -0,0 +1 @@ | |||
| This is fakeba.dll. \ No newline at end of file | |||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/Package.en-us.wxl b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/Package.en-us.wxl new file mode 100644 index 00000000..38c12ac1 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/Package.en-us.wxl | |||
| @@ -0,0 +1,11 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | |||
| 3 | <!-- | ||
| 4 | This file contains the declaration of all the localizable strings. | ||
| 5 | --> | ||
| 6 | <WixLocalization xmlns="http://wixtoolset.org/schemas/v4/wxl" Culture="en-US"> | ||
| 7 | |||
| 8 | <String Id="DowngradeError">A newer version of [ProductName] is already installed.</String> | ||
| 9 | <String Id="FeatureTitle">MsiPackage</String> | ||
| 10 | |||
| 11 | </WixLocalization> | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/PackageComponents.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/PackageComponents.wxs new file mode 100644 index 00000000..37a2c462 --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/PackageComponents.wxs | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | <?xml version="1.0" encoding="utf-8"?> | ||
| 2 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 3 | <Fragment> | ||
| 4 | <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER"> | ||
| 5 | <Component> | ||
| 6 | <File Source="example.txt" /> | ||
| 7 | </Component> | ||
| 8 | </ComponentGroup> | ||
| 9 | </Fragment> | ||
| 10 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/PackageWithTag.wxs b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/PackageWithTag.wxs new file mode 100644 index 00000000..17543c1a --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/PackageWithTag.wxs | |||
| @@ -0,0 +1,20 @@ | |||
| 1 | <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> | ||
| 2 | <Package ProductCode="8738B0C5-C4AA-4634-8C03-11EAA2F1E15D" Name="~TagTestPackage" Language="1033" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"> | ||
| 3 | |||
| 4 | <MajorUpgrade DowngradeErrorMessage="!(loc.DowngradeError)" /> | ||
| 5 | |||
| 6 | <Feature Id="ProductFeature" Title="!(loc.FeatureTitle)"> | ||
| 7 | <ComponentGroupRef Id="ProductComponents" /> | ||
| 8 | </Feature> | ||
| 9 | |||
| 10 | <SoftwareTag Regid="wixtoolset.org" InstallDirectory="INSTALLFOLDER" /> | ||
| 11 | </Package> | ||
| 12 | |||
| 13 | <Fragment> | ||
| 14 | <Directory Id="TARGETDIR" Name="SourceDir"> | ||
| 15 | <Directory Id="ProgramFilesFolder"> | ||
| 16 | <Directory Id="INSTALLFOLDER" Name="MsiPackage" /> | ||
| 17 | </Directory> | ||
| 18 | </Directory> | ||
| 19 | </Fragment> | ||
| 20 | </Wix> | ||
diff --git a/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/example.txt b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/example.txt new file mode 100644 index 00000000..1b4ffe8a --- /dev/null +++ b/src/test/WixToolsetTest.CoreIntegration/TestData/ProductTag/example.txt | |||
| @@ -0,0 +1 @@ | |||
| This is example.txt. \ No newline at end of file | |||
