aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean Hall <r.sean.hall@gmail.com>2021-03-10 18:18:38 -0600
committerSean Hall <r.sean.hall@gmail.com>2021-03-11 20:24:18 -0600
commitaf68033509730ffe01602f839861a47287bb709f (patch)
tree2960f6cdd023e74a4ca2bbc49d0294b7bfbed5c5
parent10ef9d5bfbf81f454113a1c2716009831a916222 (diff)
downloadwix-af68033509730ffe01602f839861a47287bb709f.tar.gz
wix-af68033509730ffe01602f839861a47287bb709f.tar.bz2
wix-af68033509730ffe01602f839861a47287bb709f.zip
Handle when related bundles have an uninstall key but aren't cached.
#4991
-rw-r--r--src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h2
-rw-r--r--src/engine/core.cpp39
-rw-r--r--src/engine/dependency.cpp8
-rw-r--r--src/engine/detect.cpp17
-rw-r--r--src/engine/engine.mc11
-rw-r--r--src/engine/externalengine.cpp2
-rw-r--r--src/engine/plan.cpp11
-rw-r--r--src/engine/pseudobundle.cpp5
-rw-r--r--src/engine/pseudobundle.h1
-rw-r--r--src/engine/registration.h1
-rw-r--r--src/engine/relatedbundle.cpp16
-rw-r--r--src/engine/userexperience.cpp8
-rw-r--r--src/engine/userexperience.h6
-rw-r--r--src/test/BurnUnitTest/PlanTest.cpp95
14 files changed, 188 insertions, 34 deletions
diff --git a/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h b/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
index c3242167..fb4b6ea3 100644
--- a/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
+++ b/src/WixToolset.BootstrapperCore.Native/inc/BootstrapperApplication.h
@@ -491,6 +491,7 @@ struct BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_ARGS
491 LPCWSTR wzBundleTag; 491 LPCWSTR wzBundleTag;
492 BOOL fPerMachine; 492 BOOL fPerMachine;
493 LPCWSTR wzVersion; 493 LPCWSTR wzVersion;
494 BOOL fMissingFromCache;
494}; 495};
495 496
496struct BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_RESULTS 497struct BA_ONDETECTFORWARDCOMPATIBLEBUNDLE_RESULTS
@@ -547,6 +548,7 @@ struct BA_ONDETECTRELATEDBUNDLE_ARGS
547 BOOL fPerMachine; 548 BOOL fPerMachine;
548 LPCWSTR wzVersion; 549 LPCWSTR wzVersion;
549 BOOTSTRAPPER_RELATED_OPERATION operation; 550 BOOTSTRAPPER_RELATED_OPERATION operation;
551 BOOL fMissingFromCache;
550}; 552};
551 553
552struct BA_ONDETECTRELATEDBUNDLE_RESULTS 554struct BA_ONDETECTRELATEDBUNDLE_RESULTS
diff --git a/src/engine/core.cpp b/src/engine/core.cpp
index eb8a84fe..50ed6ea0 100644
--- a/src/engine/core.cpp
+++ b/src/engine/core.cpp
@@ -59,6 +59,10 @@ static void LogPackages(
59 __in const BURN_RELATED_BUNDLES* pRelatedBundles, 59 __in const BURN_RELATED_BUNDLES* pRelatedBundles,
60 __in const BOOTSTRAPPER_ACTION action 60 __in const BOOTSTRAPPER_ACTION action
61 ); 61 );
62static void LogRelatedBundles(
63 __in const BURN_RELATED_BUNDLES* pRelatedBundles,
64 __in BOOL fReverse
65 );
62 66
63 67
64// function definitions 68// function definitions
@@ -1793,15 +1797,9 @@ static void LogPackages(
1793 else 1797 else
1794 { 1798 {
1795 // Display related bundles first if uninstalling. 1799 // Display related bundles first if uninstalling.
1796 if (BOOTSTRAPPER_ACTION_UNINSTALL == action && 0 < pRelatedBundles->cRelatedBundles) 1800 if (BOOTSTRAPPER_ACTION_UNINSTALL == action)
1797 { 1801 {
1798 for (int i = pRelatedBundles->cRelatedBundles - 1; 0 <= i; --i) 1802 LogRelatedBundles(pRelatedBundles, TRUE);
1799 {
1800 const BURN_RELATED_BUNDLE* pRelatedBundle = &pRelatedBundles->rgRelatedBundles[i];
1801 const BURN_PACKAGE* pPackage = &pRelatedBundle->package;
1802
1803 LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingDependencyActionToString(pPackage->dependencyExecute));
1804 }
1805 } 1803 }
1806 1804
1807 // Display all the packages in the log. 1805 // Display all the packages in the log.
@@ -1852,13 +1850,28 @@ static void LogPackages(
1852 } 1850 }
1853 1851
1854 // Display related bundles last if caching, installing, modifying, or repairing. 1852 // Display related bundles last if caching, installing, modifying, or repairing.
1855 if (BOOTSTRAPPER_ACTION_UNINSTALL < action && 0 < pRelatedBundles->cRelatedBundles) 1853 if (BOOTSTRAPPER_ACTION_UNINSTALL < action)
1856 { 1854 {
1857 for (DWORD i = 0; i < pRelatedBundles->cRelatedBundles; ++i) 1855 LogRelatedBundles(pRelatedBundles, FALSE);
1858 { 1856 }
1859 const BURN_RELATED_BUNDLE* pRelatedBundle = &pRelatedBundles->rgRelatedBundles[i]; 1857 }
1860 const BURN_PACKAGE* pPackage = &pRelatedBundle->package; 1858}
1859
1860static void LogRelatedBundles(
1861 __in const BURN_RELATED_BUNDLES* pRelatedBundles,
1862 __in BOOL fReverse
1863 )
1864{
1865 if (0 < pRelatedBundles->cRelatedBundles)
1866 {
1867 for (DWORD i = 0; i < pRelatedBundles->cRelatedBundles; ++i)
1868 {
1869 const DWORD iRelatedBundle = fReverse ? pRelatedBundles->cRelatedBundles - 1 - i : i;
1870 const BURN_RELATED_BUNDLE* pRelatedBundle = pRelatedBundles->rgRelatedBundles + iRelatedBundle;
1871 const BURN_PACKAGE* pPackage = &pRelatedBundle->package;
1861 1872
1873 if (pRelatedBundle->fPlannable)
1874 {
1862 LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingDependencyActionToString(pPackage->dependencyExecute)); 1875 LogId(REPORT_STANDARD, MSG_PLANNED_RELATED_BUNDLE, pPackage->sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingRequestStateToString(pPackage->defaultRequested), LoggingRequestStateToString(pPackage->requested), LoggingActionStateToString(pPackage->execute), LoggingActionStateToString(pPackage->rollback), LoggingDependencyActionToString(pPackage->dependencyExecute));
1863 } 1876 }
1864 } 1877 }
diff --git a/src/engine/dependency.cpp b/src/engine/dependency.cpp
index 9ab76551..51aca239 100644
--- a/src/engine/dependency.cpp
+++ b/src/engine/dependency.cpp
@@ -260,7 +260,13 @@ extern "C" HRESULT DependencyDetect(
260 260
261 for (DWORD iRelatedBundle = 0; iRelatedBundle < pEngineState->registration.relatedBundles.cRelatedBundles; ++iRelatedBundle) 261 for (DWORD iRelatedBundle = 0; iRelatedBundle < pEngineState->registration.relatedBundles.cRelatedBundles; ++iRelatedBundle)
262 { 262 {
263 pPackage = &pEngineState->registration.relatedBundles.rgRelatedBundles[iRelatedBundle].package; 263 BURN_RELATED_BUNDLE* pRelatedBundle = pEngineState->registration.relatedBundles.rgRelatedBundles + iRelatedBundle;
264 if (!pRelatedBundle->fPlannable)
265 {
266 continue;
267 }
268
269 pPackage = &pRelatedBundle->package;
264 hr = DetectPackageDependents(pPackage, sdIgnoredDependents, pRegistration); 270 hr = DetectPackageDependents(pPackage, sdIgnoredDependents, pRegistration);
265 ExitOnFailure(hr, "Failed to detect dependents for related bundle '%ls'", pPackage->sczId); 271 ExitOnFailure(hr, "Failed to detect dependents for related bundle '%ls'", pPackage->sczId);
266 } 272 }
diff --git a/src/engine/detect.cpp b/src/engine/detect.cpp
index 74e8b9ca..8ca74986 100644
--- a/src/engine/detect.cpp
+++ b/src/engine/detect.cpp
@@ -143,13 +143,16 @@ extern "C" HRESULT DetectForwardCompatibleBundles(
143 143
144 if (nCompareResult <= 0) 144 if (nCompareResult <= 0)
145 { 145 {
146 pRelatedBundle->fForwardCompatible = TRUE; 146 if (pRelatedBundle->fPlannable)
147 pRegistration->fForwardCompatibleBundleExists = TRUE; 147 {
148 pRelatedBundle->fForwardCompatible = TRUE;
149 pRegistration->fForwardCompatibleBundleExists = TRUE;
150 }
148 151
149 hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion); 152 hr = UserExperienceOnDetectForwardCompatibleBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, BURN_CACHE_STATE_COMPLETE != pRelatedBundle->package.cache);
150 ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle."); 153 ExitOnRootFailure(hr, "BA aborted detect forward compatible bundle.");
151 154
152 LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion); 155 LogId(REPORT_STANDARD, MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingCacheStateToString(pRelatedBundle->package.cache));
153 } 156 }
154 } 157 }
155 } 158 }
@@ -222,13 +225,13 @@ extern "C" HRESULT DetectReportRelatedBundles(
222 break; 225 break;
223 } 226 }
224 227
225 LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingRelatedOperationToString(operation)); 228 LogId(REPORT_STANDARD, MSG_DETECTED_RELATED_BUNDLE, pRelatedBundle->package.sczId, LoggingRelationTypeToString(pRelatedBundle->relationType), LoggingPerMachineToString(pRelatedBundle->package.fPerMachine), pRelatedBundle->pVersion->sczVersion, LoggingRelatedOperationToString(operation), LoggingCacheStateToString(pRelatedBundle->package.cache));
226 229
227 hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, operation); 230 hr = UserExperienceOnDetectRelatedBundle(pUX, pRelatedBundle->package.sczId, pRelatedBundle->relationType, pRelatedBundle->sczTag, pRelatedBundle->package.fPerMachine, pRelatedBundle->pVersion, operation, BURN_CACHE_STATE_COMPLETE != pRelatedBundle->package.cache);
228 ExitOnRootFailure(hr, "BA aborted detect related bundle."); 231 ExitOnRootFailure(hr, "BA aborted detect related bundle.");
229 232
230 // For now, if any related bundles will be executed during uninstall by default then never automatically clean up the bundle. 233 // For now, if any related bundles will be executed during uninstall by default then never automatically clean up the bundle.
231 if (*pfEligibleForCleanup) 234 if (*pfEligibleForCleanup && pRelatedBundle->fPlannable)
232 { 235 {
233 uninstallRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE; 236 uninstallRequestState = BOOTSTRAPPER_REQUEST_STATE_NONE;
234 hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, BOOTSTRAPPER_ACTION_UNINSTALL, pRegistration->pVersion, pRelatedBundle->pVersion, &uninstallRequestState); 237 hr = PlanDefaultRelatedBundleRequestState(relationType, pRelatedBundle->relationType, BOOTSTRAPPER_ACTION_UNINSTALL, pRegistration->pVersion, pRelatedBundle->pVersion, &uninstallRequestState);
diff --git a/src/engine/engine.mc b/src/engine/engine.mc
index 687d2b60..a793540a 100644
--- a/src/engine/engine.mc
+++ b/src/engine/engine.mc
@@ -202,7 +202,7 @@ MessageId=102
202Severity=Success 202Severity=Success
203SymbolicName=MSG_DETECTED_RELATED_BUNDLE 203SymbolicName=MSG_DETECTED_RELATED_BUNDLE
204Language=English 204Language=English
205Detected related bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version: %4!ls!, operation: %5!hs! 205Detected related bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version: %4!ls!, operation: %5!hs!, cached: %6!hs!
206. 206.
207 207
208MessageId=103 208MessageId=103
@@ -237,7 +237,14 @@ MessageId=107
237Severity=Success 237Severity=Success
238SymbolicName=MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE 238SymbolicName=MSG_DETECTED_FORWARD_COMPATIBLE_BUNDLE
239Language=English 239Language=English
240Detected forward compatible bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version: %4!ls! 240Detected forward compatible bundle: %1!ls!, type: %2!hs!, scope: %3!hs!, version: %4!ls!, cached: %5!hs!
241.
242
243MessageId=108
244Severity=Warning
245SymbolicName=MSG_DETECT_RELATED_BUNDLE_NOT_FULLY_CACHED
246Language=English
247Detected partially cached related bundle: %1!ls!, cache path: %2!ls!, reason: 0x%3!x!
241. 248.
242 249
243MessageId=120 250MessageId=120
diff --git a/src/engine/externalengine.cpp b/src/engine/externalengine.cpp
index 26ab9fba..d881544c 100644
--- a/src/engine/externalengine.cpp
+++ b/src/engine/externalengine.cpp
@@ -327,7 +327,7 @@ HRESULT ExternalEngineSetUpdate(
327 sczId = pEngineState->registration.sczId; 327 sczId = pEngineState->registration.sczId;
328 } 328 }
329 329
330 hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, rpr), &pEngineState->update.package, FALSE, sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, pEngineState->registration.sczExecutableName, sczLocalSource ? sczLocalSource : wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash); 330 hr = PseudoBundleInitialize(FILEMAKEVERSION(rmj, rmm, rup, rpr), &pEngineState->update.package, FALSE, sczId, BOOTSTRAPPER_RELATION_UPDATE, BOOTSTRAPPER_PACKAGE_STATE_ABSENT, BURN_CACHE_STATE_NONE, pEngineState->registration.sczExecutableName, sczLocalSource ? sczLocalSource : wzLocalSource, wzDownloadSource, qwSize, TRUE, sczCommandline, NULL, NULL, NULL, rgbHash, cbHash);
331 ExitOnFailure(hr, "Failed to set update bundle."); 331 ExitOnFailure(hr, "Failed to set update bundle.");
332 332
333 pEngineState->update.fUpdateAvailable = TRUE; 333 pEngineState->update.fUpdateAvailable = TRUE;
diff --git a/src/engine/plan.cpp b/src/engine/plan.cpp
index 87607382..a4b8d0c1 100644
--- a/src/engine/plan.cpp
+++ b/src/engine/plan.cpp
@@ -1292,6 +1292,12 @@ extern "C" HRESULT PlanRelatedBundlesBegin(
1292 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i) 1292 for (DWORD i = 0; i < pRegistration->relatedBundles.cRelatedBundles; ++i)
1293 { 1293 {
1294 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i; 1294 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i;
1295
1296 if (!pRelatedBundle->fPlannable)
1297 {
1298 continue;
1299 }
1300
1295 pRelatedBundle->package.defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE; 1301 pRelatedBundle->package.defaultRequested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1296 pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE; 1302 pRelatedBundle->package.requested = BOOTSTRAPPER_REQUEST_STATE_NONE;
1297 1303
@@ -1417,6 +1423,11 @@ extern "C" HRESULT PlanRelatedBundlesComplete(
1417 DWORD *pdwInsertIndex = NULL; 1423 DWORD *pdwInsertIndex = NULL;
1418 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i; 1424 BURN_RELATED_BUNDLE* pRelatedBundle = pRegistration->relatedBundles.rgRelatedBundles + i;
1419 1425
1426 if (!pRelatedBundle->fPlannable)
1427 {
1428 continue;
1429 }
1430
1420 // Do not execute if a major upgrade to the related bundle is an embedded bundle (Provider keys are the same) 1431 // Do not execute if a major upgrade to the related bundle is an embedded bundle (Provider keys are the same)
1421 if (0 < pRelatedBundle->package.cDependencyProviders) 1432 if (0 < pRelatedBundle->package.cDependencyProviders)
1422 { 1433 {
diff --git a/src/engine/pseudobundle.cpp b/src/engine/pseudobundle.cpp
index 3b05ea0b..63300065 100644
--- a/src/engine/pseudobundle.cpp
+++ b/src/engine/pseudobundle.cpp
@@ -10,6 +10,7 @@ extern "C" HRESULT PseudoBundleInitialize(
10 __in_z LPCWSTR wzId, 10 __in_z LPCWSTR wzId,
11 __in BOOTSTRAPPER_RELATION_TYPE relationType, 11 __in BOOTSTRAPPER_RELATION_TYPE relationType,
12 __in BOOTSTRAPPER_PACKAGE_STATE state, 12 __in BOOTSTRAPPER_PACKAGE_STATE state,
13 __in BURN_CACHE_STATE cacheState,
13 __in_z LPCWSTR wzFilePath, 14 __in_z LPCWSTR wzFilePath,
14 __in_z LPCWSTR wzLocalSource, 15 __in_z LPCWSTR wzLocalSource,
15 __in_z_opt LPCWSTR wzDownloadSource, 16 __in_z_opt LPCWSTR wzDownloadSource,
@@ -66,14 +67,14 @@ extern "C" HRESULT PseudoBundleInitialize(
66 memcpy_s(pPackage->rgPayloads->pPayload->pbHash, pPackage->rgPayloads->pPayload->cbHash, pbHash, cbHash); 67 memcpy_s(pPackage->rgPayloads->pPayload->pbHash, pPackage->rgPayloads->pPayload->cbHash, pbHash, cbHash);
67 } 68 }
68 69
69 pPackage->rgPayloads->fCached = (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || BOOTSTRAPPER_PACKAGE_STATE_CACHED == state); 70 pPackage->rgPayloads->fCached = BURN_CACHE_STATE_NONE < cacheState;
70 71
71 pPackage->Exe.fPseudoBundle = TRUE; 72 pPackage->Exe.fPseudoBundle = TRUE;
72 73
73 pPackage->type = BURN_PACKAGE_TYPE_EXE; 74 pPackage->type = BURN_PACKAGE_TYPE_EXE;
74 pPackage->fPerMachine = fPerMachine; 75 pPackage->fPerMachine = fPerMachine;
75 pPackage->currentState = state; 76 pPackage->currentState = state;
76 pPackage->cache = (BOOTSTRAPPER_PACKAGE_STATE_PRESENT == state || BOOTSTRAPPER_PACKAGE_STATE_CACHED == state) ? BURN_CACHE_STATE_COMPLETE : BURN_CACHE_STATE_NONE; 77 pPackage->cache = cacheState;
77 pPackage->qwInstallSize = qwSize; 78 pPackage->qwInstallSize = qwSize;
78 pPackage->qwSize = qwSize; 79 pPackage->qwSize = qwSize;
79 pPackage->fVital = fVital; 80 pPackage->fVital = fVital;
diff --git a/src/engine/pseudobundle.h b/src/engine/pseudobundle.h
index 3b8157a0..c7940976 100644
--- a/src/engine/pseudobundle.h
+++ b/src/engine/pseudobundle.h
@@ -13,6 +13,7 @@ HRESULT PseudoBundleInitialize(
13 __in_z LPCWSTR wzId, 13 __in_z LPCWSTR wzId,
14 __in BOOTSTRAPPER_RELATION_TYPE relationType, 14 __in BOOTSTRAPPER_RELATION_TYPE relationType,
15 __in BOOTSTRAPPER_PACKAGE_STATE state, 15 __in BOOTSTRAPPER_PACKAGE_STATE state,
16 __in BURN_CACHE_STATE cacheState,
16 __in_z LPCWSTR wzFilePath, 17 __in_z LPCWSTR wzFilePath,
17 __in_z LPCWSTR wzLocalSource, 18 __in_z LPCWSTR wzLocalSource,
18 __in_z_opt LPCWSTR wzDownloadSource, 19 __in_z_opt LPCWSTR wzDownloadSource,
diff --git a/src/engine/registration.h b/src/engine/registration.h
index bb87b6e9..e0418fa3 100644
--- a/src/engine/registration.h
+++ b/src/engine/registration.h
@@ -62,6 +62,7 @@ typedef struct _BURN_RELATED_BUNDLE
62 62
63 VERUTIL_VERSION* pVersion; 63 VERUTIL_VERSION* pVersion;
64 LPWSTR sczTag; 64 LPWSTR sczTag;
65 BOOL fPlannable;
65 66
66 BURN_PACKAGE package; 67 BURN_PACKAGE package;
67} BURN_RELATED_BUNDLE; 68} BURN_RELATED_BUNDLE;
diff --git a/src/engine/relatedbundle.cpp b/src/engine/relatedbundle.cpp
index bc79b954..a4948a88 100644
--- a/src/engine/relatedbundle.cpp
+++ b/src/engine/relatedbundle.cpp
@@ -398,6 +398,7 @@ static HRESULT LoadRelatedBundleFromKey(
398 DWORD64 qwEngineVersion = 0; 398 DWORD64 qwEngineVersion = 0;
399 LPWSTR sczBundleVersion = NULL; 399 LPWSTR sczBundleVersion = NULL;
400 LPWSTR sczCachePath = NULL; 400 LPWSTR sczCachePath = NULL;
401 BURN_CACHE_STATE cacheState = BURN_CACHE_STATE_NONE;
401 DWORD64 qwFileSize = 0; 402 DWORD64 qwFileSize = 0;
402 BURN_DEPENDENCY_PROVIDER dependencyProvider = { }; 403 BURN_DEPENDENCY_PROVIDER dependencyProvider = { };
403 404
@@ -423,7 +424,18 @@ static HRESULT LoadRelatedBundleFromKey(
423 ExitOnFailure(hr, "Failed to read cache path from registry for bundle: %ls", wzRelatedBundleId); 424 ExitOnFailure(hr, "Failed to read cache path from registry for bundle: %ls", wzRelatedBundleId);
424 425
425 hr = FileSize(sczCachePath, reinterpret_cast<LONGLONG *>(&qwFileSize)); 426 hr = FileSize(sczCachePath, reinterpret_cast<LONGLONG *>(&qwFileSize));
426 ExitOnFailure(hr, "Failed to get size of pseudo bundle: %ls", sczCachePath); 427 if (SUCCEEDED(hr))
428 {
429 cacheState = BURN_CACHE_STATE_COMPLETE;
430 }
431 else if (E_FILENOTFOUND != hr)
432 {
433 cacheState = BURN_CACHE_STATE_PARTIAL;
434 LogId(REPORT_STANDARD, MSG_DETECT_RELATED_BUNDLE_NOT_FULLY_CACHED, wzRelatedBundleId, sczCachePath, hr);
435 }
436 hr = S_OK;
437
438 pRelatedBundle->fPlannable = BURN_CACHE_STATE_COMPLETE == cacheState;
427 439
428 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY, &dependencyProvider.sczKey); 440 hr = RegReadString(hkBundleId, BURN_REGISTRATION_REGISTRY_BUNDLE_PROVIDER_KEY, &dependencyProvider.sczKey);
429 if (E_FILENOTFOUND != hr) 441 if (E_FILENOTFOUND != hr)
@@ -452,7 +464,7 @@ static HRESULT LoadRelatedBundleFromKey(
452 pRelatedBundle->relationType = relationType; 464 pRelatedBundle->relationType = relationType;
453 465
454 hr = PseudoBundleInitialize(qwEngineVersion, &pRelatedBundle->package, fPerMachine, wzRelatedBundleId, pRelatedBundle->relationType, 466 hr = PseudoBundleInitialize(qwEngineVersion, &pRelatedBundle->package, fPerMachine, wzRelatedBundleId, pRelatedBundle->relationType,
455 BOOTSTRAPPER_PACKAGE_STATE_PRESENT, sczCachePath, sczCachePath, NULL, qwFileSize, FALSE, 467 BOOTSTRAPPER_PACKAGE_STATE_PRESENT, cacheState, sczCachePath, sczCachePath, NULL, qwFileSize, FALSE,
456 L"-quiet", L"-repair -quiet", L"-uninstall -quiet", 468 L"-quiet", L"-repair -quiet", L"-uninstall -quiet",
457 (dependencyProvider.sczKey && *dependencyProvider.sczKey) ? &dependencyProvider : NULL, 469 (dependencyProvider.sczKey && *dependencyProvider.sczKey) ? &dependencyProvider : NULL,
458 NULL, 0); 470 NULL, 0);
diff --git a/src/engine/userexperience.cpp b/src/engine/userexperience.cpp
index e1e32a87..ad1529ea 100644
--- a/src/engine/userexperience.cpp
+++ b/src/engine/userexperience.cpp
@@ -763,7 +763,8 @@ EXTERN_C BAAPI UserExperienceOnDetectForwardCompatibleBundle(
763 __in BOOTSTRAPPER_RELATION_TYPE relationType, 763 __in BOOTSTRAPPER_RELATION_TYPE relationType,
764 __in_z LPCWSTR wzBundleTag, 764 __in_z LPCWSTR wzBundleTag,
765 __in BOOL fPerMachine, 765 __in BOOL fPerMachine,
766 __in VERUTIL_VERSION* pVersion 766 __in VERUTIL_VERSION* pVersion,
767 __in BOOL fMissingFromCache
767 ) 768 )
768{ 769{
769 HRESULT hr = S_OK; 770 HRESULT hr = S_OK;
@@ -776,6 +777,7 @@ EXTERN_C BAAPI UserExperienceOnDetectForwardCompatibleBundle(
776 args.wzBundleTag = wzBundleTag; 777 args.wzBundleTag = wzBundleTag;
777 args.fPerMachine = fPerMachine; 778 args.fPerMachine = fPerMachine;
778 args.wzVersion = pVersion->sczVersion; 779 args.wzVersion = pVersion->sczVersion;
780 args.fMissingFromCache = fMissingFromCache;
779 781
780 results.cbSize = sizeof(results); 782 results.cbSize = sizeof(results);
781 783
@@ -879,7 +881,8 @@ EXTERN_C BAAPI UserExperienceOnDetectRelatedBundle(
879 __in_z LPCWSTR wzBundleTag, 881 __in_z LPCWSTR wzBundleTag,
880 __in BOOL fPerMachine, 882 __in BOOL fPerMachine,
881 __in VERUTIL_VERSION* pVersion, 883 __in VERUTIL_VERSION* pVersion,
882 __in BOOTSTRAPPER_RELATED_OPERATION operation 884 __in BOOTSTRAPPER_RELATED_OPERATION operation,
885 __in BOOL fMissingFromCache
883 ) 886 )
884{ 887{
885 HRESULT hr = S_OK; 888 HRESULT hr = S_OK;
@@ -893,6 +896,7 @@ EXTERN_C BAAPI UserExperienceOnDetectRelatedBundle(
893 args.fPerMachine = fPerMachine; 896 args.fPerMachine = fPerMachine;
894 args.wzVersion = pVersion->sczVersion; 897 args.wzVersion = pVersion->sczVersion;
895 args.operation = operation; 898 args.operation = operation;
899 args.fMissingFromCache = fMissingFromCache;
896 900
897 results.cbSize = sizeof(results); 901 results.cbSize = sizeof(results);
898 902
diff --git a/src/engine/userexperience.h b/src/engine/userexperience.h
index eccc0786..bac79e33 100644
--- a/src/engine/userexperience.h
+++ b/src/engine/userexperience.h
@@ -200,7 +200,8 @@ BAAPI UserExperienceOnDetectForwardCompatibleBundle(
200 __in BOOTSTRAPPER_RELATION_TYPE relationType, 200 __in BOOTSTRAPPER_RELATION_TYPE relationType,
201 __in_z LPCWSTR wzBundleTag, 201 __in_z LPCWSTR wzBundleTag,
202 __in BOOL fPerMachine, 202 __in BOOL fPerMachine,
203 __in VERUTIL_VERSION* pVersion 203 __in VERUTIL_VERSION* pVersion,
204 __in BOOL fMissingFromCache
204 ); 205 );
205BAAPI UserExperienceOnDetectMsiFeature( 206BAAPI UserExperienceOnDetectMsiFeature(
206 __in BURN_USER_EXPERIENCE* pUserExperience, 207 __in BURN_USER_EXPERIENCE* pUserExperience,
@@ -225,7 +226,8 @@ BAAPI UserExperienceOnDetectRelatedBundle(
225 __in_z LPCWSTR wzBundleTag, 226 __in_z LPCWSTR wzBundleTag,
226 __in BOOL fPerMachine, 227 __in BOOL fPerMachine,
227 __in VERUTIL_VERSION* pVersion, 228 __in VERUTIL_VERSION* pVersion,
228 __in BOOTSTRAPPER_RELATED_OPERATION operation 229 __in BOOTSTRAPPER_RELATED_OPERATION operation,
230 __in BOOL fMissingFromCache
229 ); 231 );
230BAAPI UserExperienceOnDetectRelatedMsiPackage( 232BAAPI UserExperienceOnDetectRelatedMsiPackage(
231 __in BURN_USER_EXPERIENCE* pUserExperience, 233 __in BURN_USER_EXPERIENCE* pUserExperience,
diff --git a/src/test/BurnUnitTest/PlanTest.cpp b/src/test/BurnUnitTest/PlanTest.cpp
index 40a61fe3..2a34cb16 100644
--- a/src/test/BurnUnitTest/PlanTest.cpp
+++ b/src/test/BurnUnitTest/PlanTest.cpp
@@ -293,6 +293,94 @@ namespace Bootstrapper
293 } 293 }
294 294
295 [Fact] 295 [Fact]
296 void RelatedBundleMissingFromCacheTest()
297 {
298 HRESULT hr = S_OK;
299 BURN_ENGINE_STATE engineState = { };
300 BURN_ENGINE_STATE* pEngineState = &engineState;
301 BURN_PLAN* pPlan = &engineState.plan;
302
303 InitializeEngineStateForCorePlan(wzSingleMsiManifestFileName, pEngineState);
304 DetectAttachedContainerAsAttached(pEngineState);
305 DetectPackagesAsAbsent(pEngineState);
306 BURN_RELATED_BUNDLE* pRelatedBundle = DetectUpgradeBundle(pEngineState, L"{FD9920AD-DBCA-4C6C-8CD5-B47431CE8D21}", L"0.9.0.0");
307 pRelatedBundle->fPlannable = FALSE;
308
309 hr = CorePlan(pEngineState, BOOTSTRAPPER_ACTION_INSTALL);
310 NativeAssert::Succeeded(hr, "CorePlan failed");
311
312 Assert::Equal<DWORD>(BOOTSTRAPPER_ACTION_INSTALL, pPlan->action);
313 Assert::Equal<BOOL>(TRUE, pPlan->fPerMachine);
314 Assert::Equal<BOOL>(FALSE, pPlan->fDisableRollback);
315
316 BOOL fRollback = FALSE;
317 DWORD dwIndex = 0;
318 DWORD dwPackageStart = 0;
319 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
320 dwPackageStart = ValidateCachePackageStart(pPlan, fRollback, dwIndex++, L"PackageA", 5, 2, 33743, FALSE);
321 ValidateCacheExtractContainer(pPlan, fRollback, dwIndex++, L"WixAttachedContainer", FALSE, BURN_PLAN_INVALID_ACTION_INDEX, 2);
322 ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"PackageA", TRUE, FALSE, dwPackageStart);
323 ValidateCacheCachePayload(pPlan, fRollback, dwIndex++, L"PackageA", L"cab9Ins_fTP3wNwq5Gxo41ch5VUPaQ", TRUE, FALSE, dwPackageStart);
324 ValidateCachePackageStop(pPlan, fRollback, dwIndex++, L"PackageA", FALSE);
325 ValidateCacheSignalSyncpoint(pPlan, fRollback, dwIndex++, FALSE);
326 Assert::Equal(dwIndex, pPlan->cCacheActions);
327
328 fRollback = TRUE;
329 dwIndex = 0;
330 ValidateCacheCheckpoint(pPlan, fRollback, dwIndex++, 1);
331 ValidateCacheRollbackPackage(pPlan, fRollback, dwIndex++, L"PackageA", FALSE);
332 Assert::Equal(dwIndex, pPlan->cRollbackCacheActions);
333
334 Assert::Equal(35694ull, pPlan->qwEstimatedSize);
335 Assert::Equal(33743ull, pPlan->qwCacheSizeTotal);
336
337 fRollback = FALSE;
338 dwIndex = 0;
339 DWORD dwExecuteCheckpointId = 2;
340 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
341 ValidateExecuteWaitSyncpoint(pPlan, fRollback, dwIndex++, pPlan->rgCacheActions[6].syncpoint.hEvent);
342 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
343 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
344 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_REGISTER);
345 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
346 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_INSTALL, BURN_MSI_PROPERTY_INSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
347 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
348 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_REGISTER);
349 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
350 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
351 Assert::Equal(dwIndex, pPlan->cExecuteActions);
352
353 fRollback = TRUE;
354 dwIndex = 0;
355 dwExecuteCheckpointId = 2;
356 ValidateExecuteRollbackBoundary(pPlan, fRollback, dwIndex++, L"WixDefaultBoundary", TRUE, FALSE);
357 ValidateExecuteUncachePackage(pPlan, fRollback, dwIndex++, L"PackageA");
358 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
359 ValidateExecutePackageProvider(pPlan, fRollback, dwIndex++, L"PackageA", BURN_DEPENDENCY_ACTION_UNREGISTER);
360 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
361 ValidateExecuteMsiPackage(pPlan, fRollback, dwIndex++, L"PackageA", BOOTSTRAPPER_ACTION_STATE_UNINSTALL, BURN_MSI_PROPERTY_UNINSTALL, INSTALLUILEVEL_NONE, FALSE, 0);
362 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
363 ValidateExecutePackageDependency(pPlan, fRollback, dwIndex++, L"PackageA", L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", BURN_DEPENDENCY_ACTION_UNREGISTER);
364 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
365 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
366 ValidateExecuteCheckpoint(pPlan, fRollback, dwIndex++, dwExecuteCheckpointId++);
367 Assert::Equal(dwIndex, pPlan->cRollbackActions);
368
369 Assert::Equal(1ul, pPlan->cExecutePackagesTotal);
370 Assert::Equal(2ul, pPlan->cOverallProgressTicksTotal);
371
372 dwIndex = 0;
373 Assert::Equal(dwIndex, pPlan->cCleanActions);
374
375 UINT uIndex = 0;
376 ValidatePlannedProvider(pPlan, uIndex++, L"{A6F0CBF7-1578-450C-B9D7-9CF2EEC40002}", NULL);
377 Assert::Equal(uIndex, pPlan->cPlannedProviders);
378
379 Assert::Equal(1ul, pEngineState->packages.cPackages);
380 ValidateNonPermanentPackageExpectedStates(&pEngineState->packages.rgPackages[0], L"PackageA", BURN_PACKAGE_REGISTRATION_STATE_PRESENT, BURN_PACKAGE_REGISTRATION_STATE_PRESENT);
381 }
382
383 [Fact]
296 void SingleMsiCacheTest() 384 void SingleMsiCacheTest()
297 { 385 {
298 HRESULT hr = S_OK; 386 HRESULT hr = S_OK;
@@ -1041,7 +1129,7 @@ namespace Bootstrapper
1041 } 1129 }
1042 } 1130 }
1043 1131
1044 void DetectUpgradeBundle( 1132 BURN_RELATED_BUNDLE* DetectUpgradeBundle(
1045 __in BURN_ENGINE_STATE* pEngineState, 1133 __in BURN_ENGINE_STATE* pEngineState,
1046 __in LPCWSTR wzId, 1134 __in LPCWSTR wzId,
1047 __in LPCWSTR wzVersion 1135 __in LPCWSTR wzVersion
@@ -1067,12 +1155,15 @@ namespace Bootstrapper
1067 hr = VerParseVersion(wzVersion, 0, FALSE, &pRelatedBundle->pVersion); 1155 hr = VerParseVersion(wzVersion, 0, FALSE, &pRelatedBundle->pVersion);
1068 NativeAssert::Succeeded(hr, "Failed to parse pseudo bundle version: %ls", wzVersion); 1156 NativeAssert::Succeeded(hr, "Failed to parse pseudo bundle version: %ls", wzVersion);
1069 1157
1158 pRelatedBundle->fPlannable = TRUE;
1070 pRelatedBundle->relationType = BOOTSTRAPPER_RELATION_UPGRADE; 1159 pRelatedBundle->relationType = BOOTSTRAPPER_RELATION_UPGRADE;
1071 1160
1072 hr = PseudoBundleInitialize(0, &pRelatedBundle->package, TRUE, wzId, pRelatedBundle->relationType, BOOTSTRAPPER_PACKAGE_STATE_PRESENT, NULL, NULL, NULL, 0, FALSE, L"-quiet", L"-repair -quiet", L"-uninstall -quiet", &dependencyProvider, NULL, 0); 1161 hr = PseudoBundleInitialize(0, &pRelatedBundle->package, TRUE, wzId, pRelatedBundle->relationType, BOOTSTRAPPER_PACKAGE_STATE_PRESENT, BURN_CACHE_STATE_COMPLETE, NULL, NULL, NULL, 0, FALSE, L"-quiet", L"-repair -quiet", L"-uninstall -quiet", &dependencyProvider, NULL, 0);
1073 NativeAssert::Succeeded(hr, "Failed to initialize related bundle to represent bundle: %ls", wzId); 1162 NativeAssert::Succeeded(hr, "Failed to initialize related bundle to represent bundle: %ls", wzId);
1074 1163
1075 ++pRelatedBundles->cRelatedBundles; 1164 ++pRelatedBundles->cRelatedBundles;
1165
1166 return pRelatedBundle;
1076 } 1167 }
1077 1168
1078 void DetectAsRelatedUpgradeBundle( 1169 void DetectAsRelatedUpgradeBundle(