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 }