Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support naked files. #479

Merged
merged 1 commit into from
Jan 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions src/api/wix/WixToolset.Data/ErrorMessages.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2256,6 +2256,11 @@ public static Message IllegalInnerText(SourceLineNumber sourceLineNumbers, strin
return Message(sourceLineNumbers, Ids.IllegalInnerText, "The {0} element contains inner text which is obsolete. Use the {1} attribute instead.", elementName, attributeName);
}

public static Message IllegalAttributeWhenNested(SourceLineNumber sourceLineNumbers, string attributeName)
{
return Message(sourceLineNumbers, Ids.IllegalAttributeWhenNested, "The File element contains an attribute '{0}' that cannot be used in a File element that is a child of a Component element.", attributeName);
}

private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
{
return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
Expand Down
354 changes: 276 additions & 78 deletions src/wix/WixToolset.Core/Compiler.cs

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions src/wix/WixToolset.Core/Compiler_Module.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,9 @@ private void ParseModuleElement(XElement node)
case "Exclusion":
this.ParseExclusionElement(child);
break;
case "File":
this.ParseNakedFileElement(child, ComplexReferenceParentType.Module, this.activeName, null, null);
break;
case "Icon":
this.ParseIconElement(child);
break;
Expand Down
3 changes: 3 additions & 0 deletions src/wix/WixToolset.Core/Compiler_Package.cs
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,9 @@ private void ParsePackageElement(XElement node)
case "FeatureGroupRef":
this.ParseFeatureGroupRefElement(child, ComplexReferenceParentType.Product, productCode);
break;
case "File":
this.ParseNakedFileElement(child, ComplexReferenceParentType.Product, productCode, null, null);
break;
case "Icon":
this.ParseIconElement(child);
break;
Expand Down
4 changes: 4 additions & 0 deletions src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ public void Execute()
return;
}

// If a directory with id INSTALLFOLDER hasn't been authored, provide a default one.
if (!this.Find.SymbolsByName.ContainsKey(WixStandardInstallFolderReference))
{
var sourceLineNumber = new SourceLineNumber("DefaultInstallFolder");
Expand All @@ -51,6 +52,9 @@ public void Execute()
);
}

// If an upgrade hasn't been authored and the upgrade strategy is MajorUpgrade,
// conjure a default major upgrade with the stdlib localization string for the
// downgrade error message.
var symbols = this.Sections.SelectMany(section => section.Symbols);
var upgradeSymbols = symbols.OfType<UpgradeSymbol>();
if (!upgradeSymbols.Any())
Expand Down
2 changes: 2 additions & 0 deletions src/wix/WixToolset.Core/Link/SymbolWithSection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ namespace WixToolset.Core.Link
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using WixToolset.Data;
using WixToolset.Data.Symbols;

/// <summary>
/// Symbol with section representing a single unique symbol.
/// </summary>
[DebuggerDisplay("{Symbol.DebuggerDisplay}")]
internal class SymbolWithSection
{
private List<WixSimpleReferenceSymbol> directReferences;
Expand Down
29 changes: 0 additions & 29 deletions src/wix/test/WixToolsetTest.CoreIntegration/ComponentFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,34 +41,5 @@ public void CanDetectDuplicateComponentGuids()
}, errors.Select(e => e.Id).ToArray());
}
}

[Fact]
public void CannotBuildMissingDirectoryAttributeWithSubdirectory()
{
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 result = WixRunner.Execute(new[]
{
"build",
Path.Combine(folder, "Component", "MissingDirectoryWithSubdirectory.wxs"),
Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
"-bindpath", Path.Combine(folder, "SingleFile", "data"),
"-intermediateFolder", intermediateFolder,
"-o", msiPath
});

var errors = result.Messages.Select(m => m.ToString()).ToArray();
WixAssert.CompareLineByLine(new[]
{
"The Component/@Directory attribute was not found; it is required."
}, errors);
}
}
}
}
247 changes: 247 additions & 0 deletions src/wix/test/WixToolsetTest.CoreIntegration/NakedFileFixture.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
// 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 WixToolsetTest.CoreIntegration
{
using System.Data;
using System.IO;
using System.Linq;
using WixInternal.Core.TestPackage;
using WixInternal.TestSupport;
using WixToolset.Data.WindowsInstaller;
using Xunit;

public class NakedFileFixture
{
[Fact]
public void CanBuildNakedFilesInComponentGroup()
{
var rows = BuildAndQueryComponentAndFileTables("ComponentGroup.wxs");

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesInFeature()
{
var rows = BuildAndQueryComponentAndFileTables("Feature.wxs");

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesInDirectory()
{
var rows = BuildAndQueryComponentAndFileTables("Directory.wxs");

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesInDirectoryRef()
{
var rows = BuildAndQueryComponentAndFileTables("DirectoryRef.wxs");

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesInFeatureRef()
{
var rows = BuildAndQueryComponentAndFileTables("FeatureRef.wxs");

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesInFeatureGroup()
{
var rows = BuildAndQueryComponentAndFileTables("FeatureGroup.wxs");

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesInFragments()
{
var rows = BuildAndQueryComponentAndFileTables("Fragment.wxs");

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesInStandardDirectory()
{
var rows = BuildAndQueryComponentAndFileTables("StandardDirectory.wxs");

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesInModule()
{
var rows = BuildAndQueryComponentAndFileTables("Module.wxs", isPackage: false);

AssertFileComponentIds(2, rows);
}

[Fact]
public void CanBuildNakedFilesWithConditions()
{
var rows = BuildAndQueryComponentAndFileTables("Condition.wxs");
var componentRows = rows.Where(row => row.StartsWith("Component:")).ToArray();

// Coincidentally, the files' ids are the same as the component conditions.
foreach (var componentRow in componentRows)
{
var columns = componentRow.Split(':', '\t');
Assert.Equal(columns[1], columns[5]);
}
}

[Fact]
public void CanBuildNakedFilesUnderPackage()
{
var rows = BuildAndQueryComponentAndFileTables("Package.wxs");
AssertFileComponentIds(4, rows);
}

[Fact]
public void CanBuildNakedFilesUnderPackageWithDefaultInstallFolder()
{
var rows = BuildAndQueryComponentAndFileTables("PackageWithDefaultInstallFolder.wxs");
AssertFileComponentIds(4, rows);
}

[Fact]
public void NakedFilesUnderPackageWithAuthoredFeatureAreOrphaned()
{
var messages = BuildAndQueryComponentAndFileTables("PackageWithoutDefaultFeature.wxs", isPackage: true, 267);
Assert.Equal(new[]
{
"267",
"267",
}, messages);
}

[Fact]
public void IllegalAttributesWhenNonNakedFailTheBuild()
{
var messages = BuildAndQueryComponentAndFileTables("BadAttributes.wxs", isPackage: true, 62);
Assert.Equal(new[]
{
"62",
"62",
"62",
"62",
}, messages);
}

[Fact]
public void CanBuildNakedFileFromWixlibComponentGroup()
{
var rows = BuildPackageWithWixlib("WixlibComponentGroup.wxs", "WixlibComponentGroupPackage.wxs");

AssertFileComponentIds(2, rows);
}

private static string[] BuildPackageWithWixlib(string wixlibSourcePath, string msiSourcePath)
{
var folder = TestData.Get("TestData", "NakedFile");

using (var fs = new DisposableFileSystem())
{
var baseFolder = fs.GetFolder();
var intermediateFolder = Path.Combine(baseFolder, "obj");
var binFolder = Path.Combine(baseFolder, "bin");
var wixlibPath = Path.Combine(binFolder, Path.ChangeExtension(wixlibSourcePath, ".wixlib"));

var result = WixRunner.Execute(new[]
{
"build",
Path.Combine(folder, wixlibSourcePath),
"-intermediateFolder", intermediateFolder,
"-bindpath", folder,
"-o", wixlibPath,
});

result.AssertSuccess();

var msiPath = Path.Combine(binFolder, "test.msi");

result = WixRunner.Execute(new[]
{
"build",
Path.Combine(folder, msiSourcePath),
wixlibPath,
"-intermediateFolder", intermediateFolder,
"-bindpath", folder,
"-o", msiPath,
});
result.AssertSuccess();

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

private static string[] BuildAndQueryComponentAndFileTables(string file, bool isPackage = true, int? exitCode = null)
{
var folder = TestData.Get("TestData", "NakedFile");

using (var fs = new DisposableFileSystem())
{
var baseFolder = fs.GetFolder();
var intermediateFolder = Path.Combine(baseFolder, "obj");
var binFolder = Path.Combine(baseFolder, "bin");
var msiPath = Path.Combine(binFolder, isPackage ? "test.msi" : "test.msm");

var result = WixRunner.Execute(new[]
{
"build",
Path.Combine(folder, file),
"-intermediateFolder", intermediateFolder,
"-bindpath", folder,
"-o", msiPath,
});

if (exitCode.HasValue)
{
Assert.Equal(exitCode.Value, result.ExitCode);

return result.Messages.Select(m => m.Id.ToString()).ToArray();
}
else
{
result.AssertSuccess();

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

private static void AssertFileComponentIds(int fileCount, string[] rows)
{
var componentRows = rows.Where(row => row.StartsWith("Component:")).ToArray();
var fileRows = rows.Where(row => row.StartsWith("File:")).ToArray();

Assert.Equal(fileCount, componentRows.Length);
Assert.Equal(componentRows.Length, fileRows.Length);

// Component id == Component keypath == File id
foreach (var componentRow in componentRows)
{
var columns = componentRow.Split(':', '\t');
Assert.Equal(columns[1], columns[6]);
}

foreach (var fileRow in fileRows)
{
var columns = fileRow.Split(':', '\t');
Assert.Equal(columns[1], columns[2]);
}
}
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<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." />

<Feature Id="ProductFeature">
<Component Directory="ProgramFilesFolder" Subdirectory="MsiPackage">
<File Source="test.txt" Bitness="always64" Condition="BLAHBLAHBLAH" Directory="ProgramFilesFolder" Subdirectory="MsiPackage" />
</Component>
</Feature>
</Package>
</Wix>
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<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." />

<Feature Id="ProductFeature">
<ComponentGroupRef Id="Files" />
</Feature>

<ComponentGroup Id="Files" Directory="ProgramFilesFolder" Subdirectory="MsiPackage">
<File Source="test.txt" />
<File Source="test.txt" Name="test2.txt" />
</ComponentGroup>
</Package>
</Wix>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<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." />

<Feature Id="ProductFeature">
<File Id="FILE1" Condition="FILE1" Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Source="test.txt" />
<File Id="FILE2" Condition="FILE2" Directory="ProgramFilesFolder" Subdirectory="MsiPackage" Source="test.txt" Name="test2.txt" />
</Feature>
</Package>
</Wix>
Loading