winget-cli

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

commit d0039d013f9be8274055b8df2c539acf26e228d5
parent 6abb614f23b155c4ef00bd8d4adbabdf6cf9bd70
Author: Kaleb Luedtke <jluedtk@jci.com>
Date:   Tue, 29 Aug 2023 20:37:17 -0500

Add UpgradeBehavior deny (#3512)


Diffstat:
Mdoc/windows/package-manager/winget/returnCodes.md | 1+
Mschemas/JSON/manifests/v1.6.0/manifest.installer.1.6.0.json | 3++-
Mschemas/JSON/manifests/v1.6.0/manifest.singleton.1.6.0.json | 3++-
Msrc/AppInstallerCLICore/Resources.h | 1+
Msrc/AppInstallerCLICore/Workflows/InstallFlow.cpp | 11+++++++++++
Msrc/AppInstallerCLIE2ETests/Constants.cs | 1+
Asrc/AppInstallerCLIE2ETests/TestData/Manifests/TestUpgradeDeny.1.0.0.0.yaml | 16++++++++++++++++
Asrc/AppInstallerCLIE2ETests/TestData/Manifests/TestUpgradeDeny.2.0.0.0.yaml | 16++++++++++++++++
Msrc/AppInstallerCLIE2ETests/UpgradeCommand.cs | 17+++++++++++++++++
Msrc/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw | 3+++
Msrc/AppInstallerCommonCore/Manifest/ManifestCommon.cpp | 6++++++
Msrc/AppInstallerCommonCore/Public/winget/ManifestCommon.h | 1+
Msrc/AppInstallerSharedLib/Errors.cpp | 2++
Msrc/AppInstallerSharedLib/Public/AppInstallerErrors.h | 1+
14 files changed, 80 insertions(+), 2 deletions(-)

diff --git a/doc/windows/package-manager/winget/returnCodes.md b/doc/windows/package-manager/winget/returnCodes.md @@ -146,6 +146,7 @@ Installation failed. Restart your PC then try again. | | 0x8A150111 | -1978334959 | APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE_BY_APPLICATION | Application is currently in use by another application. | | 0x8A150112 | -1978334958 | APPINSTALLER_CLI_ERROR_INSTALL_INVALID_PARAMETER | Invalid parameter. | | 0x8A150113 | -1978334957 | APPINSTALLER_CLI_ERROR_INSTALL_SYSTEM_NOT_SUPPORTED | Package not supported by the system. | +| 0x8A150114 | -1978334956 | APPINSTALLER_CLI_ERROR_INSTALL_UPGRADE_NOT_SUPPORTED | The installer does not support upgrading an existing package. | ## Check for package installed status diff --git a/schemas/JSON/manifests/v1.6.0/manifest.installer.1.6.0.json b/schemas/JSON/manifests/v1.6.0/manifest.installer.1.6.0.json @@ -255,7 +255,8 @@ "type": [ "string", "null" ], "enum": [ "install", - "uninstallPrevious" + "uninstallPrevious", + "deny" ], "description": "The upgrade method" }, diff --git a/schemas/JSON/manifests/v1.6.0/manifest.singleton.1.6.0.json b/schemas/JSON/manifests/v1.6.0/manifest.singleton.1.6.0.json @@ -355,7 +355,8 @@ "type": [ "string", "null" ], "enum": [ "install", - "uninstallPrevious" + "uninstallPrevious", + "deny" ], "description": "The upgrade method" }, diff --git a/src/AppInstallerCLICore/Resources.h b/src/AppInstallerCLICore/Resources.h @@ -552,6 +552,7 @@ namespace AppInstaller::CLI::Resource WINGET_DEFINE_RESOURCE_STRINGID(UpgradeArgumentDescription); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeAvailableForPinned); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeBlockedByPinCount); + WINGET_DEFINE_RESOURCE_STRINGID(UpgradeBlockedByManifest); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeCommandLongDescription); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeCommandShortDescription); WINGET_DEFINE_RESOURCE_STRINGID(UpgradeDifferentInstallTechnology); diff --git a/src/AppInstallerCLICore/Workflows/InstallFlow.cpp b/src/AppInstallerCLICore/Workflows/InstallFlow.cpp @@ -594,6 +594,17 @@ namespace AppInstaller::CLI::Workflow AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_INSTALLER_PROHIBITS_ELEVATION); } + // This installer cannot be used to upgrade the currently installed application + // Because the upgrade mechanism may be package-specific, simply block. + bool isUpdate = WI_IsFlagSet(context.GetFlags(), Execution::ContextFlag::InstallerExecutionUseUpdate); + UpdateBehaviorEnum updateBehavior = installer->UpdateBehavior; + if (isUpdate && (updateBehavior == UpdateBehaviorEnum::Deny)) + { + AICLI_LOG(CLI, Info, << "Manifest specifies update behavior is denied. The attempt will be cancelled."); + context.Reporter.Error() << Resource::String::UpgradeBlockedByManifest << std::endl; + AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_INSTALL_UPGRADE_NOT_SUPPORTED); + } + context << Workflow::EnsureRunningAsAdminForMachineScopeInstall << Workflow::EnsureSupportForPortableInstall << diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs @@ -271,6 +271,7 @@ namespace AppInstallerCLIE2ETests public const int ERROR_INSTALL_PACKAGE_IN_USE_BY_APPLICATION = unchecked((int)0x8A150111); public const int ERROR_INSTALL_INVALID_PARAMETER = unchecked((int)0x8A150112); public const int ERROR_INSTALL_SYSTEM_NOT_SUPPORTED = unchecked((int)0x8A150113); + public const int APPINSTALLER_CLI_ERROR_INSTALL_UPGRADE_NOT_SUPPORTED = unchecked((int)0x8A150114); public const int INSTALLED_STATUS_ARP_ENTRY_NOT_FOUND = unchecked((int)0x8A150201); public const int INSTALLED_STATUS_INSTALL_LOCATION_NOT_APPLICABLE = unchecked((int)0x0A150202); diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestUpgradeDeny.1.0.0.0.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestUpgradeDeny.1.0.0.0.yaml @@ -0,0 +1,15 @@ +PackageIdentifier: AppInstallerTest.TestUpgradeDeny +PackageVersion: 1.0.0.0 +PackageName: TestUpgradeDeny +PackageLocale: en-US +Publisher: AppInstallerTest +License: Test +ShortDescription: E2E test for upgrade deny. +Installers: + - Architecture: x64 + InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + InstallerType: portable + InstallerSha256: <EXEHASH> + UpgradeBehavior: deny +ManifestType: singleton +ManifestVersion: 1.6.0+ \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestUpgradeDeny.2.0.0.0.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestUpgradeDeny.2.0.0.0.yaml @@ -0,0 +1,15 @@ +PackageIdentifier: AppInstallerTest.TestUpgradeDeny +PackageVersion: 2.0.0.0 +PackageName: TestUpgradeDeny +PackageLocale: en-US +Publisher: AppInstallerTest +License: Test +ShortDescription: E2E test for upgrade deny. +Installers: + - Architecture: x64 + InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + InstallerType: portable + InstallerSha256: <EXEHASH> + UpgradeBehavior: deny +ManifestType: singleton +ManifestVersion: 1.6.0+ \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/UpgradeCommand.cs b/src/AppInstallerCLIE2ETests/UpgradeCommand.cs @@ -112,6 +112,23 @@ namespace AppInstallerCLIE2ETests } /// <summary> + /// Test upgrade with deny behavior. + /// </summary> + [Test] + public void UpgradeBehaviorDeny() + { + string packageId = "AppInstallerTest.TestUpgradeDeny"; + + var result = TestCommon.RunAICLICommand("install", $"{packageId} -v 1.0.0.0"); + Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); + Assert.True(result.StdOut.Contains("Successfully installed")); + + var result2 = TestCommon.RunAICLICommand("upgrade", $"{packageId} -v 2.0.0.0"); + Assert.AreEqual(Constants.ErrorCode.APPINSTALLER_CLI_ERROR_INSTALL_UPGRADE_NOT_SUPPORTED, result2.ExitCode); + Assert.True(result2.StdOut.Contains("package cannot be upgraded using winget")); + } + + /// <summary> /// Test upgrade portable package machine scope. /// </summary> [Test] diff --git a/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw b/src/AppInstallerCLIPackage/Shared/Strings/en-us/winget.resw @@ -1697,6 +1697,9 @@ Please specify one of them using the --source option to proceed.</value> <value>{0} package(s) have a pin that needs to be removed before upgrade</value> <comment>{Locked="{0}"} {0} is a placeholder that is replaced by an integer number of packages with pins that prevent upgrade</comment> </data> + <data name="UpgradeBlockedByManifest" xml:space="preserve"> + <value>The package cannot be upgraded using winget. Please use the method provided by the publisher for upgrading this package.</value> + </data> <data name="IncludePinnedArgumentDescription" xml:space="preserve"> <value>Upgrade packages even if they have a non-blocking pin</value> </data> diff --git a/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp b/src/AppInstallerCommonCore/Manifest/ManifestCommon.cpp @@ -178,6 +178,10 @@ namespace AppInstaller::Manifest { result = UpdateBehaviorEnum::UninstallPrevious; } + else if (Utility::CaseInsensitiveEquals(in, "deny")) + { + result = UpdateBehaviorEnum::Deny; + } return result; } @@ -641,6 +645,8 @@ namespace AppInstaller::Manifest return "install"sv; case UpdateBehaviorEnum::UninstallPrevious: return "uninstallPrevious"sv; + case UpdateBehaviorEnum::Deny: + return "deny"sv; } return "unknown"sv; diff --git a/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h b/src/AppInstallerCommonCore/Public/winget/ManifestCommon.h @@ -96,6 +96,7 @@ namespace AppInstaller::Manifest Unknown, Install, UninstallPrevious, + Deny, }; enum class InstallerSwitchType diff --git a/src/AppInstallerSharedLib/Errors.cpp b/src/AppInstallerSharedLib/Errors.cpp @@ -270,6 +270,8 @@ namespace AppInstaller return "Invalid parameter."; case APPINSTALLER_CLI_ERROR_INSTALL_SYSTEM_NOT_SUPPORTED: return "Package not supported by the system."; + case APPINSTALLER_CLI_ERROR_INSTALL_UPGRADE_NOT_SUPPORTED: + return "The installer does not support upgrading an existing package."; // Status values for check package installed status results. case WINGET_INSTALLED_STATUS_ARP_ENTRY_NOT_FOUND: diff --git a/src/AppInstallerSharedLib/Public/AppInstallerErrors.h b/src/AppInstallerSharedLib/Public/AppInstallerErrors.h @@ -142,6 +142,7 @@ #define APPINSTALLER_CLI_ERROR_INSTALL_PACKAGE_IN_USE_BY_APPLICATION ((HRESULT)0x8A150111) #define APPINSTALLER_CLI_ERROR_INSTALL_INVALID_PARAMETER ((HRESULT)0x8A150112) #define APPINSTALLER_CLI_ERROR_INSTALL_SYSTEM_NOT_SUPPORTED ((HRESULT)0x8A150113) +#define APPINSTALLER_CLI_ERROR_INSTALL_UPGRADE_NOT_SUPPORTED ((HRESULT)0x8A150114) // Status values for check package installed status results. // Partial success has the success bit(first bit) set to 0.