Add default major upgrade.
Add Package/@UpgradeStrategy to allow `none` to suppress major upgrade. Implements https://github.com/wixtoolset/issues/issues/7605. Requires https://github.com/wixtoolset/wix/pull/435.
Bob Arnson committed
Dec 23, 2023 at 21:37 UTC
1eea9c6e7b276c7c0dfde7779dfec45046ad5831
9 files changed
+164
-5
src/api/wix/WixToolset.Data/Symbols/WixPackageSymbol.cs
+12
@@ -46,6 +46,12 @@ namespace WixToolset.Data.Symbols
46
PerMachine = 0x1,
47
}
48
49
+ public enum WixPackageUpgradeStrategy
50
+ {
51
+ None = 0x0,
52
+ MajorUpgrade = 0x1,
53
+ }
54
+
55
public class WixPackageSymbol : IntermediateSymbol
56
{
57
public WixPackageSymbol() : base(SymbolDefinitions.WixPackage, null, null)
@@ -106,6 +112,12 @@ namespace WixToolset.Data.Symbols
112
set => this.Set((int)WixPackageSymbolFields.Codepage, value);
113
}
114
115
+ public WixPackageUpgradeStrategy UpgradeStrategy
116
+ {
117
+ get => (WixPackageUpgradeStrategy)this.Fields[(int)WixPackageSymbolFields.Attributes].AsNumber();
118
+ set => this.Set((int)WixPackageSymbolFields.Attributes, (int)value);
119
+ }
120
+
121
public bool PerMachine => (this.Attributes & WixPackageAttributes.PerMachine) == WixPackageAttributes.PerMachine;
122
}
123
}
src/api/wix/WixToolset.Data/WixStandardLibrary.cs
+11
-1
@@ -32,7 +32,17 @@ namespace WixToolset.Data
32
33
private static IEnumerable<Localization> YieldLocalizations()
34
{
35
- var strings = new BindVariable[0];
35
+ var sourceLineNumber = new SourceLineNumber("wixstd.wixlib");
36
+
37
+ var strings = new[] {
38
+ new BindVariable()
39
+ {
40
+ SourceLineNumbers = sourceLineNumber,
41
+ Id = "WixDowngradePreventedMessage",
42
+ Value = "A newer version of [ProductName] is already installed.",
43
+ Overridable = true,
44
+ },
45
+ };
46
47
var localizedControls = new LocalizedControl[0];
48
src/api/wix/WixToolset.Data/WixStandardLibraryIdentifiers.cs
+5
@@ -21,5 +21,10 @@ namespace WixToolset.Data
21
/// Default feature name.
22
/// </summary>
23
public static readonly string DefaultFeatureName = "WixDefaultFeature";
24
+
25
+ /// <summary>
26
+ /// WiX Standard localization strings.
27
+ /// </summary>
28
+ public static readonly string WixStandardLocalizationStrings = "WixStandardLocalizationStrings";
29
}
30
}
src/wix/WixToolset.Core/Compiler_Package.cs
+17
@@ -41,6 +41,7 @@ namespace WixToolset.Core
41
var isPackageNameSet = false;
42
var isKeywordsSet = false;
43
var isPackageAuthorSet = false;
44
+ var upgradeStrategy = WixPackageUpgradeStrategy.MajorUpgrade;
45
46
this.GetDefaultPlatformAndInstallerVersion(out var platform, out var msiVersion);
47
@@ -111,6 +112,21 @@ namespace WixToolset.Core
112
case "UpgradeCode":
113
upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false);
114
break;
115
+ case "UpgradeStrategy":
116
+ var strategy = this.Core.GetAttributeValue(sourceLineNumbers, attrib);
117
+ switch (strategy)
118
+ {
119
+ case "majorUpgrade":
120
+ upgradeStrategy = WixPackageUpgradeStrategy.MajorUpgrade;
121
+ break;
122
+ case "none":
123
+ upgradeStrategy = WixPackageUpgradeStrategy.None;
124
+ break;
125
+ default:
126
+ this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, strategy, "majorUpgrade", "none"));
127
+ break;
128
+ }
129
+ break;
130
case "Version":
131
version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib);
132
break;
@@ -382,6 +398,7 @@ namespace WixToolset.Core
398
Manufacturer = manufacturer,
399
Attributes = isPerMachine ? WixPackageAttributes.PerMachine : WixPackageAttributes.None,
400
Codepage = codepage,
401
+ UpgradeStrategy = upgradeStrategy,
402
});
403
404
if (!isCommentsSet)
src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs
+64
-3
@@ -2,6 +2,7 @@
2
3
namespace WixToolset.Core.Link
4
{
5
+ using System;
6
using System.Collections.Generic;
7
using System.Linq;
8
using WixToolset.Data;
@@ -49,20 +50,80 @@ namespace WixToolset.Core.Link
50
}
51
);
52
}
53
+
54
+ var symbols = this.Sections.SelectMany(section => section.Symbols);
55
+ var upgradeSymbols = symbols.OfType<UpgradeSymbol>();
56
+ if (!upgradeSymbols.Any())
57
+ {
58
+ var packageSymbol = this.Find.EntrySection.Symbols.OfType<WixPackageSymbol>().FirstOrDefault();
59
+
60
+ if (packageSymbol?.UpgradeStrategy == WixPackageUpgradeStrategy.MajorUpgrade
61
+ && !String.IsNullOrEmpty(packageSymbol?.UpgradeCode))
62
+ {
63
+ this.AddDefaultMajorUpgrade(packageSymbol);
64
+ }
65
+ }
66
+ }
67
+
68
+ private void AddDefaultMajorUpgrade(WixPackageSymbol packageSymbol)
69
+ {
70
+ this.AddSymbols(this.Find.EntrySection,
71
+ new UpgradeSymbol(packageSymbol.SourceLineNumbers)
72
+ {
73
+ UpgradeCode = packageSymbol.UpgradeCode,
74
+ MigrateFeatures = true,
75
+ ActionProperty = WixUpgradeConstants.UpgradeDetectedProperty,
76
+ VersionMax = packageSymbol.Version,
77
+ Language = packageSymbol.Language,
78
+ },
79
+ new UpgradeSymbol(packageSymbol.SourceLineNumbers)
80
+ {
81
+ UpgradeCode = packageSymbol.UpgradeCode,
82
+ VersionMin = packageSymbol.Version,
83
+ Language = packageSymbol.Language,
84
+ OnlyDetect = true,
85
+ ActionProperty = WixUpgradeConstants.DowngradeDetectedProperty,
86
+ },
87
+ new LaunchConditionSymbol(packageSymbol.SourceLineNumbers)
88
+ {
89
+ Condition = WixUpgradeConstants.DowngradePreventedCondition,
90
+ Description = "!(loc.WixDowngradePreventedMessage)",
91
+ },
92
+ new WixActionSymbol(packageSymbol.SourceLineNumbers,
93
+ new Identifier(AccessModifier.Global, SequenceTable.InstallExecuteSequence, "RemoveExistingProducts"))
94
+ {
95
+ SequenceTable = SequenceTable.InstallExecuteSequence,
96
+ Action = "RemoveExistingProducts",
97
+ After = "InstallValidate",
98
+ },
99
+ new WixSimpleReferenceSymbol(packageSymbol.SourceLineNumbers)
100
+ {
101
+ Table = SymbolDefinitions.WixAction.Name,
102
+ PrimaryKeys = "InstallExecuteSequence/InstallValidate",
103
+ });
104
}
105
106
private void AddSymbolsToNewSection(string sectionId, params IntermediateSymbol[] symbols)
107
{
108
var section = new IntermediateSection(sectionId, SectionType.Fragment);
109
+
110
this.Sections.Add(section);
111
112
+ this.AddSymbols(section, symbols);
113
+ }
114
+
115
+ private void AddSymbols(IntermediateSection section, params IntermediateSymbol[] symbols)
116
+ {
117
foreach (var symbol in symbols)
118
{
119
section.AddSymbol(symbol);
120
63
- var symbolWithSection = new SymbolWithSection(section, symbol);
64
- var fullName = symbolWithSection.GetFullName();
65
- this.Find.SymbolsByName.Add(fullName, symbolWithSection);
121
+ if (!String.IsNullOrEmpty(symbol.Id?.Id))
122
+ {
123
+ var symbolWithSection = new SymbolWithSection(section, symbol);
124
+ var fullName = symbolWithSection.GetFullName();
125
+ this.Find.SymbolsByName.Add(fullName, symbolWithSection);
126
+ }
127
}
128
}
129
}
src/wix/WixToolset.Core/Linker.cs
+6
-1
@@ -90,7 +90,7 @@ namespace WixToolset.Core
90
if (library.Localizations?.Count > 0)
91
{
92
// Include localizations from the extension data and be sure to note that the localization came from
93
- // an extension. It is important to remember whiche localization came from an extension when filtering
93
+ // an extension. It is important to remember which localization came from an extension when filtering
94
// localizations during the resolve process later.
95
localizations.AddRange(library.Localizations.Select(l => l.UpdateLocation(LocalizationLocation.Extension)));
96
}
@@ -103,6 +103,11 @@ namespace WixToolset.Core
103
var stdlib = WixStandardLibrary.Build(this.Context.Platform);
104
105
sections.AddRange(stdlib.Sections);
106
+
107
+ if (stdlib.Localizations?.Count > 0)
108
+ {
109
+ localizations.AddRange(stdlib.Localizations);
110
+ }
111
}
112
113
var multipleFeatureComponents = new Hashtable();
src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgrade/DefaultMajorUpgrade.wxs
new
+12
@@ -0,0 +1,12 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Package Name="MajorUpgradeDowngradeMessage" Language="1033" Version="2.0.0" Manufacturer="Example Corporation" UpgradeCode="7ab24276-c628-43db-9e65-a184d052909b" Scope="perMachine">
3
+ <Feature Id="ProductFeature" Title="MsiPackageTitle">
4
+ </Feature>
5
+ </Package>
6
+
7
+ <Fragment>
8
+ <StandardDirectory Id="ProgramFiles6432Folder">
9
+ <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
10
+ </StandardDirectory>
11
+ </Fragment>
12
+</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgradeNone/DefaultMajorUpgradeNone.wxs
new
+12
@@ -0,0 +1,12 @@
1
+<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
2
+ <Package Name="MajorUpgradeDowngradeMessage" UpgradeStrategy="none" Language="1033" Version="2.0.0" Manufacturer="Example Corporation" UpgradeCode="7ab24276-c628-43db-9e65-a184d052909b" Scope="perMachine">
3
+ <Feature Id="ProductFeature" Title="MsiPackageTitle">
4
+ </Feature>
5
+ </Package>
6
+
7
+ <Fragment>
8
+ <StandardDirectory Id="ProgramFiles6432Folder">
9
+ <Directory Id="INSTALLFOLDER" Name="MsiPackage" />
10
+ </StandardDirectory>
11
+ </Fragment>
12
+</Wix>
src/wix/test/WixToolsetTest.CoreIntegration/UpgradeFixture.cs
+25
@@ -58,6 +58,31 @@ namespace WixToolsetTest.CoreIntegration
58
}, results);
59
}
60
61
+ [Fact]
62
+ public void DefaultMajorUpgradePopulatesUpgradeRowsAsExpected()
63
+ {
64
+ var folder = TestData.Get("TestData", "DefaultMajorUpgrade");
65
+ var build = new Builder(folder, new Type[] { }, new[] { folder });
66
+
67
+ var results = build.BuildAndQuery(Build, "Upgrade", "LaunchCondition");
68
+ WixAssert.CompareLineByLine(new[]
69
+ {
70
+ "LaunchCondition:NOT WIX_DOWNGRADE_DETECTED\tA newer version of [ProductName] is already installed.",
71
+ "Upgrade:{7AB24276-C628-43DB-9E65-A184D052909B}\t\t2.0.0\t1033\t1\t\tWIX_UPGRADE_DETECTED",
72
+ "Upgrade:{7AB24276-C628-43DB-9E65-A184D052909B}\t2.0.0\t\t1033\t2\t\tWIX_DOWNGRADE_DETECTED",
73
+ }, results);
74
+ }
75
+
76
+ [Fact]
77
+ public void UpgradeStrategyNoneDoesNotCreateDefaultMajorUpgrade()
78
+ {
79
+ var folder = TestData.Get("TestData", "DefaultMajorUpgradeNone");
80
+ var build = new Builder(folder, new Type[] { }, new[] { folder });
81
+
82
+ var results = build.BuildAndQuery(Build, "Upgrade", "LaunchCondition");
83
+ Assert.Empty(results);
84
+ }
85
+
86
private static void Build(string[] args)
87
{
88
var result = WixRunner.Execute(args);