winget-cli

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

MultiQueryFlow.cpp (6653B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "MultiQueryFlow.h"
      5 #include "UpdateFlow.h"
      6 
      7 using namespace AppInstaller::CLI;
      8 using namespace AppInstaller::CLI::Execution;
      9 using namespace AppInstaller::Repository;
     10 using namespace AppInstaller::Utility::literals;
     11 
     12 namespace AppInstaller::CLI::Workflow
     13 {
     14     namespace
     15     {
     16         Utility::LocIndString GetPackageStringFromSearchRequest(const SearchRequest& searchRequest)
     17         {
     18             if (searchRequest.Query)
     19             {
     20                 return Utility::LocIndString{ searchRequest.Query->Value };
     21             }
     22 
     23             if (!searchRequest.Inclusions.empty())
     24             {
     25                 return Utility::LocIndString{ searchRequest.Inclusions[0].Value };
     26             }
     27 
     28             if (!searchRequest.Filters.empty())
     29             {
     30                 return Utility::LocIndString{ searchRequest.Filters[0].Value };
     31             }
     32 
     33             return ""_lis;
     34         }
     35     }
     36 
     37     void GetMultiSearchRequests(Execution::Context& context)
     38     {
     39         std::vector<std::unique_ptr<Execution::Context>> packageSubContexts;
     40         auto& source = context.Get<Execution::Data::Source>();
     41         for (const auto& query : *context.Args.GetArgs(Execution::Args::Type::MultiQuery))
     42         {
     43             auto searchContextPtr = context.CreateSubContext();
     44             Execution::Context& searchContext = *searchContextPtr;
     45             auto previousThreadGlobals = searchContext.SetForCurrentThread();
     46 
     47             searchContext.Add<Execution::Data::Source>(source);
     48             searchContext.Args.AddArg(Execution::Args::Type::Query, query);
     49 
     50             AICLI_LOG(CLI, Info, << "Creating search query for package [" << query << "]");
     51             searchContext << GetSearchRequestForSingle;
     52 
     53             packageSubContexts.emplace_back(std::move(searchContextPtr));
     54         }
     55 
     56         context.Add<Execution::Data::PackageSubContexts>(std::move(packageSubContexts));
     57     }
     58 
     59     void SearchSubContextsForSingle::operator()(Execution::Context& context) const
     60     {
     61         std::vector<std::unique_ptr<Execution::Context>> packageSubContexts;
     62         bool foundAll = true;
     63 
     64         for (auto& searchContextPtr : context.Get<Execution::Data::PackageSubContexts>())
     65         {
     66             auto& searchContext = *searchContextPtr;
     67             SearchRequest searchRequest = searchContext.Get<Execution::Data::SearchRequest>();
     68             searchContext.Add<Execution::Data::SearchResult>(searchContext.Get<Execution::Data::Source>().Search(searchRequest));
     69 
     70             switch (m_operationType)
     71             {
     72             case OperationType::Install:
     73             case OperationType::Upgrade:
     74                 searchContext << Workflow::SelectSinglePackageVersionForInstallOrUpgrade(m_operationType);
     75                 break;
     76             case OperationType::Uninstall:
     77                 searchContext <<
     78                     Workflow::HandleSearchResultFailures <<
     79                     Workflow::EnsureOneMatchFromSearchResult(m_operationType);
     80                 break;
     81             default:
     82                 THROW_HR(E_UNEXPECTED);
     83             }
     84 
     85             if (searchContext.IsTerminated())
     86             {
     87                 if (context.IsTerminated() && context.GetTerminationHR() == E_ABORT)
     88                 {
     89                     // This means that the subcontext being terminated is due to an overall abort
     90                     context.Reporter.Info() << Resource::String::Cancelled << std::endl;
     91                     return;
     92                 }
     93                 else
     94                 {
     95                     // We already reported the error from the sub-context, but we repeat it here because
     96                     // for multi-queries we can a bit more verbose as the queries here are easier to report.
     97                     auto packageString = GetPackageStringFromSearchRequest(searchRequest);
     98                     auto searchTerminationHR = searchContext.GetTerminationHR();
     99                     if (searchTerminationHR == APPINSTALLER_CLI_ERROR_UPDATE_NOT_APPLICABLE ||
    100                         searchTerminationHR == APPINSTALLER_CLI_ERROR_PACKAGE_ALREADY_INSTALLED)
    101                     {
    102                         AICLI_LOG(CLI, Info, << "Package is already installed: [" << packageString << "]");
    103                         context.Reporter.Info() << Resource::String::MultiQueryPackageAlreadyInstalled(packageString) << std::endl;
    104                         continue;
    105                     }
    106                     else
    107                     {
    108                         if (searchTerminationHR == APPINSTALLER_CLI_ERROR_NO_APPLICATIONS_FOUND)
    109                         {
    110                             AICLI_LOG(CLI, Info, << "Package not found for query: [" << packageString << "]");
    111                             context.Reporter.Warn() << Resource::String::MultiQueryPackageNotFound(packageString) << std::endl;
    112                         }
    113                         else if (searchTerminationHR == APPINSTALLER_CLI_ERROR_MULTIPLE_APPLICATIONS_FOUND)
    114                         {
    115                             AICLI_LOG(CLI, Info, << "Multiple packages found for query: [" << packageString << "]");
    116                             context.Reporter.Warn() << Resource::String::MultiQuerySearchFoundMultiple(packageString) << std::endl;
    117                         }
    118                         else
    119                         {
    120                             AICLI_LOG(CLI, Info, << "Search failed for query: [" << packageString << "]");
    121                             context.Reporter.Info() << Resource::String::MultiQuerySearchFailed(packageString) << std::endl;
    122                         }
    123 
    124                         // Keep searching for the remaining packages and only fail at the end.
    125                         foundAll = false;
    126                         continue;
    127                     }
    128                 }
    129             }
    130 
    131             packageSubContexts.emplace_back(std::move(searchContextPtr));
    132         }
    133 
    134         if (!foundAll)
    135         {
    136             AICLI_LOG(CLI, Info, << "Not all queries returned one result");
    137             if (context.Args.Contains(Execution::Args::Type::IgnoreUnavailable))
    138             {
    139                 AICLI_LOG(CLI, Info, << "Ignoring unavailable packages due to command line argument");
    140             }
    141             else
    142             {
    143                 AICLI_TERMINATE_CONTEXT(APPINSTALLER_CLI_ERROR_NOT_ALL_QUERIES_FOUND_SINGLE);
    144             }
    145         }
    146 
    147         context.Add<Execution::Data::PackageSubContexts>(std::move(packageSubContexts));
    148     }
    149 }