winget-cli

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

commit 6966cf11730f43aaafef98cd9358008f01811ba0
parent f19f8934d1b7509fe600d1d842ae9ce81d560064
Author: Ryan Fu <69221034+ryfu-msft@users.noreply.github.com>
Date:   Wed,  8 Mar 2023 12:57:24 -0800

Expose Agreements and Locale Fields in COM (#2897)


Diffstat:
Msrc/AppInstallerCLICore/COMContext.h | 2--
Msrc/AppInstallerCLICore/ExecutionContext.h | 5++---
Msrc/AppInstallerCLICore/Workflows/PromptFlow.cpp | 12------------
Msrc/AppInstallerCLIE2ETests/Interop/BaseInterop.cs | 1+
Msrc/AppInstallerCLIE2ETests/Interop/FindPackagesInterop.cs | 133++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
Msrc/AppInstallerCLIE2ETests/Interop/InstallInterop.cs | 47+++++++++++++++++++++++++++++++++++++++++++++++
Asrc/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_CatalogPackageMetadata.yaml | 48++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_MultipleLocale.yaml | 58++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/AppInstallerRepositoryCore/Public/winget/RepositorySource.h | 8+++++---
Msrc/Microsoft.Management.Deployment.Projection/ClassesDefinition.cs | 4++--
Msrc/Microsoft.Management.Deployment/CatalogPackage.cpp | 1+
Asrc/Microsoft.Management.Deployment/CatalogPackageMetadata.cpp | 137+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Microsoft.Management.Deployment/CatalogPackageMetadata.h | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/Microsoft.Management.Deployment/Converters.h | 3+++
Asrc/Microsoft.Management.Deployment/Documentation.cpp | 22++++++++++++++++++++++
Asrc/Microsoft.Management.Deployment/Documentation.h | 25+++++++++++++++++++++++++
Msrc/Microsoft.Management.Deployment/InstallOptions.cpp | 9++++++++-
Msrc/Microsoft.Management.Deployment/InstallOptions.h | 3+++
Msrc/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj | 8++++++++
Msrc/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters | 8++++++++
Asrc/Microsoft.Management.Deployment/PackageAgreement.cpp | 26++++++++++++++++++++++++++
Asrc/Microsoft.Management.Deployment/PackageAgreement.h | 26++++++++++++++++++++++++++
Msrc/Microsoft.Management.Deployment/PackageCatalogReference.cpp | 35++++++++++++++++++++++++++++++++++-
Msrc/Microsoft.Management.Deployment/PackageCatalogReference.h | 7+++++++
Msrc/Microsoft.Management.Deployment/PackageManager.cpp | 11+++++++++++
Msrc/Microsoft.Management.Deployment/PackageManager.idl | 117+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/Microsoft.Management.Deployment/PackageVersionInfo.cpp | 34+++++++++++++++++++++++++++++++++-
Msrc/Microsoft.Management.Deployment/PackageVersionInfo.h | 8+++++---
Asrc/Microsoft.Management.Deployment/SourceAgreement.cpp | 27+++++++++++++++++++++++++++
Asrc/Microsoft.Management.Deployment/SourceAgreement.h | 26++++++++++++++++++++++++++
30 files changed, 887 insertions(+), 31 deletions(-)

diff --git a/src/AppInstallerCLICore/COMContext.h b/src/AppInstallerCLICore/COMContext.h @@ -40,14 +40,12 @@ namespace AppInstaller::CLI::Execution { Reporter.SetChannel(Reporter::Channel::Disabled); Reporter.SetProgressSink(this); - SetFlags(CLI::Execution::ContextFlag::AgreementsAcceptedByCaller); SetFlags(CLI::Execution::ContextFlag::DisableInteractivity); } COMContext(std::ostream& out, std::istream& in) : CLI::Execution::Context(out, in) { Reporter.SetProgressSink(this); - SetFlags(CLI::Execution::ContextFlag::AgreementsAcceptedByCaller); SetFlags(CLI::Execution::ContextFlag::DisableInteractivity); } diff --git a/src/AppInstallerCLICore/ExecutionContext.h b/src/AppInstallerCLICore/ExecutionContext.h @@ -59,11 +59,10 @@ namespace AppInstaller::CLI::Execution InstallerExecutionUseUpdate = 0x1, InstallerHashMatched = 0x2, InstallerTrusted = 0x4, - AgreementsAcceptedByCaller = 0x8, // Allows a failure in a single source to generate a warning rather than an error. // TODO: Remove when the source interface is refactored. - TreatSourceFailuresAsWarning = 0x10, - ShowSearchResultsOnPartialFailure = 0x20, + TreatSourceFailuresAsWarning = 0x8, + ShowSearchResultsOnPartialFailure = 0x10, DisableInteractivity = 0x40, }; diff --git a/src/AppInstallerCLICore/Workflows/PromptFlow.cpp b/src/AppInstallerCLICore/Workflows/PromptFlow.cpp @@ -189,12 +189,6 @@ namespace AppInstaller::CLI::Workflow return; } - if (WI_IsFlagSet(context.GetFlags(), Execution::ContextFlag::AgreementsAcceptedByCaller)) - { - AICLI_LOG(CLI, Info, << "Skipping package agreements acceptance check because AgreementsAcceptedByCaller flag is set."); - return; - } - if (context.Args.Contains(Execution::Args::Type::AcceptPackageAgreements)) { AICLI_LOG(CLI, Info, << "Package agreements accepted by CLI flag"); @@ -387,12 +381,6 @@ namespace AppInstaller::CLI::Workflow void HandleSourceAgreements::operator()(Execution::Context& context) const { - if (WI_IsFlagSet(context.GetFlags(), Execution::ContextFlag::AgreementsAcceptedByCaller)) - { - AICLI_LOG(CLI, Info, << "Skipping source agreements acceptance check because AgreementsAcceptedByCaller flag is set."); - return; - } - bool allAccepted = true; if (m_source.IsComposite()) diff --git a/src/AppInstallerCLIE2ETests/Interop/BaseInterop.cs b/src/AppInstallerCLIE2ETests/Interop/BaseInterop.cs @@ -78,6 +78,7 @@ namespace AppInstallerCLIE2ETests.Interop // Connect and find package var source = packageCatalogReference.Connect().PackageCatalog; + return source.FindPackages(findPackageOptions).Matches; } } diff --git a/src/AppInstallerCLIE2ETests/Interop/FindPackagesInterop.cs b/src/AppInstallerCLIE2ETests/Interop/FindPackagesInterop.cs @@ -5,7 +5,7 @@ // ----------------------------------------------------------------------------- namespace AppInstallerCLIE2ETests.Interop -{ +{ using Microsoft.Management.Deployment; using Microsoft.Management.Deployment.Projection; using NUnit.Framework; @@ -64,5 +64,136 @@ namespace AppInstallerCLIE2ETests.Interop // Assert Assert.AreEqual(2, searchResult.Count); } + + /// <summary> + /// Test to find a package and verify the CatalogPackageMetadata COM output. + /// </summary> + [Test] + public void FindPackagesVerifyDefaultLocaleFields() + { + var searchResult = this.FindAllPackages(this.testSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, "AppInstallerTest.CatalogPackageMetadata"); + + Assert.AreEqual(1, searchResult.Count); + + var catalogPackage = searchResult[0].CatalogPackage; + var packageVersionId = catalogPackage.AvailableVersions[0]; + var packageVersionInfo = catalogPackage.GetPackageVersionInfo(packageVersionId); + var catalogPackageMetadata = packageVersionInfo.GetCatalogPackageMetadata(); + + Assert.AreEqual("testAuthor", catalogPackageMetadata.Author); + Assert.AreEqual("AppInstallerTest", catalogPackageMetadata.Publisher); + Assert.AreEqual("https://testPublisherUrl.com", catalogPackageMetadata.PublisherUrl); + Assert.AreEqual("https://testPublisherSupportUrl.com", catalogPackageMetadata.PublisherSupportUrl); + Assert.AreEqual("https://testPrivacyUrl.com", catalogPackageMetadata.PrivacyUrl); + + Assert.AreEqual("https://testPackageUrl.com", catalogPackageMetadata.PackageUrl); + Assert.AreEqual("testLicense", catalogPackageMetadata.License); + Assert.AreEqual("https://testLicenseUrl.com", catalogPackageMetadata.LicenseUrl); + Assert.AreEqual("testCopyright", catalogPackageMetadata.Copyright); + Assert.AreEqual("https://testCopyrightUrl.com", catalogPackageMetadata.CopyrightUrl); + Assert.AreEqual("testDescription", catalogPackageMetadata.Description); + Assert.AreEqual("testShortDescription", catalogPackageMetadata.ShortDescription); + Assert.AreEqual("https://testPurchaseUrl.com", catalogPackageMetadata.PurchaseUrl); + + var tags = catalogPackageMetadata.Tags; + Assert.AreEqual(2, tags.Count); + Assert.AreEqual("tag1", tags[0]); + Assert.AreEqual("tag2", tags[1]); + Assert.AreEqual("testReleaseNotes", catalogPackageMetadata.ReleaseNotes); + Assert.AreEqual("https://testReleaseNotes.net", catalogPackageMetadata.ReleaseNotesUrl); + Assert.AreEqual("testInstallationNotes", catalogPackageMetadata.InstallationNotes); + + var packageAgreements = catalogPackageMetadata.Agreements; + Assert.AreEqual(1, packageAgreements.Count); + + var agreement = packageAgreements[0]; + Assert.AreEqual("testAgreementLabel", agreement.Label); + Assert.AreEqual("testAgreementText", agreement.Text); + Assert.AreEqual("https://testAgreementUrl.net", agreement.Url); + + var documentations = catalogPackageMetadata.Documentations; + Assert.AreEqual(1, documentations.Count); + + var documentation = documentations[0]; + Assert.AreEqual("testDocumentLabel", documentation.DocumentLabel); + Assert.AreEqual("https://testDocumentUrl.com", documentation.DocumentUrl); + } + + /// <summary> + /// Verifies that an exception is thrown if the provided locale string is invalid. + /// </summary> + [Test] + public void FindPackagesInvalidLocale() + { + var searchResult = this.FindAllPackages(this.testSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, "AppInstallerTest.CatalogPackageMetadata"); + var catalogPackage = searchResult[0].CatalogPackage; + var packageVersionId = catalogPackage.AvailableVersions[0]; + var packageVersionInfo = catalogPackage.GetPackageVersionInfo(packageVersionId); + Assert.Throws<System.ArgumentException>(() => packageVersionInfo.GetCatalogPackageMetadata("badLocale")); + } + + /// <summary> + /// Verifies that the correct CatalogPackageMetadata is exposed when specifying a locale. + /// </summary> + [Test] + public void FindPackagesGetCatalogPackageMetadataLocale() + { + var searchResult = this.FindAllPackages(this.testSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, "AppInstallerTest.MultipleLocale"); + Assert.AreEqual(1, searchResult.Count); + + var catalogPackage = searchResult[0].CatalogPackage; + var packageVersionId = catalogPackage.AvailableVersions[0]; + var packageVersionInfo = catalogPackage.GetPackageVersionInfo(packageVersionId); + var catalogPackageMetadata = packageVersionInfo.GetCatalogPackageMetadata("zh-CN"); + + Assert.AreEqual("zh-CN", catalogPackageMetadata.Locale); + Assert.AreEqual("localeLicense", catalogPackageMetadata.License); + Assert.AreEqual("localePackageName", catalogPackageMetadata.PackageName); + Assert.AreEqual("localePublisher", catalogPackageMetadata.Publisher); + Assert.AreEqual("localeReleaseNotes", catalogPackageMetadata.ReleaseNotes); + Assert.AreEqual("https://localeReleaseNotesUrl.com", catalogPackageMetadata.ReleaseNotesUrl); + Assert.AreEqual("https://localePurchaseUrl.com", catalogPackageMetadata.PurchaseUrl); + + var tags = catalogPackageMetadata.Tags; + Assert.AreEqual(2, tags.Count); + Assert.AreEqual("tag1", tags[0]); + Assert.AreEqual("tag2", tags[1]); + + var packageAgreements = catalogPackageMetadata.Agreements; + Assert.AreEqual(1, packageAgreements.Count); + + var agreement = packageAgreements[0]; + Assert.AreEqual("localeAgreementLabel", agreement.Label); + Assert.AreEqual("localeAgreement", agreement.Text); + Assert.AreEqual("https://localeAgreementUrl.net", agreement.Url); + + var documentations = catalogPackageMetadata.Documentations; + Assert.AreEqual(1, documentations.Count); + + var documentation = documentations[0]; + Assert.AreEqual("localeDocumentLabel", documentation.DocumentLabel); + Assert.AreEqual("https://localeDocumentUrl.com", documentation.DocumentUrl); + } + + /// <summary> + /// Verifies that GetCatalogPackageMetadata returns the correct metadata based on the specified locale. + /// </summary> + [Test] + public void FindPackagesGetAllCatalogPackageMetadata() + { + var searchResult = this.FindAllPackages(this.testSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, "AppInstallerTest.MultipleLocale"); + Assert.AreEqual(1, searchResult.Count); + + var catalogPackage = searchResult[0].CatalogPackage; + var packageVersionId = catalogPackage.AvailableVersions[0]; + var packageVersionInfo = catalogPackage.GetPackageVersionInfo(packageVersionId); + + var catalogPackageMetadata1 = packageVersionInfo.GetCatalogPackageMetadata("zh-CN"); + Assert.AreEqual("zh-CN", catalogPackageMetadata1.Locale); + + var catalogPackageMetadata2 = packageVersionInfo.GetCatalogPackageMetadata("en-GB"); + Assert.AreEqual("en-GB", catalogPackageMetadata2.Locale); + Assert.AreEqual("packageNameUK", catalogPackageMetadata2.PackageName); + } } } \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs b/src/AppInstallerCLIE2ETests/Interop/InstallInterop.cs @@ -58,6 +58,7 @@ namespace AppInstallerCLIE2ETests.Interop var installOptions = this.TestFactory.CreateInstallOptions(); installOptions.PackageInstallMode = PackageInstallMode.Silent; installOptions.PreferredInstallLocation = this.installDir; + installOptions.AcceptPackageAgreements = true; // Install var installResult = await this.packageManager.InstallPackageAsync(searchResult.CatalogPackage, installOptions); @@ -518,6 +519,52 @@ namespace AppInstallerCLIE2ETests.Interop } /// <summary> + /// Test installing package with agreements and accepting those agreements. + /// </summary> + /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns> + [Test] + public async Task InstallWithAgreementsAccepted() + { + // Find package + var searchResult = this.FindOnePackage(this.testSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, "AppInstallerTest.CatalogPackageMetadata"); + + // Configure installation + var installOptions = this.TestFactory.CreateInstallOptions(); + installOptions.PackageInstallMode = PackageInstallMode.Silent; + installOptions.PreferredInstallLocation = this.installDir; + installOptions.AcceptPackageAgreements = true; + + // Install + var installResult = await this.packageManager.InstallPackageAsync(searchResult.CatalogPackage, installOptions); + + // Assert + Assert.AreEqual(InstallResultStatus.Ok, installResult.Status); + } + + /// <summary> + /// Test installing package with agreements and not accepting those agreements. + /// </summary> + /// <returns>A <see cref="Task"/> representing the asynchronous unit test.</returns> + [Test] + public async Task InstallWithAgreementsNotAccepted() + { + // Find package + var searchResult = this.FindOnePackage(this.testSource, PackageMatchField.Id, PackageFieldMatchOption.Equals, "AppInstallerTest.CatalogPackageMetadata"); + + // Configure installation + var installOptions = this.TestFactory.CreateInstallOptions(); + installOptions.PackageInstallMode = PackageInstallMode.Silent; + installOptions.PreferredInstallLocation = this.installDir; + installOptions.AcceptPackageAgreements = false; + + // Install + var installResult = await this.packageManager.InstallPackageAsync(searchResult.CatalogPackage, installOptions); + + // Assert + Assert.AreEqual(InstallResultStatus.PackageAgreementsNotAccepted, installResult.Status); + } + + /// <summary> /// Test to verify the GetApplicableInstaller() COM call returns the correct manifest installer metadata. /// </summary> [Test] diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_CatalogPackageMetadata.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_CatalogPackageMetadata.yaml @@ -0,0 +1,47 @@ +# Manifest for verifying the output of the CatalogPackageMetadata COM object. +PackageIdentifier: AppInstallerTest.CatalogPackageMetadata +PackageVersion: 1.0.0.0 +PackageName: TestCatalogPackageMetadata +PackageLocale: en-US +Publisher: AppInstallerTest +License: testLicense +ShortDescription: testShortDescription +Installers: + - Architecture: x64 + InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + InstallerType: exe + InstallerSha256: <EXEHASH> + InstallerSwitches: + Custom: /execustom + SilentWithProgress: /exeswp + Silent: /exesilent + Interactive: /exeinteractive + Language: /exeenus + Log: /LogFile <LOGPATH> + InstallLocation: /InstallDir <INSTALLPATH> +Agreements: + - AgreementLabel: testAgreementLabel + Agreement: testAgreementText + AgreementUrl: https://testAgreementUrl.net +PublisherUrl: https://testPublisherUrl.com +PublisherSupportUrl: https://testPublisherSupportUrl.com +PrivacyUrl: https://testPrivacyUrl.com +Author: testAuthor +PackageUrl: https://testPackageUrl.com +LicenseUrl: https://testLicenseUrl.com +Copyright: testCopyright +CopyrightUrl: https://testCopyrightUrl.com +Description: testDescription +Moniker: testMoniker +PurchaseUrl: https://testPurchaseUrl.com +Tags: + - "tag1" + - "tag2" +ReleaseNotes: testReleaseNotes +ReleaseNotesUrl: https://testReleaseNotes.net +InstallationNotes: testInstallationNotes +Documentations: + - DocumentLabel: testDocumentLabel + DocumentUrl: https://testDocumentUrl.com +ManifestType: singleton +ManifestVersion: 1.2.0+ \ No newline at end of file diff --git a/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_MultipleLocale.yaml b/src/AppInstallerCLIE2ETests/TestData/Manifests/TestExeInstaller_MultipleLocale.yaml @@ -0,0 +1,57 @@ +# Manifest for verifying multiple locales +PackageIdentifier: AppInstallerTest.MultipleLocale +PackageVersion: 1.0.0.0 +PackageName: TestMultipleLocale +PackageLocale: en-US +Publisher: AppInstallerTest +License: testLicense +LicenseUrl: https://testLicenseUrl.com +ShortDescription: testShortDescription +Installers: + - Architecture: x64 + InstallerUrl: https://localhost:5001/TestKit/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe + InstallerType: exe + InstallerSha256: <EXEHASH> + InstallerSwitches: + Custom: /execustom + SilentWithProgress: /exeswp + Silent: /exesilent + Interactive: /exeinteractive + Language: /exeenus + Log: /LogFile <LOGPATH> + InstallLocation: /InstallDir <INSTALLPATH> +Agreements: + - AgreementLabel: testAgreementLabel + Agreement: testAgreementText + AgreementUrl: https://testAgreementUrl.net +Localization: +- Author: localeAuthor + Copyright: localeCopyright + License: localeLicense + LicenseUrl: https://localeLicenseUrl.com + PackageLocale: zh-CN + PackageName: localePackageName + PackageUrl: https://localePackageUrl.com + Publisher: localePublisher + PublisherSupportUrl: https://localePublisherSupportUrl.com + PublisherUrl: https://localePublisherUrl.com + Moniker: localeMoniker + PurchaseUrl: https://localePurchaseUrl.com + ReleaseNotes: localeReleaseNotes + ReleaseNotesUrl: https://localeReleaseNotesUrl.com + Agreements: + - AgreementLabel: localeAgreementLabel + Agreement: localeAgreement + AgreementUrl: https://localeAgreementUrl.net + Documentations: + - DocumentLabel: localeDocumentLabel + DocumentUrl: https://localeDocumentUrl.com + Tags: + - tag1 + - tag2 +- PackageLocale: en-GB + PackageName: packageNameUK + License: licenseUK + Publisher: publisherUK +ManifestType: merged +ManifestVersion: 1.2.0+ \ No newline at end of file diff --git a/src/AppInstallerRepositoryCore/Public/winget/RepositorySource.h b/src/AppInstallerRepositoryCore/Public/winget/RepositorySource.h @@ -130,12 +130,14 @@ namespace AppInstaller::Repository // Individual source agreement entry. Label will be highlighted in the display as the key of the agreement entry. struct SourceAgreement { - std::string Label; - std::string Text; - std::string Url; + SourceAgreement() = default; SourceAgreement(std::string label, std::string text, std::string url) : Label(std::move(label)), Text(std::move(text)), Url(std::move(url)) {} + + std::string Label; + std::string Text; + std::string Url; }; // Interface for retrieving information about a source after opening the source. diff --git a/src/Microsoft.Management.Deployment.Projection/ClassesDefinition.cs b/src/Microsoft.Management.Deployment.Projection/ClassesDefinition.cs @@ -80,8 +80,8 @@ namespace Microsoft.Management.Deployment.Projection [ClsidContext.OutOfProc] = new Guid("D02C9DAF-99DC-429C-B503-4E504E4AB000"), [ClsidContext.OutOfProcDev] = new Guid("3F85B9F4-487A-4C48-9035-2903F8A6D9E8"), } - }, - + }, + [typeof(PackageManagerSettings)] = new() { ProjectedClassType = typeof(PackageManagerSettings), diff --git a/src/Microsoft.Management.Deployment/CatalogPackage.cpp b/src/Microsoft.Management.Deployment/CatalogPackage.cpp @@ -12,6 +12,7 @@ #include "CheckInstalledStatusResult.h" #include <wil\cppwinrt_wrl.h> + namespace winrt::Microsoft::Management::Deployment::implementation { void CatalogPackage::Initialize( diff --git a/src/Microsoft.Management.Deployment/CatalogPackageMetadata.cpp b/src/Microsoft.Management.Deployment/CatalogPackageMetadata.cpp @@ -0,0 +1,137 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include <winget/RepositorySource.h> +#include "CatalogPackageMetadata.h" +#include "CatalogPackageMetadata.g.cpp" +#include <wil\cppwinrt_wrl.h> + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + using Localization = ::AppInstaller::Manifest::Localization; + + void CatalogPackageMetadata::Initialize(::AppInstaller::Manifest::ManifestLocalization manifestLocalization) + { + m_manifestLocalization = std::move(manifestLocalization); + } + + hstring CatalogPackageMetadata::Locale() + { + return winrt::to_hstring(m_manifestLocalization.Locale); + } + hstring CatalogPackageMetadata::Publisher() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::Publisher>()); + } + hstring CatalogPackageMetadata::PublisherUrl() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::PublisherUrl>()); + } + hstring CatalogPackageMetadata::PublisherSupportUrl() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::PublisherSupportUrl>()); + } + hstring CatalogPackageMetadata::PrivacyUrl() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::PrivacyUrl>()); + } + hstring CatalogPackageMetadata::Author() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::Author>()); + } + hstring CatalogPackageMetadata::PackageName() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::PackageName>()); + } + hstring CatalogPackageMetadata::PackageUrl() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::PackageUrl>()); + } + hstring CatalogPackageMetadata::License() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::License>()); + } + hstring CatalogPackageMetadata::LicenseUrl() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::LicenseUrl>()); + } + hstring CatalogPackageMetadata::Copyright() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::Copyright>()); + } + hstring CatalogPackageMetadata::CopyrightUrl() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::CopyrightUrl>()); + } + hstring CatalogPackageMetadata::ShortDescription() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::ShortDescription>()); + } + hstring CatalogPackageMetadata::Description() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::Description>()); + } + hstring CatalogPackageMetadata::ReleaseNotes() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::ReleaseNotes>()); + } + hstring CatalogPackageMetadata::ReleaseNotesUrl() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::ReleaseNotesUrl>()); + } + hstring CatalogPackageMetadata::PurchaseUrl() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::PurchaseUrl>()); + } + hstring CatalogPackageMetadata::InstallationNotes() + { + return winrt::to_hstring(m_manifestLocalization.Get<Localization::InstallationNotes>()); + } + winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::PackageAgreement> CatalogPackageMetadata::Agreements() + { + if (!m_packageAgreements) + { + auto agreements = winrt::single_threaded_vector<winrt::Microsoft::Management::Deployment::PackageAgreement>(); + for (auto const& agreement : m_manifestLocalization.Get<AppInstaller::Manifest::Localization::Agreements>()) + { + auto packageAgreement = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::PackageAgreement>>(); + packageAgreement->Initialize(agreement); + agreements.Append(*packageAgreement); + } + m_packageAgreements = agreements; + } + + return m_packageAgreements.GetView(); + } + winrt::Windows::Foundation::Collections::IVectorView<hstring> CatalogPackageMetadata::Tags() + { + if (!m_tags) + { + // Vector hasn't been created yet, create and populate it. + auto tags = winrt::single_threaded_vector<hstring>(); + for (auto&& tag : m_manifestLocalization.Get<Localization::Tags>()) + { + tags.Append(winrt::to_hstring(tag)); + } + m_tags = tags; + } + + return m_tags.GetView(); + } + winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::Documentation> CatalogPackageMetadata::Documentations() + { + if (!m_documentations) + { + auto documentations = winrt::single_threaded_vector<winrt::Microsoft::Management::Deployment::Documentation>(); + for (auto const& documentation : m_manifestLocalization.Get<AppInstaller::Manifest::Localization::Documentations>()) + { + auto documentationImpl = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::Documentation>>(); + documentationImpl->Initialize(documentation); + documentations.Append(*documentationImpl); + } + m_documentations = documentations; + } + + return m_documentations.GetView(); + } +} diff --git a/src/Microsoft.Management.Deployment/CatalogPackageMetadata.h b/src/Microsoft.Management.Deployment/CatalogPackageMetadata.h @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "CatalogPackageMetadata.g.h" +#include "PackageAgreement.h" +#include "Documentation.h" + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + struct CatalogPackageMetadata : CatalogPackageMetadataT<CatalogPackageMetadata> + { + CatalogPackageMetadata() = default; + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + void Initialize(::AppInstaller::Manifest::ManifestLocalization manifestLocalization); +#endif + hstring Locale(); + + hstring Publisher(); + + hstring PublisherUrl(); + + hstring PublisherSupportUrl(); + + hstring PrivacyUrl(); + + hstring Author(); + + hstring PackageName(); + + hstring PackageUrl(); + + hstring License(); + + hstring LicenseUrl(); + + hstring Copyright(); + + hstring CopyrightUrl(); + + hstring ShortDescription(); + + hstring Description(); + + winrt::Windows::Foundation::Collections::IVectorView<hstring> Tags(); + + winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::PackageAgreement> Agreements(); + + winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::Documentation> Documentations(); + + hstring ReleaseNotes(); + + hstring ReleaseNotesUrl(); + + hstring PurchaseUrl(); + + hstring InstallationNotes(); + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + private: + ::AppInstaller::Manifest::ManifestLocalization m_manifestLocalization; + Windows::Foundation::Collections::IVector<winrt::Microsoft::Management::Deployment::PackageAgreement> m_packageAgreements{ nullptr }; + Windows::Foundation::Collections::IVector<winrt::Microsoft::Management::Deployment::Documentation> m_documentations{ nullptr }; + Windows::Foundation::Collections::IVector<hstring> m_tags{ nullptr }; +#endif + }; +} diff --git a/src/Microsoft.Management.Deployment/Converters.h b/src/Microsoft.Management.Deployment/Converters.h @@ -69,6 +69,9 @@ namespace winrt::Microsoft::Management::Deployment::implementation case APPINSTALLER_CLI_ERROR_EXEC_UNINSTALL_COMMAND_FAILED: WINGET_GET_OPERATION_RESULT_STATUS(InstallError, UninstallError); break; + case APPINSTALLER_CLI_ERROR_PACKAGE_AGREEMENTS_NOT_ACCEPTED: + WINGET_GET_OPERATION_RESULT_STATUS(PackageAgreementsNotAccepted, InternalError); + break; case APPINSTALLER_CLI_ERROR_CANNOT_WRITE_TO_UPLEVEL_INDEX: case APPINSTALLER_CLI_ERROR_INDEX_INTEGRITY_COMPROMISED: case APPINSTALLER_CLI_ERROR_YAML_INIT_FAILED: diff --git a/src/Microsoft.Management.Deployment/Documentation.cpp b/src/Microsoft.Management.Deployment/Documentation.cpp @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "Documentation.g.cpp" +#include "Documentation.h" +#include <wil\cppwinrt_wrl.h> + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + void Documentation::Initialize(::AppInstaller::Manifest::Documentation documentation) + { + m_documentation = std::move(documentation); + } + hstring Documentation::DocumentLabel() + { + return winrt::to_hstring(m_documentation.DocumentLabel); + } + hstring Documentation::DocumentUrl() + { + return winrt::to_hstring(m_documentation.DocumentUrl); + } +} diff --git a/src/Microsoft.Management.Deployment/Documentation.h b/src/Microsoft.Management.Deployment/Documentation.h @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "Documentation.g.h" +#include <winget/Manifest.h> + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + struct Documentation : DocumentationT<Documentation> + { + Documentation() = default; + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + void Initialize(::AppInstaller::Manifest::Documentation documentation); +#endif + + hstring DocumentLabel(); + hstring DocumentUrl(); + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + private: + ::AppInstaller::Manifest::Documentation m_documentation{}; +#endif + }; +} diff --git a/src/Microsoft.Management.Deployment/InstallOptions.cpp b/src/Microsoft.Management.Deployment/InstallOptions.cpp @@ -128,6 +128,13 @@ namespace winrt::Microsoft::Management::Deployment::implementation { m_force = value; } - + void InstallOptions::AcceptPackageAgreements(bool value) + { + m_acceptPackageAgreements = value; + } + bool InstallOptions::AcceptPackageAgreements() + { + return m_acceptPackageAgreements; + } CoCreatableMicrosoftManagementDeploymentClass(InstallOptions); } diff --git a/src/Microsoft.Management.Deployment/InstallOptions.h b/src/Microsoft.Management.Deployment/InstallOptions.h @@ -36,6 +36,8 @@ namespace winrt::Microsoft::Management::Deployment::implementation void AllowUpgradeToUnknownVersion(bool value); bool Force(); void Force(bool value); + bool AcceptPackageAgreements(); + void AcceptPackageAgreements(bool value); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: @@ -53,6 +55,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::single_threaded_vector<winrt::Windows::System::ProcessorArchitecture>() }; bool m_allowUpgradeToUnknownVersion = false; bool m_force = false; + bool m_acceptPackageAgreements = true; #endif }; } diff --git a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj @@ -141,6 +141,7 @@ <ClInclude Include="ConnectResult.h" /> <ClInclude Include="Converters.h" /> <ClInclude Include="CreateCompositePackageCatalogOptions.h" /> + <ClInclude Include="Documentation.h" /> <ClInclude Include="FindPackagesOptions.h" /> <ClInclude Include="FindPackagesResult.h" /> <ClInclude Include="Helpers.h" /> @@ -148,11 +149,13 @@ <ClInclude Include="InstallOptions.h" /> <ClInclude Include="InstallResult.h" /> <ClInclude Include="MatchResult.h" /> + <ClInclude Include="PackageAgreement.h" /> <ClInclude Include="PackageCatalog.h" /> <ClInclude Include="PackageCatalogInfo.h" /> <ClInclude Include="PackageCatalogReference.h" /> <ClInclude Include="PackageInstallerInfo.h" /> <ClInclude Include="PackageInstallerInstalledStatus.h" /> + <ClInclude Include="CatalogPackageMetadata.h" /> <ClInclude Include="PackageManager.h" /> <ClInclude Include="PackageManagerSettings.h" /> <ClInclude Include="PackageMatchFilter.h" /> @@ -160,6 +163,7 @@ <ClInclude Include="PackageVersionInfo.h" /> <ClInclude Include="pch.h" /> <ClInclude Include="Public\ComClsids.h" /> + <ClInclude Include="SourceAgreement.h" /> <ClInclude Include="UninstallOptions.h" /> <ClInclude Include="UninstallResult.h" /> </ItemGroup> @@ -170,6 +174,7 @@ <ClCompile Include="ConnectResult.cpp" /> <ClCompile Include="Converters.cpp" /> <ClCompile Include="CreateCompositePackageCatalogOptions.cpp" /> + <ClCompile Include="Documentation.cpp" /> <ClCompile Include="FindPackagesOptions.cpp" /> <ClCompile Include="FindPackagesResult.cpp" /> <ClCompile Include="Helpers.cpp" /> @@ -177,11 +182,13 @@ <ClCompile Include="InstallOptions.cpp" /> <ClCompile Include="InstallResult.cpp" /> <ClCompile Include="MatchResult.cpp" /> + <ClCompile Include="PackageAgreement.cpp" /> <ClCompile Include="PackageCatalog.cpp" /> <ClCompile Include="PackageCatalogInfo.cpp" /> <ClCompile Include="PackageCatalogReference.cpp" /> <ClCompile Include="PackageInstallerInfo.cpp" /> <ClCompile Include="PackageInstallerInstalledStatus.cpp" /> + <ClCompile Include="CatalogPackageMetadata.cpp" /> <ClCompile Include="PackageManager.cpp" /> <ClCompile Include="PackageManagerSettings.cpp" /> <ClCompile Include="PackageMatchFilter.cpp" /> @@ -190,6 +197,7 @@ <ClCompile Include="pch.cpp"> <PrecompiledHeader>Create</PrecompiledHeader> </ClCompile> + <ClCompile Include="SourceAgreement.cpp" /> <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> <ClCompile Include="UninstallOptions.cpp" /> <ClCompile Include="UninstallResult.cpp" /> diff --git a/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters b/src/Microsoft.Management.Deployment/Microsoft.Management.Deployment.vcxproj.filters @@ -5,21 +5,25 @@ <ClCompile Include="ConnectResult.cpp" /> <ClCompile Include="Converters.cpp" /> <ClCompile Include="CreateCompositePackageCatalogOptions.cpp" /> + <ClInclude Include="Documentation.cpp" /> <ClCompile Include="FindPackagesOptions.cpp" /> <ClCompile Include="FindPackagesResult.cpp" /> <ClCompile Include="Helpers.cpp" /> <ClCompile Include="InstallOptions.cpp" /> <ClCompile Include="InstallResult.cpp" /> <ClCompile Include="MatchResult.cpp" /> + <ClCompile Include="PackageAgreement.cpp" /> <ClCompile Include="PackageCatalog.cpp" /> <ClCompile Include="PackageCatalogInfo.cpp" /> <ClCompile Include="PackageCatalogReference.cpp" /> + <ClCompile Include="CatalogPackageMetadata.cpp" /> <ClCompile Include="PackageManager.cpp" /> <ClCompile Include="PackageMatchFilter.cpp" /> <ClCompile Include="PackageVersionId.cpp" /> <ClCompile Include="PackageVersionInfo.cpp" /> <ClCompile Include="pch.cpp" /> <ClCompile Include="$(GeneratedFilesDir)module.g.cpp" /> + <ClCompile Include="SourceAgreement.cpp" /> <ClCompile Include="UninstallOptions.cpp" /> <ClCompile Include="UninstallResult.cpp" /> <ClCompile Include="ComClsids.cpp" /> @@ -34,20 +38,24 @@ <ClInclude Include="ConnectResult.h" /> <ClInclude Include="Converters.h" /> <ClInclude Include="CreateCompositePackageCatalogOptions.h" /> + <ClInclude Include="Documentation.h" /> <ClInclude Include="FindPackagesOptions.h" /> <ClInclude Include="FindPackagesResult.h" /> <ClInclude Include="Helpers.h" /> <ClInclude Include="InstallOptions.h" /> <ClInclude Include="InstallResult.h" /> <ClInclude Include="MatchResult.h" /> + <ClInclude Include="PackageAgreement.h" /> <ClInclude Include="PackageCatalog.h" /> <ClInclude Include="PackageCatalogInfo.h" /> <ClInclude Include="PackageCatalogReference.h" /> + <ClCompile Include="CatalogPackageMetadata.h" /> <ClInclude Include="PackageManager.h" /> <ClInclude Include="PackageMatchFilter.h" /> <ClInclude Include="PackageVersionId.h" /> <ClInclude Include="PackageVersionInfo.h" /> <ClInclude Include="pch.h" /> + <ClCompile Include="SourceAgreement.h" /> <ClInclude Include="UninstallOptions.h" /> <ClInclude Include="UninstallResult.h" /> <ClInclude Include="Public\ComClsids.h"> diff --git a/src/Microsoft.Management.Deployment/PackageAgreement.cpp b/src/Microsoft.Management.Deployment/PackageAgreement.cpp @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include "PackageAgreement.h" +#include "PackageAgreement.g.cpp" +#include <wil\cppwinrt_wrl.h> + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + void PackageAgreement::Initialize(::AppInstaller::Manifest::Agreement packageAgreement) + { + m_packageAgreement = std::move(packageAgreement); + } + hstring PackageAgreement::Label() + { + return winrt::to_hstring(m_packageAgreement.Label); + } + hstring PackageAgreement::Text() + { + return winrt::to_hstring(m_packageAgreement.AgreementText); + } + hstring PackageAgreement::Url() + { + return winrt::to_hstring(m_packageAgreement.AgreementUrl); + } +} diff --git a/src/Microsoft.Management.Deployment/PackageAgreement.h b/src/Microsoft.Management.Deployment/PackageAgreement.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "PackageAgreement.g.h" +#include <winget/Manifest.h> + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + struct PackageAgreement : PackageAgreementT<PackageAgreement> + { + PackageAgreement() = default; + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + void Initialize(::AppInstaller::Manifest::Agreement packageAgreement); +#endif + + hstring Label(); + hstring Text(); + hstring Url(); + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + private: + ::AppInstaller::Manifest::Agreement m_packageAgreement{}; +#endif + }; +} diff --git a/src/Microsoft.Management.Deployment/PackageCatalogReference.cpp b/src/Microsoft.Management.Deployment/PackageCatalogReference.cpp @@ -6,6 +6,7 @@ #include "PackageCatalogReference.g.cpp" #include "PackageCatalogInfo.h" #include "PackageCatalog.h" +#include "SourceAgreement.h" #include "ConnectResult.h" #include "Workflows/WorkflowBase.h" #include "Converters.h" @@ -44,6 +45,12 @@ namespace winrt::Microsoft::Management::Deployment::implementation connectResult->Initialize(winrt::Microsoft::Management::Deployment::ConnectResultStatus::CatalogError, nullptr); return *connectResult; } + winrt::Microsoft::Management::Deployment::ConnectResult GetConnectSourceAgreementsNotAcceptedErrorResult() + { + auto connectResult = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::ConnectResult>>(); + connectResult->Initialize(winrt::Microsoft::Management::Deployment::ConnectResultStatus::SourceAgreementsNotAccepted, nullptr); + return *connectResult; + } winrt::Microsoft::Management::Deployment::ConnectResult PackageCatalogReference::Connect() { try @@ -54,6 +61,11 @@ namespace winrt::Microsoft::Management::Deployment::implementation return GetConnectCatalogErrorResult(); } + if (!m_acceptSourceAgreements && m_sourceAgreements.Size() != 0) + { + return GetConnectSourceAgreementsNotAcceptedErrorResult(); + } + ::AppInstaller::ProgressCallback progress; ::AppInstaller::Repository::Source source; if (m_compositePackageCatalogOptions) @@ -124,7 +136,20 @@ namespace winrt::Microsoft::Management::Deployment::implementation } return GetConnectCatalogErrorResult(); } - + winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::SourceAgreement> PackageCatalogReference::SourceAgreements() + { + std::call_once(m_sourceAgreementsOnceFlag, + [&]() + { + for (auto const& agreement : m_sourceReference.GetInformation().SourceAgreements) + { + auto sourceAgreement = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::SourceAgreement>>(); + sourceAgreement->Initialize(agreement); + m_sourceAgreements.Append(*sourceAgreement); + } + }); + return m_sourceAgreements.GetView(); + } hstring PackageCatalogReference::AdditionalPackageCatalogArguments() { if (!IsComposite()) @@ -150,4 +175,12 @@ namespace winrt::Microsoft::Management::Deployment::implementation m_sourceReference.SetCustomHeader(m_additionalPackageCatalogArguments); } } + void PackageCatalogReference::AcceptSourceAgreements(bool value) + { + m_acceptSourceAgreements = value; + } + bool PackageCatalogReference::AcceptSourceAgreements() + { + return m_acceptSourceAgreements; + } } diff --git a/src/Microsoft.Management.Deployment/PackageCatalogReference.h b/src/Microsoft.Management.Deployment/PackageCatalogReference.h @@ -19,15 +19,22 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::Microsoft::Management::Deployment::PackageCatalogInfo Info(); winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Management::Deployment::ConnectResult> ConnectAsync(); winrt::Microsoft::Management::Deployment::ConnectResult Connect(); + winrt::Windows::Foundation::Collections::IVectorView<winrt::Microsoft::Management::Deployment::SourceAgreement> SourceAgreements(); hstring AdditionalPackageCatalogArguments(); void AdditionalPackageCatalogArguments(hstring const& value); + // Contract 6.0 + bool AcceptSourceAgreements(); + void AcceptSourceAgreements(bool value); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) private: winrt::Microsoft::Management::Deployment::CreateCompositePackageCatalogOptions m_compositePackageCatalogOptions{ nullptr }; winrt::Microsoft::Management::Deployment::PackageCatalogInfo m_info{ nullptr }; + winrt::Windows::Foundation::Collections::IVector<winrt::Microsoft::Management::Deployment::SourceAgreement> m_sourceAgreements{ winrt::single_threaded_vector<winrt::Microsoft::Management::Deployment::SourceAgreement>() }; ::AppInstaller::Repository::Source m_sourceReference; std::optional<std::string> m_additionalPackageCatalogArguments; + bool m_acceptSourceAgreements = true; + std::once_flag m_sourceAgreementsOnceFlag; #endif }; } diff --git a/src/Microsoft.Management.Deployment/PackageManager.cpp b/src/Microsoft.Management.Deployment/PackageManager.cpp @@ -401,6 +401,16 @@ namespace winrt::Microsoft::Management::Deployment::implementation } // Note: AdditionalPackageCatalogArguments is not needed during install since the manifest is already known so no additional calls to the source are needed. The property is deprecated. + + if (options.AcceptPackageAgreements()) + { + context->Args.AddArg(Execution::Args::Type::AcceptPackageAgreements); + } + } + else + { + // Note: If no install options are specified, we assume the caller is accepting the package agreements by default. + context->Args.AddArg(Execution::Args::Type::AcceptPackageAgreements); } } @@ -562,6 +572,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation { // Add installed version AddInstalledVersionToContext(package.InstalledVersion(), comContext.get()); + // Add Package which is used by RecordUninstall later for removing from tracking catalog of correlated available sources as best effort winrt::Microsoft::Management::Deployment::implementation::CatalogPackage* catalogPackageImpl = get_self<winrt::Microsoft::Management::Deployment::implementation::CatalogPackage>(package); std::shared_ptr<::AppInstaller::Repository::IPackage> internalPackage = catalogPackageImpl->GetRepositoryPackage(); diff --git a/src/Microsoft.Management.Deployment/PackageManager.idl b/src/Microsoft.Management.Deployment/PackageManager.idl @@ -62,6 +62,10 @@ namespace Microsoft.Management.Deployment [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 4)] { NoApplicableUpgrade, + }, + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + { + PackageAgreementsNotAccepted, } }; @@ -274,9 +278,15 @@ namespace Microsoft.Management.Deployment /// Gets the publisher string for this package version, if one is available. String Publisher { get; }; } - + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] { + /// Gets the package catalog metadata of this package version with the default localization based on user settings. + CatalogPackageMetadata GetCatalogPackageMetadata(); + + /// Gets the package catalog metadata of this package version with the preferred locale. + CatalogPackageMetadata GetCatalogPackageMetadata(String preferredLocale); + /// Gets the applicable installer for this package version. PackageInstallerInfo GetApplicableInstaller(InstallOptions options); } @@ -578,7 +588,7 @@ namespace Microsoft.Management.Deployment /// If true, the results were truncated by the given ResultLimit /// USAGE NOTE: Windows Package Manager does not support result pagination, there is no way to continue /// getting more results. - Boolean WasLimitExceeded{ get; }; + Boolean WasLimitExceeded { get; }; } /// Options for FindPackages @@ -631,6 +641,10 @@ namespace Microsoft.Management.Deployment { Ok, CatalogError, + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + { + SourceAgreementsNotAccepted, + } }; /// Result of the Connect call @@ -650,6 +664,7 @@ namespace Microsoft.Management.Deployment /// Gets a value indicating whether this package catalog is a composite of other package catalogs, /// and thus the packages may come from disparate package catalogs as well. Boolean IsComposite { get; }; + /// The details of the package catalog if it is not a composite. PackageCatalogInfo Info { get; }; @@ -663,6 +678,14 @@ namespace Microsoft.Management.Deployment /// A string that will be passed to the source server if using a REST source String AdditionalPackageCatalogArguments; } + + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + { + /// Gets the required agreements for connecting to the package catalog (source). + Windows.Foundation.Collections.IVectorView<SourceAgreement> SourceAgreements { get; }; + + Boolean AcceptSourceAgreements; + } } /// Catalogs with PackageCatalogOrigin Predefined @@ -791,6 +814,9 @@ namespace Microsoft.Management.Deployment /// A string that will be passed to the installer /// IMPLEMENTATION NOTE: maps to "--custom" in the winget cmd line String AdditionalInstallerArguments; + + /// Accept the package agreements required for installation. + Boolean AcceptPackageAgreements; } } @@ -830,6 +856,7 @@ namespace Microsoft.Management.Deployment /// Silent, Interactive, or Default PackageUninstallMode PackageUninstallMode; + /// Directs the logging to a log file. If provided, the installer must have write access to the file String LogOutputPath; @@ -846,6 +873,84 @@ namespace Microsoft.Management.Deployment } } + /// IMPLEMENTATION NOTE: Documentation from AppInstaller::Repository::Documentation + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + runtimeclass Documentation + { + String DocumentLabel { get; }; + + String DocumentUrl { get; }; + } + + /// IMPLEMENTATION NOTE: SourceAgreement from AppInstaller::Repository::SourceAgreement + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + runtimeclass SourceAgreement + { + String Label { get; }; + + String Text { get; }; + + String Url { get; }; + } + + /// IMPLEMENTATION NOTE: PackageAgreement from AppInstaller::Manifest::Agreement + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + runtimeclass PackageAgreement + { + String Label { get; }; + + String Text { get; }; + + String Url { get; }; + } + + /// IMPLEMENTATION NOTE: CatalogPackageMetadata from AppInstaller::Manifest::Localization + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 6)] + runtimeclass CatalogPackageMetadata + { + String Locale { get; }; + + String Publisher { get; }; + + String PublisherUrl { get; }; + + String PublisherSupportUrl { get; }; + + String PrivacyUrl { get; }; + + String Author { get; }; + + String PackageName { get; }; + + String PackageUrl { get; }; + + String License { get; }; + + String LicenseUrl { get; }; + + String Copyright { get; }; + + String CopyrightUrl { get; }; + + String ShortDescription { get; }; + + String Description { get; }; + + Windows.Foundation.Collections.IVectorView<String> Tags { get; }; + + Windows.Foundation.Collections.IVectorView<PackageAgreement> Agreements { get; }; + + Windows.Foundation.Collections.IVectorView<Documentation> Documentations { get; }; + + String ReleaseNotes { get; }; + + String ReleaseNotesUrl { get; }; + + String PurchaseUrl { get; }; + + String InstallationNotes { get; }; + } + [contract(Microsoft.Management.Deployment.WindowsPackageManagerContract, 1)] runtimeclass PackageManager { @@ -954,5 +1059,13 @@ namespace Microsoft.Management.Deployment interface Windows.Foundation.Collections.IVectorView<PackageInstallerInstalledStatus>; interface Windows.Foundation.Collections.IVector<CheckInstalledStatusResult>; interface Windows.Foundation.Collections.IVectorView<CheckInstalledStatusResult>; + interface Windows.Foundation.Collections.IVector<SourceAgreement>; + interface Windows.Foundation.Collections.IVectorView<SourceAgreement>; + interface Windows.Foundation.Collections.IVector<PackageAgreement>; + interface Windows.Foundation.Collections.IVectorView<PackageAgreement>; + interface Windows.Foundation.Collections.IVector<Documentation>; + interface Windows.Foundation.Collections.IVectorView<Documentation>; + interface Windows.Foundation.Collections.IVector<CatalogPackageMetadata>; + interface Windows.Foundation.Collections.IVectorView<CatalogPackageMetadata>; } } diff --git a/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp b/src/Microsoft.Management.Deployment/PackageVersionInfo.cpp @@ -9,6 +9,7 @@ #include "PackageCatalog.h" #include "PackageInstallerInfo.h" #include "CatalogPackage.h" +#include "CatalogPackageMetadata.h" #include "ComContext.h" #include "Workflows/WorkflowBase.h" #include "Workflows/ManifestComparator.h" @@ -21,6 +22,7 @@ #include "PackageManager.h" #pragma warning( pop ) #include <wil\cppwinrt_wrl.h> +#include <winget/Locale.h> namespace winrt::Microsoft::Management::Deployment::implementation { @@ -106,7 +108,7 @@ namespace winrt::Microsoft::Management::Deployment::implementation return m_packageCatalog; } - winrt::Microsoft::Management::Deployment::CompareResult PackageVersionInfo::CompareToVersion(hstring versionString) + winrt::Microsoft::Management::Deployment::CompareResult PackageVersionInfo::CompareToVersion(const hstring& versionString) { if (versionString.empty()) { @@ -159,4 +161,34 @@ namespace winrt::Microsoft::Management::Deployment::implementation return nullptr; } } + Microsoft::Management::Deployment::CatalogPackageMetadata PackageVersionInfo::GetCatalogPackageMetadata() + { + auto catalogPackageMetadata = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::CatalogPackageMetadata>>(); + if (m_packageVersion) + { + auto manifest = m_packageVersion->GetManifest(); + manifest.ApplyLocale(); + catalogPackageMetadata->Initialize(manifest.CurrentLocalization); + } + + return *catalogPackageMetadata; + } + Microsoft::Management::Deployment::CatalogPackageMetadata PackageVersionInfo::GetCatalogPackageMetadata(const hstring& preferredLocale) + { + std::string localeString = winrt::to_string(preferredLocale); + if (!::AppInstaller::Locale::IsWellFormedBcp47Tag(localeString)) + { + throw hresult_invalid_argument(); + } + + auto catalogPackageMetadata = winrt::make_self<wil::details::module_count_wrapper<winrt::Microsoft::Management::Deployment::implementation::CatalogPackageMetadata>>(); + if (m_packageVersion) + { + auto manifest = m_packageVersion->GetManifest(); + manifest.ApplyLocale(localeString); + catalogPackageMetadata->Initialize(manifest.CurrentLocalization); + } + + return *catalogPackageMetadata; + } } diff --git a/src/Microsoft.Management.Deployment/PackageVersionInfo.h b/src/Microsoft.Management.Deployment/PackageVersionInfo.h @@ -23,10 +23,12 @@ namespace winrt::Microsoft::Management::Deployment::implementation winrt::Windows::Foundation::Collections::IVectorView<hstring> PackageFamilyNames(); winrt::Windows::Foundation::Collections::IVectorView<hstring> ProductCodes(); winrt::Microsoft::Management::Deployment::PackageCatalog PackageCatalog(); - winrt::Microsoft::Management::Deployment::CompareResult CompareToVersion(hstring versionString); - // Contract version 4 + winrt::Microsoft::Management::Deployment::CompareResult CompareToVersion(const hstring& versionString); + // Contract 4.0 bool HasApplicableInstaller(InstallOptions options); - // Contract version 6 + // Contract 6.0 + winrt::Microsoft::Management::Deployment::CatalogPackageMetadata GetCatalogPackageMetadata(); + winrt::Microsoft::Management::Deployment::CatalogPackageMetadata GetCatalogPackageMetadata(const hstring& preferredLocale); winrt::Microsoft::Management::Deployment::PackageInstallerInfo GetApplicableInstaller(InstallOptions options); #if !defined(INCLUDE_ONLY_INTERFACE_METHODS) diff --git a/src/Microsoft.Management.Deployment/SourceAgreement.cpp b/src/Microsoft.Management.Deployment/SourceAgreement.cpp @@ -0,0 +1,27 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#include "pch.h" +#include <winget/RepositorySource.h> +#include "SourceAgreement.h" +#include "SourceAgreement.g.cpp" +#include <wil\cppwinrt_wrl.h> + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + void SourceAgreement::Initialize(::AppInstaller::Repository::SourceAgreement sourceAgreement) + { + m_sourceAgreement = std::move(sourceAgreement); + } + hstring SourceAgreement::Label() + { + return winrt::to_hstring(m_sourceAgreement.Label); + } + hstring SourceAgreement::Text() + { + return winrt::to_hstring(m_sourceAgreement.Text); + } + hstring SourceAgreement::Url() + { + return winrt::to_hstring(m_sourceAgreement.Url); + } +} diff --git a/src/Microsoft.Management.Deployment/SourceAgreement.h b/src/Microsoft.Management.Deployment/SourceAgreement.h @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +#pragma once +#include "SourceAgreement.g.h" +#include <winget/RepositorySource.h> + +namespace winrt::Microsoft::Management::Deployment::implementation +{ + struct SourceAgreement : SourceAgreementT<SourceAgreement> + { + SourceAgreement() = default; + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + void Initialize(::AppInstaller::Repository::SourceAgreement sourceAgreement); +#endif + + hstring Label(); + hstring Text(); + hstring Url(); + +#if !defined(INCLUDE_ONLY_INTERFACE_METHODS) + private: + ::AppInstaller::Repository::SourceAgreement m_sourceAgreement{}; +#endif + }; +}