winget-cli

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

commit a9c9cd678c8643bcd106af27c41c11a00487597c
parent 6bfc3d04c4a7f917815486fddcf1042c8ba1fb10
Author: Ryan Fu <69221034+ryfu-msft@users.noreply.github.com>
Date:   Mon, 13 Feb 2023 10:05:28 -0800

Add support for elevation requirement in COM (#2919)


Diffstat:
Msrc/AppInstallerCLIE2ETests/Interop/InstallInterop.cs | 36++++++++++++++++++++++++++++++++++++
Asrc/AppInstallerCLIE2ETests/TestData/Manifests/TestZipInstaller_PackageInstallerInfo.yaml | 22++++++++++++++++++++++
Msrc/Microsoft.Management.Deployment/Converters.cpp | 17+++++++++++++++++
Msrc/Microsoft.Management.Deployment/Converters.h | 1+
Msrc/Microsoft.Management.Deployment/PackageInstallerInfo.cpp | 4++++
Msrc/Microsoft.Management.Deployment/PackageInstallerInfo.h | 2++
Msrc/Microsoft.Management.Deployment/PackageManager.idl | 34+++++++++++++++++++++++++++-------
Msrc/Microsoft.Management.Deployment/PackageVersionInfo.cpp | 27++++++++++++++++++++++++---
Msrc/Microsoft.Management.Deployment/PackageVersionInfo.h | 2++
9 files changed, 135 insertions(+), 10 deletions(-)

diff --git a/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs b/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs @@ -516,5 +516,41 @@ namespace AppInstallerCLIE2ETests.Interop // Assert Assert.AreEqual(InstallResultStatus.Ok, installResult.Status); } + + /// <summary> + /// Test to verify the GetApplicableInstaller() COM call returns the correct manifest installer metadata. + /// </summary> + [Test] + public void GetApplicableInstaller() + { + // Find package + var searchResult = this.FindAllPackages(this.testSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, "AppInstallerTest.PackageInstallerInfo"); + Assert.AreEqual(1, searchResult.Count); + + // Configure installation + var catalogPackage = searchResult[0].CatalogPackage; + var packageVersionId = catalogPackage.AvailableVersions[0]; + var packageVersionInfo = catalogPackage.GetPackageVersionInfo(packageVersionId); + + // Use install options with no applicable match. + var badInstallOptions = this.TestFactory.CreateInstallOptions(); + badInstallOptions.PackageInstallScope = PackageInstallScope.System; + + Assert.IsNull(packageVersionInfo.GetApplicableInstaller(badInstallOptions)); + + // Use install options with valid applicable match. + var installOptions = this.TestFactory.CreateInstallOptions(); + installOptions.PackageInstallScope = PackageInstallScope.User; + var packageInstallerInfo = packageVersionInfo.GetApplicableInstaller(installOptions); + + // Assert + Assert.IsNotNull(packageInstallerInfo); + Assert.AreEqual(ElevationRequirement.ElevationRequired, packageInstallerInfo.ElevationRequirement); + Assert.AreEqual(Windows.System.ProcessorArchitecture.X64, packageInstallerInfo.Architecture); + Assert.AreEqual(PackageInstallerType.Zip, packageInstallerInfo.InstallerType); + Assert.AreEqual(PackageInstallerType.Exe, packageInstallerInfo.NestedInstallerType); + Assert.AreEqual(PackageInstallerScope.User, packageInstallerInfo.Scope); + Assert.AreEqual("en-US", packageInstallerInfo.Locale); + } } } \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestZipInstaller_PackageInstallerInfo.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestZipInstaller_PackageInstallerInfo.yaml @@ -0,0 +1,21 @@ +# Test manifest for verifying the behavior of retrieving a PackageInstallerInfo COM object. +PackageIdentifier: AppInstallerTest.PackageInstallerInfo +PackageVersion: 1.0.0.0 +PackageName: TestPackageInstallerInfo +PackageLocale: en-US +Publisher: AppInstallerTest +License: Test +ShortDescription: E2E test for PackageInstallerInfo COM object. +Installers: + - Architecture: x64 + Scope: User + InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestZipInstaller/AppInstallerTestZipInstaller.zip + InstallerType: zip + InstallerSha256: <EXEHASH> + NestedInstallerType: exe + NestedInstallerFiles: + - RelativeFilePath: AppInstallerTestExeInstaller.exe + ElevationRequirement: elevationRequired + InstallerLocale: en-US +ManifestType: singleton +ManifestVersion: 1.4.0+ \ No newline at end of file diff --git a/src/Microsoft.Management.Deployment/Converters.cpp b/src/Microsoft.Management.Deployment/Converters.cpp @@ -322,4 +322,21 @@ namespace winrt::Microsoft::Management::Deployment::implementation return ::AppInstaller::Manifest::ScopeEnum::Unknown; } + + winrt::Microsoft::Management::Deployment::ElevationRequirement GetDeploymentElevationRequirement(::AppInstaller::Manifest::ElevationRequirementEnum elevationRequirement) + { + switch (elevationRequirement) + { + case ::AppInstaller::Manifest::ElevationRequirementEnum::ElevationRequired: + return Microsoft::Management::Deployment::ElevationRequirement::ElevationRequired; + case ::AppInstaller::Manifest::ElevationRequirementEnum::ElevationProhibited: + return Microsoft::Management::Deployment::ElevationRequirement::ElevationProhibited; + case ::AppInstaller::Manifest::ElevationRequirementEnum::ElevatesSelf: + return Microsoft::Management::Deployment::ElevationRequirement::ElevatesSelf; + case ::AppInstaller::Manifest::ElevationRequirementEnum::Unknown: + return Microsoft::Management::Deployment::ElevationRequirement::Unknown; + } + + return Microsoft::Management::Deployment::ElevationRequirement::Unknown; + } } diff --git a/src/Microsoft.Management.Deployment/Converters.h b/src/Microsoft.Management.Deployment/Converters.h @@ -21,6 +21,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::Microsoft::Management::Deployment::PackageInstallerType GetDeploymentInstallerType(::AppInstaller::Manifest::InstallerTypeEnum installerType); winrt::Microsoft::Management::Deployment::PackageInstallerScope GetDeploymentInstallerScope(::AppInstaller::Manifest::ScopeEnum installerScope); ::AppInstaller::Manifest::ScopeEnum GetManifestUninstallScope(winrt::Microsoft::Management::Deployment::PackageUninstallScope scope); + winrt::Microsoft::Management::Deployment::ElevationRequirement GetDeploymentElevationRequirement(::AppInstaller::Manifest::ElevationRequirementEnum elevationRequirement); #define WINGET_GET_OPERATION_RESULT_STATUS(_installResultStatus_, _uninstallResultStatus_) \ if constexpr (std::is_same_v<TStatus, winrt::Microsoft::Management::Deployment::InstallResultStatus>) \ diff --git a/src/Microsoft.Management.Deployment/PackageInstallerInfo.cpp b/src/Microsoft.Management.Deployment/PackageInstallerInfo.cpp @@ -33,4 +33,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation { return winrt::to_hstring(m_manifestInstaller.Locale); } + winrt::Microsoft::Management::Deployment::ElevationRequirement PackageInstallerInfo::ElevationRequirement() + { + return GetDeploymentElevationRequirement(m_manifestInstaller.ElevationRequirement); + } } diff --git a/src/Microsoft.Management.Deployment/PackageInstallerInfo.h b/src/Microsoft.Management.Deployment/PackageInstallerInfo.h @@ -19,6 +19,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::Windows::System::ProcessorArchitecture Architecture(); winrt::Microsoft::Management::Deployment::PackageInstallerScope Scope(); hstring Locale(); + // Contract 6.0 + winrt::Microsoft::Management::Deployment::ElevationRequirement ElevationRequirement(); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: diff --git a/src/Microsoft.Management.Deployment/PackageManager.idl b/src/Microsoft.Management.Deployment/PackageManager.idl @@ -274,12 +274,12 @@ namespace Microsoft.Management.Deployment /// Gets the publisher string for this package version, if one is available. String Publisher { get; }; } - - /// DESIGN NOTE: - /// GetManifest from IPackageVersion in winget/RepositorySearch is not implemented in V1. That class has - /// a lot of fields and no one requesting it. - /// Gets the manifest of this package version. - /// virtual Manifest::Manifest GetManifest() = 0; + + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + { + /// Gets the applicable installer for this package version. + PackageInstallerInfo GetApplicableInstaller(InstallOptions options); + } } /// IMPLEMENTATION NOTE: PackageVersionKey from winget/RepositorySearch.h @@ -335,6 +335,20 @@ namespace Microsoft.Management.Deployment System, }; + /// The package installer elevation requirement. + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + enum ElevationRequirement + { + /// Elevation requirement not declared. + Unknown, + /// Package installer requires elevation. + ElevationRequired, + /// Package installer prohibits elevation. + ElevationProhibited, + /// Package installer elevates self. + ElevatesSelf, + }; + /// Interface for retrieving information about a package installer. [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 5)] runtimeclass PackageInstallerInfo @@ -348,7 +362,13 @@ namespace Microsoft.Management.Deployment /// The package installer scope. PackageInstallerScope Scope { get; }; /// The package installer locale. - String Locale{ get; }; + String Locale { get; }; + + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + { + /// The package installer elevation requirement. + ElevationRequirement ElevationRequirement { get; }; + } }; /// The installed status type. The values need to match InstalledStatusType from winget/RepositorySearch.h. diff --git a/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp b/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp @@ -7,6 +7,7 @@ #include "PackageVersionInfo.g.cpp" #include "PackageCatalogInfo.h" #include "PackageCatalog.h" +#include "PackageInstallerInfo.h" #include "CatalogPackage.h" #include "ComContext.h" #include "Workflows/WorkflowBase.h" @@ -27,6 +28,10 @@ namespace winrt::Microsoft::Management::Deployment::implementation { m_packageVersion = std::move(packageVersion); } + std::shared_ptr<::AppInstaller::Repository::IPackageVersion> PackageVersionInfo::GetRepositoryPackageVersion() + { + return m_packageVersion; + } hstring PackageVersionInfo::GetMetadata(winrt::Microsoft::Management::Deployment::PackageVersionMetadataField const& metadataField) { ::AppInstaller::Repository::PackageVersionMetadata metadataKey = GetRepositoryPackageVersionMetadata(metadataField); @@ -134,8 +139,24 @@ namespace winrt::Microsoft::Management::Deployment::implementation auto result = manifestComparator.GetPreferredInstaller(manifest); return result.installer.has_value(); } - std::shared_ptr<::AppInstaller::Repository::IPackageVersion> PackageVersionInfo::GetRepositoryPackageVersion() - { - return m_packageVersion; + winrt::Microsoft::Management::Deployment::PackageInstallerInfo PackageVersionInfo::GetApplicableInstaller(InstallOptions options) + { + AppInstaller::CLI::Execution::COMContext context; + PopulateContextFromInstallOptions(&context, options); + AppInstaller::Repository::IPackageVersion::Metadata installationMetadata; + AppInstaller::CLI::Workflow::ManifestComparator manifestComparator{ context, installationMetadata }; + AppInstaller::Manifest::Manifest manifest = m_packageVersion->GetManifest(); + auto result = manifestComparator.GetPreferredInstaller(manifest); + + if (result.installer.has_value()) + { + auto packageInstallerInfo = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageInstallerInfo>>(); + packageInstallerInfo->Initialize(result.installer.value()); + return *packageInstallerInfo; + } + else + { + return nullptr; + } } } diff --git a/src/Microsoft.Management.Deployment/PackageVersionInfo.h b/src/Microsoft.Management.Deployment/PackageVersionInfo.h @@ -26,6 +26,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::Microsoft::Management::Deployment::CompareResult CompareToVersion(hstring versionString); // Contract version 4 bool HasApplicableInstaller(InstallOptions options); + // Contract version 6 + winrt::Microsoft::Management::Deployment::PackageInstallerInfo GetApplicableInstaller(InstallOptions options); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: