Set the log file path for MSI transactions.
Nir Bar committed
Aug 12, 2021 at 14:16 UTC
bb18c9c4f0e6da640775b85ebda68b31f2b391ed
12 files changed
+158
-46
src/api/wix/WixToolset.Data/Symbols/WixBundleRollbackBoundarySymbol.cs
+8
@@ -12,6 +12,7 @@ namespace WixToolset.Data
12
{
13
new IntermediateFieldDefinition(nameof(WixBundleRollbackBoundarySymbolFields.Vital), IntermediateFieldType.Number),
14
new IntermediateFieldDefinition(nameof(WixBundleRollbackBoundarySymbolFields.Transaction), IntermediateFieldType.Number),
15
+ new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.LogPathVariable), IntermediateFieldType.String),
16
},
17
typeof(WixBundleRollbackBoundarySymbol));
18
}
@@ -23,6 +24,7 @@ namespace WixToolset.Data.Symbols
24
{
25
Vital,
26
Transaction,
27
+ LogPathVariable,
28
}
29
30
public class WixBundleRollbackBoundarySymbol : IntermediateSymbol
@@ -48,5 +50,11 @@ namespace WixToolset.Data.Symbols
50
get => (bool?)this.Fields[(int)WixBundleRollbackBoundarySymbolFields.Transaction];
51
set => this.Set((int)WixBundleRollbackBoundarySymbolFields.Transaction, value);
52
}
53
+
54
+ public string LogPathVariable
55
+ {
56
+ get => (string)this.Fields[(int)WixBundleRollbackBoundarySymbolFields.LogPathVariable];
57
+ set => this.Set((int)WixBundleRollbackBoundarySymbolFields.LogPathVariable, value);
58
+ }
59
}
60
}
\ No newline at end of file
src/burn/engine/elevation.cpp
+12
-3
@@ -3246,7 +3246,10 @@ static HRESULT OnMsiBeginTransaction(
3246
hr = PackageFindRollbackBoundaryById(pPackages, sczId, &pRollbackBoundary);
3247
ExitOnFailure(hr, "Failed to find rollback boundary: %ls", sczId);
3248
3249
- pRollbackBoundary->sczLogPath = sczLogPath;
3249
+ if (sczLogPath && *sczLogPath)
3250
+ {
3251
+ pRollbackBoundary->sczLogPath = sczLogPath;
3252
+ }
3253
3254
hr = MsiEngineBeginTransaction(pRollbackBoundary);
3255
@@ -3284,7 +3287,10 @@ static HRESULT OnMsiCommitTransaction(
3287
hr = PackageFindRollbackBoundaryById(pPackages, sczId, &pRollbackBoundary);
3288
ExitOnFailure(hr, "Failed to find rollback boundary: %ls", sczId);
3289
3287
- pRollbackBoundary->sczLogPath = sczLogPath;
3290
+ if (sczLogPath && *sczLogPath)
3291
+ {
3292
+ pRollbackBoundary->sczLogPath = sczLogPath;
3293
+ }
3294
3295
hr = MsiEngineCommitTransaction(pRollbackBoundary);
3296
@@ -3322,7 +3328,10 @@ static HRESULT OnMsiRollbackTransaction(
3328
hr = PackageFindRollbackBoundaryById(pPackages, sczId, &pRollbackBoundary);
3329
ExitOnFailure(hr, "Failed to find rollback boundary: %ls", sczId);
3330
3325
- pRollbackBoundary->sczLogPath = sczLogPath;
3331
+ if (sczLogPath && *sczLogPath)
3332
+ {
3333
+ pRollbackBoundary->sczLogPath = sczLogPath;
3334
+ }
3335
3336
hr = MsiEngineRollbackTransaction(pRollbackBoundary);
3337
src/burn/engine/logging.cpp
+30
-5
@@ -242,11 +242,6 @@ extern "C" HRESULT LoggingSetPackageVariable(
242
// Make sure that no package log files are created when logging has been disabled via Log element.
243
if (BURN_LOGGING_STATE_DISABLED == pLog->state)
244
{
245
- if (psczLogPath)
246
- {
247
- *psczLogPath = NULL;
248
- }
249
-
245
ExitFunction();
246
}
247
@@ -272,6 +267,36 @@ LExit:
267
return hr;
268
}
269
270
+extern "C" HRESULT LoggingSetTransactionVariable(
271
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
272
+ __in_z_opt LPCWSTR wzSuffix,
273
+ __in BURN_LOGGING* pLog,
274
+ __in BURN_VARIABLES* pVariables
275
+ )
276
+{
277
+ HRESULT hr = S_OK;
278
+
279
+ // Make sure that no log files are created when logging has been disabled via Log element.
280
+ if (BURN_LOGGING_STATE_DISABLED == pLog->state)
281
+ {
282
+ ExitFunction();
283
+ }
284
+
285
+ if (pRollbackBoundary && pRollbackBoundary->sczLogPathVariable && *pRollbackBoundary->sczLogPathVariable)
286
+ {
287
+ hr = StrAllocFormatted(&pRollbackBoundary->sczLogPath, L"%ls%hs%ls_%03u_%ls.%ls", pLog->sczPrefix, wzSuffix && *wzSuffix ? "_" : "", wzSuffix && *wzSuffix ? wzSuffix : L"", vdwPackageSequence, pRollbackBoundary->sczId, pLog->sczExtension);
288
+ ExitOnFailure(hr, "Failed to allocate path for transaction log.");
289
+
290
+ hr = VariableSetString(pVariables, pRollbackBoundary->sczLogPathVariable, pRollbackBoundary->sczLogPath, FALSE, FALSE);
291
+ ExitOnFailure(hr, "Failed to set log path into variable.");
292
+ }
293
+
294
+LExit:
295
+ ++vdwPackageSequence;
296
+
297
+ return hr;
298
+}
299
+
300
extern "C" LPCSTR LoggingBurnActionToString(
301
__in BOOTSTRAPPER_ACTION action
302
)
src/burn/engine/logging.h
+7
@@ -62,6 +62,13 @@ HRESULT LoggingSetPackageVariable(
62
__out_opt LPWSTR* psczLogPath
63
);
64
65
+HRESULT LoggingSetTransactionVariable(
66
+ __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary,
67
+ __in_z_opt LPCWSTR wzSuffix,
68
+ __in BURN_LOGGING* pLog,
69
+ __in BURN_VARIABLES* pVariables
70
+ );
71
+
72
LPCSTR LoggingBurnActionToString(
73
__in BOOTSTRAPPER_ACTION action
74
);
src/burn/engine/package.cpp
+30
-32
@@ -36,6 +36,7 @@ extern "C" HRESULT PackagesParseFromXml(
36
BSTR bstrNodeName = NULL;
37
DWORD cMspPackages = 0;
38
LPWSTR scz = NULL;
39
+ BOOL fFoundXml = FALSE;
40
41
// select rollback boundary nodes
42
hr = XmlSelectNodes(pixnBundle, L"RollbackBoundary", &pixnNodes);
@@ -63,15 +64,19 @@ extern "C" HRESULT PackagesParseFromXml(
64
65
// @Id
66
hr = XmlGetAttributeEx(pixnNode, L"Id", &pRollbackBoundary->sczId);
66
- ExitOnFailure(hr, "Failed to get @Id.");
67
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Id.");
68
69
// @Vital
70
hr = XmlGetYesNoAttribute(pixnNode, L"Vital", &pRollbackBoundary->fVital);
70
- ExitOnFailure(hr, "Failed to get @Vital.");
71
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Vital.");
72
73
// @Transaction
74
hr = XmlGetYesNoAttribute(pixnNode, L"Transaction", &pRollbackBoundary->fTransactionAuthored);
74
- ExitOnFailure(hr, "Failed to get @Transaction.");
75
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Transaction.");
76
+
77
+ // @LogPathVariable
78
+ hr = XmlGetAttributeEx(pixnNode, L"LogPathVariable", &pRollbackBoundary->sczLogPathVariable);
79
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @LogPathVariable.");
80
81
// prepare next iteration
82
ReleaseNullObject(pixnNode);
@@ -110,11 +115,13 @@ extern "C" HRESULT PackagesParseFromXml(
115
116
// @Id
117
hr = XmlGetAttributeEx(pixnNode, L"Id", &pPackage->sczId);
113
- ExitOnFailure(hr, "Failed to get @Id.");
118
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Id.");
119
120
// @Cache
121
hr = XmlGetAttributeEx(pixnNode, L"Cache", &scz);
117
- if (SUCCEEDED(hr))
122
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Cache.");
123
+
124
+ if (fFoundXml)
125
{
126
if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"remove", -1))
127
{
@@ -134,72 +141,62 @@ extern "C" HRESULT PackagesParseFromXml(
141
ExitOnRootFailure(hr, "Invalid cache type: %ls", scz);
142
}
143
}
137
- ExitOnFailure(hr, "Failed to get @Cache.");
144
145
// @CacheId
146
hr = XmlGetAttributeEx(pixnNode, L"CacheId", &pPackage->sczCacheId);
141
- ExitOnFailure(hr, "Failed to get @CacheId.");
147
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @CacheId.");
148
149
// @Size
150
hr = XmlGetAttributeUInt64(pixnNode, L"Size", &pPackage->qwSize);
145
- ExitOnFailure(hr, "Failed to get @Size.");
151
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Size.");
152
153
// @InstallSize
154
hr = XmlGetAttributeUInt64(pixnNode, L"InstallSize", &pPackage->qwInstallSize);
149
- ExitOnFailure(hr, "Failed to get @InstallSize.");
155
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallSize.");
156
157
// @PerMachine
158
hr = XmlGetYesNoAttribute(pixnNode, L"PerMachine", &pPackage->fPerMachine);
153
- ExitOnFailure(hr, "Failed to get @PerMachine.");
159
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @PerMachine.");
160
161
// @Permanent
162
hr = XmlGetYesNoAttribute(pixnNode, L"Permanent", &pPackage->fUninstallable);
157
- ExitOnFailure(hr, "Failed to get @Permanent.");
163
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Permanent.");
164
pPackage->fUninstallable = !pPackage->fUninstallable; // TODO: change "Uninstallable" variable name to permanent, until then Uninstallable is the opposite of Permanent so fix the variable.
165
pPackage->fCanAffectRegistration = pPackage->fUninstallable;
166
167
// @Vital
168
hr = XmlGetYesNoAttribute(pixnNode, L"Vital", &pPackage->fVital);
163
- ExitOnFailure(hr, "Failed to get @Vital.");
169
+ ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Vital.");
170
171
// @LogPathVariable
172
hr = XmlGetAttributeEx(pixnNode, L"LogPathVariable", &pPackage->sczLogPathVariable);
167
- if (E_NOTFOUND != hr)
168
- {
169
- ExitOnFailure(hr, "Failed to get @LogPathVariable.");
170
- }
173
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @LogPathVariable.");
174
175
// @RollbackLogPathVariable
176
hr = XmlGetAttributeEx(pixnNode, L"RollbackLogPathVariable", &pPackage->sczRollbackLogPathVariable);
174
- if (E_NOTFOUND != hr)
175
- {
176
- ExitOnFailure(hr, "Failed to get @RollbackLogPathVariable.");
177
- }
177
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RollbackLogPathVariable.");
178
179
// @InstallCondition
180
hr = XmlGetAttributeEx(pixnNode, L"InstallCondition", &pPackage->sczInstallCondition);
181
- if (E_NOTFOUND != hr)
182
- {
183
- ExitOnFailure(hr, "Failed to get @InstallCondition.");
184
- }
181
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallCondition.");
182
183
// @RollbackBoundaryForward
184
hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryForward", &scz);
188
- if (E_NOTFOUND != hr)
189
- {
190
- ExitOnFailure(hr, "Failed to get @RollbackBoundaryForward.");
185
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RollbackBoundaryForward.");
186
192
- hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryForward);
187
+ if (fFoundXml)
188
+ {
189
+ hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryForward);
190
ExitOnFailure(hr, "Failed to find forward transaction boundary: %ls", scz);
191
}
192
193
// @RollbackBoundaryBackward
194
hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryBackward", &scz);
198
- if (E_NOTFOUND != hr)
199
- {
200
- ExitOnFailure(hr, "Failed to get @RollbackBoundaryBackward.");
195
+ ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RollbackBoundaryBackward.");
196
202
- hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryBackward);
197
+ if (fFoundXml)
198
+ {
199
+ hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryBackward);
200
ExitOnFailure(hr, "Failed to find backward transaction boundary: %ls", scz);
201
}
202
@@ -378,6 +375,7 @@ extern "C" void PackagesUninitialize(
375
{
376
ReleaseStr(pPackages->rgRollbackBoundaries[i].sczId);
377
ReleaseStr(pPackages->rgRollbackBoundaries[i].sczLogPath);
378
+ ReleaseStr(pPackages->rgRollbackBoundaries[i].sczLogPathVariable);
379
}
380
MemFree(pPackages->rgRollbackBoundaries);
381
}
src/burn/engine/package.h
+1
@@ -195,6 +195,7 @@ typedef struct _BURN_ROLLBACK_BOUNDARY
195
BOOL fTransactionAuthored;
196
BOOL fTransaction;
197
BOOL fActiveTransaction; // only valid during Apply.
198
+ LPWSTR sczLogPathVariable;
199
LPWSTR sczLogPath;
200
} BURN_ROLLBACK_BOUNDARY;
201
src/burn/engine/plan.cpp
+4
-2
@@ -1709,8 +1709,8 @@ LExit:
1709
extern "C" HRESULT PlanRollbackBoundaryBegin(
1710
__in BURN_PLAN* pPlan,
1711
__in BURN_USER_EXPERIENCE* pUX,
1712
- __in BURN_LOGGING* /*pLog*/,
1713
- __in BURN_VARIABLES* /*pVariables*/,
1712
+ __in BURN_LOGGING* pLog,
1713
+ __in BURN_VARIABLES* pVariables,
1714
__in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary
1715
)
1716
{
@@ -1744,6 +1744,8 @@ extern "C" HRESULT PlanRollbackBoundaryBegin(
1744
}
1745
else
1746
{
1747
+ LoggingSetTransactionVariable(pRollbackBoundary, NULL, pLog, pVariables); // ignore errors.
1748
+
1749
// Add begin MSI transaction to execute plan.
1750
hr = PlanExecuteCheckpoint(pPlan);
1751
ExitOnFailure(hr, "Failed to append checkpoint before MSI transaction begin action.");
src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs
+1
-1
@@ -393,7 +393,7 @@ namespace WixToolset.Core.Burn
393
// Generate the core-defined BA manifest tables...
394
string baManifestPath;
395
{
396
- var command = new CreateBootstrapperApplicationManifestCommand(section, bundleSymbol, orderedFacades, uxPayloadIndex, payloadSymbols, packagesPayloads, this.IntermediateFolder, this.InternalBurnBackendHelper);
396
+ var command = new CreateBootstrapperApplicationManifestCommand(section, bundleSymbol, boundaries, orderedFacades, uxPayloadIndex, payloadSymbols, packagesPayloads, this.IntermediateFolder, this.InternalBurnBackendHelper);
397
command.Execute();
398
399
var baManifestPayload = command.BootstrapperApplicationManifestPayloadRow;
src/wix/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs
+24
-1
@@ -15,10 +15,11 @@ namespace WixToolset.Core.Burn.Bundles
15
16
internal class CreateBootstrapperApplicationManifestCommand
17
{
18
- public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable<PackageFacade> chainPackages, int lastUXPayloadIndex, Dictionary<string, WixBundlePayloadSymbol> payloadSymbols, Dictionary<string, Dictionary<string, WixBundlePayloadSymbol>> packagesPayloads, string intermediateFolder, IInternalBurnBackendHelper internalBurnBackendHelper)
18
+ public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable<WixBundleRollbackBoundarySymbol> boundaries, IEnumerable<PackageFacade> chainPackages, int lastUXPayloadIndex, Dictionary<string, WixBundlePayloadSymbol> payloadSymbols, Dictionary<string, Dictionary<string, WixBundlePayloadSymbol>> packagesPayloads, string intermediateFolder, IInternalBurnBackendHelper internalBurnBackendHelper)
19
{
20
this.Section = section;
21
this.BundleSymbol = bundleSymbol;
22
+ this.RollbackBoundaries = boundaries;
23
this.ChainPackages = chainPackages;
24
this.LastUXPayloadIndex = lastUXPayloadIndex;
25
this.Payloads = payloadSymbols;
@@ -31,6 +32,8 @@ namespace WixToolset.Core.Burn.Bundles
32
33
private WixBundleSymbol BundleSymbol { get; }
34
35
+ private IEnumerable<WixBundleRollbackBoundarySymbol> RollbackBoundaries { get; }
36
+
37
private IEnumerable<PackageFacade> ChainPackages { get; }
38
39
private IInternalBurnBackendHelper InternalBurnBackendHelper { get; }
@@ -70,6 +73,8 @@ namespace WixToolset.Core.Burn.Bundles
73
74
this.WriteCommandLineInfo(writer);
75
76
+ this.WriteRollbackBoundaryInfo(writer);
77
+
78
this.WritePackageInfo(writer);
79
80
this.WriteFeatureInfo(writer);
@@ -116,6 +121,24 @@ namespace WixToolset.Core.Burn.Bundles
121
writer.WriteEndElement();
122
}
123
124
+ private void WriteRollbackBoundaryInfo(XmlTextWriter writer)
125
+ {
126
+ foreach (var rollbackBoundary in this.RollbackBoundaries)
127
+ {
128
+ writer.WriteStartElement("WixRollbackBoundary");
129
+ writer.WriteAttributeString("Id", rollbackBoundary.Id.Id);
130
+ writer.WriteAttributeString("Vital", rollbackBoundary.Vital == false ? "no" : "yes");
131
+ writer.WriteAttributeString("Transaction", rollbackBoundary.Transaction == true ? "yes" : "no");
132
+
133
+ if (!String.IsNullOrEmpty(rollbackBoundary.LogPathVariable))
134
+ {
135
+ writer.WriteAttributeString("LogPathVariable", rollbackBoundary.LogPathVariable);
136
+ }
137
+
138
+ writer.WriteEndElement();
139
+ }
140
+ }
141
+
142
private void WritePackageInfo(XmlTextWriter writer)
143
{
144
foreach (var package in this.ChainPackages)
src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs
+6
@@ -188,6 +188,12 @@ namespace WixToolset.Core.Burn.Bundles
188
writer.WriteAttributeString("Id", rollbackBoundary.Id.Id);
189
writer.WriteAttributeString("Vital", rollbackBoundary.Vital == false ? "no" : "yes");
190
writer.WriteAttributeString("Transaction", rollbackBoundary.Transaction == true ? "yes" : "no");
191
+
192
+ if (!String.IsNullOrEmpty(rollbackBoundary.LogPathVariable))
193
+ {
194
+ writer.WriteAttributeString("LogPathVariable", rollbackBoundary.LogPathVariable);
195
+ }
196
+
197
writer.WriteEndElement();
198
}
199
src/wix/WixToolset.Core/Compiler_Bundle.cs
+24
-2
@@ -1860,6 +1860,7 @@ namespace WixToolset.Core
1860
Identifier id = null;
1861
var vital = YesNoType.Yes;
1862
var transaction = YesNoType.No;
1863
+ string logPathVariable = null;
1864
1865
// This list lets us evaluate extension attributes *after* all core attributes
1866
// have been parsed and dealt with, regardless of authoring order.
@@ -1885,6 +1886,9 @@ namespace WixToolset.Core
1886
case "Transaction":
1887
transaction = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib);
1888
break;
1889
+ case "LogPathVariable":
1890
+ logPathVariable = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty);
1891
+ break;
1892
default:
1893
allowed = false;
1894
break;
@@ -1932,9 +1936,21 @@ namespace WixToolset.Core
1936
1937
this.Core.ParseForExtensionElements(node);
1938
1939
+ if (transaction == YesNoType.Yes)
1940
+ {
1941
+ if (logPathVariable == null)
1942
+ {
1943
+ logPathVariable = String.Concat("WixBundleLog_", id.Id);
1944
+ }
1945
+ }
1946
+ else if (logPathVariable != null)
1947
+ {
1948
+ this.Core.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "LogPathVariable", logPathVariable, "Transaction"));
1949
+ }
1950
+
1951
if (!this.Core.EncounteredError)
1952
{
1937
- this.CreateRollbackBoundary(sourceLineNumbers, id, vital, transaction, parentType, parentId, previousType, previousId);
1953
+ this.CreateRollbackBoundary(sourceLineNumbers, id, vital, transaction, logPathVariable, parentType, parentId, previousType, previousId);
1954
}
1955
1956
return id.Id;
@@ -2759,11 +2775,12 @@ namespace WixToolset.Core
2775
/// <param name="id">Identifier for the rollback boundary.</param>
2776
/// <param name="vital">Indicates whether the rollback boundary is vital or not.</param>
2777
/// <param name="transaction">Indicates whether the rollback boundary will use an MSI transaction.</param>
2778
+ /// <param name="logPathVariable">The variable for the path of the MSI transaction log.</param>
2779
/// <param name="parentType">Type of parent group.</param>
2780
/// <param name="parentId">Identifier of parent group.</param>
2781
/// <param name="previousType">Type of previous item, if any.</param>
2782
/// <param name="previousId">Identifier of previous item, if any.</param>
2766
- private void CreateRollbackBoundary(SourceLineNumber sourceLineNumbers, Identifier id, YesNoType vital, YesNoType transaction, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId)
2783
+ private void CreateRollbackBoundary(SourceLineNumber sourceLineNumbers, Identifier id, YesNoType vital, YesNoType transaction, string logPathVariable, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId)
2784
{
2785
this.Core.AddSymbol(new WixChainItemSymbol(sourceLineNumbers, id));
2786
@@ -2777,6 +2794,11 @@ namespace WixToolset.Core
2794
if (YesNoType.NotSet != transaction)
2795
{
2796
rollbackBoundary.Transaction = (transaction == YesNoType.Yes);
2797
+
2798
+ if (logPathVariable != null)
2799
+ {
2800
+ rollbackBoundary.LogPathVariable = logPathVariable;
2801
+ }
2802
}
2803
2804
this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id.Id, previousType, previousId, null);
src/wix/test/WixToolsetTest.CoreIntegration/MsiTransactionFixture.cs
+11
@@ -2,6 +2,7 @@
2
3
namespace WixToolsetTest.CoreIntegration
4
{
5
+ using System.Collections.Generic;
6
using System.IO;
7
using WixBuildTools.TestSupport;
8
using WixToolset.Core.TestPackage;
@@ -50,6 +51,8 @@ namespace WixToolsetTest.CoreIntegration
51
var intermediateFolder = Path.Combine(baseFolder, "obj");
52
var binFolder = Path.Combine(baseFolder, "bin");
53
var exePath = Path.Combine(binFolder, "test.exe");
54
+ var baFolderPath = Path.Combine(baseFolder, "ba");
55
+ var extractFolderPath = Path.Combine(baseFolder, "extract");
56
57
BuildMsiPackages(folder, intermediateFolder, binFolder);
58
@@ -68,6 +71,14 @@ namespace WixToolsetTest.CoreIntegration
71
result.AssertSuccess();
72
73
Assert.True(File.Exists(exePath));
74
+
75
+ var extractResult = BundleExtractor.ExtractBAContainer(null, exePath, baFolderPath, extractFolderPath);
76
+ extractResult.AssertSuccess();
77
+
78
+ var rollbackBoundaries = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:RollbackBoundary");
79
+ Assert.Equal(2, rollbackBoundaries.Count);
80
+ Assert.Equal("<RollbackBoundary Id='WixDefaultBoundary' Vital='yes' Transaction='no' />", rollbackBoundaries[0].GetTestXml());
81
+ Assert.Equal("<RollbackBoundary Id='rba31DvS6_ninGllmavuS.cp4RYckk' Vital='yes' Transaction='yes' LogPathVariable='WixBundleLog_rba31DvS6_ninGllmavuS.cp4RYckk' />", rollbackBoundaries[1].GetTestXml());
82
}
83
}
84