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 /src | |
| 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.
Diffstat (limited to 'src')
| -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"; |
