From 72e20f682c0d64102e86439ba5527dd0d71932ae Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Fri, 22 Apr 2022 16:55:29 -0500 Subject: Add RepairCondition. Fixes 6758 --- src/burn/engine/package.cpp | 5 ++ src/burn/engine/package.h | 1 + src/burn/engine/plan.cpp | 24 ++++-- src/burn/engine/plan.h | 1 + src/burn/engine/userexperience.cpp | 2 + src/burn/engine/userexperience.h | 1 + src/burn/test/BurnUnitTest/PlanTest.cpp | 95 ++++++++++++++++++++++ .../PlanTest/BundlePackage_Multiple_manifest.xml | 2 +- src/burn/test/BurnUnitTest/VariableTest.cpp | 1 + 9 files changed, 126 insertions(+), 6 deletions(-) (limited to 'src/burn') diff --git a/src/burn/engine/package.cpp b/src/burn/engine/package.cpp index 89203ada..88e7cb9d 100644 --- a/src/burn/engine/package.cpp +++ b/src/burn/engine/package.cpp @@ -178,6 +178,10 @@ extern "C" HRESULT PackagesParseFromXml( hr = XmlGetAttributeEx(pixnNode, L"InstallCondition", &pPackage->sczInstallCondition); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @InstallCondition."); + // @RepairCondition + hr = XmlGetAttributeEx(pixnNode, L"RepairCondition", &pPackage->sczRepairCondition); + ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RepairCondition."); + // @RollbackBoundaryForward hr = XmlGetAttributeEx(pixnNode, L"RollbackBoundaryForward", &scz); ExitOnOptionalXmlQueryFailure(hr, fFoundXml, "Failed to get @RollbackBoundaryForward."); @@ -362,6 +366,7 @@ extern "C" void PackageUninitialize( ReleaseStr(pPackage->sczLogPathVariable); ReleaseStr(pPackage->sczRollbackLogPathVariable); ReleaseStr(pPackage->sczInstallCondition); + ReleaseStr(pPackage->sczRepairCondition); ReleaseStr(pPackage->sczCacheId); if (pPackage->rgDependencyProviders) diff --git a/src/burn/engine/package.h b/src/burn/engine/package.h index eb8e7543..3ec77baf 100644 --- a/src/burn/engine/package.h +++ b/src/burn/engine/package.h @@ -250,6 +250,7 @@ typedef struct _BURN_PACKAGE LPWSTR sczRollbackLogPathVariable; // name of the variable that will be set to the rollback path. LPWSTR sczInstallCondition; + LPWSTR sczRepairCondition; BOOL fPerMachine; BOOL fPermanent; BOOL fVital; diff --git a/src/burn/engine/plan.cpp b/src/burn/engine/plan.cpp index 2c267415..47da22c0 100644 --- a/src/burn/engine/plan.cpp +++ b/src/burn/engine/plan.cpp @@ -347,6 +347,7 @@ extern "C" HRESULT PlanDefaultPackageRequestState( __in BOOTSTRAPPER_PACKAGE_STATE currentState, __in BOOTSTRAPPER_ACTION action, __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition, + __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition, __in BOOTSTRAPPER_RELATION_TYPE relationType, __out BOOTSTRAPPER_REQUEST_STATE* pRequestState ) @@ -408,6 +409,10 @@ extern "C" HRESULT PlanDefaultPackageRequestState( { defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT <= defaultRequestState ? BOOTSTRAPPER_REQUEST_STATE_NONE : defaultRequestState; } + else if (BOOTSTRAPPER_ACTION_REPAIR == action && BOOTSTRAPPER_PACKAGE_CONDITION_FALSE == repairCondition) + { + defaultRequestState = BOOTSTRAPPER_REQUEST_STATE_PRESENT; + } } *pRequestState = defaultRequestState; @@ -905,7 +910,8 @@ static HRESULT InitializePackage( { HRESULT hr = S_OK; BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition = BOOTSTRAPPER_PACKAGE_CONDITION_DEFAULT; - BOOL fInstallCondition = FALSE; + BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition = BOOTSTRAPPER_PACKAGE_CONDITION_DEFAULT; + BOOL fEvaluatedCondition = FALSE; BOOL fBeginCalled = FALSE; BOOTSTRAPPER_RELATION_TYPE relationType = pPlan->pCommand->relationType; @@ -927,20 +933,28 @@ static HRESULT InitializePackage( if (pPackage->sczInstallCondition && *pPackage->sczInstallCondition) { - hr = ConditionEvaluate(pVariables, pPackage->sczInstallCondition, &fInstallCondition); + hr = ConditionEvaluate(pVariables, pPackage->sczInstallCondition, &fEvaluatedCondition); ExitOnFailure(hr, "Failed to evaluate install condition."); - installCondition = fInstallCondition ? BOOTSTRAPPER_PACKAGE_CONDITION_TRUE : BOOTSTRAPPER_PACKAGE_CONDITION_FALSE; + installCondition = fEvaluatedCondition ? BOOTSTRAPPER_PACKAGE_CONDITION_TRUE : BOOTSTRAPPER_PACKAGE_CONDITION_FALSE; + } + + if (pPackage->sczRepairCondition && *pPackage->sczRepairCondition) + { + hr = ConditionEvaluate(pVariables, pPackage->sczRepairCondition, &fEvaluatedCondition); + ExitOnFailure(hr, "Failed to evaluate repair condition."); + + repairCondition = fEvaluatedCondition ? BOOTSTRAPPER_PACKAGE_CONDITION_TRUE : BOOTSTRAPPER_PACKAGE_CONDITION_FALSE; } // Remember the default requested state so the engine doesn't get blamed for planning the wrong thing if the BA changes it. - hr = PlanDefaultPackageRequestState(pPackage->type, pPackage->currentState, pPlan->action, installCondition, relationType, &pPackage->defaultRequested); + hr = PlanDefaultPackageRequestState(pPackage->type, pPackage->currentState, pPlan->action, installCondition, repairCondition, relationType, &pPackage->defaultRequested); ExitOnFailure(hr, "Failed to set default package state."); pPackage->requested = pPackage->defaultRequested; fBeginCalled = TRUE; - hr = UserExperienceOnPlanPackageBegin(pUX, pPackage->sczId, pPackage->currentState, pPackage->fCached, installCondition, &pPackage->requested, &pPackage->cacheType); + hr = UserExperienceOnPlanPackageBegin(pUX, pPackage->sczId, pPackage->currentState, pPackage->fCached, installCondition, repairCondition, &pPackage->requested, &pPackage->cacheType); ExitOnRootFailure(hr, "BA aborted plan package begin."); if (BURN_PACKAGE_TYPE_MSI == pPackage->type) diff --git a/src/burn/engine/plan.h b/src/burn/engine/plan.h index 87214cc8..fbb7a5a1 100644 --- a/src/burn/engine/plan.h +++ b/src/burn/engine/plan.h @@ -342,6 +342,7 @@ HRESULT PlanDefaultPackageRequestState( __in BOOTSTRAPPER_PACKAGE_STATE currentState, __in BOOTSTRAPPER_ACTION action, __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition, + __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition, __in BOOTSTRAPPER_RELATION_TYPE relationType, __out BOOTSTRAPPER_REQUEST_STATE* pRequestState ); diff --git a/src/burn/engine/userexperience.cpp b/src/burn/engine/userexperience.cpp index a1a010d2..a3cbcd4a 100644 --- a/src/burn/engine/userexperience.cpp +++ b/src/burn/engine/userexperience.cpp @@ -2169,6 +2169,7 @@ EXTERN_C BAAPI UserExperienceOnPlanPackageBegin( __in BOOTSTRAPPER_PACKAGE_STATE state, __in BOOL fCached, __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition, + __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition, __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState, __inout BOOTSTRAPPER_CACHE_TYPE* pRequestedCacheType ) @@ -2182,6 +2183,7 @@ EXTERN_C BAAPI UserExperienceOnPlanPackageBegin( args.state = state; args.fCached = fCached; args.installCondition = installCondition; + args.repairCondition = repairCondition; args.recommendedState = *pRequestedState; args.recommendedCacheType = *pRequestedCacheType; diff --git a/src/burn/engine/userexperience.h b/src/burn/engine/userexperience.h index 90a047ed..2059b521 100644 --- a/src/burn/engine/userexperience.h +++ b/src/burn/engine/userexperience.h @@ -501,6 +501,7 @@ BAAPI UserExperienceOnPlanPackageBegin( __in BOOTSTRAPPER_PACKAGE_STATE state, __in BOOL fCached, __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT installCondition, + __in BOOTSTRAPPER_PACKAGE_CONDITION_RESULT repairCondition, __inout BOOTSTRAPPER_REQUEST_STATE* pRequestedState, __inout BOOTSTRAPPER_CACHE_TYPE* pRequestedCacheType ); diff --git a/src/burn/test/BurnUnitTest/PlanTest.cpp b/src/burn/test/BurnUnitTest/PlanTest.cpp index 87bbbffd..f69606a0 100644 --- a/src/burn/test/BurnUnitTest/PlanTest.cpp +++ b/src/burn/test/BurnUnitTest/PlanTest.cpp @@ -458,6 +458,101 @@ namespace Bootstrapper ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageB", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); } + [Fact] + void MultipleBundlePackageRepairTest() + { + HRESULT hr = S_OK; + BURN_ENGINE_STATE engineState = { }; + BURN_ENGINE_STATE* pEngineState = &engineState; + BURN_PLAN* pPlan = &engineState.plan; + + InitializeEngineStateForCorePlan(wzMultipleBundlePackageManifestFileName, pEngineState); + DetectAttachedContainerAsAttached(pEngineState); + DetectPackagesAsPresentAndCached(pEngineState); + + hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_REPAIR); + NativeAssert::Succeeded(hr, "CorePlan failed"); + + Assert::Equal(BOOTSTRAPPER_ACTION_REPAIR, pPlan->action); + NativeAssert::StringEqual(L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", pPlan->wzBundleId); + NativeAssert::StringEqual(L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", pPlan->wzBundleProviderKey); + Assert::Equal(FALSE, pPlan->fEnabledForwardCompatibleBundle); + Assert::Equal(TRUE, pPlan->fPerMachine); + Assert::Equal(TRUE, pPlan->fCanAffectMachineState); + Assert::Equal(FALSE, pPlan->fDisableRollback); + Assert::Equal(FALSE, pPlan->fDisallowRemoval); + Assert::Equal(FALSE, pPlan->fDowngrade); + Assert::Equal(BURN_REGISTRATION_ACTION_OPERATIONS_CACHE_BUNDLE | BURN_REGISTRATION_ACTION_OPERATIONS_WRITE_PROVIDER_KEY, pPlan->dwRegistrationOperations); + + BOOL fRollback = FALSE; + DWORD dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRegistrationActions); + + fRollback = TRUE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRollbackRegistrationActions); + + fRollback = FALSE; + dwIndex = 0; + ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 2); + ValidateCachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); + ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++); + Assert::Equal(dwIndex, pPlan->cCacheActions); + + fRollback = TRUE; + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRollbackCacheActions); + + Assert::Equal(18575450ull, pPlan->qwEstimatedSize); + Assert::Equal(52254105ull, pPlan->qwCacheSizeTotal); + + fRollback = FALSE; + dwIndex = 0; + DWORD dwExecuteCheckpointId = 1; + ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", registerActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + dwExecuteCheckpointId += 1; // cache checkpoints + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteWaitCachePackage(pPlan, fRollback, dwIndex++, L"PackageB"); + ValidateExecuteBundlePackage(pPlan, fRollback, dwIndex++, L"PackageB", BOOTSTRAPPER_ACTION_STATE_REPAIR, L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}"); + ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageB", L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", registerActions1, 1); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); + Assert::Equal(dwIndex, pPlan->cExecuteActions); + + fRollback = TRUE; + dwIndex = 0; + dwExecuteCheckpointId = 1; + ValidateExecuteRollbackBoundaryStart(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + dwExecuteCheckpointId += 1; // cache checkpoints + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++); + ValidateExecuteRollbackBoundaryEnd(pPlan, fRollback, dwIndex++); + Assert::Equal(dwIndex, pPlan->cRollbackActions); + + Assert::Equal(1ul, pPlan->cExecutePackagesTotal); + Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal); + + dwIndex = 0; + Assert::Equal(dwIndex, pPlan->cRestoreRelatedBundleActions); + + dwIndex = 0; + ValidateCleanAction(pPlan, dwIndex++, L"NetFx48Web"); + Assert::Equal(dwIndex, pPlan->cCleanActions); + + UINT uIndex = 0; + ValidatePlannedProvider(pPlan, uIndex++, L"{35192ED0-C70A-49B2-9D12-3B1FA39B5E6F}", NULL); + Assert::Equal(uIndex, pPlan->cPlannedProviders); + + Assert::Equal(3ul, pEngineState->packages.cPackages); + ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[1], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); + ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[2], L"PackageB", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT); + } + [Fact] void OrphanCompatiblePackageTest() { diff --git a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml index 0b521faa..b02c2056 100644 --- a/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml +++ b/src/burn/test/BurnUnitTest/TestData/PlanTest/BundlePackage_Multiple_manifest.xml @@ -1 +1 @@ - + diff --git a/src/burn/test/BurnUnitTest/VariableTest.cpp b/src/burn/test/BurnUnitTest/VariableTest.cpp index d0361c0e..1d5fc6f3 100644 --- a/src/burn/test/BurnUnitTest/VariableTest.cpp +++ b/src/burn/test/BurnUnitTest/VariableTest.cpp @@ -388,6 +388,7 @@ namespace Bootstrapper Assert::True(EvaluateFailureConditionHelper(&variables, L"1A")); Assert::True(EvaluateFailureConditionHelper(&variables, L"*")); + Assert::False(EvaluateFailureConditionHelper(&variables, L"0")); Assert::True(EvaluateFailureConditionHelper(&variables, L"1 == 1")); } finally -- cgit v1.2.3-55-g6feb