winget-cli

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

DependencyNodeProcessor.cpp (5496B)


      1 // Copyright (c) Microsoft Corporation.
      2 // Licensed under the MIT License.
      3 #include "pch.h"
      4 #include "DependencyNodeProcessor.h"
      5 #include "WorkflowBase.h"
      6 #include <winget/PinningData.h>
      7 #include <winget/PackageVersionSelection.h>
      8 
      9 using namespace AppInstaller::Manifest;
     10 using namespace AppInstaller::Repository;
     11 
     12 namespace AppInstaller::CLI::Workflow
     13 {
     14     DependencyNodeProcessor::DependencyNodeProcessor(Execution::Context& context)
     15         : m_context(context) {}
     16 
     17     DependencyNodeProcessorResult DependencyNodeProcessor::EvaluateDependencies(Dependency& dependencyNode)
     18     {
     19         SearchRequest searchRequest;
     20         const auto& source = m_context.Get<Execution::Data::DependencySource>();
     21         auto error = m_context.Reporter.Error();
     22         auto info = m_context.Reporter.Info();
     23 
     24         searchRequest.Filters.emplace_back(PackageMatchFilter(PackageMatchField::Id, MatchType::CaseInsensitive, dependencyNode.Id()));
     25 
     26         const auto& matches = source.Search(searchRequest).Matches;
     27 
     28         if (matches.empty())
     29         {
     30             error << Resource::String::DependenciesFlowNoMatches << std::endl;
     31             return DependencyNodeProcessorResult::Error;
     32         }
     33 
     34         if (matches.size() > 1)
     35         {
     36             auto dependencyNodeId = Utility::LocIndString{ Utility::Normalize(dependencyNode.Id()) };
     37             error << Resource::String::DependenciesFlowSourceTooManyMatches(dependencyNodeId) << std::endl;
     38             AICLI_LOG(CLI, Error, << "Too many matches for package " << dependencyNode.Id());
     39             return DependencyNodeProcessorResult::Error;
     40         }
     41 
     42         const auto& match = matches.at(0);
     43         const auto& package = match.Package;
     44         auto packageId = package->GetProperty(PackageProperty::Id);
     45         m_nodePackageInstalledVersion = GetInstalledVersion(package);
     46         std::shared_ptr<IPackageVersionCollection> availableVersions = GetAvailableVersionsForInstalledVersion(package);
     47 
     48         if (m_context.Args.Contains(Execution::Args::Type::Force))
     49         {
     50             m_nodePackageLatestVersion = availableVersions->GetLatestVersion();
     51         }
     52         else
     53         {
     54             Pinning::PinBehavior pinBehavior = m_context.Args.Contains(Execution::Args::Type::IncludePinned) ? Pinning::PinBehavior::IncludePinned : Pinning::PinBehavior::ConsiderPins;
     55 
     56             Pinning::PinningData pinningData{ Pinning::PinningData::Disposition::ReadOnly };
     57             auto evaluator = pinningData.CreatePinStateEvaluator(pinBehavior, m_nodePackageInstalledVersion);
     58 
     59             m_nodePackageLatestVersion = evaluator.GetLatestAvailableVersionForPins(availableVersions);
     60         }
     61 
     62         if (m_nodePackageInstalledVersion && dependencyNode.IsVersionOk(Utility::Version(m_nodePackageInstalledVersion->GetProperty(PackageVersionProperty::Version))))
     63         {
     64             // return empty dependency list,
     65             // as we won't keep searching for dependencies for installed packages
     66             return DependencyNodeProcessorResult::Skipped;
     67         }
     68 
     69         if (!m_nodePackageLatestVersion)
     70         {
     71             error << Resource::String::DependenciesFlowPackageVersionNotFound(Utility::LocIndView{ Utility::Normalize(packageId) }) << std::endl;
     72             AICLI_LOG(CLI, Error, << "Latest available version not found for package " << packageId);
     73             return DependencyNodeProcessorResult::Error;
     74         }
     75 
     76         if (!dependencyNode.IsVersionOk(Utility::Version(m_nodePackageLatestVersion->GetProperty(PackageVersionProperty::Version))))
     77         {
     78             error << Resource::String::DependenciesFlowNoMinVersion(Utility::LocIndView{ Utility::Normalize(packageId) }) << std::endl;
     79             AICLI_LOG(CLI, Error, << "No suitable min version found for package " << packageId);
     80             return DependencyNodeProcessorResult::Error;
     81         }
     82 
     83         m_nodeManifest = m_nodePackageLatestVersion->GetManifest();
     84         m_nodeManifest.ApplyLocale();
     85 
     86         if (m_nodeManifest.Installers.empty())
     87         {
     88             error << Resource::String::DependenciesFlowNoInstallerFound(Utility::LocIndView{ Utility::Normalize(m_nodeManifest.Id) }) << std::endl;
     89             AICLI_LOG(CLI, Error, << "Installer not found for manifest " << m_nodeManifest.Id << " with version" << m_nodeManifest.Version);
     90             return DependencyNodeProcessorResult::Error;
     91         }
     92 
     93         IPackageVersion::Metadata installationMetadata;
     94         if (m_nodePackageInstalledVersion)
     95         {
     96             installationMetadata = m_nodePackageInstalledVersion->GetMetadata();
     97         }
     98 
     99         ManifestComparator manifestComparator(GetManifestComparatorOptions(m_context, installationMetadata));
    100         auto [installer, inapplicabilities] = manifestComparator.GetPreferredInstaller(m_nodeManifest);
    101 
    102         if (!installer.has_value())
    103         {
    104             auto manifestId = Utility::LocIndString{ Utility::Normalize(m_nodeManifest.Id) };
    105             auto manifestVersion = Utility::LocIndString{ m_nodeManifest.Version };
    106             error << Resource::String::DependenciesFlowNoSuitableInstallerFound(manifestId, manifestVersion) << std::endl;
    107             AICLI_LOG(CLI, Error, << "No suitable installer found for manifest " << m_nodeManifest.Id << " with version " << m_nodeManifest.Version);
    108             return DependencyNodeProcessorResult::Error;
    109         }
    110 
    111         m_installer = installer.value();
    112         m_dependenciesList = m_installer.Dependencies;
    113         return DependencyNodeProcessorResult::Success;
    114     }
    115 }