Skip to content

Commit

Permalink
Add default major upgrade.
Browse files Browse the repository at this point in the history
Add Package/@UpgradeStrategy to allow `none` to suppress major upgrade.

Implements wixtoolset/issues#7605.

Requires #435.
  • Loading branch information
barnson committed Dec 29, 2023
1 parent f504182 commit 9e62f89
Show file tree
Hide file tree
Showing 9 changed files with 171 additions and 8 deletions.
12 changes: 12 additions & 0 deletions src/api/wix/WixToolset.Data/Symbols/WixPackageSymbol.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ public enum WixPackageAttributes
PerMachine = 0x1,
}

public enum WixPackageUpgradeStrategy
{
None = 0x0,
MajorUpgrade = 0x1,
}

public class WixPackageSymbol : IntermediateSymbol
{
public WixPackageSymbol() : base(SymbolDefinitions.WixPackage, null, null)
Expand Down Expand Up @@ -106,6 +112,12 @@ public string Codepage
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;
}
}
12 changes: 11 additions & 1 deletion src/api/wix/WixToolset.Data/WixStandardLibrary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,17 @@ public static Intermediate Build(Platform platform)

private static IEnumerable<Localization> 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];

Expand Down
5 changes: 5 additions & 0 deletions src/api/wix/WixToolset.Data/WixStandardLibraryIdentifiers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,10 @@ public static class WixStandardLibraryIdentifiers
/// Default feature name.
/// </summary>
public static readonly string DefaultFeatureName = "WixDefaultFeature";

/// <summary>
/// WiX Standard localization strings.
/// </summary>
public static readonly string WixStandardLocalizationStrings = "WixStandardLocalizationStrings";
}
}
17 changes: 17 additions & 0 deletions src/wix/WixToolset.Core/Compiler_Package.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ private void ParsePackageElement(XElement node)
var isPackageNameSet = false;
var isKeywordsSet = false;
var isPackageAuthorSet = false;
var upgradeStrategy = WixPackageUpgradeStrategy.MajorUpgrade;

this.GetDefaultPlatformAndInstallerVersion(out var platform, out var msiVersion);

Expand Down Expand Up @@ -111,6 +112,21 @@ private void ParsePackageElement(XElement node)
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;
Expand Down Expand Up @@ -382,6 +398,7 @@ private void ParsePackageElement(XElement node)
Manufacturer = manufacturer,
Attributes = isPerMachine ? WixPackageAttributes.PerMachine : WixPackageAttributes.None,
Codepage = codepage,
UpgradeStrategy = upgradeStrategy,
});

if (!isCommentsSet)
Expand Down
77 changes: 71 additions & 6 deletions src/wix/WixToolset.Core/Link/AddDefaultSymbolsCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace WixToolset.Core.Link
{
using System;
using System.Collections.Generic;
using System.Linq;
using WixToolset.Data;
Expand All @@ -19,8 +20,6 @@ public AddDefaultSymbolsCommand(FindEntrySectionAndLoadSymbolsCommand find, List
this.Sections = sections;
}

public IntermediateSection EntrySection { get; }

public IEnumerable<IntermediateSection> Sections { get; }

public FindEntrySectionAndLoadSymbolsCommand Find { get; }
Expand All @@ -34,8 +33,8 @@ public void Execute()
}

var symbols = this.Sections.SelectMany(s => s.Symbols);
var directorySymbols = symbols.OfType<DirectorySymbol>();
var referenceSymbols = symbols.OfType<WixSimpleReferenceSymbol>();
var directorySymbols = symbols.OfType<DirectorySymbol>();

if (referenceSymbols.Any(s => s.SymbolicName == WixStandardInstallFolderReference)
&& !directorySymbols.Any(d => d.Id.Id == WixStandardInstallFolder))
Expand All @@ -55,15 +54,81 @@ public void Execute()
PrimaryKeys = WixStandardInstallFolderParent,
});
}

var upgradeSymbols = symbols.OfType<UpgradeSymbol>();
if (!upgradeSymbols.Any())
{
var packageSymbol = this.Find.EntrySection.Symbols.OfType<WixPackageSymbol>().FirstOrDefault();

if (packageSymbol?.UpgradeStrategy == WixPackageUpgradeStrategy.MajorUpgrade
&& !String.IsNullOrEmpty(packageSymbol?.UpgradeCode))
{
this.AddDefaultMajorUpgrade(packageSymbol);
}

}
}

private void AddDefaultMajorUpgrade(WixPackageSymbol packageSymbol)
{
this.AddSymbol(new UpgradeSymbol(packageSymbol.SourceLineNumbers)
{
UpgradeCode = packageSymbol.UpgradeCode,
MigrateFeatures = true,
ActionProperty = WixUpgradeConstants.UpgradeDetectedProperty,
VersionMax = packageSymbol.Version,
Language = packageSymbol.Language,
});

this.AddSymbol(new UpgradeSymbol(packageSymbol.SourceLineNumbers)
{
UpgradeCode = packageSymbol.UpgradeCode,
VersionMin = packageSymbol.Version,
Language = packageSymbol.Language,
OnlyDetect = true,
ActionProperty = WixUpgradeConstants.DowngradeDetectedProperty,
});

this.AddSymbol(new LaunchConditionSymbol(packageSymbol.SourceLineNumbers)
{
Condition = WixUpgradeConstants.DowngradePreventedCondition,
Description = "!(loc.WixDowngradePreventedMessage)",
});

this.CreateActionSymbol(this.Find.EntrySection, packageSymbol.SourceLineNumbers, SequenceTable.InstallExecuteSequence, "RemoveExistingProducts", "InstallValidate");
}

public WixActionSymbol CreateActionSymbol(IntermediateSection section, SourceLineNumber sourceLineNumbers, SequenceTable sequence, string actionName, string afterAction)
{
var actionId = new Identifier(AccessModifier.Global, sequence, actionName);

var actionSymbol = section.AddSymbol(new WixActionSymbol(sourceLineNumbers, actionId)
{
SequenceTable = sequence,
Action = actionName,
After = afterAction,
});

section.AddSymbol(new WixSimpleReferenceSymbol(sourceLineNumbers)
{
Table = SymbolDefinitions.WixAction.Name,
PrimaryKeys = $"{sequence}/{afterAction}",
});

return actionSymbol;
}

private void AddSymbol(IntermediateSymbol symbol)
{
this.Find.EntrySection.AddSymbol(symbol);

var symbolWithSection = new SymbolWithSection(this.Find.EntrySection, symbol);
var fullName = symbolWithSection.GetFullName();
this.Find.SymbolsByName.Add(fullName, symbolWithSection);
if (!String.IsNullOrEmpty(symbol.Id?.Id))
{
var symbolWithSection = new SymbolWithSection(this.Find.EntrySection, symbol);
var fullName = symbolWithSection.GetFullName();

this.Find.SymbolsByName.Add(fullName, symbolWithSection);
}
}
}
}
7 changes: 6 additions & 1 deletion src/wix/WixToolset.Core/Linker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public Intermediate Link(ILinkContext context)
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)));
}
Expand All @@ -103,6 +103,11 @@ public Intermediate Link(ILinkContext context)
var stdlib = WixStandardLibrary.Build(this.Context.Platform);

sections.AddRange(stdlib.Sections);

if (stdlib.Localizations?.Count > 0)
{
localizations.AddRange(stdlib.Localizations);
}
}

var multipleFeatureComponents = new Hashtable();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package Name="MajorUpgradeDowngradeMessage" Language="1033" Version="2.0.0" Manufacturer="Example Corporation" UpgradeCode="7ab24276-c628-43db-9e65-a184d052909b" Scope="perMachine">
<Feature Id="ProductFeature" Title="MsiPackageTitle">
</Feature>
</Package>

<Fragment>
<StandardDirectory Id="ProgramFiles6432Folder">
<Directory Id="INSTALLFOLDER" Name="MsiPackage" />
</StandardDirectory>
</Fragment>
</Wix>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<Package Name="MajorUpgradeDowngradeMessage" UpgradeStrategy="none" Language="1033" Version="2.0.0" Manufacturer="Example Corporation" UpgradeCode="7ab24276-c628-43db-9e65-a184d052909b" Scope="perMachine">
<Feature Id="ProductFeature" Title="MsiPackageTitle">
</Feature>
</Package>

<Fragment>
<StandardDirectory Id="ProgramFiles6432Folder">
<Directory Id="INSTALLFOLDER" Name="MsiPackage" />
</StandardDirectory>
</Fragment>
</Wix>
25 changes: 25 additions & 0 deletions src/wix/test/WixToolsetTest.CoreIntegration/UpgradeFixture.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,31 @@ public void MajorUpgradeDowngradeMessagePopulatesRowsAsExpected()
}, 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);
Expand Down

0 comments on commit 9e62f89

Please sign in to comment.