From 184fd7663696e52fe5386f6623b3313a41e05979 Mon Sep 17 00:00:00 2001 From: Rob Mensching Date: Fri, 4 Nov 2022 12:26:42 -0700 Subject: Move Directory code generation to the linker Adding all referenced standard directories requires access to the references. However, references do no survive the linker. Which means the binder is too late to add standard directories. Fixes 6977 --- .../Bind/AddRequiredStandardDirectories.cs | 95 ---------------- .../Bind/BindDatabaseCommand.cs | 6 - src/wix/WixToolset.Core/Compiler.cs | 5 + .../Link/AddRequiredStandardDirectories.cs | 125 +++++++++++++++++++++ src/wix/WixToolset.Core/Linker.cs | 10 +- .../DirectoryFixture.cs | 66 ++--------- 6 files changed, 148 insertions(+), 159 deletions(-) delete mode 100644 src/wix/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs create mode 100644 src/wix/WixToolset.Core/Link/AddRequiredStandardDirectories.cs diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs deleted file mode 100644 index ee3bcc91..00000000 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/AddRequiredStandardDirectories.cs +++ /dev/null @@ -1,95 +0,0 @@ -// 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.Linq; - using WixToolset.Data; - using WixToolset.Data.Symbols; - using WixToolset.Data.WindowsInstaller; - - /// - /// Add referenced standard directory symbols, if not already present. - /// - internal class AddRequiredStandardDirectories - { - internal AddRequiredStandardDirectories(IntermediateSection section, Platform platform) - { - this.Section = section; - this.Platform = platform; - } - - private IntermediateSection Section { get; } - - private Platform Platform { get; } - - public void Execute() - { - var directories = this.Section.Symbols.OfType().ToList(); - var directoryIds = new SortedSet(directories.Select(d => d.Id.Id)); - - foreach (var directory in directories) - { - var parentDirectoryId = directory.ParentDirectoryRef; - - if (String.IsNullOrEmpty(parentDirectoryId)) - { - if (directory.Id.Id != "TARGETDIR") - { - directory.ParentDirectoryRef = "TARGETDIR"; - } - } - else - { - this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, directory.SourceLineNumbers); - } - } - - if (!directoryIds.Contains("TARGETDIR") && WindowsInstallerStandard.TryGetStandardDirectory("TARGETDIR", out var targetDir)) - { - directoryIds.Add(targetDir.Id.Id); - this.Section.AddSymbol(targetDir); - } - } - - private void EnsureStandardDirectoryAdded(ISet directoryIds, string directoryId, SourceLineNumber sourceLineNumbers) - { - if (!directoryIds.Contains(directoryId) && WindowsInstallerStandard.TryGetStandardDirectory(directoryId, out var standardDirectory)) - { - var parentDirectoryId = this.GetStandardDirectoryParent(directoryId); - - var directory = new DirectorySymbol(sourceLineNumbers, standardDirectory.Id) - { - Name = standardDirectory.Name, - ParentDirectoryRef = parentDirectoryId, - }; - - directoryIds.Add(directory.Id.Id); - this.Section.AddSymbol(directory); - - if (!String.IsNullOrEmpty(parentDirectoryId)) - { - this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, sourceLineNumbers); - } - } - } - - private string GetStandardDirectoryParent(string directoryId) - { - switch (directoryId) - { - case "TARGETDIR": - return null; - - case "CommonFiles6432Folder": - case "ProgramFiles6432Folder": - case "System6432Folder": - return WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directoryId, this.Platform); - - default: - return "TARGETDIR"; - } - } - } -} diff --git a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs index b3008d6e..81be3794 100644 --- a/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs +++ b/src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs @@ -171,12 +171,6 @@ namespace WixToolset.Core.WindowsInstaller.Bind command.Execute(); } - if (section.Type == SectionType.Product || section.Type == SectionType.Module) - { - var command = new AddRequiredStandardDirectories(section, platform); - command.Execute(); - } - { var command = new CreateSpecialPropertiesCommand(section); command.Execute(); diff --git a/src/wix/WixToolset.Core/Compiler.cs b/src/wix/WixToolset.Core/Compiler.cs index b9c42aaf..79bb40e7 100644 --- a/src/wix/WixToolset.Core/Compiler.cs +++ b/src/wix/WixToolset.Core/Compiler.cs @@ -7131,6 +7131,11 @@ namespace WixToolset.Core this.Core.ParseExtensionElement(node, child); } } + + if (!this.Core.EncounteredError) + { + this.Core.CreateSimpleReference(sourceLineNumbers, SymbolDefinitions.Directory, id); + } } /// diff --git a/src/wix/WixToolset.Core/Link/AddRequiredStandardDirectories.cs b/src/wix/WixToolset.Core/Link/AddRequiredStandardDirectories.cs new file mode 100644 index 00000000..49483552 --- /dev/null +++ b/src/wix/WixToolset.Core/Link/AddRequiredStandardDirectories.cs @@ -0,0 +1,125 @@ +// 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.Link +{ + using System; + using System.Collections.Generic; + using System.Linq; + using WixToolset.Data; + using WixToolset.Data.Symbols; + using WixToolset.Data.WindowsInstaller; + + /// + /// Add referenced standard directory symbols, if not already present. + /// + internal class AddRequiredStandardDirectories + { + public AddRequiredStandardDirectories(IntermediateSection section, List references) + { + this.Section = section; + this.References = references; + } + + private IntermediateSection Section { get; } + + private List References { get; } + + public void Execute() + { + var platform = this.GetPlatformFromSection(); + + var directories = this.Section.Symbols.OfType().ToList(); + var directoryIds = new SortedSet(directories.Select(d => d.Id.Id)); + + // Ensure any standard directory references symbols are added. + foreach (var directoryReference in this.References.Where(r => r.Table == "Directory")) + { + this.EnsureStandardDirectoryAdded(directoryIds, directoryReference.PrimaryKeys, directoryReference.SourceLineNumbers, platform); + } + + foreach (var directory in directories) + { + var parentDirectoryId = directory.ParentDirectoryRef; + + if (String.IsNullOrEmpty(parentDirectoryId)) + { + if (directory.Id.Id != "TARGETDIR") + { + directory.ParentDirectoryRef = "TARGETDIR"; + } + } + else + { + this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, directory.SourceLineNumbers, platform); + } + } + + if (!directoryIds.Contains("TARGETDIR") && WindowsInstallerStandard.TryGetStandardDirectory("TARGETDIR", out var targetDir)) + { + directoryIds.Add(targetDir.Id.Id); + this.Section.AddSymbol(targetDir); + } + } + + private void EnsureStandardDirectoryAdded(ISet directoryIds, string directoryId, SourceLineNumber sourceLineNumbers, Platform platform) + { + if (!directoryIds.Contains(directoryId) && WindowsInstallerStandard.TryGetStandardDirectory(directoryId, out var standardDirectory)) + { + var parentDirectoryId = this.GetStandardDirectoryParent(directoryId, platform); + + var directory = new DirectorySymbol(sourceLineNumbers, standardDirectory.Id) + { + Name = standardDirectory.Name, + ParentDirectoryRef = parentDirectoryId, + }; + + directoryIds.Add(directory.Id.Id); + this.Section.AddSymbol(directory); + + if (!String.IsNullOrEmpty(parentDirectoryId)) + { + this.EnsureStandardDirectoryAdded(directoryIds, parentDirectoryId, sourceLineNumbers, platform); + } + } + } + + private string GetStandardDirectoryParent(string directoryId, Platform platform) + { + switch (directoryId) + { + case "TARGETDIR": + return null; + + case "CommonFiles6432Folder": + case "ProgramFiles6432Folder": + case "System6432Folder": + return WindowsInstallerStandard.GetPlatformSpecificDirectoryId(directoryId, platform); + + default: + return "TARGETDIR"; + } + } + + private Platform GetPlatformFromSection() + { + var symbol = this.Section.Symbols.OfType().First(p => p.PropertyId == SummaryInformationType.PlatformAndLanguage); + + var value = symbol.Value; + var separatorIndex = value.IndexOf(';'); + var platformValue = separatorIndex > 0 ? value.Substring(0, separatorIndex) : value; + + switch (platformValue) + { + case "x64": + return Platform.X64; + + case "Arm64": + return Platform.ARM64; + + case "Intel": + default: + return Platform.X86; + } + } + } +} diff --git a/src/wix/WixToolset.Core/Linker.cs b/src/wix/WixToolset.Core/Linker.cs index 1aeb783b..887372f8 100644 --- a/src/wix/WixToolset.Core/Linker.cs +++ b/src/wix/WixToolset.Core/Linker.cs @@ -90,8 +90,6 @@ namespace WixToolset.Core } } - //this.activeOutput = null; - var multipleFeatureComponents = new Hashtable(); var wixVariables = new Dictionary(); @@ -178,6 +176,7 @@ namespace WixToolset.Core // Create a new section to hold the linked content. Start with the entry section's // metadata. var resolvedSection = new IntermediateSection(find.EntrySection.Id, find.EntrySection.Type); + var references = new List(); foreach (var section in sections) { @@ -248,6 +247,7 @@ namespace WixToolset.Core case SymbolDefinitionType.WixSimpleReference: copySymbol = false; + references.Add(symbol as WixSimpleReferenceSymbol); break; case SymbolDefinitionType.WixVariable: @@ -288,6 +288,12 @@ namespace WixToolset.Core var command = new FlattenAndProcessBundleTablesCommand(resolvedSection, this.Messaging); command.Execute(); } + else if (resolvedSection.Type == SectionType.Product || resolvedSection.Type == SectionType.Module) + { + // Packages and modules get standard directories add. + var command = new AddRequiredStandardDirectories(resolvedSection, references); + command.Execute(); + } if (this.Messaging.EncounteredError) { diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs index f2ace1d0..429b69ef 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/DirectoryFixture.cs @@ -97,54 +97,8 @@ namespace WixToolsetTest.CoreIntegration { var baseFolder = fs.GetFolder(); var intermediateFolder = Path.Combine(baseFolder, "obj"); - var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); - - var result = WixRunner.Execute(new[] - { - "build", - Path.Combine(folder, "Directory", "DefaultName.wxs"), - Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"), - "-bindpath", Path.Combine(folder, "SingleFile", "data"), - "-intermediateFolder", intermediateFolder, - "-o", msiPath - }); - - result.AssertSuccess(); - - var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); - var section = intermediate.Sections.Single(); - - var dirSymbols = section.Symbols.OfType().ToList(); - WixAssert.CompareLineByLine(new[] - { - "BinFolder\tCompanyFolder\t.", - "CompanyFolder\tProgramFilesFolder\tExample Corporation", - "ProgramFilesFolder\tTARGETDIR\tPFiles", - "TARGETDIR\t\tSourceDir" - }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => String.Join('\t', d.Id.Id, d.ParentDirectoryRef, d.Name)).ToArray()); - - var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); - var directoryRows = data.Tables["Directory"].Rows; - WixAssert.CompareLineByLine(new[] - { - "BinFolder\tCompanyFolder\t.", - "CompanyFolder\tProgramFilesFolder\tu7-b4gch|Example Corporation", - "ProgramFilesFolder\tTARGETDIR\tPFiles", - "TARGETDIR\t\tSourceDir" - }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).ToArray()); - } - } - - [Fact(Skip = "https://github.com/wixtoolset/issues/issues/6977")] - public void CanGetEmptyStandardDirectory() - { - var folder = TestData.Get(@"TestData"); - - using (var fs = new DisposableFileSystem()) - { - var baseFolder = fs.GetFolder(); - var intermediateFolder = Path.Combine(baseFolder, "obj"); - var msiPath = Path.Combine(baseFolder, @"bin\test.msi"); + var msiPath = Path.Combine(baseFolder, "bin", "test.msi"); + var wixpdbPath = Path.Combine(baseFolder, "bin", "test.wixpdb"); var result = WixRunner.Execute(new[] { @@ -158,7 +112,7 @@ namespace WixToolsetTest.CoreIntegration result.AssertSuccess(); - var intermediate = Intermediate.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); + var intermediate = Intermediate.Load(wixpdbPath); var section = intermediate.Sections.Single(); var dirSymbols = section.Symbols.OfType().ToList(); @@ -166,23 +120,23 @@ namespace WixToolsetTest.CoreIntegration { "BinFolder\tCompanyFolder\t.", "CompanyFolder\tProgramFilesFolder\tExample Corporation", - "DesktopFolder\tTARGETDIR\t.", + "DesktopFolder\tTARGETDIR\tDesktop", "ProgramFilesFolder\tTARGETDIR\tPFiles", - "ProgramMenuFolder\tTARGETDIR\t.", + "ProgramMenuFolder\tTARGETDIR\tPMenu", "TARGETDIR\t\tSourceDir" - }, dirSymbols.OrderBy(d => d.Id.Id).Select(d => String.Join('\t', d.Id.Id, d.ParentDirectoryRef, d.Name)).ToArray()); + }, dirSymbols.Select(d => String.Join('\t', d.Id.Id, d.ParentDirectoryRef, d.Name)).OrderBy(s => s).ToArray()); - var data = WindowsInstallerData.Load(Path.Combine(baseFolder, @"bin\test.wixpdb")); + var data = WindowsInstallerData.Load(wixpdbPath); var directoryRows = data.Tables["Directory"].Rows; WixAssert.CompareLineByLine(new[] { "BinFolder\tCompanyFolder\t.", "CompanyFolder\tProgramFilesFolder\tu7-b4gch|Example Corporation", - "DesktopFolder\tTARGETDIR\t.", + "DesktopFolder\tTARGETDIR\tDesktop", "ProgramFilesFolder\tTARGETDIR\tPFiles", - "ProgramMenuFolder\tTARGETDIR\t.", + "ProgramMenuFolder\tTARGETDIR\tPMenu", "TARGETDIR\t\tSourceDir" - }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).ToArray()); + }, directoryRows.Select(r => String.Join('\t', r.FieldAsString(0), r.FieldAsString(1), r.FieldAsString(2))).OrderBy(s => s).ToArray()); } } -- cgit v1.2.3-55-g6feb