@joebigelow / wix-1 / commits / bb18c9c4

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