@joebigelow / wix-1 / commits / 574785ab

Add default rollback boundary in the Burn binder instead of the compiler

Fixes wixtoolset/issues#6312

Rob Mensching committed Mar 11, 2021 at 18:47 UTC 574785ab1421c9b67336c13ade5c2263e665ca07
4 files changed +35 -31
src/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+1 -4
@@ -357,10 +357,7 @@ namespace WixToolset.Core.Burn
357 IEnumerable<PackageFacade> orderedFacades;
358 IEnumerable<WixBundleRollbackBoundarySymbol> boundaries;
359 {
360 - var groupSymbols = section.Symbols.OfType<WixGroupSymbol>();
361 - var boundarySymbolsById = section.Symbols.OfType<WixBundleRollbackBoundarySymbol>().ToDictionary(b => b.Id.Id);
362 -
363 - var command = new OrderPackagesAndRollbackBoundariesCommand(this.Messaging, groupSymbols, boundarySymbolsById, facades);
360 + var command = new OrderPackagesAndRollbackBoundariesCommand(this.Messaging, section, facades);
361 command.Execute();
362
363 orderedFacades = command.OrderedPackageFacades;
src/WixToolset.Core.Burn/Bundles/OrderPackagesAndRollbackBoundariesCommand.cs
+31 -21
@@ -4,27 +4,27 @@ namespace WixToolset.Core.Burn.Bundles
4 {
5 using System;
6 using System.Collections.Generic;
7 + using System.Linq;
8 using WixToolset.Data;
9 using WixToolset.Data.Symbols;
10 using WixToolset.Extensibility.Services;
11
12 internal class OrderPackagesAndRollbackBoundariesCommand
13 {
13 - public OrderPackagesAndRollbackBoundariesCommand(IMessaging messaging, IEnumerable<WixGroupSymbol> groupSymbols, Dictionary<string, WixBundleRollbackBoundarySymbol> boundarySymbols, IDictionary<string, PackageFacade> packageFacades)
14 + private const string DefaultBoundaryId = "WixDefaultBoundary";
15 +
16 + public OrderPackagesAndRollbackBoundariesCommand(IMessaging messaging, IntermediateSection section, IDictionary<string, PackageFacade> packageFacades)
17 {
18 this.Messaging = messaging;
16 - this.GroupSymbols = groupSymbols;
17 - this.Boundaries = boundarySymbols;
19 + this.Section = section;
20 this.PackageFacades = packageFacades;
21 }
22
23 private IMessaging Messaging { get; }
24
23 - public IEnumerable<WixGroupSymbol> GroupSymbols { get; }
24 -
25 - public Dictionary<string, WixBundleRollbackBoundarySymbol> Boundaries { get; }
25 + private IntermediateSection Section { get; }
26
27 - public IDictionary<string, PackageFacade> PackageFacades { get; }
27 + private IDictionary<string, PackageFacade> PackageFacades { get; }
28
29 public IEnumerable<PackageFacade> OrderedPackageFacades { get; private set; }
30
@@ -32,6 +32,9 @@ namespace WixToolset.Core.Burn.Bundles
32
33 public void Execute()
34 {
35 + var groupSymbols = this.Section.Symbols.OfType<WixGroupSymbol>().ToList();
36 + var boundariesById = this.Section.Symbols.OfType<WixBundleRollbackBoundarySymbol>().ToDictionary(b => b.Id.Id);
37 +
38 var orderedFacades = new List<PackageFacade>();
39 var usedBoundaries = new List<WixBundleRollbackBoundarySymbol>();
40
@@ -44,20 +47,27 @@ namespace WixToolset.Core.Burn.Bundles
47 // We handle uninstall (aka: backwards) rollback boundaries after
48 // we get these install/repair (aka: forward) rollback boundaries
49 // defined.
47 - WixBundleRollbackBoundarySymbol pendingRollbackBoundary = null;
48 - WixBundleRollbackBoundarySymbol lastRollbackBoundary = null;
50 + var pendingRollbackBoundary = new WixBundleRollbackBoundarySymbol(null, new Identifier(AccessModifier.Section, DefaultBoundaryId)) { Vital = true };
51 + var lastRollbackBoundary = pendingRollbackBoundary;
52 var boundaryHadX86Package = false;
53 var warnedMsiTransaction = false;
54
52 - foreach (var groupSymbol in this.GroupSymbols)
55 + foreach (var groupSymbol in groupSymbols)
56 {
57 if (ComplexReferenceChildType.Package == groupSymbol.ChildType && ComplexReferenceParentType.PackageGroup == groupSymbol.ParentType && "WixChain" == groupSymbol.ParentId)
58 {
59 if (this.PackageFacades.TryGetValue(groupSymbol.ChildId, out var facade))
60 {
58 - var insideMsiTransaction = lastRollbackBoundary != null && lastRollbackBoundary.Transaction.HasValue && lastRollbackBoundary.Transaction.Value;
61 + var insideMsiTransaction = lastRollbackBoundary?.Transaction ?? false;
62 +
63 if (null != pendingRollbackBoundary)
64 {
65 + // If we used the default boundary, ensure the symbol is added to the section.
66 + if (pendingRollbackBoundary.Id.Id == DefaultBoundaryId)
67 + {
68 + this.Section.Symbols.Add(pendingRollbackBoundary);
69 + }
70 +
71 if (insideMsiTransaction && !warnedMsiTransaction)
72 {
73 warnedMsiTransaction = true;
@@ -72,12 +82,11 @@ namespace WixToolset.Core.Burn.Bundles
82 }
83
84 // Error if MSI transaction has x86 package preceding x64 packages
75 - if (insideMsiTransaction
76 - && boundaryHadX86Package
77 - && facade.PackageSymbol.Win64)
85 + if (insideMsiTransaction && boundaryHadX86Package && facade.PackageSymbol.Win64)
86 {
87 this.Messaging.Write(ErrorMessages.MsiTransactionX86BeforeX64(facade.PackageSymbol.SourceLineNumbers));
88 }
89 +
90 boundaryHadX86Package |= !facade.PackageSymbol.Win64;
91
92 orderedFacades.Add(facade);
@@ -85,15 +94,16 @@ namespace WixToolset.Core.Burn.Bundles
94 else // must be a rollback boundary.
95 {
96 // Discard the next rollback boundary if we have a previously defined boundary.
88 - var nextRollbackBoundary = this.Boundaries[groupSymbol.ChildId];
97 + var nextRollbackBoundary = boundariesById[groupSymbol.ChildId];
98 if (null != pendingRollbackBoundary)
99 {
91 - this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(nextRollbackBoundary.SourceLineNumbers, nextRollbackBoundary.Id.Id));
92 - }
93 - else
94 - {
95 - lastRollbackBoundary = pendingRollbackBoundary = nextRollbackBoundary;
100 + if (pendingRollbackBoundary.Id.Id != DefaultBoundaryId)
101 + {
102 + this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(nextRollbackBoundary.SourceLineNumbers, nextRollbackBoundary.Id.Id));
103 + }
104 }
105 +
106 + lastRollbackBoundary = pendingRollbackBoundary = nextRollbackBoundary;
107 }
108 }
109 }
@@ -135,7 +145,7 @@ namespace WixToolset.Core.Burn.Bundles
145 string previousRollbackBoundaryId = null;
146 PackageFacade previousFacade = null;
147
138 - foreach (PackageFacade package in orderedFacades)
148 + foreach (var package in orderedFacades)
149 {
150 if (null != package.PackageSymbol.RollbackBoundaryRef)
151 {
src/WixToolset.Core/Compiler_Bundle.cs
+2 -5
@@ -1726,11 +1726,8 @@ namespace WixToolset.Core
1726 }
1727 }
1728
1729 - // Ensure there is always a rollback boundary at the beginning of the chain.
1730 - this.CreateRollbackBoundary(sourceLineNumbers, new Identifier(AccessModifier.Global, "WixDefaultBoundary"), YesNoType.Yes, YesNoType.No, ComplexReferenceParentType.PackageGroup, "WixChain", ComplexReferenceChildType.Unknown, null);
1731 -
1732 - var previousId = "WixDefaultBoundary";
1733 - var previousType = ComplexReferenceChildType.Package;
1729 + string previousId = null;
1730 + var previousType = ComplexReferenceChildType.Unknown;
1731
1732 foreach (var child in node.Elements())
1733 {
src/test/WixToolsetTest.CoreIntegration/RollbackBoundaryFixture.cs
+1 -1
@@ -9,7 +9,7 @@ namespace WixToolsetTest.CoreIntegration
9
10 public class RollbackBoundaryFixture
11 {
12 - [Fact(Skip = "Test demonstrates failure")]
12 + [Fact]
13 public void CanStartChainWithRollbackBoundary()
14 {
15 var folder = TestData.Get(@"TestData");