Skip to content

Commit

Permalink
Ensure naked files take Subdirectory into account.
Browse files Browse the repository at this point in the history
Naked files generated their ids using the attributes that are common to
both naked and clothed files. But naked files also support @subdirectory
to magic up a subdirectory in a specified directory (@Directory) or the
default INSTALLFOLDER. That subdirectory needs to factor in to the
generated file id (which is then used as the component id too).
Without it, generated ids for files with the same name but from
different @subdirectory values would be duplicated. (Authored file ids
must also continue to be supported.)

Naked files now generate different file and component ids. :(

Fixes wixtoolset/issues#8674
  • Loading branch information
barnson committed Aug 4, 2024
1 parent ce73352 commit d9c3799
Show file tree
Hide file tree
Showing 12 changed files with 100 additions and 22 deletions.
44 changes: 35 additions & 9 deletions src/wix/WixToolset.Core/Compiler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5348,7 +5348,7 @@ private YesNoType ParseFileElementAttributes(XElement node, string componentId,
}
}

if (null == id)
if (null == id && !isNakedFile)
{
id = this.Core.CreateIdentifier("fil", directoryId, name);
}
Expand Down Expand Up @@ -5610,8 +5610,6 @@ private void ParseNakedFileElement(XElement node, ComplexReferenceParentType par
string condition = null;
string subdirectory = null;

var keyPath = this.ParseFileElementAttributes(node, "@WixTemporaryComponentId", directoryId, diskId: CompilerConstants.IntegerNotSet, sourcePath, out var _, componentGuid: "*", isNakedFile: true, out var fileSymbol, out var assemblySymbol);

if (!this.Core.EncounteredError)
{
// Naked files have additional attributes to handle common component attributes.
Expand Down Expand Up @@ -5661,13 +5659,44 @@ private void ParseNakedFileElement(XElement node, ComplexReferenceParentType par

directoryId = this.HandleSubdirectory(sourceLineNumbers, node, directoryId, subdirectory, "Directory", "Subdirectory");

this.Core.AddSymbol(new ComponentSymbol(sourceLineNumbers, fileSymbol.Id)
var keyPath = this.ParseFileElementAttributes(node, "@WixTemporaryComponentId", directoryId, diskId: CompilerConstants.IntegerNotSet, sourcePath, out var _, componentGuid: "*", isNakedFile: true, out var fileSymbol, out var assemblySymbol);

// Now that we have all the data we need to generate a good id, do
// so and create a file and component symbol with the right data.
var id = fileSymbol.Id ?? this.Core.CreateIdentifier("nkf", directoryId, fileSymbol.Name, condition, win64.ToString());

this.Core.AddSymbol(new FileSymbol(sourceLineNumbers, id)
{
ComponentRef = id.Id,
Name = fileSymbol.Name,
ShortName = fileSymbol.ShortName,
FileSize = fileSymbol.FileSize,
Version = fileSymbol.Version,
Language = fileSymbol.Language,
Attributes = fileSymbol.Attributes,
DirectoryRef = fileSymbol.DirectoryRef,
DiskId = fileSymbol.DiskId,
Source = fileSymbol.Source,
FontTitle = fileSymbol.FontTitle,
SelfRegCost = fileSymbol.SelfRegCost,
BindPath = fileSymbol.BindPath,
PatchGroup = fileSymbol.PatchGroup,
PatchAttributes = fileSymbol.PatchAttributes,
RetainLengths = fileSymbol.RetainLengths,
IgnoreOffsets = fileSymbol.IgnoreOffsets,
IgnoreLengths = fileSymbol.IgnoreLengths,
RetainOffsets = fileSymbol.RetainOffsets,
SymbolPaths = fileSymbol.SymbolPaths,

});

this.Core.AddSymbol(new ComponentSymbol(sourceLineNumbers, id)
{
ComponentId = "*",
DirectoryRef = directoryId,
Location = ComponentLocation.LocalOnly,
Condition = condition,
KeyPath = fileSymbol.Id.Id,
KeyPath = id.Id,
KeyPathType = ComponentKeyPathType.File,
DisableRegistryReflection = false,
NeverOverwrite = false,
Expand All @@ -5679,9 +5708,6 @@ private void ParseNakedFileElement(XElement node, ComplexReferenceParentType par
Win64 = win64,
});

fileSymbol.ComponentRef = fileSymbol.Id.Id;
this.Core.AddSymbol(fileSymbol);

if (assemblySymbol != null)
{
this.Core.AddSymbol(assemblySymbol);
Expand All @@ -5692,7 +5718,7 @@ private void ParseNakedFileElement(XElement node, ComplexReferenceParentType par
if (ComplexReferenceParentType.Unknown != parentType && null != parentId) // if parent was provided, add a complex reference to that.
{
// If the naked file's component is defined directly under a feature, then mark the complex reference primary.
this.Core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.Component, fileSymbol.Id.Id, ComplexReferenceParentType.Feature == parentType);
this.Core.CreateComplexReference(sourceLineNumbers, parentType, parentId, null, ComplexReferenceChildType.Component, id.Id, ComplexReferenceParentType.Feature == parentType);
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/wix/WixToolset.Core/Linker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ private void FlattenGroup(string parentTypeAndId, Stack<string> loopDetector, Di
var childTypeAndId = this.CombineTypeAndId(wixComplexReferenceRow.ChildType, wixComplexReferenceRow.Child);
if (loopDetector.Contains(childTypeAndId))
{
// Create a comma delimited list of the references that participate in the
// Create an arrow-delimited list of the references that participate in the
// loop for the error message. Start at the bottom of the stack and work the
// way up to present the loop as a directed graph.
var loop = String.Join(" -> ", loopDetector);
Expand Down
35 changes: 35 additions & 0 deletions src/wix/test/WixToolsetTest.CoreIntegration/HarvestFilesFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,41 @@ public void CanHarvestFilesInFiveLines()
Build("PackageFiveLiner.wxs", (msiPath, _) => AssertFileIdsAndTargetPaths(msiPath, expected));
}

[Fact]
public void CanHarvestFilesWithDuplicateNames()
{
var expectedFiles = new[]
{
"File:fls47G631z.20kTPzBwIPjGuWifsVo\tfls47G631z.20kTPzBwIPjGuWifsVo\tfile.x\t0\t\t\t512\t2",
"File:flshOXYGoD0VHcQhrkIILRPNOVbYuM\tflshOXYGoD0VHcQhrkIILRPNOVbYuM\tfile.x\t0\t\t\t512\t1",
"File:flsp2QdFvBeSwll1i5tN0jM72w3Hu4\tflsp2QdFvBeSwll1i5tN0jM72w3Hu4\tfile.x\t0\t\t\t512\t3",
"File:flsqopW5ihQpwCTF7t_51GkHd4Hf6s\tflsqopW5ihQpwCTF7t_51GkHd4Hf6s\tfile.x\t0\t\t\t512\t4",
};

var expectedFilesAndDirectories = new[]
{
@"fls47G631z.20kTPzBwIPjGuWifsVo=PFiles\Example Corporation MsiPackage\b\file.x",
@"flshOXYGoD0VHcQhrkIILRPNOVbYuM=PFiles\Example Corporation MsiPackage\a\file.x",
@"flsp2QdFvBeSwll1i5tN0jM72w3Hu4=PFiles\Example Corporation MsiPackage\c\file.x",
@"flsqopW5ihQpwCTF7t_51GkHd4Hf6s=PFiles\Example Corporation MsiPackage\d\file.x",
};

Build("DuplicateNames.wxs", (msiPath, result) => AssertFileAndComponentIdsAndTargetPaths(msiPath, result, expectedFiles, expectedFilesAndDirectories));
}

private static void AssertFileAndComponentIdsAndTargetPaths(string msiPath, WixRunnerResult result, string[] expectedFiles, string[] expectedFilesAndDirectories)
{
result.AssertSuccess();

var files = Query.QueryDatabase(msiPath, new[] { "File" })
.OrderBy(s => s)
.ToArray();

Assert.Equal(expectedFiles, files);

AssertFileIdsAndTargetPaths(msiPath, expectedFilesAndDirectories);
}

private static void AssertFileIdsAndTargetPaths(string msiPath, string[] expected)
{
var pkg = new WixToolset.Dtf.WindowsInstaller.Package.InstallPackage(msiPath,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ public void CanBuildNakedFilesUnderPackage()
AssertFileComponentIds(4, rows);
}

[Fact]
public void CanBuildNakedFilesUnderPackageWithDuplicateNames()
{
var rows = BuildAndQueryComponentAndFileTables("DuplicateNames.wxs");
AssertFileComponentIds(5, rows);
}

[Fact]
public void CanBuildNakedFilesUnderPackageWithDefaultInstallFolder()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
<Files Include="dupes\**" />
</Package>
</Wix>
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package Name="GenManyComponents 5x1" Manufacturer="FireGiant" Version="1.0.0.0" UpgradeCode="b146c9a9-7184-413c-8ab2-b65ed869feb9">
<File Subdirectory='0000' Name='0000.x' Source='$(sys.SOURCEFILEPATH)' />
<File Subdirectory='0001' Name='0000.x' Source='$(sys.SOURCEFILEPATH)' />
<File Subdirectory='0002' Name='0000.x' Source='$(sys.SOURCEFILEPATH)' />
<File Subdirectory='0003' Name='0000.x' Source='$(sys.SOURCEFILEPATH)' />
<File Subdirectory='0004' Name='0000.x' Source='$(sys.SOURCEFILEPATH)' />
</Package>
</Wix>
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
<MajorUpgrade DowngradeErrorMessage="Downgrade error message." />

<File Directory="INSTALLFOLDER" Source="test.txt" />
<File Directory="INSTALLFOLDER" Source="test.txt" Name="test2.txt" />
<File Directory="INSTALLFOLDER" Source="test.txt" Name="test3.txt" />
<File Directory="INSTALLFOLDER" Source="test.txt" Name="test4.txt" />
<File Directory="INSTALLFOLDER" Subdirectory="X" Source="test.txt" />
<File Directory="INSTALLFOLDER" Subdirectory="X" Source="test.txt" Name="test2.txt" />
<File Directory="INSTALLFOLDER" Subdirectory="X3" Source="test.txt" Name="test3.txt" />
<File Directory="INSTALLFOLDER" Subdirectory="X4" Source="test.txt" Name="test4.txt" />
</Package>
</Wix>
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package Name="MsiPackage" Version="1.0.0.0" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
<MajorUpgrade DowngradeErrorMessage="Downgrade error message." />

<File Source="test.txt" />
<File Source="test.txt" Name="test2.txt" />
<File Source="test.txt" Name="test3.txt" />
<File Source="test.txt" Name="test4.txt" />
<File Subdirectory="X" Name="test.txt" Source="test.txt" />
<File Subdirectory="X" Name="test2.txt" Source="test.txt" />
<File Subdirectory="X3" Name="test3.txt" Source="test.txt" />
<File Subdirectory="X4" Name="test4.txt" Source="test.txt" />
</Package>
</Wix>

0 comments on commit d9c3799

Please sign in to comment.