From 1eea9c6e7b276c7c0dfde7779dfec45046ad5831 Mon Sep 17 00:00:00 2001 From: Bob Arnson Date: Sat, 23 Dec 2023 21:37:02 -0500 Subject: 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. --- .../WixToolset.Data/Symbols/WixPackageSymbol.cs | 12 ++++ src/api/wix/WixToolset.Data/WixStandardLibrary.cs | 12 +++- .../WixStandardLibraryIdentifiers.cs | 5 ++ src/wix/WixToolset.Core/Compiler_Package.cs | 17 ++++++ .../Link/AddDefaultSymbolsCommand.cs | 67 +++++++++++++++++++++- src/wix/WixToolset.Core/Linker.cs | 7 ++- .../DefaultMajorUpgrade/DefaultMajorUpgrade.wxs | 12 ++++ .../DefaultMajorUpgradeNone.wxs | 12 ++++ .../UpgradeFixture.cs | 25 ++++++++ 9 files changed, 164 insertions(+), 5 deletions(-) create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgrade/DefaultMajorUpgrade.wxs create mode 100644 src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgradeNone/DefaultMajorUpgradeNone.wxs diff --git a/src/api/wix/WixToolset.Data/Symbols/WixPackageSymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixPackageSymbol.cs index e1720033..4a112266 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixPackageSymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixPackageSymbol.cs @@ -46,6 +46,12 @@ namespace WixToolset.Data.Symbols PerMachine = 0x1, } + public enum WixPackageUpgradeStrategy + { + None = 0x0, + MajorUpgrade = 0x1, + } + public class WixPackageSymbol : IntermediateSymbol { public WixPackageSymbol() : base(SymbolDefinitions.WixPackage, null, null) @@ -106,6 +112,12 @@ namespace WixToolset.Data.Symbols set => this.Set((int)WixPackageSymbolFields.Codepage, value); } + public WixPackageUpgradeStrategy UpgradeStrategy + { + get => (WixPackageUpgradeStrategy)this.Fields[(int)WixPackageSymbolFields.Attributes].AsNumber(); + set => this.Set((int)WixPackageSymbolFields.Attributes, (int)value); + } + public bool PerMachine => (this.Attributes & WixPackageAttributes.PerMachine) == WixPackageAttributes.PerMachine; } } diff --git a/src/api/wix/WixToolset.Data/WixStandardLibrary.cs b/src/api/wix/WixToolset.Data/WixStandardLibrary.cs index 3758e5b1..3f851f09 100644 --- a/src/api/wix/WixToolset.Data/WixStandardLibrary.cs +++ b/src/api/wix/WixToolset.Data/WixStandardLibrary.cs @@ -32,7 +32,17 @@ namespace WixToolset.Data private static IEnumerable YieldLocalizations() { - var strings = new BindVariable[0]; + var sourceLineNumber = new SourceLineNumber("wixstd.wixlib"); + + var strings = new[] { + new BindVariable() + { + SourceLineNumbers = sourceLineNumber, + Id = "WixDowngradePreventedMessage", + Value = "A newer version of [ProductName] is already installed.", + Overridable = true, + }, + }; var localizedControls = new LocalizedControl[0]; diff --git a/src/api/wix/WixToolset.Data/WixStandardLibraryIdentifiers.cs b/src/api/wix/WixToolset.Data/WixStandardLibraryIdentifiers.cs index 6579a42b..73e4245b 100644 --- a/src/api/wix/WixToolset.Data/WixStandardLibraryIdentifiers.cs +++ b/src/api/wix/WixToolset.Data/WixStandardLibraryIdentifiers.cs @@ -21,5 +21,10 @@ namespace WixToolset.Data /// Default feature name. /// public static readonly string DefaultFeatureName = "WixDefaultFeature"; + + /// + /// WiX Standard localization strings. + /// + public static readonly string WixStandardLocalizationStrings = "WixStandardLocalizationStrings"; } } diff --git a/src/wix/WixToolset.Core/Compiler_Package.cs b/src/wix/WixToolset.Core/Compiler_Package.cs index 17a6a913..31b8e81c 100644 --- a/src/wix/WixToolset.Core/Compiler_Package.cs +++ b/src/wix/WixToolset.Core/Compiler_Package.cs @@ -41,6 +41,7 @@ namespace WixToolset.Core var isPackageNameSet = false; var isKeywordsSet = false; var isPackageAuthorSet = false; + var upgradeStrategy = WixPackageUpgradeStrategy.MajorUpgrade; this.GetDefaultPlatformAndInstallerVersion(out var platform, out var msiVersion); @@ -111,6 +112,21 @@ namespace WixToolset.Core case "UpgradeCode": upgradeCode = this.Core.GetAttributeGuidValue(sourceLineNumbers, attrib, false); break; + case "UpgradeStrategy": + var strategy = this.Core.GetAttributeValue(sourceLineNumbers, attrib); + switch (strategy) + { + case "majorUpgrade": + upgradeStrategy = WixPackageUpgradeStrategy.MajorUpgrade; + break; + case "none": + upgradeStrategy = WixPackageUpgradeStrategy.None; + break; + default: + this.Core.Write(ErrorMessages.IllegalAttributeValue(sourceLineNumbers, node.Name.LocalName, attrib.Name.LocalName, strategy, "majorUpgrade", "none")); + break; + } + break; case "Version": version = this.Core.GetAttributeVersionValue(sourceLineNumbers, attrib); break; @@ -382,6 +398,7 @@ namespace WixToolset.Core Manufacturer = manufacturer, Attributes = isPerMachine ? WixPackageAttributes.PerMachine : WixPackageAttributes.None, Codepage = codepage, + UpgradeStrategy = upgradeStrategy, }); if (!isCommentsSet) diff --git a/src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs b/src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs index 221b5411..8d9f7cab 100644 --- a/src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs +++ b/src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs @@ -2,6 +2,7 @@ namespace WixToolset.Core.Link { + using System; using System.Collections.Generic; using System.Linq; using WixToolset.Data; @@ -49,20 +50,80 @@ namespace WixToolset.Core.Link } ); } + + var symbols = this.Sections.SelectMany(section => section.Symbols); + var upgradeSymbols = symbols.OfType(); + if (!upgradeSymbols.Any()) + { + var packageSymbol = this.Find.EntrySection.Symbols.OfType().FirstOrDefault(); + + if (packageSymbol?.UpgradeStrategy == WixPackageUpgradeStrategy.MajorUpgrade + && !String.IsNullOrEmpty(packageSymbol?.UpgradeCode)) + { + this.AddDefaultMajorUpgrade(packageSymbol); + } + } + } + + private void AddDefaultMajorUpgrade(WixPackageSymbol packageSymbol) + { + this.AddSymbols(this.Find.EntrySection, + new UpgradeSymbol(packageSymbol.SourceLineNumbers) + { + UpgradeCode = packageSymbol.UpgradeCode, + MigrateFeatures = true, + ActionProperty = WixUpgradeConstants.UpgradeDetectedProperty, + VersionMax = packageSymbol.Version, + Language = packageSymbol.Language, + }, + new UpgradeSymbol(packageSymbol.SourceLineNumbers) + { + UpgradeCode = packageSymbol.UpgradeCode, + VersionMin = packageSymbol.Version, + Language = packageSymbol.Language, + OnlyDetect = true, + ActionProperty = WixUpgradeConstants.DowngradeDetectedProperty, + }, + new LaunchConditionSymbol(packageSymbol.SourceLineNumbers) + { + Condition = WixUpgradeConstants.DowngradePreventedCondition, + Description = "!(loc.WixDowngradePreventedMessage)", + }, + new WixActionSymbol(packageSymbol.SourceLineNumbers, + new Identifier(AccessModifier.Global, SequenceTable.InstallExecuteSequence, "RemoveExistingProducts")) + { + SequenceTable = SequenceTable.InstallExecuteSequence, + Action = "RemoveExistingProducts", + After = "InstallValidate", + }, + new WixSimpleReferenceSymbol(packageSymbol.SourceLineNumbers) + { + Table = SymbolDefinitions.WixAction.Name, + PrimaryKeys = "InstallExecuteSequence/InstallValidate", + }); } private void AddSymbolsToNewSection(string sectionId, params IntermediateSymbol[] symbols) { var section = new IntermediateSection(sectionId, SectionType.Fragment); + this.Sections.Add(section); + this.AddSymbols(section, symbols); + } + + private void AddSymbols(IntermediateSection section, params IntermediateSymbol[] symbols) + { foreach (var symbol in symbols) { section.AddSymbol(symbol); - var symbolWithSection = new SymbolWithSection(section, symbol); - var fullName = symbolWithSection.GetFullName(); - this.Find.SymbolsByName.Add(fullName, symbolWithSection); + if (!String.IsNullOrEmpty(symbol.Id?.Id)) + { + var symbolWithSection = new SymbolWithSection(section, symbol); + var fullName = symbolWithSection.GetFullName(); + this.Find.SymbolsByName.Add(fullName, symbolWithSection); + } } } } diff --git a/src/wix/WixToolset.Core/Linker.cs b/src/wix/WixToolset.Core/Linker.cs index 32ccb144..a536c049 100644 --- a/src/wix/WixToolset.Core/Linker.cs +++ b/src/wix/WixToolset.Core/Linker.cs @@ -90,7 +90,7 @@ namespace WixToolset.Core if (library.Localizations?.Count > 0) { // Include localizations from the extension data and be sure to note that the localization came from - // an extension. It is important to remember whiche localization came from an extension when filtering + // an extension. It is important to remember which localization came from an extension when filtering // localizations during the resolve process later. localizations.AddRange(library.Localizations.Select(l => l.UpdateLocation(LocalizationLocation.Extension))); } @@ -103,6 +103,11 @@ namespace WixToolset.Core var stdlib = WixStandardLibrary.Build(this.Context.Platform); sections.AddRange(stdlib.Sections); + + if (stdlib.Localizations?.Count > 0) + { + localizations.AddRange(stdlib.Localizations); + } } var multipleFeatureComponents = new Hashtable(); diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgrade/DefaultMajorUpgrade.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgrade/DefaultMajorUpgrade.wxs new file mode 100644 index 00000000..ce9fd96f --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgrade/DefaultMajorUpgrade.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgradeNone/DefaultMajorUpgradeNone.wxs b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgradeNone/DefaultMajorUpgradeNone.wxs new file mode 100644 index 00000000..63ff178b --- /dev/null +++ b/src/wix/test/WixToolsetTest.CoreIntegration/TestData/DefaultMajorUpgradeNone/DefaultMajorUpgradeNone.wxs @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/UpgradeFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/UpgradeFixture.cs index 3d2aa722..1ae74210 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/UpgradeFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/UpgradeFixture.cs @@ -58,6 +58,31 @@ namespace WixToolsetTest.CoreIntegration }, results); } + [Fact] + public void DefaultMajorUpgradePopulatesUpgradeRowsAsExpected() + { + var folder = TestData.Get("TestData", "DefaultMajorUpgrade"); + var build = new Builder(folder, new Type[] { }, new[] { folder }); + + var results = build.BuildAndQuery(Build, "Upgrade", "LaunchCondition"); + WixAssert.CompareLineByLine(new[] + { + "LaunchCondition:NOT WIX_DOWNGRADE_DETECTED\tA newer version of [ProductName] is already installed.", + "Upgrade:{7AB24276-C628-43DB-9E65-A184D052909B}\t\t2.0.0\t1033\t1\t\tWIX_UPGRADE_DETECTED", + "Upgrade:{7AB24276-C628-43DB-9E65-A184D052909B}\t2.0.0\t\t1033\t2\t\tWIX_DOWNGRADE_DETECTED", + }, results); + } + + [Fact] + public void UpgradeStrategyNoneDoesNotCreateDefaultMajorUpgrade() + { + var folder = TestData.Get("TestData", "DefaultMajorUpgradeNone"); + var build = new Builder(folder, new Type[] { }, new[] { folder }); + + var results = build.BuildAndQuery(Build, "Upgrade", "LaunchCondition"); + Assert.Empty(results); + } + private static void Build(string[] args) { var result = WixRunner.Execute(args); -- cgit v1.2.3-55-g6feb