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 }