From bb18c9c4f0e6da640775b85ebda68b31f2b391ed Mon Sep 17 00:00:00 2001 From: Nir Bar Date: Thu, 12 Aug 2021 14:16:01 -0500 Subject: Set the log file path for MSI transactions. --- .../Symbols/WixBundleRollbackBoundarySymbol.cs | 8 +++ src/burn/engine/elevation.cpp | 15 ++++-- src/burn/engine/logging.cpp | 35 ++++++++++-- src/burn/engine/logging.h | 7 +++ src/burn/engine/package.cpp | 62 +++++++++++----------- src/burn/engine/package.h | 1 + src/burn/engine/plan.cpp | 6 ++- .../WixToolset.Core.Burn/Bind/BindBundleCommand.cs | 2 +- ...CreateBootstrapperApplicationManifestCommand.cs | 25 ++++++++- .../Bundles/CreateBurnManifestCommand.cs | 6 +++ src/wix/WixToolset.Core/Compiler_Bundle.cs | 26 ++++++++- .../MsiTransactionFixture.cs | 11 ++++ 12 files changed, 158 insertions(+), 46 deletions(-) (limited to 'src') diff --git a/src/api/wix/WixToolset.Data/Symbols/WixBundleRollbackBoundarySymbol.cs b/src/api/wix/WixToolset.Data/Symbols/WixBundleRollbackBoundarySymbol.cs index e54e898e..1f91cef2 100644 --- a/src/api/wix/WixToolset.Data/Symbols/WixBundleRollbackBoundarySymbol.cs +++ b/src/api/wix/WixToolset.Data/Symbols/WixBundleRollbackBoundarySymbol.cs @@ -12,6 +12,7 @@ namespace WixToolset.Data { new IntermediateFieldDefinition(nameof(WixBundleRollbackBoundarySymbolFields.Vital), IntermediateFieldType.Number), new IntermediateFieldDefinition(nameof(WixBundleRollbackBoundarySymbolFields.Transaction), IntermediateFieldType.Number), + new IntermediateFieldDefinition(nameof(WixBundlePackageSymbolFields.LogPathVariable), IntermediateFieldType.String), }, typeof(WixBundleRollbackBoundarySymbol)); } @@ -23,6 +24,7 @@ namespace WixToolset.Data.Symbols { Vital, Transaction, + LogPathVariable, } public class WixBundleRollbackBoundarySymbol : IntermediateSymbol @@ -48,5 +50,11 @@ namespace WixToolset.Data.Symbols get => (bool?)this.Fields[(int)WixBundleRollbackBoundarySymbolFields.Transaction]; set => this.Set((int)WixBundleRollbackBoundarySymbolFields.Transaction, value); } + + public string LogPathVariable + { + get => (string)this.Fields[(int)WixBundleRollbackBoundarySymbolFields.LogPathVariable]; + set => this.Set((int)WixBundleRollbackBoundarySymbolFields.LogPathVariable, value); + } } } \ No newline at end of file diff --git a/src/burn/engine/elevation.cpp b/src/burn/engine/elevation.cpp index 0e1cf0b7..ba6b1dd3 100644 --- a/src/burn/engine/elevation.cpp +++ b/src/burn/engine/elevation.cpp @@ -3246,7 +3246,10 @@ static HRESULT OnMsiBeginTransaction( hr = PackageFindRollbackBoundaryById(pPackages, sczId, &pRollbackBoundary); ExitOnFailure(hr, "Failed to find rollback boundary: %ls", sczId); - pRollbackBoundary->sczLogPath = sczLogPath; + if (sczLogPath && *sczLogPath) + { + pRollbackBoundary->sczLogPath = sczLogPath; + } hr = MsiEngineBeginTransaction(pRollbackBoundary); @@ -3284,7 +3287,10 @@ static HRESULT OnMsiCommitTransaction( hr = PackageFindRollbackBoundaryById(pPackages, sczId, &pRollbackBoundary); ExitOnFailure(hr, "Failed to find rollback boundary: %ls", sczId); - pRollbackBoundary->sczLogPath = sczLogPath; + if (sczLogPath && *sczLogPath) + { + pRollbackBoundary->sczLogPath = sczLogPath; + } hr = MsiEngineCommitTransaction(pRollbackBoundary); @@ -3322,7 +3328,10 @@ static HRESULT OnMsiRollbackTransaction( hr = PackageFindRollbackBoundaryById(pPackages, sczId, &pRollbackBoundary); ExitOnFailure(hr, "Failed to find rollback boundary: %ls", sczId); - pRollbackBoundary->sczLogPath = sczLogPath; + if (sczLogPath && *sczLogPath) + { + pRollbackBoundary->sczLogPath = sczLogPath; + } hr = MsiEngineRollbackTransaction(pRollbackBoundary); diff --git a/src/burn/engine/logging.cpp b/src/burn/engine/logging.cpp index 9aaf60ed..33295acd 100644 --- a/src/burn/engine/logging.cpp +++ b/src/burn/engine/logging.cpp @@ -242,11 +242,6 @@ extern "C" HRESULT LoggingSetPackageVariable( // Make sure that no package log files are created when logging has been disabled via Log element. if (BURN_LOGGING_STATE_DISABLED == pLog->state) { - if (psczLogPath) - { - *psczLogPath = NULL; - } - ExitFunction(); } @@ -272,6 +267,36 @@ LExit: return hr; } +extern "C" HRESULT LoggingSetTransactionVariable( + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary, + __in_z_opt LPCWSTR wzSuffix, + __in BURN_LOGGING* pLog, + __in BURN_VARIABLES* pVariables + ) +{ + HRESULT hr = S_OK; + + // Make sure that no log files are created when logging has been disabled via Log element. + if (BURN_LOGGING_STATE_DISABLED == pLog->state) + { + ExitFunction(); + } + + if (pRollbackBoundary && pRollbackBoundary->sczLogPathVariable && *pRollbackBoundary->sczLogPathVariable) + { + hr = StrAllocFormatted(&pRollbackBoundary->sczLogPath, L"%ls%hs%ls_%03u_%ls.%ls", pLog->sczPrefix, wzSuffix && *wzSuffix ? "_" : "", wzSuffix && *wzSuffix ? wzSuffix : L"", vdwPackageSequence, pRollbackBoundary->sczId, pLog->sczExtension); + ExitOnFailure(hr, "Failed to allocate path for transaction log."); + + hr = VariableSetString(pVariables, pRollbackBoundary->sczLogPathVariable, pRollbackBoundary->sczLogPath, FALSE, FALSE); + ExitOnFailure(hr, "Failed to set log path into variable."); + } + +LExit: + ++vdwPackageSequence; + + return hr; +} + extern "C" LPCSTR LoggingBurnActionToString( __in BOOTSTRAPPER_ACTION action ) diff --git a/src/burn/engine/logging.h b/src/burn/engine/logging.h index 492e14b6..367b94a3 100644 --- a/src/burn/engine/logging.h +++ b/src/burn/engine/logging.h @@ -62,6 +62,13 @@ HRESULT LoggingSetPackageVariable( __out_opt LPWSTR* psczLogPath ); +HRESULT LoggingSetTransactionVariable( + __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary, + __in_z_opt LPCWSTR wzSuffix, + __in BURN_LOGGING* pLog, + __in BURN_VARIABLES* pVariables + ); + LPCSTR LoggingBurnActionToString( __in BOOTSTRAPPER_ACTION action ); diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp index cd871bc5..bea48cb5 100644 --- a/src/burn/engine/package.cpp +++ b/src/burn/engine/package.cpp @@ -36,6 +36,7 @@ extern "C" HRESULT PackagesParseFromXml( BSTR bstrNodeName = NULL; DWORD cMspPackages = 0; LPWSTR scz = NULL; + BOOL fFoundXml = FALSE; // select rollback boundary nodes hr = XmlSelectNodes(pixnBundle, L"RollbackBoundary", &pixnNodes); @@ -63,15 +64,19 @@ extern "C" HRESULT PackagesParseFromXml( // @Id hr = XmlGetAttributeEx(pixnNode, L"Id", &pRollbackBoundary->sczId); - ExitOnFailure(hr, "Failed to get @Id."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Id."); // @Vital hr = XmlGetYesNoAttribute(pixnNode, L"Vital", &pRollbackBoundary->fVital); - ExitOnFailure(hr, "Failed to get @Vital."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Vital."); // @Transaction hr = XmlGetYesNoAttribute(pixnNode, L"Transaction", &pRollbackBoundary->fTransactionAuthored); - ExitOnFailure(hr, "Failed to get @Transaction."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Transaction."); + + // @LogPathVariable + hr = XmlGetAttributeEx(pixnNode, L"LogPathVariable", &pRollbackBoundary->sczLogPathVariable); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @LogPathVariable."); // prepare next iteration ReleaseNullObject(pixnNode); @@ -110,11 +115,13 @@ extern "C" HRESULT PackagesParseFromXml( // @Id hr = XmlGetAttributeEx(pixnNode, L"Id", &pPackage->sczId); - ExitOnFailure(hr, "Failed to get @Id."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Id."); // @Cache hr = XmlGetAttributeEx(pixnNode, L"Cache", &scz); - if (SUCCEEDED(hr)) + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Cache."); + + if (fFoundXml) { if (CSTR_EQUAL == ::CompareStringW(LOCALE_INVARIANT, 0, scz, -1, L"remove", -1)) { @@ -134,72 +141,62 @@ extern "C" HRESULT PackagesParseFromXml( ExitOnRootFailure(hr, "Invalid cache type: %ls", scz); } } - ExitOnFailure(hr, "Failed to get @Cache."); // @CacheId hr = XmlGetAttributeEx(pixnNode, L"CacheId", &pPackage->sczCacheId); - ExitOnFailure(hr, "Failed to get @CacheId."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @CacheId."); // @Size hr = XmlGetAttributeUInt64(pixnNode, L"Size", &pPackage->qwSize); - ExitOnFailure(hr, "Failed to get @Size."); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @Size."); // @InstallSize hr = XmlGetAttributeUInt64(pixnNode, L"InstallSize", &pPackage->qwInstallSize); - ExitOnFailure(hr, "Failed to get @InstallSize."); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallSize."); // @PerMachine hr = XmlGetYesNoAttribute(pixnNode, L"PerMachine", &pPackage->fPerMachine); - ExitOnFailure(hr, "Failed to get @PerMachine."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @PerMachine."); // @Permanent hr = XmlGetYesNoAttribute(pixnNode, L"Permanent", &pPackage->fUninstallable); - ExitOnFailure(hr, "Failed to get @Permanent."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Permanent."); pPackage->fUninstallable = !pPackage->fUninstallable; // TODO: change "Uninstallable" variable name to permanent, until then Uninstallable is the opposite of Permanent so fix the variable. pPackage->fCanAffectRegistration = pPackage->fUninstallable; // @Vital hr = XmlGetYesNoAttribute(pixnNode, L"Vital", &pPackage->fVital); - ExitOnFailure(hr, "Failed to get @Vital."); + ExitOnRequiredXmlQueryFailure(hr, "Failed to get @Vital."); // @LogPathVariable hr = XmlGetAttributeEx(pixnNode, L"LogPathVariable", &pPackage->sczLogPathVariable); - if (E_NOTFOUND != hr) - { - ExitOnFailure(hr, "Failed to get @LogPathVariable."); - } + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @LogPathVariable."); // @RollbackLogPathVariable hr = XmlGetAttributeEx(pixnNode, L"RollbackLogPathVariable", &pPackage->sczRollbackLogPathVariable); - if (E_NOTFOUND != hr) - { - ExitOnFailure(hr, "Failed to get @RollbackLogPathVariable."); - } + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RollbackLogPathVariable."); // @InstallCondition hr = XmlGetAttributeEx(pixnNode, L"InstallCondition", &pPackage->sczInstallCondition); - if (E_NOTFOUND != hr) - { - ExitOnFailure(hr, "Failed to get @InstallCondition."); - } + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallCondition."); // @RollbackBoundaryForward hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryForward", &scz); - if (E_NOTFOUND != hr) - { - ExitOnFailure(hr, "Failed to get @RollbackBoundaryForward."); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RollbackBoundaryForward."); - hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryForward); + if (fFoundXml) + { + hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryForward); ExitOnFailure(hr, "Failed to find forward transaction boundary: %ls", scz); } // @RollbackBoundaryBackward hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryBackward", &scz); - if (E_NOTFOUND != hr) - { - ExitOnFailure(hr, "Failed to get @RollbackBoundaryBackward."); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RollbackBoundaryBackward."); - hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryBackward); + if (fFoundXml) + { + hr = FindRollbackBoundaryById(pPackages, scz, &pPackage->pRollbackBoundaryBackward); ExitOnFailure(hr, "Failed to find backward transaction boundary: %ls", scz); } @@ -378,6 +375,7 @@ extern "C" void PackagesUninitialize( { ReleaseStr(pPackages->rgRollbackBoundaries[i].sczId); ReleaseStr(pPackages->rgRollbackBoundaries[i].sczLogPath); + ReleaseStr(pPackages->rgRollbackBoundaries[i].sczLogPathVariable); } MemFree(pPackages->rgRollbackBoundaries); } diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index 3d8233d1..f2a1c304 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -195,6 +195,7 @@ typedef struct _BURN_ROLLBACK_BOUNDARY BOOL fTransactionAuthored; BOOL fTransaction; BOOL fActiveTransaction; // only valid during Apply. + LPWSTR sczLogPathVariable; LPWSTR sczLogPath; } BURN_ROLLBACK_BOUNDARY; diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index 85d958a6..58981352 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -1709,8 +1709,8 @@ LExit: extern "C" HRESULT PlanRollbackBoundaryBegin( __in BURN_PLAN* pPlan, __in BURN_USER_EXPERIENCE* pUX, - __in BURN_LOGGING* /*pLog*/, - __in BURN_VARIABLES* /*pVariables*/, + __in BURN_LOGGING* pLog, + __in BURN_VARIABLES* pVariables, __in BURN_ROLLBACK_BOUNDARY* pRollbackBoundary ) { @@ -1744,6 +1744,8 @@ extern "C" HRESULT PlanRollbackBoundaryBegin( } else { + LoggingSetTransactionVariable(pRollbackBoundary, NULL, pLog, pVariables); // ignore errors. + // Add begin MSI transaction to execute plan. hr = PlanExecuteCheckpoint(pPlan); ExitOnFailure(hr, "Failed to append checkpoint before MSI transaction begin action."); diff --git a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs index 97007022..cd00232a 100644 --- a/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bind/BindBundleCommand.cs @@ -393,7 +393,7 @@ namespace WixToolset.Core.Burn // Generate the core-defined BA manifest tables... string baManifestPath; { - var command = new CreateBootstrapperApplicationManifestCommand(section, bundleSymbol, orderedFacades, uxPayloadIndex, payloadSymbols, packagesPayloads, this.IntermediateFolder, this.InternalBurnBackendHelper); + var command = new CreateBootstrapperApplicationManifestCommand(section, bundleSymbol, boundaries, orderedFacades, uxPayloadIndex, payloadSymbols, packagesPayloads, this.IntermediateFolder, this.InternalBurnBackendHelper); command.Execute(); var baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs index 764a38ab..42e3381a 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBootstrapperApplicationManifestCommand.cs @@ -15,10 +15,11 @@ namespace WixToolset.Core.Burn.Bundles internal class CreateBootstrapperApplicationManifestCommand { - public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable chainPackages, int lastUXPayloadIndex, Dictionary payloadSymbols, Dictionary> packagesPayloads, string intermediateFolder, IInternalBurnBackendHelper internalBurnBackendHelper) + public CreateBootstrapperApplicationManifestCommand(IntermediateSection section, WixBundleSymbol bundleSymbol, IEnumerable boundaries, IEnumerable chainPackages, int lastUXPayloadIndex, Dictionary payloadSymbols, Dictionary> packagesPayloads, string intermediateFolder, IInternalBurnBackendHelper internalBurnBackendHelper) { this.Section = section; this.BundleSymbol = bundleSymbol; + this.RollbackBoundaries = boundaries; this.ChainPackages = chainPackages; this.LastUXPayloadIndex = lastUXPayloadIndex; this.Payloads = payloadSymbols; @@ -31,6 +32,8 @@ namespace WixToolset.Core.Burn.Bundles private WixBundleSymbol BundleSymbol { get; } + private IEnumerable RollbackBoundaries { get; } + private IEnumerable ChainPackages { get; } private IInternalBurnBackendHelper InternalBurnBackendHelper { get; } @@ -70,6 +73,8 @@ namespace WixToolset.Core.Burn.Bundles this.WriteCommandLineInfo(writer); + this.WriteRollbackBoundaryInfo(writer); + this.WritePackageInfo(writer); this.WriteFeatureInfo(writer); @@ -116,6 +121,24 @@ namespace WixToolset.Core.Burn.Bundles writer.WriteEndElement(); } + private void WriteRollbackBoundaryInfo(XmlTextWriter writer) + { + foreach (var rollbackBoundary in this.RollbackBoundaries) + { + writer.WriteStartElement("WixRollbackBoundary"); + writer.WriteAttributeString("Id", rollbackBoundary.Id.Id); + writer.WriteAttributeString("Vital", rollbackBoundary.Vital == false ? "no" : "yes"); + writer.WriteAttributeString("Transaction", rollbackBoundary.Transaction == true ? "yes" : "no"); + + if (!String.IsNullOrEmpty(rollbackBoundary.LogPathVariable)) + { + writer.WriteAttributeString("LogPathVariable", rollbackBoundary.LogPathVariable); + } + + writer.WriteEndElement(); + } + } + private void WritePackageInfo(XmlTextWriter writer) { foreach (var package in this.ChainPackages) diff --git a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs index 27b1f234..19dc7933 100644 --- a/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs +++ b/src/wix/WixToolset.Core.Burn/Bundles/CreateBurnManifestCommand.cs @@ -188,6 +188,12 @@ namespace WixToolset.Core.Burn.Bundles writer.WriteAttributeString("Id", rollbackBoundary.Id.Id); writer.WriteAttributeString("Vital", rollbackBoundary.Vital == false ? "no" : "yes"); writer.WriteAttributeString("Transaction", rollbackBoundary.Transaction == true ? "yes" : "no"); + + if (!String.IsNullOrEmpty(rollbackBoundary.LogPathVariable)) + { + writer.WriteAttributeString("LogPathVariable", rollbackBoundary.LogPathVariable); + } + writer.WriteEndElement(); } diff --git a/src/wix/WixToolset.Core/Compiler_Bundle.cs b/src/wix/WixToolset.Core/Compiler_Bundle.cs index 20af017d..851561d1 100644 --- a/src/wix/WixToolset.Core/Compiler_Bundle.cs +++ b/src/wix/WixToolset.Core/Compiler_Bundle.cs @@ -1860,6 +1860,7 @@ namespace WixToolset.Core Identifier id = null; var vital = YesNoType.Yes; var transaction = YesNoType.No; + string logPathVariable = null; // This list lets us evaluate extension attributes *after* all core attributes // have been parsed and dealt with, regardless of authoring order. @@ -1885,6 +1886,9 @@ namespace WixToolset.Core case "Transaction": transaction = this.Core.GetAttributeYesNoValue(sourceLineNumbers, attrib); break; + case "LogPathVariable": + logPathVariable = this.Core.GetAttributeValue(sourceLineNumbers, attrib, EmptyRule.CanBeEmpty); + break; default: allowed = false; break; @@ -1932,9 +1936,21 @@ namespace WixToolset.Core this.Core.ParseForExtensionElements(node); + if (transaction == YesNoType.Yes) + { + if (logPathVariable == null) + { + logPathVariable = String.Concat("WixBundleLog_", id.Id); + } + } + else if (logPathVariable != null) + { + this.Core.Write(ErrorMessages.IllegalAttributeValueWithoutOtherAttribute(sourceLineNumbers, node.Name.LocalName, "LogPathVariable", logPathVariable, "Transaction")); + } + if (!this.Core.EncounteredError) { - this.CreateRollbackBoundary(sourceLineNumbers, id, vital, transaction, parentType, parentId, previousType, previousId); + this.CreateRollbackBoundary(sourceLineNumbers, id, vital, transaction, logPathVariable, parentType, parentId, previousType, previousId); } return id.Id; @@ -2759,11 +2775,12 @@ namespace WixToolset.Core /// Identifier for the rollback boundary. /// Indicates whether the rollback boundary is vital or not. /// Indicates whether the rollback boundary will use an MSI transaction. + /// The variable for the path of the MSI transaction log. /// Type of parent group. /// Identifier of parent group. /// Type of previous item, if any. /// Identifier of previous item, if any. - private void CreateRollbackBoundary(SourceLineNumber sourceLineNumbers, Identifier id, YesNoType vital, YesNoType transaction, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) + private void CreateRollbackBoundary(SourceLineNumber sourceLineNumbers, Identifier id, YesNoType vital, YesNoType transaction, string logPathVariable, ComplexReferenceParentType parentType, string parentId, ComplexReferenceChildType previousType, string previousId) { this.Core.AddSymbol(new WixChainItemSymbol(sourceLineNumbers, id)); @@ -2777,6 +2794,11 @@ namespace WixToolset.Core if (YesNoType.NotSet != transaction) { rollbackBoundary.Transaction = (transaction == YesNoType.Yes); + + if (logPathVariable != null) + { + rollbackBoundary.LogPathVariable = logPathVariable; + } } this.CreateChainPackageMetaRows(sourceLineNumbers, parentType, parentId, ComplexReferenceChildType.Package, id.Id, previousType, previousId, null); diff --git a/src/wix/test/WixToolsetTest.CoreIntegration/MsiTransactionFixture.cs b/src/wix/test/WixToolsetTest.CoreIntegration/MsiTransactionFixture.cs index a566b490..573ae4b4 100644 --- a/src/wix/test/WixToolsetTest.CoreIntegration/MsiTransactionFixture.cs +++ b/src/wix/test/WixToolsetTest.CoreIntegration/MsiTransactionFixture.cs @@ -2,6 +2,7 @@ namespace WixToolsetTest.CoreIntegration { + using System.Collections.Generic; using System.IO; using WixBuildTools.TestSupport; using WixToolset.Core.TestPackage; @@ -50,6 +51,8 @@ namespace WixToolsetTest.CoreIntegration var intermediateFolder = Path.Combine(baseFolder, "obj"); var binFolder = Path.Combine(baseFolder, "bin"); var exePath = Path.Combine(binFolder, "test.exe"); + var baFolderPath = Path.Combine(baseFolder, "ba"); + var extractFolderPath = Path.Combine(baseFolder, "extract"); BuildMsiPackages(folder, intermediateFolder, binFolder); @@ -68,6 +71,14 @@ namespace WixToolsetTest.CoreIntegration result.AssertSuccess(); Assert.True(File.Exists(exePath)); + + var extractResult = BundleExtractor.ExtractBAContainer(null, exePath, baFolderPath, extractFolderPath); + extractResult.AssertSuccess(); + + var rollbackBoundaries = extractResult.SelectManifestNodes("/burn:BurnManifest/burn:RollbackBoundary"); + Assert.Equal(2, rollbackBoundaries.Count); + Assert.Equal("", rollbackBoundaries[0].GetTestXml()); + Assert.Equal("", rollbackBoundaries[1].GetTestXml()); } } -- cgit v1.2.3-55-g6feb