diff options
author | Sean Hall <r.sean.hall@gmail.com> | 2022-01-31 16:48:58 -0600 |
---|---|---|
committer | Sean Hall <r.sean.hall@gmail.com> | 2022-02-01 23:36:23 -0600 |
commit | 328d6df64373cf340628a09e52dd77ea338bc838 (patch) | |
tree | bba49ce9fe09bb2e3f178d5f1df62e5ee42cad78 | |
parent | a2b98c1abd6e6a1469936af5d93e4ace713b3fba (diff) | |
download | wix-328d6df64373cf340628a09e52dd77ea338bc838.tar.gz wix-328d6df64373cf340628a09e52dd77ea338bc838.tar.bz2 wix-328d6df64373cf340628a09e52dd77ea338bc838.zip |
Don't uninstall package during rollback if there are dependents.
-rw-r--r-- | src/burn/engine/dependency.cpp | 63 | ||||
-rw-r--r-- | src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs | 150 |
2 files changed, 181 insertions, 32 deletions
diff --git a/src/burn/engine/dependency.cpp b/src/burn/engine/dependency.cpp index b783d4c4..221c7bbf 100644 --- a/src/burn/engine/dependency.cpp +++ b/src/burn/engine/dependency.cpp | |||
@@ -445,47 +445,44 @@ extern "C" HRESULT DependencyPlanPackageBegin( | |||
445 | ExitFunction1(hr = S_OK); | 445 | ExitFunction1(hr = S_OK); |
446 | } | 446 | } |
447 | 447 | ||
448 | // If we're uninstalling the package, check if any dependents are registered. | 448 | // Check if any dependents are registered which would prevent the package from being uninstalled. |
449 | if (fAttemptingUninstall) | 449 | // Build up a list of dependents to ignore, including the current bundle. |
450 | hr = GetIgnoredDependents(pPackage, pPlan, &sdIgnoredDependents); | ||
451 | ExitOnFailure(hr, "Failed to build the list of ignored dependents."); | ||
452 | |||
453 | // Skip the dependency check if "ALL" was authored for IGNOREDEPENDENCIES. | ||
454 | hr = DictKeyExists(sdIgnoredDependents, L"ALL"); | ||
455 | if (E_NOTFOUND != hr) | ||
456 | { | ||
457 | ExitOnFailure(hr, "Failed to check if \"ALL\" was set in IGNOREDEPENDENCIES."); | ||
458 | } | ||
459 | else | ||
450 | { | 460 | { |
451 | // Build up a list of dependents to ignore, including the current bundle. | 461 | hr = S_OK; |
452 | hr = GetIgnoredDependents(pPackage, pPlan, &sdIgnoredDependents); | ||
453 | ExitOnFailure(hr, "Failed to build the list of ignored dependents."); | ||
454 | 462 | ||
455 | // Skip the dependency check if "ALL" was authored for IGNOREDEPENDENCIES. | 463 | for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) |
456 | hr = DictKeyExists(sdIgnoredDependents, L"ALL"); | ||
457 | if (E_NOTFOUND != hr) | ||
458 | { | ||
459 | ExitOnFailure(hr, "Failed to check if \"ALL\" was set in IGNOREDEPENDENCIES."); | ||
460 | } | ||
461 | else | ||
462 | { | 464 | { |
463 | hr = S_OK; | 465 | const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders + i; |
464 | 466 | ||
465 | for (DWORD i = 0; i < pPackage->cDependencyProviders; ++i) | 467 | for (DWORD j = 0; j < pProvider->cDependents; ++j) |
466 | { | 468 | { |
467 | const BURN_DEPENDENCY_PROVIDER* pProvider = pPackage->rgDependencyProviders + i; | 469 | const DEPENDENCY* pDependency = pProvider->rgDependents + j; |
468 | 470 | ||
469 | for (DWORD j = 0; j < pProvider->cDependents; ++j) | 471 | hr = DictKeyExists(sdIgnoredDependents, pDependency->sczKey); |
472 | if (E_NOTFOUND == hr) | ||
470 | { | 473 | { |
471 | const DEPENDENCY* pDependency = pProvider->rgDependents + j; | 474 | hr = S_OK; |
472 | 475 | ||
473 | hr = DictKeyExists(sdIgnoredDependents, pDependency->sczKey); | 476 | if (!fDependentBlocksUninstall) |
474 | if (E_NOTFOUND == hr) | ||
475 | { | 477 | { |
476 | hr = S_OK; | 478 | fDependentBlocksUninstall = TRUE; |
477 | |||
478 | if (!fDependentBlocksUninstall) | ||
479 | { | ||
480 | fDependentBlocksUninstall = TRUE; | ||
481 | |||
482 | LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS, pPackage->sczId); | ||
483 | } | ||
484 | 479 | ||
485 | LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_DEPENDENT, pDependency->sczKey, LoggingStringOrUnknownIfNull(pDependency->sczName)); | 480 | LogId(REPORT_STANDARD, MSG_DEPENDENCY_PACKAGE_HASDEPENDENTS, pPackage->sczId); |
486 | } | 481 | } |
487 | ExitOnFailure(hr, "Failed to check the dictionary of ignored dependents."); | 482 | |
483 | LogId(REPORT_VERBOSE, MSG_DEPENDENCY_PACKAGE_DEPENDENT, pDependency->sczKey, LoggingStringOrUnknownIfNull(pDependency->sczName)); | ||
488 | } | 484 | } |
485 | ExitOnFailure(hr, "Failed to check the dictionary of ignored dependents."); | ||
489 | } | 486 | } |
490 | } | 487 | } |
491 | } | 488 | } |
@@ -499,7 +496,7 @@ extern "C" HRESULT DependencyPlanPackageBegin( | |||
499 | CalculateDependencyActionStates(pPackage, &dependencyExecuteAction, &dependencyRollbackAction); | 496 | CalculateDependencyActionStates(pPackage, &dependencyExecuteAction, &dependencyRollbackAction); |
500 | 497 | ||
501 | // If dependents were found, change the action to not uninstall the package. | 498 | // If dependents were found, change the action to not uninstall the package. |
502 | if (fDependentBlocksUninstall) | 499 | if (fAttemptingUninstall && fDependentBlocksUninstall) |
503 | { | 500 | { |
504 | pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE; | 501 | pPackage->execute = BOOTSTRAPPER_ACTION_STATE_NONE; |
505 | pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE; | 502 | pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE; |
@@ -509,6 +506,12 @@ extern "C" HRESULT DependencyPlanPackageBegin( | |||
509 | } | 506 | } |
510 | else | 507 | else |
511 | { | 508 | { |
509 | // Trust the forward compatible nature of providers - don't uninstall the package during rollback if there were dependents. | ||
510 | if (fDependentBlocksUninstall && BOOTSTRAPPER_ACTION_STATE_UNINSTALL == pPackage->rollback) | ||
511 | { | ||
512 | pPackage->rollback = BOOTSTRAPPER_ACTION_STATE_NONE; | ||
513 | } | ||
514 | |||
512 | // Only plan providers when the package is current (not obsolete). | 515 | // Only plan providers when the package is current (not obsolete). |
513 | if (BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE != pPackage->currentState) | 516 | if (BOOTSTRAPPER_PACKAGE_STATE_OBSOLETE != pPackage->currentState) |
514 | { | 517 | { |
diff --git a/src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs b/src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs index 7c74f348..7e3e28c1 100644 --- a/src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs +++ b/src/test/burn/WixToolsetTest.BurnE2E/DependencyTests.cs | |||
@@ -540,7 +540,7 @@ namespace WixToolsetTest.BurnE2E | |||
540 | } | 540 | } |
541 | 541 | ||
542 | [Fact(Skip = "https://github.com/wixtoolset/issues/issues/3421")] | 542 | [Fact(Skip = "https://github.com/wixtoolset/issues/issues/3421")] |
543 | public void DoesntLoseDependenciesOnFailedMajorUpgradeBundleFromMajorUpdateMsi() | 543 | public void DoesntLoseDependenciesOnFailedMajorUpgradeBundleFromMajorUpdateMsiFifo() |
544 | { | 544 | { |
545 | var packageAv1 = this.CreatePackageInstaller("PackageAv1"); | 545 | var packageAv1 = this.CreatePackageInstaller("PackageAv1"); |
546 | var packageC = this.CreatePackageInstaller("PackageC"); | 546 | var packageC = this.CreatePackageInstaller("PackageC"); |
@@ -611,8 +611,80 @@ namespace WixToolsetTest.BurnE2E | |||
611 | packageGv2.VerifyInstalled(false); | 611 | packageGv2.VerifyInstalled(false); |
612 | } | 612 | } |
613 | 613 | ||
614 | [Fact(Skip = "https://github.com/wixtoolset/issues/issues/3421")] | ||
615 | public void DoesntLoseDependenciesOnFailedMajorUpgradeBundleFromMajorUpdateMsiLifo() | ||
616 | { | ||
617 | var packageAv1 = this.CreatePackageInstaller("PackageAv1"); | ||
618 | var packageC = this.CreatePackageInstaller("PackageC"); | ||
619 | var packageFv1 = this.CreatePackageInstaller("PackageFv1"); | ||
620 | var packageFv2 = this.CreatePackageInstaller("PackageFv2"); | ||
621 | var packageGv1 = this.CreatePackageInstaller("PackageGv1"); | ||
622 | var packageGv2 = this.CreatePackageInstaller("PackageGv2"); | ||
623 | var bundleM = this.CreateBundleInstaller("BundleM"); | ||
624 | var bundleNv1 = this.CreateBundleInstaller("BundleNv1"); | ||
625 | var bundleNv2 = this.CreateBundleInstaller("BundleNv2"); | ||
626 | var testBAController = this.CreateTestBAController(); | ||
627 | |||
628 | packageAv1.VerifyInstalled(false); | ||
629 | packageC.VerifyInstalled(false); | ||
630 | packageFv1.VerifyInstalled(false); | ||
631 | packageFv2.VerifyInstalled(false); | ||
632 | packageGv1.VerifyInstalled(false); | ||
633 | packageGv2.VerifyInstalled(false); | ||
634 | |||
635 | bundleM.Install(); | ||
636 | bundleM.VerifyRegisteredAndInPackageCache(); | ||
637 | |||
638 | packageAv1.VerifyInstalled(true); | ||
639 | packageFv1.VerifyInstalled(true); | ||
640 | packageFv2.VerifyInstalled(false); | ||
641 | packageGv1.VerifyInstalled(false); | ||
642 | packageGv2.VerifyInstalled(false); | ||
643 | |||
644 | bundleNv1.Install(); | ||
645 | bundleNv1.VerifyRegisteredAndInPackageCache(); | ||
646 | |||
647 | packageAv1.VerifyInstalled(true); | ||
648 | packageFv1.VerifyInstalled(true); | ||
649 | packageFv2.VerifyInstalled(false); | ||
650 | packageGv1.VerifyInstalled(true); | ||
651 | packageGv2.VerifyInstalled(false); | ||
652 | |||
653 | // Make PackageC fail. | ||
654 | testBAController.SetPackageCancelExecuteAtProgress("PackageC", 10); | ||
655 | |||
656 | bundleNv2.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); | ||
657 | bundleNv2.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
658 | bundleNv1.VerifyRegisteredAndInPackageCache(); | ||
659 | |||
660 | packageAv1.VerifyInstalled(true); | ||
661 | packageC.VerifyInstalled(false); | ||
662 | packageFv1.VerifyInstalled(true); | ||
663 | packageFv2.VerifyInstalled(false); | ||
664 | packageGv1.VerifyInstalled(true); | ||
665 | packageGv2.VerifyInstalled(false); | ||
666 | |||
667 | bundleNv1.Uninstall(); | ||
668 | bundleNv1.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
669 | |||
670 | packageAv1.VerifyInstalled(true); | ||
671 | packageFv1.VerifyInstalled(true); | ||
672 | packageFv2.VerifyInstalled(false); | ||
673 | packageGv1.VerifyInstalled(false); | ||
674 | packageGv2.VerifyInstalled(false); | ||
675 | |||
676 | bundleM.Uninstall(); | ||
677 | bundleM.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
678 | |||
679 | packageAv1.VerifyInstalled(false); | ||
680 | packageFv1.VerifyInstalled(false); | ||
681 | packageFv2.VerifyInstalled(false); | ||
682 | packageGv1.VerifyInstalled(false); | ||
683 | packageGv2.VerifyInstalled(false); | ||
684 | } | ||
685 | |||
614 | [Fact] | 686 | [Fact] |
615 | public void DoesntLoseDependenciesOnFailedMajorUpgradeBundleFromMinorUpdateMsi() | 687 | public void DoesntLoseDependenciesOnFailedMajorUpgradeBundleFromMinorUpdateMsiFifo() |
616 | { | 688 | { |
617 | var packageAv1 = this.CreatePackageInstaller("PackageAv1"); | 689 | var packageAv1 = this.CreatePackageInstaller("PackageAv1"); |
618 | var packageC = this.CreatePackageInstaller("PackageC"); | 690 | var packageC = this.CreatePackageInstaller("PackageC"); |
@@ -686,6 +758,80 @@ namespace WixToolsetTest.BurnE2E | |||
686 | } | 758 | } |
687 | 759 | ||
688 | [Fact] | 760 | [Fact] |
761 | public void DoesntLoseDependenciesOnFailedMajorUpgradeBundleFromMinorUpdateMsiLifo() | ||
762 | { | ||
763 | var packageAv1 = this.CreatePackageInstaller("PackageAv1"); | ||
764 | var packageC = this.CreatePackageInstaller("PackageC"); | ||
765 | var packageFv1 = this.CreatePackageInstaller("PackageFv1"); | ||
766 | var packageFv101 = this.CreatePackageInstaller("PackageFv1_0_1"); | ||
767 | var packageGv1 = this.CreatePackageInstaller("PackageGv1"); | ||
768 | var packageGv101 = this.CreatePackageInstaller("PackageGv1_0_1"); | ||
769 | var bundleM = this.CreateBundleInstaller("BundleM"); | ||
770 | var bundleNv1 = this.CreateBundleInstaller("BundleNv1"); | ||
771 | var bundleNv101 = this.CreateBundleInstaller("BundleNv1_0_1"); | ||
772 | var testBAController = this.CreateTestBAController(); | ||
773 | |||
774 | packageAv1.VerifyInstalled(false); | ||
775 | packageC.VerifyInstalled(false); | ||
776 | packageFv1.VerifyInstalledWithVersion(false); | ||
777 | packageFv101.VerifyInstalledWithVersion(false); | ||
778 | packageGv1.VerifyInstalledWithVersion(false); | ||
779 | packageGv101.VerifyInstalledWithVersion(false); | ||
780 | |||
781 | bundleM.Install(); | ||
782 | bundleM.VerifyRegisteredAndInPackageCache(); | ||
783 | |||
784 | packageAv1.VerifyInstalled(true); | ||
785 | packageFv1.VerifyInstalledWithVersion(true); | ||
786 | packageFv101.VerifyInstalledWithVersion(false); | ||
787 | packageGv1.VerifyInstalledWithVersion(false); | ||
788 | packageGv101.VerifyInstalledWithVersion(false); | ||
789 | |||
790 | bundleNv1.Install(); | ||
791 | bundleNv1.VerifyRegisteredAndInPackageCache(); | ||
792 | |||
793 | packageAv1.VerifyInstalled(true); | ||
794 | packageFv1.VerifyInstalledWithVersion(true); | ||
795 | packageFv101.VerifyInstalledWithVersion(false); | ||
796 | packageGv1.VerifyInstalledWithVersion(true); | ||
797 | packageGv101.VerifyInstalledWithVersion(false); | ||
798 | |||
799 | // Make PackageC fail. | ||
800 | testBAController.SetPackageCancelExecuteAtProgress("PackageC", 10); | ||
801 | |||
802 | // Verify https://github.com/wixtoolset/issues/issues/6510 - Dependency provider removed on rollback even though package is not rolled back | ||
803 | bundleNv101.Install((int)MSIExec.MSIExecReturnCode.ERROR_INSTALL_USEREXIT); | ||
804 | bundleNv101.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
805 | bundleNv1.VerifyRegisteredAndInPackageCache(); | ||
806 | |||
807 | // The expected values will change after implementing https://github.com/wixtoolset/issues/issues/6535 and https://github.com/wixtoolset/issues/issues/3421 | ||
808 | packageAv1.VerifyInstalled(true); | ||
809 | packageC.VerifyInstalled(false); | ||
810 | packageFv1.VerifyInstalledWithVersion(false); | ||
811 | packageFv101.VerifyInstalledWithVersion(true); | ||
812 | packageGv1.VerifyInstalledWithVersion(false); | ||
813 | packageGv101.VerifyInstalledWithVersion(true); | ||
814 | |||
815 | bundleNv1.Uninstall(); | ||
816 | bundleNv1.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
817 | |||
818 | packageAv1.VerifyInstalled(true); | ||
819 | packageFv1.VerifyInstalledWithVersion(false); | ||
820 | packageFv101.VerifyInstalledWithVersion(true); | ||
821 | packageGv1.VerifyInstalledWithVersion(false); | ||
822 | packageGv101.VerifyInstalledWithVersion(false); | ||
823 | |||
824 | bundleM.Uninstall(); | ||
825 | bundleM.VerifyUnregisteredAndRemovedFromPackageCache(); | ||
826 | |||
827 | packageAv1.VerifyInstalled(false); | ||
828 | packageFv1.VerifyInstalledWithVersion(false); | ||
829 | packageFv101.VerifyInstalledWithVersion(false); | ||
830 | packageGv1.VerifyInstalledWithVersion(false); | ||
831 | packageGv101.VerifyInstalledWithVersion(false); | ||
832 | } | ||
833 | |||
834 | [Fact] | ||
689 | public void DoesntRegisterDependencyOnPackageNotSelectedForInstall() | 835 | public void DoesntRegisterDependencyOnPackageNotSelectedForInstall() |
690 | { | 836 | { |
691 | var testRegistryValueExe = "ExeA"; | 837 | var testRegistryValueExe = "ExeA"; |