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" />