winget-cli

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

PackageCatalog.cpp (8266B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include <mutex>
      5 #include <winget/RepositorySource.h>
      6 #include "Workflows/WorkflowBase.h"
      7 #include "Converters.h"
      8 #include "PackageCatalog.h"
      9 #include "PackageCatalog.g.cpp"
     10 #include "PackageCatalogInfo.h"
     11 #include "FindPackagesResult.h"
     12 #include "MatchResult.h"
     13 #include "CatalogPackage.h"
     14 #include "Commands/RootCommand.h"
     15 #include "ExecutionContext.h"
     16 #pragma warning( push )
     17 #pragma warning ( disable : 4467 6388)
     18 // 6388 Allow CreateInstance.
     19 #include <wil\cppwinrt_wrl.h>
     20 // 4467 Allow use of uuid attribute for com object creation.
     21 #include "PackageMatchFilter.h"
     22 #pragma warning( pop )
     23 #include "Microsoft/PredefinedInstalledSourceFactory.h"
     24 #include <winget/GroupPolicy.h>
     25 #include <AppInstallerErrors.h>
     26 
     27 namespace winrt::Microsoft::Management::Deployment::implementation
     28 {
     29     void PackageCatalog::Initialize(
     30         winrt::Microsoft::Management::Deployment::PackageCatalogInfo info,
     31         ::AppInstaller::Repository::Source source,
     32         bool isComposite)
     33     {
     34         m_info = info;
     35         m_source = std::move(source);
     36         m_isComposite = isComposite;
     37     }
     38     bool PackageCatalog::IsComposite()
     39     {
     40         // Can't use m_source->IsComposite for this because all remote sources are turned into composite sources 
     41         // behind the scenes when being opened in PackageCatalogReference.cpp so that CatalogPackage.IsInstalled works.
     42         return m_isComposite;
     43     }
     44     winrt::Microsoft::Management::Deployment::PackageCatalogInfo PackageCatalog::Info()
     45     {
     46         return m_info;
     47     }
     48     winrt::Windows::Foundation::IAsyncOperation<winrt::Microsoft::Management::Deployment::FindPackagesResult> PackageCatalog::FindPackagesAsync(winrt::Microsoft::Management::Deployment::FindPackagesOptions options)
     49     {
     50         auto strong_this = get_strong();
     51         co_await resume_background();
     52         co_return FindPackages(options);
     53     }
     54 
     55     HRESULT PopulateSearchRequestFromVector(
     56         ::AppInstaller::Repository::SearchRequest* searchRequest,
     57         Windows::Foundation::Collections::IVector<Microsoft::Management::Deployment::PackageMatchFilter> vector,
     58         bool isSelector)
     59     {
     60         // Populates either the Filters vector of a searchRequest (if isSelector is false),
     61         // or the Inclusions and Query (if true)
     62         for (uint32_t i = 0; i < vector.Size(); ++i)
     63         {
     64             Microsoft::Management::Deployment::PackageMatchFilter filter = vector.GetAt(i);
     65 
     66             if (filter.Value().size() == 0)
     67             {
     68                 // If the caller did not add a value it can't actually be used to filter or include anything so just ignore it.
     69                 continue;
     70             }
     71             ::AppInstaller::Repository::MatchType packageFieldMatchOption = GetRepositoryMatchType(filter.Option());
     72             ::AppInstaller::Repository::PackageMatchField matchField = GetRepositoryMatchField(filter.Field());
     73 
     74             if (isSelector)
     75             {
     76                 if (filter.Field() == Microsoft::Management::Deployment::PackageMatchField::CatalogDefault)
     77                 {
     78                     if (searchRequest->Query.has_value())
     79                     {
     80                         // CatalogDefault match field can't be used twice.
     81                         return E_INVALIDARG;
     82                     }
     83                     searchRequest->Query = ::AppInstaller::Repository::RequestMatch(packageFieldMatchOption, winrt::to_string(filter.Value()));
     84                 }
     85                 else
     86                 {
     87                     auto matchFilter = ::AppInstaller::Repository::PackageMatchFilter(matchField, packageFieldMatchOption, winrt::to_string(filter.Value()));
     88                     searchRequest->Inclusions.emplace_back(matchFilter);
     89                 }
     90             }
     91             else
     92             {
     93                 if (filter.Field() == Microsoft::Management::Deployment::PackageMatchField::CatalogDefault)
     94                 {
     95                     // CatalogDefault match fields can't be used in the Filters.
     96                     return E_INVALIDARG;
     97                 }
     98                 auto matchFilter = ::AppInstaller::Repository::PackageMatchFilter(matchField, packageFieldMatchOption, winrt::to_string(filter.Value()));
     99                 searchRequest->Filters.emplace_back(matchFilter);
    100             }
    101         }
    102         return S_OK;
    103     }
    104 
    105     HRESULT PopulateSearchRequest(
    106         ::AppInstaller::Repository::SearchRequest* searchRequest,
    107         winrt::Microsoft::Management::Deployment::FindPackagesOptions const& options)
    108     {
    109         RETURN_IF_FAILED(PopulateSearchRequestFromVector(searchRequest, options.Filters(), false));
    110         RETURN_IF_FAILED(PopulateSearchRequestFromVector(searchRequest, options.Selectors(), true));
    111         return S_OK;
    112     }
    113 
    114     winrt::Microsoft::Management::Deployment::FindPackagesResult GetFindPackagesResult(HRESULT hr, bool isTruncated, Windows::Foundation::Collections::IVector<Microsoft::Management::Deployment::MatchResult> matches)
    115     {
    116         auto findPackagesResult = winrt::make_self<wil::details::module_count_wrapper<
    117             winrt::Microsoft::Management::Deployment::implementation::FindPackagesResult>>();
    118         // TODO: Add search timeout and error code.
    119         winrt::Microsoft::Management::Deployment::FindPackagesResultStatus status = FindPackagesResultStatus(hr);
    120         findPackagesResult->Initialize(status, isTruncated, matches, hr);
    121         return *findPackagesResult;
    122     }
    123 
    124     winrt::Microsoft::Management::Deployment::FindPackagesResult PackageCatalog::FindPackages(winrt::Microsoft::Management::Deployment::FindPackagesOptions const& options)
    125     {
    126         bool isTruncated = false;
    127         Windows::Foundation::Collections::IVector<Microsoft::Management::Deployment::MatchResult> matches{ winrt::single_threaded_vector<Microsoft::Management::Deployment::MatchResult>() };
    128         ::AppInstaller::Repository::SearchRequest searchRequest;
    129 
    130         HRESULT hr = S_OK;
    131         try
    132         {
    133             // No need to check for caller capability again since packageQuery was required in order to get the PackageCatalog object through Connect
    134 
    135             if (FAILED(hr = PopulateSearchRequest(&searchRequest, options)))
    136             {
    137                 return GetFindPackagesResult(hr, isTruncated, matches);
    138             }
    139         
    140             searchRequest.MaximumResults = options.ResultLimit();
    141             auto searchResult = m_source.Search(searchRequest);
    142 
    143             // Handle failures by just rethrowing the first one for now.
    144             // TODO: Look into updating the COM interface to enable the single source
    145             //       failures to flow out.
    146             if (!searchResult.Failures.empty())
    147             {
    148                 std::rethrow_exception(searchResult.Failures[0].Exception);
    149             }
    150 
    151             // Build the result object from the searchResult
    152             for (size_t i = 0; i < searchResult.Matches.size(); ++i)
    153             {
    154                 auto match = searchResult.Matches[i];
    155                 auto catalogPackage = winrt::make_self<wil::details::module_count_wrapper<
    156                     winrt::Microsoft::Management::Deployment::implementation::CatalogPackage>>();
    157                 catalogPackage->Initialize(m_source, match.Package);
    158 
    159                 auto packageMatchFilter = winrt::make_self<wil::details::module_count_wrapper<
    160                     winrt::Microsoft::Management::Deployment::implementation::PackageMatchFilter>>();
    161                 packageMatchFilter->Initialize(match.MatchCriteria);
    162 
    163                 auto matchResult = winrt::make_self<wil::details::module_count_wrapper<
    164                     winrt::Microsoft::Management::Deployment::implementation::MatchResult>>();
    165                 matchResult->Initialize(*catalogPackage, *packageMatchFilter);
    166 
    167                 matches.Append(*matchResult);
    168             }
    169             isTruncated = searchResult.Truncated;
    170         }
    171         WINGET_CATCH_STORE(hr, APPINSTALLER_CLI_ERROR_COMMAND_FAILED);
    172 
    173         return GetFindPackagesResult(hr, isTruncated, matches);
    174     }
    175 }