@joebigelow / wix / commits / 5a874790

MSI transaction cleanup.

Sean Hall committed Dec 2, 2020 at 14:33 UTC 5a874790ba9ec6c2d3c9002699114c2fe4c493ae
9 files changed +212 -15
src/WixToolset.Core.Burn/Bundles/OrderPackagesAndRollbackBoundariesCommand.cs
+21 -15
@@ -44,9 +44,10 @@ namespace WixToolset.Core.Burn.Bundles
44 // We handle uninstall (aka: backwards) rollback boundaries after
45 // we get these install/repair (aka: forward) rollback boundaries
46 // defined.
47 - WixBundleRollbackBoundarySymbol previousRollbackBoundary = null;
47 + WixBundleRollbackBoundarySymbol pendingRollbackBoundary = null;
48 WixBundleRollbackBoundarySymbol lastRollbackBoundary = null;
49 var boundaryHadX86Package = false;
50 + var warnedMsiTransaction = false;
51
52 foreach (var groupSymbol in this.GroupSymbols)
53 {
@@ -54,24 +55,30 @@ namespace WixToolset.Core.Burn.Bundles
55 {
56 if (this.PackageFacades.TryGetValue(groupSymbol.ChildId, out var facade))
57 {
57 - if (null != previousRollbackBoundary)
58 + var insideMsiTransaction = lastRollbackBoundary != null && lastRollbackBoundary.Transaction.HasValue && lastRollbackBoundary.Transaction.Value;
59 + if (null != pendingRollbackBoundary)
60 {
59 - usedBoundaries.Add(previousRollbackBoundary);
60 - facade.PackageSymbol.RollbackBoundaryRef = previousRollbackBoundary.Id.Id;
61 - previousRollbackBoundary = null;
61 + if (insideMsiTransaction && !warnedMsiTransaction)
62 + {
63 + warnedMsiTransaction = true;
64 + this.Messaging.Write(WarningMessages.MsiTransactionLimitations(pendingRollbackBoundary.SourceLineNumbers));
65 + }
66
63 - boundaryHadX86Package = facade.PackageSymbol.Win64;
67 + usedBoundaries.Add(pendingRollbackBoundary);
68 + facade.PackageSymbol.RollbackBoundaryRef = pendingRollbackBoundary.Id.Id;
69 + pendingRollbackBoundary = null;
70 +
71 + boundaryHadX86Package = !facade.PackageSymbol.Win64;
72 }
73
74 // Error if MSI transaction has x86 package preceding x64 packages
67 - if ((lastRollbackBoundary != null)
68 - && lastRollbackBoundary.Transaction == true
75 + if (insideMsiTransaction
76 && boundaryHadX86Package
77 && facade.PackageSymbol.Win64)
78 {
72 - this.Messaging.Write(ErrorMessages.MsiTransactionX86BeforeX64(lastRollbackBoundary.SourceLineNumbers));
79 + this.Messaging.Write(ErrorMessages.MsiTransactionX86BeforeX64(facade.PackageSymbol.SourceLineNumbers));
80 }
74 - boundaryHadX86Package |= facade.PackageSymbol.Win64;
81 + boundaryHadX86Package |= !facade.PackageSymbol.Win64;
82
83 orderedFacades.Add(facade);
84 }
@@ -79,22 +86,21 @@ namespace WixToolset.Core.Burn.Bundles
86 {
87 // Discard the next rollback boundary if we have a previously defined boundary.
88 var nextRollbackBoundary = this.Boundaries[groupSymbol.ChildId];
82 - if (null != previousRollbackBoundary)
89 + if (null != pendingRollbackBoundary)
90 {
91 this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(nextRollbackBoundary.SourceLineNumbers, nextRollbackBoundary.Id.Id));
92 }
93 else
94 {
88 - previousRollbackBoundary = nextRollbackBoundary;
89 - lastRollbackBoundary = nextRollbackBoundary;
95 + lastRollbackBoundary = pendingRollbackBoundary = nextRollbackBoundary;
96 }
97 }
98 }
99 }
100
95 - if (null != previousRollbackBoundary)
101 + if (null != pendingRollbackBoundary)
102 {
97 - this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(previousRollbackBoundary.SourceLineNumbers, previousRollbackBoundary.Id.Id));
103 + this.Messaging.Write(WarningMessages.DiscardedRollbackBoundary(pendingRollbackBoundary.SourceLineNumbers, pendingRollbackBoundary.Id.Id));
104 }
105
106 // With the forward rollback boundaries assigned, we can now go
src/test/WixToolsetTest.CoreIntegration/MsiTransactionFixture.cs new
+129
@@ -0,0 +1,129 @@
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 WixBuildTools.TestSupport;
7 + using WixToolset.Core.TestPackage;
8 + using Xunit;
9 +
10 + public class MsiTransactionFixture
11 + {
12 + [Fact]
13 + public void CantBuildX64AfterX86Bundle()
14 + {
15 + var folder = TestData.Get(@"TestData");
16 +
17 + using (var fs = new DisposableFileSystem())
18 + {
19 + var baseFolder = fs.GetFolder();
20 + var intermediateFolder = Path.Combine(baseFolder, "obj");
21 + var binFolder = Path.Combine(baseFolder, "bin");
22 + var exePath = Path.Combine(binFolder, "test.exe");
23 +
24 + BuildMsiPackages(folder, intermediateFolder, binFolder);
25 +
26 + var result = WixRunner.Execute(new[]
27 + {
28 + "build",
29 + Path.Combine(folder, "MsiTransaction", "X64AfterX86Bundle.wxs"),
30 + Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
31 + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
32 + "-bindpath", binFolder,
33 + "-intermediateFolder", intermediateFolder,
34 + "-o", exePath,
35 + });
36 +
37 + Assert.Equal(390, result.ExitCode);
38 + }
39 + }
40 +
41 + [Fact]
42 + public void CanBuildX86AfterX64Bundle()
43 + {
44 + var folder = TestData.Get(@"TestData");
45 +
46 + using (var fs = new DisposableFileSystem())
47 + {
48 + var baseFolder = fs.GetFolder();
49 + var intermediateFolder = Path.Combine(baseFolder, "obj");
50 + var binFolder = Path.Combine(baseFolder, "bin");
51 + var exePath = Path.Combine(binFolder, "test.exe");
52 +
53 + BuildMsiPackages(folder, intermediateFolder, binFolder);
54 +
55 + var result = WixRunner.Execute(new[]
56 + {
57 + "build",
58 + Path.Combine(folder, "MsiTransaction", "X86AfterX64Bundle.wxs"),
59 + Path.Combine(folder, "BundleWithPackageGroupRef", "Bundle.wxs"),
60 + "-bindpath", Path.Combine(folder, "SimpleBundle", "data"),
61 + "-bindpath", binFolder,
62 + "-intermediateFolder", intermediateFolder,
63 + "-o", exePath,
64 + });
65 +
66 + result.AssertSuccess();
67 +
68 + Assert.True(File.Exists(exePath));
69 + }
70 + }
71 +
72 + private static void BuildMsiPackages(string folder, string intermediateFolder, string binFolder)
73 + {
74 + var result = WixRunner.Execute(new[]
75 + {
76 + "build",
77 + Path.Combine(folder, "MsiTransaction", "FirstX86.wxs"),
78 + Path.Combine(folder, "ProductWithComponentGroupRef", "MinimalComponentGroup.wxs"),
79 + Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
80 + "-bindpath", Path.Combine(folder, "SingleFile", "data"),
81 + "-intermediateFolder", intermediateFolder,
82 + "-o", Path.Combine(binFolder, "FirstX86.msi"),
83 + });
84 +
85 + result.AssertSuccess();
86 +
87 + result = WixRunner.Execute(new[]
88 + {
89 + "build",
90 + Path.Combine(folder, "MsiTransaction", "SecondX86.wxs"),
91 + Path.Combine(folder, "ProductWithComponentGroupRef", "MinimalComponentGroup.wxs"),
92 + Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
93 + "-bindpath", Path.Combine(folder, "SingleFile", "data"),
94 + "-intermediateFolder", intermediateFolder,
95 + "-o", Path.Combine(binFolder, "SecondX86.msi"),
96 + });
97 +
98 + result.AssertSuccess();
99 +
100 + result = WixRunner.Execute(new[]
101 + {
102 + "build",
103 + Path.Combine(folder, "MsiTransaction", "FirstX64.wxs"),
104 + Path.Combine(folder, "ProductWithComponentGroupRef", "MinimalComponentGroup.wxs"),
105 + Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
106 + "-bindpath", Path.Combine(folder, "SingleFile", "data"),
107 + "-intermediateFolder", intermediateFolder,
108 + "-arch", "x64",
109 + "-o", Path.Combine(binFolder, "FirstX64.msi"),
110 + });
111 +
112 + result.AssertSuccess();
113 +
114 + result = WixRunner.Execute(new[]
115 + {
116 + "build",
117 + Path.Combine(folder, "MsiTransaction", "SecondX64.wxs"),
118 + Path.Combine(folder, "ProductWithComponentGroupRef", "MinimalComponentGroup.wxs"),
119 + Path.Combine(folder, "ProductWithComponentGroupRef", "Product.wxs"),
120 + "-bindpath", Path.Combine(folder, "SingleFile", "data"),
121 + "-intermediateFolder", intermediateFolder,
122 + "-arch", "x64",
123 + "-o", Path.Combine(binFolder, "SecondX64.msi"),
124 + });
125 +
126 + result.AssertSuccess();
127 + }
128 + }
129 +}
src/test/WixToolsetTest.CoreIntegration/TestData/MsiTransaction/FirstX64.wxs new
+8
@@ -0,0 +1,8 @@
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" />
6 + </ComponentGroup>
7 + </Fragment>
8 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/MsiTransaction/FirstX86.wxs new
+8
@@ -0,0 +1,8 @@
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" />
6 + </ComponentGroup>
7 + </Fragment>
8 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/MsiTransaction/SecondX64.wxs new
+8
@@ -0,0 +1,8 @@
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" />
6 + </ComponentGroup>
7 + </Fragment>
8 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/MsiTransaction/SecondX86.wxs new
+8
@@ -0,0 +1,8 @@
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" />
6 + </ComponentGroup>
7 + </Fragment>
8 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/MsiTransaction/X64AfterX86Bundle.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 + <PackageGroup Id="BundlePackages">
5 + <MsiPackage SourceFile="FirstX64.msi" />
6 + <RollbackBoundary Transaction="yes" />
7 + <MsiPackage SourceFile="FirstX86.msi" />
8 + <MsiPackage SourceFile="SecondX86.msi" />
9 + <MsiPackage SourceFile="SecondX64.msi" />
10 + </PackageGroup>
11 + </Fragment>
12 +</Wix>
src/test/WixToolsetTest.CoreIntegration/TestData/MsiTransaction/X86AfterX64Bundle.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 + <PackageGroup Id="BundlePackages">
5 + <MsiPackage SourceFile="FirstX86.msi" />
6 + <RollbackBoundary Transaction="yes" />
7 + <MsiPackage SourceFile="FirstX64.msi" />
8 + <MsiPackage SourceFile="SecondX64.msi" />
9 + <MsiPackage SourceFile="SecondX86.msi" />
10 + </PackageGroup>
11 + </Fragment>
12 +</Wix>
src/test/WixToolsetTest.CoreIntegration/WixToolsetTest.CoreIntegration.csproj
+6
@@ -64,6 +64,12 @@
64 <Content Include="TestData\Font\TrueType.wxs" CopyToOutputDirectory="PreserveNewest" />
65 <Content Include="TestData\Icon\SampleIcon.wxs" CopyToOutputDirectory="PreserveNewest" />
66 <Content Include="TestData\LockPermissions\EmptyPermissions.wxs" CopyToOutputDirectory="PreserveNewest" />
67 + <Content Include="TestData\MsiTransaction\FirstX64.wxs" CopyToOutputDirectory="PreserveNewest" />
68 + <Content Include="TestData\MsiTransaction\FirstX86.wxs" CopyToOutputDirectory="PreserveNewest" />
69 + <Content Include="TestData\MsiTransaction\SecondX64.wxs" CopyToOutputDirectory="PreserveNewest" />
70 + <Content Include="TestData\MsiTransaction\SecondX86.wxs" CopyToOutputDirectory="PreserveNewest" />
71 + <Content Include="TestData\MsiTransaction\X64AfterX86Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />
72 + <Content Include="TestData\MsiTransaction\X86AfterX64Bundle.wxs" CopyToOutputDirectory="PreserveNewest" />
73 <Content Include="TestData\PatchFamilyFilter\.data\Av1.0.0.txt" CopyToOutputDirectory="PreserveNewest" />
74 <Content Include="TestData\PatchFamilyFilter\.data\Av1.0.1.txt" CopyToOutputDirectory="PreserveNewest" />
75 <Content Include="TestData\PatchFamilyFilter\.data\Bv1.0.0.txt" CopyToOutputDirectory="PreserveNewest" />