Loading...
Searching...
No Matches
PluginDependencyGraph.hpp
1#pragma once
2#include <score/plugins/Addon.hpp>
3#include <score/plugins/qt_interfaces/GUIApplicationPlugin_QtInterface.hpp>
4#include <score/plugins/qt_interfaces/PluginRequirements_QtInterface.hpp>
5#include <score/tools/std/HashMap.hpp>
6
7#include <ossia/detail/pod_vector.hpp>
8
9#include <boost/graph/adjacency_list.hpp>
10#include <boost/graph/topological_sort.hpp>
11
12#include <QDebug>
13
14#include <chrono>
15#include <exception>
16#include <memory>
17#include <set>
18namespace score
19{
20namespace PluginLoader
21{
29{
31 {
33 : addon{}
34 {
35 }
36 explicit GraphVertex(const score::Addon* add)
37 : addon{add}
38 {
39 }
40 const score::Addon* addon{};
41 };
42
43 using Graph
44 = boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, GraphVertex>;
45
46public:
47 explicit PluginDependencyGraph(const std::vector<score::Addon>& addons)
48 {
49 if(addons.empty())
50 return;
51
52 score::hash_map<PluginKey, int64_t> keys;
53 std::vector<const score::Addon*> not_loaded;
54
55 // First add all the vertices to the graph
56 for(const score::Addon& addon : addons)
57 {
58 auto vx = boost::add_vertex(GraphVertex{&addon}, m_graph);
59 keys[addon.key] = vx;
60 }
61
62 // If A depends on B, then there is an edge from B to A.
63 for(const score::Addon& addon : addons)
64 {
65 auto addon_k = keys[addon.key];
66 for(const auto& k : addon.plugin->required())
67 {
68 auto it = keys.find(k);
69 if(it != keys.end())
70 {
71 boost::add_edge(addon_k, it->second, m_graph);
72 }
73 else
74 {
75 boost::clear_vertex(addon_k, m_graph);
76 boost::remove_vertex(addon_k, m_graph);
77 not_loaded.push_back(&addon);
78 break;
79 }
80 }
81 }
82
83 if(!not_loaded.empty())
84 qDebug() << not_loaded.size()
85 << "plugins were not loaded due to a dependency problem.";
86
87 // Then do a topological sort, to detect cycles and to be able to iterate
88 // easily afterwards.
89 ossia::int_vector topo_order;
90 topo_order.reserve(addons.size() - not_loaded.size());
91
92 try
93 {
94 boost::topological_sort(m_graph, std::back_inserter(topo_order));
95 for(auto e : topo_order)
96 {
97 if(m_graph[e].addon)
98 m_sorted.push_back(*m_graph[e].addon);
99 }
100 }
101 catch(const std::exception& e)
102 {
103 qDebug() << "Invalid plug-in graph: " << e.what();
104 m_graph.clear();
105 }
106 }
107
108 auto& sortedAddons() const { return m_sorted; }
109
110private:
111 Graph m_graph;
112 std::vector<score::Addon> m_sorted;
113};
114}
115}
Classes and functions used at the plug-in loading step.
Base toolkit upon which the software is built.
Definition Application.cpp:90
The Addon struct.
Definition Addon.hpp:16
Definition PluginDependencyGraph.hpp:31
Allows to load plug-ins in the order they all require each other.
Definition PluginDependencyGraph.hpp:29