diff --git a/src/api/wix/WixToolset.Data/Symbols/HarvestPayloadsSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/HarvestPayloadsSymbol.cs new file mode 100644 index 000000000..65b424acf --- /dev/null +++ b/src/api/wix/WixToolset.Data/Symbols/HarvestPayloadsSymbol.cs @@ -0,0 +1,68 @@ +// 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.Data +{ + using WixToolset.Data.Symbols; + + public static partial class SymbolDefinitions + { + public static readonly IntermediateSymbolDefinition HarvestPayloads = new IntermediateSymbolDefinition( + SymbolDefinitionType.HarvestPayloads, + new[] + { + new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.Inclusions), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.Exclusions), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.ComplexReferenceParentType), IntermediateFieldType.String), + new IntermediateFieldDefinition(nameof(HarvestFilesSymbolFields.ParentId), IntermediateFieldType.String), + }, + typeof(HarvestPayloadsSymbol)); + } +} + +namespace WixToolset.Data.Symbols +{ + public enum HarvestPayloadsSymbolFields + { + Inclusions, + Exclusions, + ComplexReferenceParentType, + ParentId, + } + + public class HarvestPayloadsSymbol : IntermediateSymbol + { + public HarvestPayloadsSymbol() : base(SymbolDefinitions.HarvestPayloads, null, null) + { + } + + public HarvestPayloadsSymbol(SourceLineNumber sourceLineNumber, Identifier id = null) : base(SymbolDefinitions.HarvestPayloads, sourceLineNumber, id) + { + } + + public IntermediateField this[HarvestPayloadsSymbolFields index] => this.Fields[(int)index]; + + public string Inclusions + { + get => (string)this.Fields[(int)HarvestPayloadsSymbolFields.Inclusions]; + set => this.Set((int)HarvestPayloadsSymbolFields.Inclusions, value); + } + + public string Exclusions + { + get => (string)this.Fields[(int)HarvestPayloadsSymbolFields.Exclusions]; + set => this.Set((int)HarvestPayloadsSymbolFields.Exclusions, value); + } + + public string ComplexReferenceParentType + { + get => (string)this.Fields[(int)HarvestPayloadsSymbolFields.ComplexReferenceParentType]; + set => this.Set((int)HarvestPayloadsSymbolFields.ComplexReferenceParentType, value); + } + + public string ParentId + { + get => (string)this.Fields[(int)HarvestPayloadsSymbolFields.ParentId]; + set => this.Set((int)HarvestPayloadsSymbolFields.ParentId, value); + } + } +} diff --git a/src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs b/src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs index 64f51162e..64c1a2a55 100644 --- a/src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs +++ b/src/api/wix/WixToolset.Data/Symbols/SymbolDefinitions.cs @@ -41,6 +41,7 @@ public enum SymbolDefinitionType File, FileSFPCatalog, HarvestFiles, + HarvestPayloads, Icon, ImageFamilies, IniFile, diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/EarliestCoreBundleSCD.wixproj b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/EarliestCoreBundleSCD.wixproj index 1179bea7a..aea77d1b1 100644 --- a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/EarliestCoreBundleSCD.wixproj +++ b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/EarliestCoreBundleSCD.wixproj @@ -1,14 +1,6 @@ - - - publish.Example.EarliestCoreMBA.scd - ba.xslt - - - - - + diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/SelfContainedBundle.wxs b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/SelfContainedBundle.wxs index 38a167f17..68b697e72 100644 --- a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/SelfContainedBundle.wxs +++ b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/SelfContainedBundle.wxs @@ -1,9 +1,11 @@  - - - + + + + + diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/ba.xslt b/src/ext/Bal/test/examples/EarliestCoreBundleSCD/ba.xslt deleted file mode 100644 index d30b2564a..000000000 --- a/src/ext/Bal/test/examples/EarliestCoreBundleSCD/ba.xslt +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/EarliestCoreBundleTrimmedSCD.wixproj b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/EarliestCoreBundleTrimmedSCD.wixproj index f9926550b..5475022cc 100644 --- a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/EarliestCoreBundleTrimmedSCD.wixproj +++ b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/EarliestCoreBundleTrimmedSCD.wixproj @@ -1,14 +1,6 @@ - - - publish.Example.EarliestCoreMBA.trimmedscd - ba.xslt - - - - - + diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs index bf4ad6e37..8895b279f 100644 --- a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs +++ b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs @@ -1,9 +1,11 @@  - - - + + + + + diff --git a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/ba.xslt b/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/ba.xslt deleted file mode 100644 index d30b2564a..000000000 --- a/src/ext/Bal/test/examples/EarliestCoreBundleTrimmedSCD/ba.xslt +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - diff --git a/src/ext/Bal/test/examples/LatestCoreBundleSCD/LatestCoreBundleSCD.wixproj b/src/ext/Bal/test/examples/LatestCoreBundleSCD/LatestCoreBundleSCD.wixproj index 048e3c976..73582984e 100644 --- a/src/ext/Bal/test/examples/LatestCoreBundleSCD/LatestCoreBundleSCD.wixproj +++ b/src/ext/Bal/test/examples/LatestCoreBundleSCD/LatestCoreBundleSCD.wixproj @@ -1,14 +1,6 @@ - - - publish.Example.LatestCoreMBA.scd - ba.xslt - - - - - + diff --git a/src/ext/Bal/test/examples/LatestCoreBundleSCD/SelfContainedBundle.wxs b/src/ext/Bal/test/examples/LatestCoreBundleSCD/SelfContainedBundle.wxs index 0022b6908..1f379b598 100644 --- a/src/ext/Bal/test/examples/LatestCoreBundleSCD/SelfContainedBundle.wxs +++ b/src/ext/Bal/test/examples/LatestCoreBundleSCD/SelfContainedBundle.wxs @@ -1,9 +1,11 @@  - - - + + + + + diff --git a/src/ext/Bal/test/examples/LatestCoreBundleSCD/ba.xslt b/src/ext/Bal/test/examples/LatestCoreBundleSCD/ba.xslt deleted file mode 100644 index f606296eb..000000000 --- a/src/ext/Bal/test/examples/LatestCoreBundleSCD/ba.xslt +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - diff --git a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/LatestCoreBundleTrimmedSCD.wixproj b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/LatestCoreBundleTrimmedSCD.wixproj index 056bf2bb8..532f09b46 100644 --- a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/LatestCoreBundleTrimmedSCD.wixproj +++ b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/LatestCoreBundleTrimmedSCD.wixproj @@ -1,14 +1,6 @@ - - - publish.Example.LatestCoreMBA.trimmedscd - ba.xslt - - - - - + diff --git a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs index 322a27a3a..cd32628a5 100644 --- a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs +++ b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/TrimmedSelfContainedBundle.wxs @@ -1,9 +1,11 @@  - - - + + + + + diff --git a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/ba.xslt b/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/ba.xslt deleted file mode 100644 index f606296eb..000000000 --- a/src/ext/Bal/test/examples/LatestCoreBundleTrimmedSCD/ba.xslt +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - diff --git a/src/ext/Bal/test/examples/examples.proj b/src/ext/Bal/test/examples/examples.proj index c15447668..e439c288f 100644 --- a/src/ext/Bal/test/examples/examples.proj +++ b/src/ext/Bal/test/examples/examples.proj @@ -34,16 +34,12 @@ Condition="'%(CoreMBAProject.SkipFDD)'==''" /> - + diff --git a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp index 381ea39af..12a2aaf1c 100644 --- a/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp +++ b/src/libs/dutil/test/DUtilUnitTest/PathUtilTest.cpp @@ -142,7 +142,15 @@ namespace DutilTests else { NativeAssert::Succeeded(hr, "Failed to canonicalize path"); - NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + + if ('\\' == *sczCanonicalized) + { + NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + } + else + { + NativeAssert::StringEqual(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + } } hr = PathCanonicalizeForComparison(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", 0, &sczCanonicalized); @@ -153,7 +161,15 @@ namespace DutilTests else { NativeAssert::Succeeded(hr, "Failed to canonicalize path"); - NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + + if ('\\' == *sczCanonicalized) + { + NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + } + else + { + NativeAssert::StringEqual(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + } } hr = PathCanonicalizeForComparison(L"\\\\server", PATH_CANONICALIZE_KEEP_UNC_ROOT, &sczCanonicalized); @@ -288,7 +304,15 @@ namespace DutilTests { hr = PathAllocCanonicalizePath(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); NativeAssert::Succeeded(hr, "Failed to canonicalize path"); - NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + + if ('\\' == *sczCanonicalized) + { + NativeAssert::StringEqual(L"\\\\?\\C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + } + else + { + NativeAssert::StringEqual(L"C:\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", sczCanonicalized); + } hr = PathAllocCanonicalizePath(L"abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789\\abcdefghijklomnopqrstuvwxyz0123456789", PATHCCH_ALLOW_LONG_PATHS, &sczCanonicalized); NativeAssert::Succeeded(hr, "Failed to canonicalize path"); @@ -937,50 +961,22 @@ namespace DutilTests void PathGetTempPathTest() { HRESULT hr = S_OK; - LPCWSTR wzEnvName = L"TMP"; - LPCWSTR wzEnvName2 = L"TEMP"; - LPCWSTR wzLongTempPath = L"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\\bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb\\cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc\\"; LPWSTR sczTempPath = NULL; - WCHAR wzOriginalTemp[MAX_PATH + 1] = { }; - WCHAR wzOriginalTemp2[MAX_PATH + 1] = { }; DWORD cch = 0; - DWORD cch2 = 0; SIZE_T cchTemp = 0; - size_t cchTemp2 = 0; - - try - { - cch = ::GetEnvironmentVariableW(wzEnvName, wzOriginalTemp, countof(wzOriginalTemp)); - Assert::NotEqual(0, cch); - - if (!::SetEnvironmentVariableW(wzEnvName, wzLongTempPath)) - { - Assert::Equal(0xFFFFFFFF, ::GetLastError()); - } + WCHAR wzPath[MAX_PATH + 1]; - cch2 = ::GetEnvironmentVariableW(wzEnvName2, wzOriginalTemp2, countof(wzOriginalTemp2)); - Assert::NotEqual(0, cch2); + hr = PathGetTempPath(&sczTempPath, &cchTemp); + NativeAssert::Succeeded(hr, "Failed to get temp path."); - hr = PathGetTempPath(&sczTempPath, &cchTemp); - NativeAssert::Succeeded(hr, "Failed to get temp path."); + cch = countof(wzPath); + cch = ::GetTempPathW(cch, wzPath); + Assert::NotEqual((DWORD)0, cch); - PathFixedBackslashTerminate(wzOriginalTemp2, countof(wzOriginalTemp2)); + // normalize trailing backslash + PathFixedBackslashTerminate(wzPath, cch); - hr = ::StringCchLengthW(wzOriginalTemp2, countof(wzOriginalTemp2), &cchTemp2); - NativeAssert::Succeeded(hr, "Failed to get temp path length."); - - NativeAssert::StringEqual(wzOriginalTemp2, sczTempPath); - Assert::Equal(cchTemp2, cchTemp); - } - finally - { - if (cch) - { - ::SetEnvironmentVariableW(wzEnvName, wzOriginalTemp); - } - - ReleaseStr(sczTempPath); - } + NativeAssert::StringEqual(wzPath, sczTempPath); } [Fact] diff --git a/src/libs/libs.cmd b/src/libs/libs.cmd index d8b81f546..acf5ff555 100644 --- a/src/libs/libs.cmd +++ b/src/libs/libs.cmd @@ -22,6 +22,7 @@ msbuild -Restore libs_t.proj -p:Configuration=%_C% -tl -nologo -m -warnaserror -bl:%_L%\libs_build.binlog || exit /b dotnet test ^ + --results-directory %_L%\TestResults --blame-hang-timeout 1min --blame-hang-dump-type mini -l:"console;verbosity=detailed" ^ %_B%\net6.0\WixToolsetTest.Versioning.dll ^ %_B%\x86\DUtilUnitTest.dll ^ %_B%\x64\DUtilUnitTest.dll ^ diff --git a/src/test/burn/TestData/Manual/BundleB/Bundle.wxs b/src/test/burn/TestData/Manual/BundleB/Bundle.wxs index 8c670577c..248ec05c3 100644 --- a/src/test/burn/TestData/Manual/BundleB/Bundle.wxs +++ b/src/test/burn/TestData/Manual/BundleB/Bundle.wxs @@ -30,11 +30,11 @@ - + - + diff --git a/src/test/burn/TestData/Manual/BundleB/BundleB.wixproj b/src/test/burn/TestData/Manual/BundleB/BundleB.wixproj index 36792c2bd..d0b05bc11 100644 --- a/src/test/burn/TestData/Manual/BundleB/BundleB.wixproj +++ b/src/test/burn/TestData/Manual/BundleB/BundleB.wixproj @@ -7,25 +7,11 @@ -generate payloadgroup -sw5149 - - - BAPayloads - BAPayloads - ba.xslt - - - PackagePayloads - PackagePayloads - package.xslt - - - - diff --git a/src/test/burn/TestData/Manual/BundleB/BundleB.wxs b/src/test/burn/TestData/Manual/BundleB/BundleB.wxs index 54082131d..f1a044456 100644 --- a/src/test/burn/TestData/Manual/BundleB/BundleB.wxs +++ b/src/test/burn/TestData/Manual/BundleB/BundleB.wxs @@ -4,7 +4,7 @@ - + diff --git a/src/test/burn/TestData/Manual/BundleB/ba.xslt b/src/test/burn/TestData/Manual/BundleB/ba.xslt deleted file mode 100644 index 54bc7fe64..000000000 --- a/src/test/burn/TestData/Manual/BundleB/ba.xslt +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - ba_ - BAPayloads - - - diff --git a/src/test/burn/TestData/Manual/BundleB/package.xslt b/src/test/burn/TestData/Manual/BundleB/package.xslt deleted file mode 100644 index 304ff78b8..000000000 --- a/src/test/burn/TestData/Manual/BundleB/package.xslt +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - package_ - PackagePayloads - - - diff --git a/src/wix/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs index f5a9781b7..be337a601 100644 --- a/src/wix/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bind/GenerateManifestDataFromIRCommand.cs @@ -58,6 +58,7 @@ public void Execute() switch (symbol.Definition.Type) { // Symbols used internally and are not added to a data manifest. + case SymbolDefinitionType.HarvestPayloads: case SymbolDefinitionType.ProvidesDependency: case SymbolDefinitionType.WixApprovedExeForElevation: case SymbolDefinitionType.WixBootstrapperApplication: diff --git a/src/wix/WixToolset.Core/Compiler.cs b/src/wix/WixToolset.Core/Compiler.cs index 2efca5ebe..21604ad58 100644 --- a/src/wix/WixToolset.Core/Compiler.cs +++ b/src/wix/WixToolset.Core/Compiler.cs @@ -5787,7 +5787,7 @@ private void ParseFilesElement(XElement node, ComplexReferenceParentType parentT switch (child.Name.LocalName) { case "Exclude": - this.ParseFilesExcludeElement(child, exclusions); + this.ParseFilesOrPayloadsExcludeElement(child, exclusions); break; default: this.Core.UnexpectedElement(node, child); @@ -5833,7 +5833,7 @@ private void ParseFilesElement(XElement node, ComplexReferenceParentType parentT }); } - private void ParseFilesExcludeElement(XElement node, IList paths) + private void ParseFilesOrPayloadsExcludeElement(XElement node, IList paths) { var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); diff --git a/src/wix/WixToolset.Core/Compiler_Bundle.cs b/src/wix/WixToolset.Core/Compiler_Bundle.cs index 14de99eb8..49a729dbb 100644 --- a/src/wix/WixToolset.Core/Compiler_Bundle.cs +++ b/src/wix/WixToolset.Core/Compiler_Bundle.cs @@ -364,6 +364,9 @@ private void ParseBundleElement(XElement node) case "PayloadGroupRef": this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Layout, Compiler.BundleLayoutOnlyPayloads); break; + case "Payloads": + this.ParsePayloadsElement(child, ComplexReferenceParentType.Layout, Compiler.BundleLayoutOnlyPayloads); + break; case "RelatedBundle": this.ParseRelatedBundleElement(child); break; @@ -694,15 +697,15 @@ private void ParseBootstrapperApplicationElement(XElement node) this.Messaging.Write(CompilerErrors.AlreadyDefinedBootstrapperApplicationSource(childSourceLineNumbers, exePayloadSourceLineNumbers, exePayloadRefNode.Name.LocalName)); } break; - case "Payload": this.ParsePayloadElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId, isRemoteAllowed: false); break; - case "PayloadGroupRef": this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId); break; - + case "Payloads": + this.ParsePayloadsElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId); + break; default: this.Core.UnexpectedElement(node, child); break; @@ -879,6 +882,9 @@ private void ParseBootstrapperApplicationRefElement(XElement node) case "PayloadGroupRef": this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId); break; + case "Payloads": + this.ParsePayloadsElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId); + break; default: this.Core.UnexpectedElement(node, child); break; @@ -1264,6 +1270,9 @@ private void ParseBootstrapperExtensionElement(XElement node) case "PayloadGroupRef": this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId); break; + case "Payloads": + this.ParsePayloadsElement(child, ComplexReferenceParentType.Container, Compiler.BurnUXContainerId); + break; default: this.Core.UnexpectedElement(node, child); break; @@ -1560,6 +1569,9 @@ private void ParsePayloadGroupElement(XElement node, ComplexReferenceParentType case "PayloadGroupRef": this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.PayloadGroup, id); break; + case "Payloads": + this.ParsePayloadsElement(child, ComplexReferenceParentType.PayloadGroup, id); + break; default: this.Core.UnexpectedElement(node, child); break; @@ -1632,6 +1644,80 @@ private Identifier ParsePayloadGroupRefElement(XElement node, ComplexReferencePa return id; } + /// + /// Parses a payloads harvesting element. + /// + /// Element to parse. + /// ComplexReferenceParentType of parent element (BA or PayloadGroup). + /// Identifier of parent element. + private void ParsePayloadsElement(XElement node, ComplexReferenceParentType parentType, Identifier parentId) + { + var sourceLineNumbers = Preprocessor.GetSourceLineNumbers(node); + var win64 = this.Context.IsCurrentPlatform64Bit; + var inclusions = new List(); + var exclusions = new List(); + + foreach (var attrib in node.Attributes()) + { + if (String.IsNullOrEmpty(attrib.Name.NamespaceName) || CompilerCore.WixNamespace == attrib.Name.Namespace) + { + switch (attrib.Name.LocalName) + { + case "Include": + inclusions.AddRange(this.Core.GetAttributeValue(sourceLineNumbers, attrib).Split(';')); + break; + default: + this.Core.UnexpectedAttribute(node, attrib); + break; + } + } + else + { + var context = new Dictionary() { { "Win64", win64.ToString() } }; + this.Core.ParseExtensionAttribute(node, attrib, context); + } + } + + foreach (var child in node.Elements()) + { + if (CompilerCore.WixNamespace == child.Name.Namespace) + { + switch (child.Name.LocalName) + { + case "Exclude": + this.ParseFilesOrPayloadsExcludeElement(child, exclusions); + break; + default: + this.Core.UnexpectedElement(node, child); + break; + } + } + else + { + var context = new Dictionary() { { "Win64", win64.ToString() } }; + this.Core.ParseExtensionElement(node, child, context); + } + } + + if (!inclusions.Any()) + { + this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Include")); + } + + var inclusionsAsString = String.Join(";", inclusions); + var exclusionsAsString = String.Join(";", exclusions); + + var id = this.Core.CreateIdentifier("hvp", parentId.Id, inclusionsAsString, exclusionsAsString); + + this.Core.AddSymbol(new HarvestPayloadsSymbol(sourceLineNumbers, id) + { + Inclusions = inclusionsAsString, + Exclusions = exclusionsAsString, + ComplexReferenceParentType = parentType.ToString(), + ParentId = parentId.Id, + }); + } + /// /// Parse ExitCode element. /// @@ -2279,6 +2365,9 @@ private string ParseChainPackage(XElement node, WixBundlePackageType packageType case "PayloadGroupRef": this.ParsePayloadGroupRefElement(child, ComplexReferenceParentType.Package, id); break; + case "Payloads": + this.ParsePayloadsElement(child, ComplexReferenceParentType.Package, id); + break; case "Provides": this.ParseProvidesElement(child, packageType, id.Id, out _); break; diff --git a/src/wix/WixToolset.Core/HarvestFilesCommand.cs b/src/wix/WixToolset.Core/HarvestFilesAndPayloadsCommand.cs similarity index 72% rename from src/wix/WixToolset.Core/HarvestFilesCommand.cs rename to src/wix/WixToolset.Core/HarvestFilesAndPayloadsCommand.cs index 33c38589c..3b1b13580 100644 --- a/src/wix/WixToolset.Core/HarvestFilesCommand.cs +++ b/src/wix/WixToolset.Core/HarvestFilesAndPayloadsCommand.cs @@ -11,11 +11,11 @@ namespace WixToolset.Core using WixToolset.Extensibility.Data; using WixToolset.Extensibility.Services; - internal class HarvestFilesCommand + internal class HarvestFilesAndPayloadsCommand { private const string BindPathOpenString = "!(bindpath."; - public HarvestFilesCommand(IOptimizeContext context) + public HarvestFilesAndPayloadsCommand(IOptimizeContext context) { this.Context = context; this.Messaging = this.Context.ServiceProvider.GetService(); @@ -31,6 +31,7 @@ public HarvestFilesCommand(IOptimizeContext context) internal void Execute() { var harvestedFiles = new HashSet(); + var harvestedPayloads = new HashSet(); foreach (var section in this.Context.Intermediates.SelectMany(i => i.Sections)) { @@ -39,6 +40,14 @@ internal void Execute() this.HarvestFiles(harvestFiles, section, harvestedFiles); } } + + foreach (var section in this.Context.Intermediates.SelectMany(i => i.Sections)) + { + foreach (var harvestPayloads in section.Symbols.OfType().ToList()) + { + this.HarvestPayloads(harvestPayloads, section, harvestedPayloads); + } + } } private void HarvestFiles(HarvestFilesSymbol harvestFile, IntermediateSection section, ISet harvestedFiles) @@ -52,8 +61,8 @@ private void HarvestFiles(HarvestFilesSymbol harvestFile, IntermediateSection se var resolvedFiles = Enumerable.Empty(); - var included = this.GetWildcardFiles(harvestFile, inclusions); - var excluded = this.GetWildcardFiles(harvestFile, exclusions); + var included = this.GetWildcardFiles(inclusions, harvestFile.SourceLineNumbers, harvestFile.SourcePath); + var excluded = this.GetWildcardFiles(exclusions, harvestFile.SourceLineNumbers, harvestFile.SourcePath); foreach (var excludedFile in excluded) { @@ -128,10 +137,70 @@ private void HarvestFiles(HarvestFilesSymbol harvestFile, IntermediateSection se } } - private IEnumerable GetWildcardFiles(HarvestFilesSymbol harvestFile, IEnumerable patterns) + private void HarvestPayloads(HarvestPayloadsSymbol harvestPayload, IntermediateSection section, HashSet harvestedPayloads) + { + var sourceLineNumbers = harvestPayload.SourceLineNumbers; + var inclusions = harvestPayload.Inclusions.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + var exclusions = harvestPayload.Exclusions.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + + var comparer = new WildcardFileComparer(); + + var resolvedFiles = Enumerable.Empty(); + + var included = this.GetWildcardFiles(inclusions, sourceLineNumbers); + var excluded = this.GetWildcardFiles(exclusions, sourceLineNumbers); + + foreach (var excludedFile in excluded) + { + this.Messaging.Write(OptimizerVerboses.ExcludedFile(sourceLineNumbers, excludedFile.Path)); + } + + resolvedFiles = included.Except(excluded, comparer).ToList(); + + if (!resolvedFiles.Any()) + { + this.Messaging.Write(OptimizerWarnings.ZeroFilesHarvested(sourceLineNumbers)); + } + + foreach (var payloadByRecursiveDir in resolvedFiles.GroupBy(resolvedFile => resolvedFile.RecursiveDir, resolvedFile => resolvedFile.Path)) + { + var recursiveDir = payloadByRecursiveDir.Key; + + foreach (var file in payloadByRecursiveDir) + { + if (harvestedPayloads.Add(file)) + { + var name = Path.GetFileName(file); + + var id = this.ParseHelper.CreateIdentifier("pld", harvestPayload.ParentId, recursiveDir.ToUpperInvariant(), name.ToUpperInvariant()); + + this.Messaging.Write(OptimizerVerboses.HarvestedFile(sourceLineNumbers, file)); + + section.AddSymbol(new WixBundlePayloadSymbol(sourceLineNumbers, id) + { + Name = Path.Combine(recursiveDir, name), + SourceFile = new IntermediateFieldPathValue { Path = file }, + Compressed = null, + UnresolvedSourceFile = file, // duplicate of sourceFile but in a string column so it won't get resolved to a full path during binding. + }); + + if (Enum.TryParse(harvestPayload.ComplexReferenceParentType, out var parentType) + && ComplexReferenceParentType.Unknown != parentType && null != harvestPayload.ParentId) + { + this.ParseHelper.CreateWixGroupSymbol(section, sourceLineNumbers, parentType, harvestPayload.ParentId, ComplexReferenceChildType.Payload, id.Id); + } + } + else + { + this.Messaging.Write(OptimizerWarnings.SkippingDuplicateFile(sourceLineNumbers, file)); + } + } + } + } + + private IEnumerable GetWildcardFiles(IEnumerable patterns, SourceLineNumber sourceLineNumbers, string sourcePath = null) { - var sourceLineNumbers = harvestFile.SourceLineNumbers; - var sourcePath = harvestFile.SourcePath?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + sourcePath = sourcePath?.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); var files = new List(); @@ -177,7 +246,7 @@ private IEnumerable GetWildcardFiles(HarvestFilesSymbol harvestFil } catch (DirectoryNotFoundException e) { - this.Messaging.Write(OptimizerWarnings.ExpectedDirectory(harvestFile.SourceLineNumbers, e.Message)); + this.Messaging.Write(OptimizerWarnings.ExpectedDirectory(sourceLineNumbers, e.Message)); } } } diff --git a/src/wix/WixToolset.Core/Optimizer.cs b/src/wix/WixToolset.Core/Optimizer.cs index 33f757a31..89b723e84 100644 --- a/src/wix/WixToolset.Core/Optimizer.cs +++ b/src/wix/WixToolset.Core/Optimizer.cs @@ -26,7 +26,7 @@ public void Optimize(IOptimizeContext context) } { - var command = new HarvestFilesCommand(context); + var command = new HarvestFilesAndPayloadsCommand(context); command.Execute(); } diff --git a/src/wix/WixToolset.Core/OptimizerWarnings.cs b/src/wix/WixToolset.Core/OptimizerWarnings.cs index 784dc587c..616883f45 100644 --- a/src/wix/WixToolset.Core/OptimizerWarnings.cs +++ b/src/wix/WixToolset.Core/OptimizerWarnings.cs @@ -8,7 +8,7 @@ internal static class OptimizerWarnings { public static Message ZeroFilesHarvested(SourceLineNumber sourceLineNumbers) { - return Message(sourceLineNumbers, Ids.ZeroFilesHarvested, "Files inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify your Files paths, inclusions, and exclusions for accuracy."); + return Message(sourceLineNumbers, Ids.ZeroFilesHarvested, "Inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify paths, inclusions, and exclusions on Files or Payloads for accuracy."); } public static Message ExpectedDirectory(SourceLineNumber sourceLineNumbers, string harvestDirectory) diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs index 323b5eb0d..30d3aaea1 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/BundleManifestFixture.cs @@ -9,6 +9,7 @@ namespace WixToolsetTest.CoreIntegration using WixInternal.TestSupport; using WixInternal.Core.TestPackage; using Xunit; + using System.Linq; public class BundleManifestFixture { @@ -133,13 +134,13 @@ public void PopulatesBAManifestWithPayloadInformation() { { "WixPayloadProperties", new List { "Size" } }, }; - var payloadElements = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixPayloadProperties", ignoreAttributesByElementName); + var payloadElements = extractResult.GetBADataTestXmlLines("/ba:BootstrapperApplicationData/ba:WixPayloadProperties", ignoreAttributesByElementName).OrderBy(line => line).ToArray(); WixAssert.CompareLineByLine(new[] { - "", "", - "", + "", "", + "", }, payloadElements); } } @@ -380,8 +381,8 @@ public void PopulatesManifestWithExePackages() var exePackageElements = extractResult.GetManifestTestXmlLines("/burn:BurnManifest/burn:Chain/burn:ExePackage", ignoreAttributesByElementName); WixAssert.CompareLineByLine(new[] { - "", - "", + "", + "", }, exePackageElements); } } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/HarvestFilesFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/HarvestFilesFixture.cs index b407bb86d..97f3e4425 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/HarvestFilesFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/HarvestFilesFixture.cs @@ -35,7 +35,7 @@ public void ZeroFilesHarvestedIsAWarning() var messages = result.Messages.Select(m => FormatMessage(m, sourceFolder, baseFolder)).ToArray(); WixAssert.CompareLineByLine(new[] { - "8600: Files inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify your Files paths, inclusions, and exclusions for accuracy.", + "8600: Inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify paths, inclusions, and exclusions on Files or Payloads for accuracy.", }, messages); }); } @@ -49,9 +49,9 @@ public void MissingHarvestDirectoryIsAWarning() WixAssert.CompareLineByLine(new[] { @"8601: Missing directory for harvesting files: Could not find a part of the path '\files2\MissingDirectory'.", - @"8600: Files inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify your Files paths, inclusions, and exclusions for accuracy.", + @"8600: Inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify paths, inclusions, and exclusions on Files or Payloads for accuracy.", @"8601: Missing directory for harvesting files: Could not find a part of the path '\files2\ThisDirectoryIsAlsoMissing'.", - @"8600: Files inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify your Files paths, inclusions, and exclusions for accuracy.", + @"8600: Inclusions and exclusions resulted in zero files harvested. Unless that is expected, you should verify paths, inclusions, and exclusions on Files or Payloads for accuracy.", }, messages); }); } diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SharedPayloadsBetweenPackages/SharedPayloadsBetweenPackages.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SharedPayloadsBetweenPackages/SharedPayloadsBetweenPackages.wxs index 55f9d110f..96148c6c0 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SharedPayloadsBetweenPackages/SharedPayloadsBetweenPackages.wxs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/SharedPayloadsBetweenPackages/SharedPayloadsBetweenPackages.wxs @@ -10,9 +10,10 @@ + - + diff --git a/src/xsd/wix.xsd b/src/xsd/wix.xsd index 8cf810481..d72d8e697 100644 --- a/src/xsd/wix.xsd +++ b/src/xsd/wix.xsd @@ -87,6 +87,7 @@ + @@ -462,6 +463,7 @@ + @@ -524,6 +526,7 @@ + @@ -666,6 +669,7 @@ + @@ -934,6 +938,7 @@ + @@ -998,6 +1003,7 @@ + @@ -1045,6 +1051,7 @@ + @@ -1081,6 +1088,7 @@ + @@ -1169,6 +1177,7 @@ + @@ -1930,6 +1939,7 @@ + @@ -8973,6 +8983,54 @@ + + + + Authoring to define the set of files to be harvested for inclusion in a bundle. + + + + + + + + + Extensibility point in the WiX XML Schema. Schema extensions can register additional + elements at this point in the schema. + + + + + + + + A file-selection pattern that can include directory names, file names, and wildcards. + If a pattern is not an absolute path (via a preprocessor variable, unnamed bind path, + or named bind path), it is interpreted as relative to the directory containing the + source file. Absolute paths via a named bind path are recommended. + + Wildcards include typical `*.ext` globs and MSBuild-style `**` globs to indicate + that directories should be recursed. Examples include: + + | Pattern | Description | + | ------- | ----------- | + | `!(bindpath.ToBeHarvested)\**` | All files in the parent directory identified by the `ToBeHarvested` bind path and its subdirectories. | + | `$(PayloadFiles)\bin\Release\**` | All files in the `bin\Release` subdirectory in the directory named by the `PayloadFiles` preprocessor variable and its subdirectories. | + | `!(bindpath.arm64)\**.pdb` | All files with `.pdb` extension in the parent directory identified by the `arm64` bind path and its subdirectories. | + | `**` | If an unnamed bind path was specified, all files in that directory and its subdirectories. If an unnamed bind path was _not_ specified, all files in directory of the source .wxs file and its subdirectories. | + + + + + + + Extensibility point in the WiX XML Schema. Schema extensions can register additional + attributes at this point in the schema. + + + + + @@ -9040,7 +9098,7 @@ - Using wildcards, defines the files from a parent `Files` element that should be excluded from harvesting. + Using wildcards, defines the files from a parent `Files` or `Payloads` element that should be excluded from harvesting. @@ -9057,7 +9115,7 @@ - Excludes files from the set of files harvested via the parent `Files` element. + Excludes files from the set of files harvested via the parent `Files` or `Payloads` element. Inclusion and exclusion wildcards must match paths. For example, if you have a `Files` element with `Include="!(bindpath.ToBeHarvested)\**"` and want to exclude one of the files, use an `Exclude` element with a `Files` attribute