DependenciesGraph.cpp (4411B)
1 // Copyright (c) Microsoft Corporation. 2 // Licensed under the MIT License. 3 #include "pch.h" 4 #include "winget\DependenciesGraph.h" 5 6 namespace AppInstaller::Manifest 7 { 8 // this constructor was intented for use during installation flow (we already have installer dependencies and there's no need to search the source again) 9 DependencyGraph::DependencyGraph(const Dependency& root, const DependencyList& rootDependencies, 10 std::function<const DependencyList(const Dependency&)> infoFunction) : m_root(root), getDependencies(infoFunction) 11 { 12 m_adjacents[m_root] = std::set<Dependency>(); 13 m_toCheck = std::vector<Dependency>(); 14 rootDependencies.ApplyToType(DependencyType::Package, [&](Dependency dependency) 15 { 16 m_toCheck.push_back(dependency); 17 AddNode(dependency); 18 AddAdjacent(root, dependency); 19 }); 20 m_rootDependencyEvaluated = true; 21 } 22 23 DependencyGraph::DependencyGraph(const Dependency& root, std::function<const DependencyList(const Dependency&)> infoFunction) : m_root(root), getDependencies(infoFunction) 24 { 25 m_adjacents[m_root] = std::set<Dependency>(); 26 m_toCheck = std::vector<Dependency>(); 27 } 28 29 void DependencyGraph::BuildGraph() 30 { 31 if (!m_rootDependencyEvaluated) 32 { 33 const DependencyList& rootDependencies = getDependencies(m_root); 34 rootDependencies.ApplyToType(DependencyType::Package, [&](Dependency dependency) 35 { 36 m_toCheck.push_back(dependency); 37 AddNode(dependency); 38 AddAdjacent(m_root, dependency); 39 }); 40 m_rootDependencyEvaluated = true; 41 } 42 43 if (m_toCheck.empty()) 44 { 45 return; 46 } 47 48 for (unsigned int i = 0; i < m_toCheck.size(); ++i) 49 { 50 auto node = m_toCheck.at(i); 51 52 const auto& nodeDependencies = getDependencies(node); 53 nodeDependencies.ApplyToType(DependencyType::Package, [&](Dependency dependency) 54 { 55 if (!HasNode(dependency)) 56 { 57 m_toCheck.push_back(dependency); 58 AddNode(dependency); 59 } 60 61 AddAdjacent(node, dependency); 62 }); 63 } 64 65 CheckForLoopsAndGetOrder(); 66 } 67 68 void DependencyGraph::AddNode(const Dependency& node) 69 { 70 m_adjacents[node] = std::set<Dependency>(); 71 } 72 73 void DependencyGraph::AddAdjacent(const Dependency& node, const Dependency& adjacent) 74 { 75 m_adjacents[node].emplace(adjacent); 76 } 77 78 bool DependencyGraph::HasNode(const Dependency& dependency) 79 { 80 auto search = m_adjacents.find(dependency); 81 return search != m_adjacents.end(); 82 } 83 84 bool DependencyGraph::HasLoop() 85 { 86 return m_HasLoop; 87 } 88 89 void DependencyGraph::CheckForLoopsAndGetOrder() 90 { 91 m_installationOrder = std::vector<Dependency>(); 92 std::set<Dependency> visited; 93 m_HasLoop = HasLoopDFS(visited, m_root); 94 } 95 96 std::vector<Dependency> DependencyGraph::GetInstallationOrder() 97 { 98 return m_installationOrder; 99 } 100 101 // TODO make this function iterative 102 bool DependencyGraph::HasLoopDFS(std::set<Dependency> visited, const Dependency& node) 103 { 104 bool loop = false; 105 106 visited.insert(node); 107 auto lAdjacents = m_adjacents.at(node); 108 for (const auto& adjacent : m_adjacents.at(node)) 109 { 110 auto search = visited.find(adjacent); 111 if (search == visited.end()) // if not found 112 { 113 if (HasLoopDFS(visited, adjacent)) 114 { 115 loop = true; 116 // didn't break the loop to have a complete order at the end (even if a loop exists) 117 } 118 } 119 else 120 { 121 loop = true; 122 // didn't break the loop to have a complete order at the end (even if a loop exists) 123 } 124 } 125 126 // Adding to have an order even if a loop is present 127 if (std::find(m_installationOrder.begin(), m_installationOrder.end(), node) == m_installationOrder.end()) 128 { 129 m_installationOrder.push_back(node); 130 } 131 132 return loop; 133 } 134 }