Add support for semver in bundles and dependencies
Take advantage of WixVersion/verutil functionality to support wider range of version numbers were possible in the WiX Toolset Completes 4666
Rob Mensching committed
May 9, 2022 at 22:21 UTC
02e682881979cd87592ee1e8e39b7744b575829c
36 files changed
+568
-116
src/api/wix/WixToolset.Data/ErrorMessages.cs
+4
-4
@@ -1076,7 +1076,7 @@ namespace WixToolset.Data
1076
1077
public static Message IllegalVersionValue(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string value)
1078
{
1079
- return Message(sourceLineNumbers, Ids.IllegalVersionValue, "The {0}/@{1} attribute's value, '{2}', is not a valid version. Legal version values should look like 'x.x.x.x' where x is an integer from 0 to 65534.", elementName, attributeName, value);
1079
+ return Message(sourceLineNumbers, Ids.IllegalVersionValue, "The {0}/@{1} attribute's value, '{2}', is not a valid version. Specify a four-part version or semantic version, such as '#.#.#.#' or '#.#.#-label.#'.", elementName, attributeName, value);
1080
}
1081
1082
public static Message IllegalWarningIdAsError(string warningId)
@@ -1279,9 +1279,9 @@ namespace WixToolset.Data
1279
return Message(sourceLineNumbers, Ids.InvalidMergeLanguage, "The Merge element '{0}' specified an invalid language '{1}'. Verify that localization tokens are being properly resolved to a numeric LCID.", mergeId, mergeLanguage);
1280
}
1281
1282
- public static Message InvalidModuleOrBundleVersion(SourceLineNumber sourceLineNumbers, string moduleOrBundle, string version)
1282
+ public static Message InvalidFourPartVersion(SourceLineNumber sourceLineNumbers, string elementName, string attributeName, string version)
1283
{
1284
- return Message(sourceLineNumbers, Ids.InvalidModuleOrBundleVersion, "Invalid {0}/@Version '{1}'. {0} version has a max value of \"65535.65535.65535.65535\" and must be all numeric.", moduleOrBundle, version);
1284
+ return Message(sourceLineNumbers, Ids.InvalidFourPartVersion, "Invalid {0}/@Version '{1}'. {0} version has a max value of \"65535.65535.65535.65535\" and must be all numeric.", elementName, version);
1285
}
1286
1287
public static Message InvalidPlatformValue(SourceLineNumber sourceLineNumbers, string value)
@@ -2678,7 +2678,7 @@ namespace WixToolset.Data
2678
SplitCabinetNameCollision = 377,
2679
SplitCabinetInsertionFailed = 378,
2680
InvalidPreprocessorFunctionAutoVersion = 379,
2681
- InvalidModuleOrBundleVersion = 380,
2681
+ InvalidFourPartVersion = 380,
2682
UnsupportedPlatformForElement = 381,
2683
MissingMedia = 382,
2684
IllegalYesNoAlwaysValue = 384,
src/api/wix/WixToolset.Data/WarningMessages.cs
+6
-6
@@ -367,9 +367,9 @@ namespace WixToolset.Data
367
return Message(sourceLineNumbers, Ids.InvalidHigherInstallerVersionInModule, "Merge module '{0}' has an installer version of {1} which is greater than the product's installer version of {2}. Merging a module with a higher installer version than the product it is being merged into can result in invalid values in the resulting msi. You must set the Package/@InstallerVersion attribute to {1} or greater to merge this merge module into your product.", moduleId, moduleInstallerVersion, productInstallerVersion);
368
}
369
370
- public static Message InvalidModuleOrBundleVersion(SourceLineNumber sourceLineNumbers, string moduleOrBundle, string version)
370
+ public static Message InvalidFourPartVersion(SourceLineNumber sourceLineNumbers, string elementName, string version)
371
{
372
- return Message(sourceLineNumbers, Ids.InvalidModuleOrBundleVersion, "Invalid {0}/@Version '{1}'. {0} version has a max value of \"65535.65535.65535.65535\" and must be all numeric.", moduleOrBundle, version);
372
+ return Message(sourceLineNumbers, Ids.InvalidFourPartVersion, "Invalid {0}/@Version '{1}'. {0} version has a max value of \"65535.65535.65535.65535\" and must be all numeric.", elementName, version);
373
}
374
375
public static Message InvalidRemoveFile(SourceLineNumber sourceLineNumbers, string file, string component)
@@ -663,9 +663,9 @@ namespace WixToolset.Data
663
return Message(sourceLineNumbers, Ids.VariableDeclarationCollision, "The variable '{0}' with value '{1}' was previously declared with value '{2}'.", variableName, variableValue, variableCollidingValue);
664
}
665
666
- public static Message VersionTruncated(SourceLineNumber sourceLineNumbers, string originalVersion, string package, string truncatedVersion)
666
+ public static Message InvalidMsiProductVersion(SourceLineNumber sourceLineNumbers, string version, string package)
667
{
668
- return Message(sourceLineNumbers, Ids.VersionTruncated, "Product version {0} in package '{1}' is not valid per the MSI SDK and cannot be represented in a bundle. It has been truncated to {2}.", originalVersion, package, truncatedVersion);
668
+ return Message(sourceLineNumbers, Ids.InvalidMsiProductVersion, "Invalid product version '{0}' in MSI package '{1}'. Product version should have a major version less than 256, a minor version less than 256, and a build version less than 65536. The bundle may incorrectly detect upgrades of this package.", version, package);
669
}
670
671
public static Message CollidingModularizationTypes(string tableName, string columnName, string foreignTableName, int foreignColumnNumber, string modularizationType, string foreignModularizationType)
@@ -764,7 +764,7 @@ namespace WixToolset.Data
764
DeprecatedPackageCompressedAttribute = 1087,
765
DeprecatedQuestionMarksGuid = 1090,
766
PackageCodeSet = 1091,
767
- InvalidModuleOrBundleVersion = 1093,
767
+ InvalidFourPartVersion = 1093,
768
InvalidRemoveFile = 1095,
769
PreprocessorWarning = 1096,
770
UpdateOfNonKeyPathFile = 1097,
@@ -816,7 +816,7 @@ namespace WixToolset.Data
816
AllChangesIncludedInPatch = 1145,
817
RelatedAttributeConditionallyIgnored = 1146,
818
BackslashTerminateInlineDirectorySyntax = 1147,
819
- VersionTruncated = 1148,
819
+ InvalidMsiProductVersion = 1148,
820
ServiceConfigFamilyNotSupported = 1149,
821
SymbolNotTranslatedToOutput = 1150,
822
MsiTransactionLimitations = 1151,
src/api/wix/WixToolset.Extensibility/Services/IBackendHelper.cs
+16
-2
@@ -104,12 +104,26 @@ namespace WixToolset.Extensibility.Services
104
bool IsValidBinderVariable(string variable);
105
106
/// <summary>
107
- /// Verifies the given string is a valid 4-part version module or bundle version.
107
+ /// Verifies the given string is a valid 4-part version.
108
/// </summary>
109
/// <param name="version">The version to verify.</param>
110
- /// <returns>True if version is a valid module or bundle version.</returns>
110
+ /// <returns>True if version is a valid 4-part version.</returns>
111
bool IsValidFourPartVersion(string version);
112
113
+ /// <summary>
114
+ /// Verifies the given string is a valid MSI product version.
115
+ /// </summary>
116
+ /// <param name="version">The MSI product version to verify.</param>
117
+ /// <returns>True if version is a valid MSI product version</returns>
118
+ bool IsValidMsiProductVersion(string version);
119
+
120
+ /// <summary>
121
+ /// Verifies the given string is a valid WiX version.
122
+ /// </summary>
123
+ /// <param name="version">The version to verify.</param>
124
+ /// <returns>True if version is a valid WiX version.</returns>
125
+ bool IsValidWixVersion(string version);
126
+
127
/// <summary>
128
/// Determines if value is a valid identifier.
129
/// </summary>
src/ext/Dependency/Dependency.wixext.v3.ncrunchsolution
new
+6
@@ -0,0 +1,6 @@
1
+<SolutionConfiguration>
2
+ <Settings>
3
+ <AllowParallelTestExecution>True</AllowParallelTestExecution>
4
+ <SolutionConfigured>True</SolutionConfigured>
5
+ </Settings>
6
+</SolutionConfiguration>
\ No newline at end of file
src/ext/Dependency/test/WixToolsetTest.Dependency/DependencyExtensionFixture.cs
+2
-1
@@ -17,13 +17,14 @@ namespace WixToolsetTest.Dependency
17
var folder = TestData.Get(@"TestData\UsingProvides");
18
var build = new Builder(folder, typeof(DependencyExtensionFactory), new[] { folder });
19
20
- var results = build.BuildAndQuery(Build, "CustomAction", "Wix4DependencyProvider")
20
+ var results = build.BuildAndQuery(Build, "CustomAction", "Wix4DependencyProvider", "Wix4Dependency")
21
.Select(r => Regex.Replace(r, "{[^}]*}", "{*}"))
22
.ToArray();
23
WixAssert.CompareLineByLine(new[]
24
{
25
"CustomAction:Wix4DependencyCheck_X86\t1\tDependencyCA_X86\tWixDependencyCheck\t",
26
"CustomAction:Wix4DependencyRequire_X86\t1\tDependencyCA_X86\tWixDependencyRequire\t",
27
+ "Wix4Dependency:depL8BNflcqZaN5CQEWh2U3SBHFDdg\tUsingRequires\t1.0.0-beta.9\t\t0",
28
"Wix4DependencyProvider:dep74OfIcniaqxA7EprRGBw4Oyy3r8\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\tUsingProvides\t\t\t",
29
"Wix4DependencyProvider:depTpv28q7slcxvXPWmU4Z0GfbiI.4\tfilF5_pLhBuF5b4N9XEo52g_hUM5Lo\t{*}\t\t\t",
30
}, results);
src/ext/Dependency/test/WixToolsetTest.Dependency/TestData/UsingProvides/Package.wxs
+1
-1
@@ -12,7 +12,7 @@
12
<File Name="example.txt" Source="Package.wxs" />
13
<Provides Key="UsingProvides" dep:Check="yes" />
14
<Provides>
15
- <Requires ProviderKey="UsingRequires" Minimum="1.0.0.0" dep:Enforce="yes" />
15
+ <Requires ProviderKey="UsingRequires" Minimum="1.0.0-beta.9" dep:Enforce="yes" />
16
</Provides>
17
</Component>
18
</Feature>
src/libs/dutil/WixToolset.DUtil/deputil.cpp
+22
-10
@@ -121,9 +121,10 @@ DAPI_(HRESULT) DepCheckDependency(
121
HRESULT hr = S_OK;
122
LPWSTR sczKey = NULL;
123
HKEY hkKey = NULL;
124
- DWORD64 dw64Version = 0;
125
- DWORD64 dw64MinVersion = 0;
126
- DWORD64 dw64MaxVersion = 0;
124
+ VERUTIL_VERSION* pVersion = NULL;
125
+ VERUTIL_VERSION* pMinVersion = NULL;
126
+ VERUTIL_VERSION* pMaxVersion = NULL;
127
+ int nResult = 0;
128
BOOL fAllowEqual = FALSE;
129
LPWSTR sczName = NULL;
130
@@ -138,7 +139,7 @@ DAPI_(HRESULT) DepCheckDependency(
139
DepExitOnFailure(hr, "Failed to open the registry key for dependency \"%ls\".", wzProviderKey);
140
141
// If there are no registry values, consider the key orphaned and treat it as missing.
141
- hr = RegReadVersion(hkKey, vcszVersionValue, &dw64Version);
142
+ hr = RegReadWixVersion(hkKey, vcszVersionValue, &pVersion);
143
if (E_FILENOTFOUND != hr)
144
{
145
DepExitOnFailure(hr, "Failed to read the %ls registry value for dependency \"%ls\".", vcszVersionValue, wzProviderKey);
@@ -171,11 +172,15 @@ DAPI_(HRESULT) DepCheckDependency(
172
{
173
if (*wzMinVersion)
174
{
174
- hr = FileVersionFromStringEx(wzMinVersion, 0, &dw64MinVersion);
175
- DepExitOnFailure(hr, "Failed to get the 64-bit version number from \"%ls\".", wzMinVersion);
175
+ hr = VerParseVersion(wzMinVersion, 0, FALSE, &pMinVersion);
176
+ DepExitOnFailure(hr, "Failed to get the min version number from \"%ls\".", wzMinVersion);
177
+
178
+ hr = VerCompareParsedVersions(pVersion, pMinVersion, &nResult);
179
+ DepExitOnFailure(hr, "Failed to compare dependency with min version \"%ls\".", wzMinVersion);
180
181
fAllowEqual = iAttributes & RequiresAttributesMinVersionInclusive;
178
- if (!(fAllowEqual && dw64MinVersion <= dw64Version || dw64MinVersion < dw64Version))
182
+ // !(fAllowEqual && pMinVersion <= pVersion || pMinVersion < pVersion))
183
+ if (!(fAllowEqual && 0 <= nResult || 0 < nResult))
184
{
185
hr = DictKeyExists(sdDependencies, wzProviderKey);
186
if (E_NOTFOUND != hr)
@@ -205,11 +210,15 @@ DAPI_(HRESULT) DepCheckDependency(
210
{
211
if (*wzMaxVersion)
212
{
208
- hr = FileVersionFromStringEx(wzMaxVersion, 0, &dw64MaxVersion);
209
- DepExitOnFailure(hr, "Failed to get the 64-bit version number from \"%ls\".", wzMaxVersion);
213
+ hr = VerParseVersion(wzMaxVersion, 0, FALSE, &pMaxVersion);
214
+ DepExitOnFailure(hr, "Failed to get the max version number from \"%ls\".", wzMaxVersion);
215
+
216
+ hr = VerCompareParsedVersions(pMaxVersion, pVersion, &nResult);
217
+ DepExitOnFailure(hr, "Failed to compare dependency with max version \"%ls\".", wzMaxVersion);
218
219
fAllowEqual = iAttributes & RequiresAttributesMaxVersionInclusive;
212
- if (!(fAllowEqual && dw64Version <= dw64MaxVersion || dw64Version < dw64MaxVersion))
220
+ // !(fAllowEqual && pVersion <= pMaxVersion || pVersion < pMaxVersion)
221
+ if (!(fAllowEqual && 0 <= nResult || 0 < nResult))
222
{
223
hr = DictKeyExists(sdDependencies, wzProviderKey);
224
if (E_NOTFOUND != hr)
@@ -235,6 +244,9 @@ DAPI_(HRESULT) DepCheckDependency(
244
}
245
246
LExit:
247
+ ReleaseVerutilVersion(pMaxVersion);
248
+ ReleaseVerutilVersion(pMinVersion);
249
+ ReleaseVerutilVersion(pVersion);
250
ReleaseStr(sczName);
251
ReleaseRegKey(hkKey);
252
ReleaseStr(sczKey);
src/libs/dutil/WixToolset.DUtil/inc/regutil.h
+11
@@ -1,6 +1,7 @@
1
#pragma once
2
// 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.
3
4
+#include "verutil.h"
5
6
#ifdef __cplusplus
7
extern "C" {
@@ -260,6 +261,16 @@ HRESULT DAPI RegReadVersion(
261
__out DWORD64* pdw64Version
262
);
263
264
+/********************************************************************
265
+ RegReadWixVersion - reads a registry key value as a WiX version.
266
+
267
+*********************************************************************/
268
+HRESULT DAPI RegReadWixVersion(
269
+ __in HKEY hk,
270
+ __in_z_opt LPCWSTR wzName,
271
+ __out VERUTIL_VERSION** ppVersion
272
+ );
273
+
274
/********************************************************************
275
RegReadNone - reads a NONE registry key value.
276
src/libs/dutil/WixToolset.DUtil/regutil.cpp
+53
@@ -590,6 +590,7 @@ DAPI_(HRESULT) RegReadVersion(
590
{
591
ExitFunction1(hr = E_FILENOTFOUND);
592
}
593
+
594
if (REG_SZ == dwType || REG_EXPAND_SZ == dwType)
595
{
596
hr = RegReadString(hk, wzName, &sczVersion);
@@ -614,6 +615,58 @@ LExit:
615
return hr;
616
}
617
618
+
619
+DAPI_(HRESULT) RegReadWixVersion(
620
+ __in HKEY hk,
621
+ __in_z_opt LPCWSTR wzName,
622
+ __out VERUTIL_VERSION** ppVersion
623
+ )
624
+{
625
+ HRESULT hr = S_OK;
626
+ DWORD er = ERROR_SUCCESS;
627
+ DWORD dwType = 0;
628
+ DWORD cb = 0;
629
+ DWORD64 dw64Version = 0;
630
+ LPWSTR sczVersion = NULL;
631
+ VERUTIL_VERSION* pVersion = NULL;
632
+
633
+ cb = sizeof(DWORD64);
634
+ er = vpfnRegQueryValueExW(hk, wzName, NULL, &dwType, reinterpret_cast<LPBYTE>(&dw64Version), &cb);
635
+ if (E_FILENOTFOUND == HRESULT_FROM_WIN32(er))
636
+ {
637
+ ExitFunction1(hr = E_FILENOTFOUND);
638
+ }
639
+
640
+ if (REG_SZ == dwType || REG_EXPAND_SZ == dwType)
641
+ {
642
+ hr = RegReadString(hk, wzName, &sczVersion);
643
+ RegExitOnFailure(hr, "Failed to read registry version as string.");
644
+
645
+ hr = VerParseVersion(sczVersion, 0, FALSE, &pVersion);
646
+ RegExitOnFailure(hr, "Failed to convert registry string to version.");
647
+ }
648
+ else if (REG_QWORD == dwType)
649
+ {
650
+ hr = VerVersionFromQword(dw64Version, &pVersion);
651
+ RegExitOnFailure(hr, "Failed to convert registry string to version.");
652
+ }
653
+ else // unexpected data type
654
+ {
655
+ hr = HRESULT_FROM_WIN32(ERROR_INVALID_DATATYPE);
656
+ RegExitOnRootFailure(hr, "Error reading version registry value due to unexpected data type: %u", dwType);
657
+ }
658
+
659
+ *ppVersion = pVersion;
660
+ pVersion = NULL;
661
+
662
+LExit:
663
+ ReleaseVerutilVersion(pVersion);
664
+ ReleaseStr(sczVersion);
665
+
666
+ return hr;
667
+}
668
+
669
+
670
DAPI_(HRESULT) RegReadNone(
671
__in HKEY hk,
672
__in_z_opt LPCWSTR wzName
src/test/burn/TestData/DependencyTests/PackageB/ProductComponents.wxs
+1
-1
@@ -11,7 +11,7 @@
11
<Component Id="FileComponent2" Guid="A1866388-65B4-4215-A8FB-9A7AADBE4E8E" Directory="INSTALLFOLDER">
12
<File Source="$(sys.SOURCEFILEPATH)" />
13
<Provides>
14
- <Requires ProviderKey="WiX.$(var.TestGroupName).A,v1.0" Minimum="1.0.0.0" IncludeMinimum="yes" dep:Enforce="yes" />
14
+ <Requires ProviderKey="WiX.$(var.TestGroupName).A,v1.0" Minimum="1.0.0-alpha.420" IncludeMinimum="yes" dep:Enforce="yes" />
15
</Provides>
16
</Component>
17
</Fragment>
src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs
+19
@@ -1086,5 +1086,24 @@ namespace WixToolsetTest.BurnE2E
1086
packageA.UninstallProduct();
1087
packageA.VerifyInstalled(false);
1088
}
1089
+
1090
+ [Fact]
1091
+ public void CannotInstallWhenDependencyUnsatisfied()
1092
+ {
1093
+ var packageA = this.CreatePackageInstaller("PackageAv1");
1094
+ var packageB = this.CreatePackageInstaller("PackageB");
1095
+ var bundleB = this.CreateBundleInstaller("BundleB");
1096
+ var testBAController = this.CreateTestBAController();
1097
+
1098
+ packageA.VerifyInstalled(false);
1099
+ packageB.VerifyInstalled(false);
1100
+
1101
+ // Prevent install of PackageA to cause PackageB's enforced dependency
1102
+ // to fail the install.
1103
+ testBAController.SetPackageRequestedState("PackageA", RequestState.None);
1104
+
1105
+ var bundleBInstallLogFilePath = bundleB.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_FAILURE);
1106
+ Assert.True(LogVerifier.MessageInLogFileRegex(bundleBInstallLogFilePath, @"Applied execute package: PackageB, result: 0x80070643, restart: None"));
1107
+ }
1108
}
1109
}
src/wix/WixToolset.Core.Burn/Bundles/CreateBundleExeCommand.cs
+28
-15
@@ -71,11 +71,11 @@ namespace WixToolset.Core.Burn.Bundles
71
FileSystem.CopyFile(stubFile, bundleTempPath, allowHardlink: false);
72
File.SetAttributes(bundleTempPath, FileAttributes.Normal);
73
74
- var windowsAssemblyVersion = GetWindowsAssemblyVersion(this.BundleSymbol);
74
+ var fourPartVersion = this.GetFourPartVersion(this.BundleSymbol);
75
76
- var applicationManifestData = GenerateApplicationManifest(this.BundleSymbol, this.BootstrapperApplicationDllSymbol, this.OutputPath, windowsAssemblyVersion);
76
+ var applicationManifestData = GenerateApplicationManifest(this.BundleSymbol, this.BootstrapperApplicationDllSymbol, this.OutputPath, fourPartVersion);
77
78
- UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleSymbol, windowsAssemblyVersion, applicationManifestData);
78
+ this.UpdateBurnResources(bundleTempPath, this.OutputPath, this.BundleSymbol, fourPartVersion, applicationManifestData);
79
80
// Update the .wixburn section to point to at the UX and attached container(s) then attach the containers
81
// if they should be attached.
@@ -242,24 +242,37 @@ namespace WixToolset.Core.Burn.Bundles
242
}
243
}
244
245
- private static Version GetWindowsAssemblyVersion(WixBundleSymbol bundleSymbol)
245
+ private Version GetFourPartVersion(WixBundleSymbol bundleSymbol)
246
{
247
- // Ensure the bundle info provides a full four part version.
248
- var fourPartVersion = new Version(bundleSymbol.Version);
249
- var major = (fourPartVersion.Major < 0) ? 0 : fourPartVersion.Major;
250
- var minor = (fourPartVersion.Minor < 0) ? 0 : fourPartVersion.Minor;
251
- var build = (fourPartVersion.Build < 0) ? 0 : fourPartVersion.Build;
252
- var revision = (fourPartVersion.Revision < 0) ? 0 : fourPartVersion.Revision;
247
+ // Ensure the bundle info provides a full four-part version.
248
+
249
+ if (!WixVersion.TryParse(bundleSymbol.Version, out var wixVersion))
250
+ {
251
+ // Display an error message indicating that we will require a four-part version number
252
+ // not just a WixVersion.
253
+ this.Messaging.Write(ErrorMessages.IllegalVersionValue(bundleSymbol.SourceLineNumbers, "Bundle", "Version", bundleSymbol.Version));
254
+ return new Version(0, 0);
255
+ }
256
+
257
+ var major = wixVersion.Major ?? 0;
258
+ var minor = wixVersion.Minor ?? 0;
259
+ var build = wixVersion.Patch ?? 0;
260
+ var revision = wixVersion.Revision ?? 0;
261
262
if (UInt16.MaxValue < major || UInt16.MaxValue < minor || UInt16.MaxValue < build || UInt16.MaxValue < revision)
263
{
256
- throw new WixException(ErrorMessages.InvalidModuleOrBundleVersion(bundleSymbol.SourceLineNumbers, "Bundle", bundleSymbol.Version));
264
+ major = Math.Max(major, UInt16.MaxValue);
265
+ minor = Math.Max(minor, UInt16.MaxValue);
266
+ build = Math.Max(build, UInt16.MaxValue);
267
+ revision = Math.Max(revision, UInt16.MaxValue);
268
+
269
+ this.Messaging.Write(BurnBackendWarnings.CannotParseBundleVersionAsFourPartVersion(bundleSymbol.SourceLineNumbers, bundleSymbol.Version));
270
}
271
259
- return new Version(major, minor, build, revision);
272
+ return new Version((int)major, (int)minor, (int)build, (int)revision);
273
}
274
262
- private void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleSymbol bundleInfo, Version windowsAssemblyVersion, byte[] applicationManifestData)
275
+ private void UpdateBurnResources(string bundleTempPath, string outputPath, WixBundleSymbol bundleInfo, Version fourPartVersion, byte[] applicationManifestData)
276
{
277
const int burnLocale = 1033;
278
var resources = new ResourceCollection();
@@ -268,8 +281,8 @@ namespace WixToolset.Core.Burn.Bundles
281
version.Load(bundleTempPath);
282
resources.Add(version);
283
271
- version.FileVersion = windowsAssemblyVersion;
272
- version.ProductVersion = windowsAssemblyVersion;
284
+ version.FileVersion = fourPartVersion;
285
+ version.ProductVersion = fourPartVersion;
286
287
var strings = version[burnLocale] ?? version.Add(burnLocale);
288
strings["LegalCopyright"] = bundleInfo.Copyright;
src/wix/WixToolset.Core.Burn/Bundles/ProcessMsiPackageCommand.cs
+2
-23
@@ -118,30 +118,9 @@ namespace WixToolset.Core.Burn.Bundles
118
this.ChainPackage.Version = this.MsiPackage.ProductVersion;
119
}
120
121
- if (!this.BackendHelper.IsValidFourPartVersion(this.MsiPackage.ProductVersion))
121
+ if (!this.BackendHelper.IsValidMsiProductVersion(this.MsiPackage.ProductVersion))
122
{
123
- // not a proper .NET version (e.g., five fields); can we get a valid four-part version number?
124
- string version = null;
125
- var versionParts = this.MsiPackage.ProductVersion.Split('.');
126
- var count = versionParts.Length;
127
- if (0 < count)
128
- {
129
- version = versionParts[0];
130
- for (var i = 1; i < 4 && i < count; ++i)
131
- {
132
- version = String.Concat(version, ".", versionParts[i]);
133
- }
134
- }
135
-
136
- if (!String.IsNullOrEmpty(version) && this.BackendHelper.IsValidFourPartVersion(version))
137
- {
138
- this.Messaging.Write(WarningMessages.VersionTruncated(this.PackagePayload.SourceLineNumbers, this.MsiPackage.ProductVersion, this.PackageId, version));
139
- this.MsiPackage.ProductVersion = version;
140
- }
141
- else
142
- {
143
- this.Messaging.Write(ErrorMessages.InvalidProductVersion(this.PackagePayload.SourceLineNumbers, this.MsiPackage.ProductVersion, this.PackageId));
144
- }
123
+ this.Messaging.Write(WarningMessages.InvalidMsiProductVersion(this.PackagePayload.SourceLineNumbers, this.MsiPackage.ProductVersion, this.PackageId));
124
}
125
126
this.SetPerMachineAppropriately(harvestedMsiPackage.AllUsers);
src/wix/WixToolset.Core.Burn/BurnBackendWarnings.cs
+6
@@ -16,6 +16,11 @@ namespace WixToolset.Core.Burn
16
return Message(sourceLineNumbers, Ids.AttachedContainerPayloadCollision2, "The location of the payload related to the previous error.");
17
}
18
19
+ public static Message CannotParseBundleVersionAsFourPartVersion(SourceLineNumber originalLineNumber, string version)
20
+ {
21
+ return Message(originalLineNumber, Ids.CannotParseBundleVersionAsFourPartVersion, "The Bundle/@Version was not be able to be used as a four-part version. A valid four-part version has a max value of \"65535.65535.65535.65535\" and must be all numeric.", version);
22
+ }
23
+
24
public static Message EmptyContainer(SourceLineNumber sourceLineNumbers, string containerId)
25
{
26
return Message(sourceLineNumbers, Ids.EmptyContainer, "The Container '{0}' is being ignored because it doesn't have any payloads.", containerId);
@@ -61,6 +66,7 @@ namespace WixToolset.Core.Burn
66
UnknownBundleRelationAction = 8505,
67
HiddenBundleNotSupported = 8506,
68
UnknownMsiPackagePlatform = 8507,
69
+ CannotParseBundleVersionAsFourPartVersion = 8508,
70
} // last available is 8999. 9000 is VerboseMessages.
71
}
72
}
src/wix/WixToolset.Core.Burn/ExtensibilityServices/BurnBackendHelper.cs
+10
@@ -104,6 +104,16 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
104
return this.backendHelper.IsValidIdentifier(id);
105
}
106
107
+ public bool IsValidMsiProductVersion(string version)
108
+ {
109
+ return this.backendHelper.IsValidMsiProductVersion(version);
110
+ }
111
+
112
+ public bool IsValidWixVersion(string version)
113
+ {
114
+ return this.backendHelper.IsValidWixVersion(version);
115
+ }
116
+
117
public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
118
{
119
return this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
src/wix/WixToolset.Core.Burn/ExtensibilityServices/PayloadHarvester.cs
+15
-4
@@ -52,16 +52,27 @@ namespace WixToolset.Core.Burn.ExtensibilityServices
52
53
if (null != versionInfo)
54
{
55
- // Use the fixed version info block for the file since the resource text may not be a dotted quad.
56
- var version = new Version(versionInfo.ProductMajorPart, versionInfo.ProductMinorPart, versionInfo.ProductBuildPart, versionInfo.ProductPrivatePart);
55
+ var version = versionInfo.ProductVersion;
56
58
- if (PayloadHarvester.EmptyVersion != version)
57
+ if (String.IsNullOrEmpty(version))
58
{
60
- payload.Version = version.ToString();
59
+ version = versionInfo.FileVersion;
60
+ }
61
+
62
+ if (String.IsNullOrEmpty(version))
63
+ {
64
+ // Fallback to fixed version info block for the file.
65
+ var fixedVersion = new Version(versionInfo.ProductMajorPart, versionInfo.ProductMinorPart, versionInfo.ProductBuildPart, versionInfo.ProductPrivatePart);
66
+
67
+ if (PayloadHarvester.EmptyVersion != fixedVersion)
68
+ {
69
+ version = fixedVersion.ToString();
70
+ }
71
}
72
73
payload.Description = versionInfo.FileDescription;
74
payload.DisplayName = versionInfo.ProductName;
75
+ payload.Version = version;
76
}
77
}
78
}
src/wix/WixToolset.Core.WindowsInstaller/Bind/BindDatabaseCommand.cs
+21
@@ -298,6 +298,9 @@ namespace WixToolset.Core.WindowsInstaller.Bind
298
command.Execute();
299
}
300
301
+ // Now that delayed fields are processed, validate the package/module version.
302
+ this.VerifyVersion(packageSymbol, moduleSymbol);
303
+
304
// Process dependency references.
305
if (SectionType.Product == section.Type || SectionType.Module == section.Type)
306
{
@@ -537,6 +540,24 @@ namespace WixToolset.Core.WindowsInstaller.Bind
540
return result;
541
}
542
543
+ private void VerifyVersion(WixPackageSymbol packageSymbol, WixModuleSymbol moduleSymbol)
544
+ {
545
+ if (packageSymbol != null)
546
+ {
547
+ if (!this.WindowsInstallerBackendHelper.IsValidMsiProductVersion(packageSymbol.Version))
548
+ {
549
+ this.Messaging.Write(ErrorMessages.InvalidProductVersion(packageSymbol.SourceLineNumbers, packageSymbol.Version));
550
+ }
551
+ }
552
+ else if (moduleSymbol != null)
553
+ {
554
+ if (!this.WindowsInstallerBackendHelper.IsValidFourPartVersion(moduleSymbol.Version))
555
+ {
556
+ this.Messaging.Write(WindowsInstallerBackendErrors.InvalidModuleVersion(moduleSymbol.SourceLineNumbers, moduleSymbol.Version));
557
+ }
558
+ }
559
+ }
560
+
561
private int CalculateCodepage(WixPackageSymbol packageSymbol, WixModuleSymbol moduleSymbol, WixPatchSymbol patchSymbol)
562
{
563
var codepage = packageSymbol?.Codepage ?? moduleSymbol?.Codepage ?? patchSymbol?.Codepage;
src/wix/WixToolset.Core.WindowsInstaller/Bind/CreateWindowsInstallerDataFromIRCommand.cs
+10
@@ -1033,6 +1033,16 @@ namespace WixToolset.Core.WindowsInstaller.Bind
1033
1034
private void AddUpgradeSymbol(UpgradeSymbol symbol)
1035
{
1036
+ if (!String.IsNullOrEmpty(symbol.VersionMin) && !this.BackendHelper.IsValidMsiProductVersion(symbol.VersionMin))
1037
+ {
1038
+ this.Messaging.Write(ErrorMessages.InvalidProductVersion(symbol.SourceLineNumbers, symbol.VersionMin));
1039
+ }
1040
+
1041
+ if (!String.IsNullOrEmpty(symbol.VersionMax) && !this.BackendHelper.IsValidMsiProductVersion(symbol.VersionMax))
1042
+ {
1043
+ this.Messaging.Write(ErrorMessages.InvalidProductVersion(symbol.SourceLineNumbers, symbol.VersionMax));
1044
+ }
1045
+
1046
var row = (UpgradeRow)this.CreateRow(symbol, "Upgrade");
1047
row.UpgradeCode = symbol.UpgradeCode;
1048
row.VersionMin = symbol.VersionMin;
src/wix/WixToolset.Core.WindowsInstaller/ExtensibilityServices/WindowsInstallerBackendHelper.cs
+10
@@ -93,6 +93,16 @@ namespace WixToolset.Core.WindowsInstaller.ExtensibilityServices
93
return this.backendHelper.IsValidIdentifier(id);
94
}
95
96
+ public bool IsValidMsiProductVersion(string version)
97
+ {
98
+ return this.backendHelper.IsValidMsiProductVersion(version);
99
+ }
100
+
101
+ public bool IsValidWixVersion(string version)
102
+ {
103
+ return this.backendHelper.IsValidWixVersion(version);
104
+ }
105
+
106
public bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
107
{
108
return this.backendHelper.IsValidLongFilename(filename, allowWildcards, allowRelative);
src/wix/WixToolset.Core.WindowsInstaller/WindowsInstallerBackendErrors.cs
+6
@@ -14,6 +14,11 @@ namespace WixToolset.Core.WindowsInstaller
14
return Message(sourceLineNumbers, Ids.CannotLoadWixoutAsTransform, "Could not load wixout file as a transform{1}", additionalDetail);
15
}
16
17
+ public static Message InvalidModuleVersion(SourceLineNumber originalLineNumber, string version)
18
+ {
19
+ return Message(originalLineNumber, Ids.InvalidModuleVersion, "The Module/@Version was not be able to be used as a four-part version. A valid four-part version has a max value of \"65535.65535.65535.65535\" and must be all numeric.", version);
20
+ }
21
+
22
private static Message Message(SourceLineNumber sourceLineNumber, Ids id, string format, params object[] args)
23
{
24
return new Message(sourceLineNumber, MessageLevel.Error, (int)id, format, args);
@@ -22,6 +27,7 @@ namespace WixToolset.Core.WindowsInstaller
27
public enum Ids
28
{
29
CannotLoadWixoutAsTransform = 7500,
30
+ InvalidModuleVersion = 7501,
31
} // last available is 7999. 8000 is BurnBackendErrors.
32
}
33
}
src/wix/WixToolset.Core/Common.cs
+5
@@ -132,6 +132,11 @@ namespace WixToolset.Core
132
return true;
133
}
134
135
+ public static bool IsValidMsiProductVersion(string version)
136
+ {
137
+ return Version.TryParse(version, out var ver) && ver.Major < 256 && ver.Minor < 256 && ver.Build < 65536;
138
+ }
139
+
140
public static bool IsValidLongFilename(string filename, bool allowWildcards, bool allowRelative)
141
{
142
if (String.IsNullOrEmpty(filename))
src/wix/WixToolset.Core/CompilerCore.cs
+1
-21
@@ -221,27 +221,7 @@ namespace WixToolset.Core
221
/// <returns>True if version is a valid product version</returns>
222
public static bool IsValidProductVersion(string version)
223
{
224
- if (!Common.IsValidBinderVariable(version))
225
- {
226
- Version ver = new Version(version);
227
-
228
- if (255 < ver.Major || 255 < ver.Minor || 65535 < ver.Build)
229
- {
230
- return false;
231
- }
232
- }
233
-
234
- return true;
235
- }
236
-
237
- /// <summary>
238
- /// Verifies the given string is a valid module or bundle version.
239
- /// </summary>
240
- /// <param name="version">The version to verify.</param>
241
- /// <returns>True if version is a valid module or bundle version.</returns>
242
- public static bool IsValidModuleOrBundleVersion(string version)
243
- {
244
- return Common.IsValidFourPartVersion(version);
224
+ return Common.IsValidBinderVariable(version) || Common.IsValidMsiProductVersion(version);
225
}
226
227
/// <summary>
src/wix/WixToolset.Core/Compiler_Bundle.cs
-4
@@ -246,10 +246,6 @@ namespace WixToolset.Core
246
{
247
this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
248
}
249
- else if (!CompilerCore.IsValidModuleOrBundleVersion(version))
250
- {
251
- this.Core.Write(WarningMessages.InvalidModuleOrBundleVersion(sourceLineNumbers, "Bundle", version));
252
- }
249
250
if (String.IsNullOrEmpty(upgradeCode))
251
{
src/wix/WixToolset.Core/Compiler_Module.cs
-4
@@ -96,10 +96,6 @@ namespace WixToolset.Core
96
{
97
this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
98
}
99
- else if (!CompilerCore.IsValidModuleOrBundleVersion(version))
100
- {
101
- this.Core.Write(WarningMessages.InvalidModuleOrBundleVersion(sourceLineNumbers, "Module", version));
102
- }
99
100
try
101
{
src/wix/WixToolset.Core/Compiler_Package.cs
+2
-10
@@ -105,12 +105,8 @@ namespace WixToolset.Core
105
case "UpgradeCode":
106
upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
107
break;
108
- case "Version": // if the attribute is valid version, use the attribute value as is (so "1.0000.01.01" would *not* get translated to "1.0.1.1").
109
- var verifiedVersion = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
110
- if (!String.IsNullOrEmpty(verifiedVersion))
111
- {
112
- version = attrib.Value;
113
- }
108
+ case "Version":
109
+ version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
110
break;
111
default:
112
this.Core.UnexpectedAttribute(node, attrib);
@@ -147,10 +143,6 @@ namespace WixToolset.Core
143
{
144
this.Core.Write(ErrorMessages.ExpectedAttribute(sourceLineNumbers, node.Name.LocalName, "Version"));
145
}
150
- else if (!CompilerCore.IsValidProductVersion(version))
151
- {
152
- this.Core.Write(ErrorMessages.InvalidProductVersion(sourceLineNumbers, version));
153
- }
146
147
if (compressed != YesNoDefaultType.No)
148
{
src/wix/WixToolset.Core/ExtensibilityServices/BackendHelper.cs
+10
@@ -95,6 +95,16 @@ namespace WixToolset.Core.ExtensibilityServices
95
return Common.IsValidFourPartVersion(version);
96
}
97
98
+ public bool IsValidMsiProductVersion(string version)
99
+ {
100
+ return Common.IsValidMsiProductVersion(version);
101
+ }
102
+
103
+ public bool IsValidWixVersion(string version)
104
+ {
105
+ return WixVersion.TryParse(version, out _);
106
+ }
107
+
108
public bool IsValidIdentifier(string id)
109
{
110
return Common.IsIdentifier(id);
src/wix/WixToolset.Core/ExtensibilityServices/ParseHelper.cs
+3
-2
@@ -552,9 +552,10 @@ namespace WixToolset.Core.ExtensibilityServices
552
553
if (!String.IsNullOrEmpty(value))
554
{
555
- if (Version.TryParse(value, out var version))
555
+ if (WixVersion.TryParse(value, out var version))
556
{
557
- return version.ToString();
557
+ // Return the attribute value sans-prefix, if present.
558
+ return version.Prefix.HasValue ? value.Substring(1) : value;
559
}
560
561
// Allow versions to contain binder variables.
src/wix/test/WixToolsetTest.Core/ParserHelperFixture.cs
new
+99
@@ -0,0 +1,99 @@
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.Core
4
+{
5
+ using System;
6
+ using System.Xml.Linq;
7
+ using WixToolset.Core;
8
+ using WixToolset.Data;
9
+ using WixToolset.Extensibility.Services;
10
+ using Xunit;
11
+
12
+ public class ParserHelperFixture
13
+ {
14
+ [Fact]
15
+ public void CanParseFourPartAttributeVersion()
16
+ {
17
+ var helper = GetParserHelper();
18
+
19
+ var attribute = CreateAttribute("1.2.3.4");
20
+ var result = helper.GetAttributeVersionValue(null, attribute);
21
+
22
+ Assert.Equal("1.2.3.4", result);
23
+ }
24
+
25
+ [Fact]
26
+ public void CannotParseFivePartAttributeVersion()
27
+ {
28
+ var helper = GetParserHelper();
29
+
30
+ var attribute = CreateAttribute("1.2.3.4.5");
31
+ var exception = Assert.Throws<WixException>(() => { helper.GetAttributeVersionValue(null, attribute); });
32
+ Assert.Equal("The Test/@Value attribute's value, '1.2.3.4.5', is not a valid version. Specify a four-part version or semantic version, such as '#.#.#.#' or '#.#.#-label.#'.", exception.Message);
33
+ }
34
+
35
+ [Fact]
36
+ public void CannotParseVersionTooLargeAttributeVersion()
37
+ {
38
+ var version = "4294967296.2.3.4";
39
+ AssertVersion(version);
40
+ }
41
+
42
+ private static void AssertVersion(string version)
43
+ {
44
+ var helper = GetParserHelper();
45
+ var attribute = CreateAttribute(version);
46
+ var exception = Assert.Throws<WixException>(() => { helper.GetAttributeVersionValue(null, attribute); });
47
+ Assert.Equal($"The Test/@Value attribute's value, '{version}', is not a valid version. Specify a four-part version or semantic version, such as '#.#.#.#' or '#.#.#-label.#'.", exception.Message);
48
+ }
49
+
50
+ [Fact]
51
+ public void CanParseSemverAttributeVersion()
52
+ {
53
+ var helper = GetParserHelper();
54
+
55
+ var attribute = CreateAttribute("10.99.444-preview.0");
56
+ var result = helper.GetAttributeVersionValue(null, attribute);
57
+
58
+ Assert.Equal("10.99.444-preview.0", result);
59
+ }
60
+
61
+ [Fact]
62
+ public void CanParseFourPartSemverAttributeVersion()
63
+ {
64
+ var helper = GetParserHelper();
65
+
66
+ var attribute = CreateAttribute("1.2.3.4-meta.123-other.456");
67
+ var result = helper.GetAttributeVersionValue(null, attribute);
68
+
69
+ Assert.Equal("1.2.3.4-meta.123-other.456", result);
70
+ }
71
+
72
+ [Fact]
73
+ public void CanParseVersionWithLeadingV()
74
+ {
75
+ var helper = GetParserHelper();
76
+
77
+ var attribute = CreateAttribute("v1.2.3.4");
78
+ var result = helper.GetAttributeVersionValue(null, attribute);
79
+
80
+ Assert.Equal("1.2.3.4", result);
81
+ }
82
+
83
+
84
+ private static IParseHelper GetParserHelper()
85
+ {
86
+ var sp = WixToolsetServiceProviderFactory.CreateServiceProvider();
87
+ var helper = sp.GetService<IParseHelper>();
88
+ return helper;
89
+ }
90
+
91
+ private static XAttribute CreateAttribute(string value)
92
+ {
93
+ var attribute = new XAttribute("Value", value);
94
+ _ = new XElement("Test", attribute);
95
+
96
+ return attribute;
97
+ }
98
+ }
99
+}
src/wix/test/WixToolsetTest.CoreIntegration/BundlePackageFixture.cs
+3
-3
@@ -274,8 +274,8 @@ namespace WixToolsetTest.CoreIntegration
274
.ToArray();
275
WixAssert.CompareLineByLine(new string[]
276
{
277
- $"<BundlePackage Id='chain.exe' Cache='keep' CacheId='{chainBundleId}v1.0.0.0' InstallSize='34' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' BundleId='{chainBundleId}' Version='1.0.0.0' InstallArguments='' UninstallArguments='' RepairArguments='' SupportsBurnProtocol='yes' Win64='no'>" +
278
- "<Provides Key='MyProviderKey,v1.0' Version='1.0.0.0' DisplayName='BurnBundle' Imported='yes' />" +
277
+ $"<BundlePackage Id='chain.exe' Cache='keep' CacheId='{chainBundleId}v1.0.0-foo.55' InstallSize='34' Size='*' PerMachine='yes' Permanent='yes' Vital='yes' RollbackBoundaryForward='WixDefaultBoundary' RollbackBoundaryBackward='WixDefaultBoundary' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' BundleId='{chainBundleId}' Version='1.0.0-foo.55' InstallArguments='' UninstallArguments='' RepairArguments='' SupportsBurnProtocol='yes' Win64='no'>" +
278
+ "<Provides Key='MyProviderKey,v1.0' Version='1.0.0-foo.55' DisplayName='BurnBundle' Imported='yes' />" +
279
"<RelatedBundle Id='{B94478B1-E1F3-4700-9CE8-6AA090854AEC}' Action='Upgrade' />" +
280
"<PayloadRef Id='chain.exe' />" +
281
"</BundlePackage>",
@@ -302,7 +302,7 @@ namespace WixToolsetTest.CoreIntegration
302
.ToArray();
303
WixAssert.CompareLineByLine(new string[]
304
{
305
- "<WixPackageProperties Package='chain.exe' Vital='yes' DisplayName='BurnBundle' Description='BurnBundleDescription' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='yes' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' Compressed='no' Version='1.0.0.0' Cache='keep' />",
305
+ "<WixPackageProperties Package='chain.exe' Vital='yes' DisplayName='BurnBundle' Description='BurnBundleDescription' DownloadSize='*' PackageSize='*' InstalledSize='34' PackageType='Bundle' Permanent='yes' LogPathVariable='WixBundleLog_chain.exe' RollbackLogPathVariable='WixBundleRollbackLog_chain.exe' Compressed='no' Version='1.0.0-foo.55' Cache='keep' />",
306
}, packageElements);
307
}
308
}
src/wix/test/WixToolsetTest.CoreIntegration/RemotePayloadFixture.cs
+4
-4
@@ -205,7 +205,7 @@ namespace WixToolsetTest.CoreIntegration
205
206
WixAssert.CompareLineByLine(new[]
207
{
208
- @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' DownloadUrl='https://www.example.com/files/burn.exe' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />",
208
+ @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' DownloadUrl='https://www.example.com/files/burn.exe' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.0.1703' />",
209
}, elements);
210
}
211
}
@@ -265,7 +265,7 @@ namespace WixToolsetTest.CoreIntegration
265
266
WixAssert.CompareLineByLine(new[]
267
{
268
- @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />",
268
+ @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.0.1703' />",
269
@"<Payload Name='signed_cab1.cab' CertificatePublicKey='BBD1B48A37503767C71F455624967D406A5D66C3' CertificateThumbprint='DE13B4CE635E3F63AA2394E66F95C460267BC82F' Hash='D8D3842403710E1F6036A62543224855CADF546853933C2B17BA99D789D4347B36717687C022678A9D3DE749DFC1482DAAB92B997B62BB32A8A6828B9D04C414' Size='1585' />",
270
}, elements);
271
}
@@ -296,7 +296,7 @@ namespace WixToolsetTest.CoreIntegration
296
297
WixAssert.CompareLineByLine(new[]
298
{
299
- @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />",
299
+ @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.0.1703' />",
300
@"<Payload Name='signed_cab1.cab' Hash='D8D3842403710E1F6036A62543224855CADF546853933C2B17BA99D789D4347B36717687C022678A9D3DE749DFC1482DAAB92B997B62BB32A8A6828B9D04C414' Size='1585' />",
301
}, elements);
302
}
@@ -331,7 +331,7 @@ namespace WixToolsetTest.CoreIntegration
331
332
WixAssert.CompareLineByLine(new[]
333
{
334
- @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' DownloadUrl='https://www.example.com/files/burn.exe' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.1703.0' />",
334
+ @"<ExePackagePayload Name='burn.exe' ProductName='Windows Installer XML Toolset' Description='WiX Toolset Bootstrapper' DownloadUrl='https://www.example.com/files/burn.exe' Hash='F6E722518AC3AB7E31C70099368D5770788C179AA23226110DCF07319B1E1964E246A1E8AE72E2CF23E0138AFC281BAFDE45969204405E114EB20C8195DA7E5E' Size='463360' Version='3.14.0.1703' />",
335
@"<Payload Name='a.dat' DownloadUrl='https://www.example.com/files/RemotePayload/recurse/a.dat' Hash='D13926E5CBE5ED8B46133F9199FAF2FF25B25981C67A31AE2BC3F6C20390FACBFADCD89BD22D3445D95B989C8EACFB1E68DB634BECB5C9624865BA453BCE362A' Size='16' />",
336
@"<Payload Name='b.dat' DownloadUrl='https://www.example.com/files/RemotePayload/recurse/subfolder/b.dat' Hash='5F94707BC29ADFE3B9615E6753388707FD0B8F5FD9EEEC2B17E21E72F1635FF7D7A101E7D14F614E111F263CB9AC4D0940BE1247881A7844F226D6C400293D8E' Size='37' />",
337
@"<Payload Name='c.dat' DownloadUrl='https://www.example.com/files/RemotePayload/recurse/subfolder/c.dat' Hash='97D6209A5571E05E4F72F9C6BF0987651FA03E63F971F9B53C2B3D798A666D9864F232D4E2D6442E47D9D72B282309B6EEFF4EE017B43B706FA92A0F5EF74734' Size='42' />",
src/wix/test/WixToolsetTest.CoreIntegration/TestData/BundlePackage/RemoteBundlePackage.wxs
+1
-1
@@ -18,7 +18,7 @@
18
ProtocolVersion="1"
19
ProviderKey="MyProviderKey,v1.0"
20
UpgradeCode="{B94478B1-E1F3-4700-9CE8-6AA090854AEC}"
21
- Version="1.0.0.0"
21
+ Version="1.0.0-foo.55"
22
Win64="no"
23
/>
24
</BundlePackagePayload>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/Upgrade/UpgradeInvalidMinVersion.wxs
new
+12
@@ -0,0 +1,12 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
3
+ <Fragment>
4
+ <ComponentGroup Id="ProductComponents">
5
+ <ComponentGroupRef Id="MinimalComponentGroup"></ComponentGroupRef>
6
+ </ComponentGroup>
7
+
8
+ <Upgrade Id="B05772EA-82B8-4DE0-B7EB-45B5F0CCFE6D">
9
+ <UpgradeVersion Minimum="1.256.0" Property="RELPRODFOUND"></UpgradeVersion>
10
+ </Upgrade>
11
+ </Fragment>
12
+</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/Version/Bundle.wxs
new
+11
@@ -0,0 +1,11 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Bundle Name="MsiPackage-Bundle" Version="$(Version)" Manufacturer="Example Corporation" UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a">
3
+ <BootstrapperApplication>
4
+ <BootstrapperApplicationDll SourceFile="fakeba.dll" />
5
+ </BootstrapperApplication>
6
+
7
+ <Chain>
8
+ <MsiPackage SourceFile="test1.msi" />
9
+ </Chain>
10
+ </Bundle>
11
+</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/Version/Package.wxs
new
+31
@@ -0,0 +1,31 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Package Version="$(Version)"
3
+ Name="MsiPackage"
4
+ Manufacturer="Example Corporation"
5
+ UpgradeCode="047730a5-30fe-4a62-a520-da9381b8226a"
6
+ Scope="perUser">
7
+ <MajorUpgrade DowngradeErrorMessage="Downgrade not allowed" />
8
+ <MediaTemplate EmbedCab="true" />
9
+
10
+ <Feature Id="ProductFeature" Title="Feature title">
11
+ <ComponentGroupRef Id="ProductComponents" />
12
+ </Feature>
13
+ </Package>
14
+
15
+ <Fragment>
16
+ <StandardDirectory Id="DesktopFolder">
17
+ <Directory Id="INSTALLFOLDER" Name="MsiPackage $(Version)v" />
18
+ </StandardDirectory>
19
+ </Fragment>
20
+
21
+ <Fragment>
22
+ <ComponentGroup Id="ProductComponents" Directory="INSTALLFOLDER">
23
+ <Component>
24
+ <File Source="test.txt" />
25
+ </Component>
26
+ <Component Id="Shared.dll" Shared="yes">
27
+ <File Name="Shared.dll" Source="test.txt" />
28
+ </Component>
29
+ </ComponentGroup>
30
+ </Fragment>
31
+</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/UpgradeFixture.cs
new
+43
@@ -0,0 +1,43 @@
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 WixBuildTools.TestSupport;
8
+ using WixToolset.Core.TestPackage;
9
+ using WixToolset.Data;
10
+ using Xunit;
11
+
12
+ public class UpgradeFixture
13
+ {
14
+
15
+ [Fact]
16
+ public void PopulatesInstallExecuteSequenceTable()
17
+ {
18
+ var folder = TestData.Get(@"TestData");
19
+
20
+ using (var fs = new DisposableFileSystem())
21
+ {
22
+ var baseFolder = fs.GetFolder();
23
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
24
+ var msiPath = Path.Combine(baseFolder, @"bin\test.msi");
25
+
26
+ var result = WixRunner.Execute(new[]
27
+ {
28
+ "build",
29
+ Path.Combine(folder, "Upgrade", "UpgradeInvalidMinVersion.wxs"),
30
+ Path.Combine(folder, "ProductWithComponentGroupRef", "MinimalComponentGroup.wxs"),
31
+ Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
32
+ "-bindpath", Path.Combine(folder, "SingleFile", "data"),
33
+ "-intermediateFolder", intermediateFolder,
34
+ "-o", msiPath
35
+ });
36
+
37
+ var message = result.Messages.Single(m => m.Level == MessageLevel.Error);
38
+ Assert.Equal("Invalid product version '1.256.0'. Product version must have a major version less than 256, a minor version less than 256, and a build version less than 65536.", message.ToString());
39
+ Assert.Equal(242, result.ExitCode);
40
+ }
41
+ }
42
+ }
43
+}
src/wix/test/WixToolsetTest.CoreIntegration/VersionFixture.cs
new
+94
@@ -0,0 +1,94 @@
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;
8
+ using WixBuildTools.TestSupport;
9
+ using WixToolset.Core.TestPackage;
10
+ using WixToolset.Data;
11
+ using Xunit;
12
+
13
+ public class VersionFixture
14
+ {
15
+ [Fact]
16
+ public void CannotBuildMsiWithInvalidMajorVersion()
17
+ {
18
+ var folder = TestData.Get(@"TestData");
19
+
20
+ using (var fs = new DisposableFileSystem())
21
+ {
22
+ var baseFolder = fs.GetFolder();
23
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
24
+ var msiPath = Path.Combine(baseFolder, @"bin\test1.msi");
25
+
26
+ var result = WixRunner.Execute(new[]
27
+ {
28
+ "build",
29
+ Path.Combine(folder, "Version", "Package.wxs"),
30
+ "-bindpath", Path.Combine(folder, "SingleFile", "data"),
31
+ "-intermediateFolder", intermediateFolder,
32
+ "-d", "Version=257.0.0",
33
+ "-o", msiPath
34
+ });
35
+
36
+ var message = result.Messages.Single(m => m.Level == MessageLevel.Error);
37
+ Assert.Equal("Invalid product version '257.0.0'. Product version must have a major version less than 256, a minor version less than 256, and a build version less than 65536.", message.ToString());
38
+ Assert.Equal(242, result.ExitCode);
39
+ }
40
+ }
41
+
42
+ [Fact]
43
+ public void CanBuildBundleWithSemanticVersion()
44
+ {
45
+ var folder = TestData.Get(@"TestData");
46
+
47
+ using (var fs = new DisposableFileSystem())
48
+ {
49
+ var baseFolder = fs.GetFolder();
50
+ var intermediateFolder = Path.Combine(baseFolder, "obj");
51
+ var msiPath = Path.Combine(baseFolder, @"bin\test1.msi");
52
+ var msi2Path = Path.Combine(baseFolder, @"bin\test2.msi");
53
+ var bundlePath = Path.Combine(baseFolder, @"bin\bundle.exe");
54
+
55
+ var result = WixRunner.Execute(new[]
56
+ {
57
+ "build",
58
+ Path.Combine(folder, "Version", "Package.wxs"),
59
+ "-bindpath", Path.Combine(folder, "SingleFile", "data"),
60
+ "-intermediateFolder", intermediateFolder,
61
+ "-d", "Version=255.255.65535",
62
+ "-o", msiPath
63
+ });
64
+
65
+ result.AssertSuccess();
66
+
67
+ var result3 = WixRunner.Execute(new[]
68
+{
69
+ "build",
70
+ Path.Combine(folder, "Version", "Bundle.wxs"),
71
+ "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
72
+ "-bindpath", Path.Combine(baseFolder, "bin"),
73
+ "-intermediateFolder", intermediateFolder,
74
+ "-d", "Version=2022.3.9-preview.0-build.5+0987654321abcdef1234567890",
75
+ "-o", bundlePath
76
+ });
77
+
78
+ result3.AssertSuccess();
79
+
80
+ var propertyTable = Query.QueryDatabase(msiPath, new[] { "Property" }).Select(r => r.Split('\t')).ToDictionary(r => r[0].Substring("Property:".Length), r => r[1]);
81
+ Assert.True(propertyTable.TryGetValue("ProductVersion", out var productVersion));
82
+ Assert.Equal("255.255.65535", productVersion);
83
+
84
+ var extractResult = BundleExtractor.ExtractAllContainers(null, bundlePath, Path.Combine(baseFolder, "ba"), Path.Combine(baseFolder, "attached"), Path.Combine(baseFolder, "extract"));
85
+ extractResult.AssertSuccess();
86
+
87
+ var bundleVersion = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:Registration/@Version")
88
+ .Cast<XmlAttribute>()
89
+ .Single();
90
+ Assert.Equal("2022.3.9-preview.0-build.5+0987654321abcdef1234567890", bundleVersion.Value);
91
+ }
92
+ }
93
+ }
94
+}