swift
pluginmanager.cpp
1 // SPDX-FileCopyrightText: Copyright (C) 2013 swift Project Community / Contributors
2 // SPDX-License-Identifier: GPL-3.0-or-later OR LicenseRef-swift-pilot-client-1
3 
4 #include "core/pluginmanager.h"
5 
6 #include <QDir>
7 #include <QDirIterator>
8 #include <QJsonValue>
9 #include <QJsonValueRef>
10 #include <QLibrary>
11 #include <QPluginLoader>
12 #include <QStringBuilder>
13 #include <QtGlobal>
14 
15 #include "core/application.h"
16 #include "misc/directoryutils.h"
17 #include "misc/logmessage.h"
18 #include "misc/statusmessage.h"
19 #include "misc/swiftdirectories.h"
20 
21 using namespace swift::misc;
22 
23 namespace swift::core
24 {
25  IPluginManager::IPluginManager(QObject *parent) : QObject(parent) {}
26 
28  {
29  QDir pluginDir(pluginDirectory());
30  if (!pluginDir.exists())
31  {
32  CLogMessage(this).warning(u"No such directory: %1") << pluginDir.path();
33  return;
34  }
35 
36  QDirIterator it(pluginDir, QDirIterator::FollowSymlinks);
37  while (it.hasNext()) { tryLoad(it.next()); }
38  }
39 
40  QString IPluginManager::getPluginConfigId(const QString &identifier)
41  {
42  return m_configs.contains(identifier) ? m_configs.value(identifier) : QString();
43  }
44 
46 
47  bool IPluginManager::isValid(const QJsonObject &metadata) const
48  {
49  if (!metadata["MetaData"].isObject()) { return false; }
50 
51  QJsonObject data = metadata["MetaData"].toObject();
52  if (!data.contains("identifier") || !data["identifier"].isString()) { return false; }
53 
54  auto iids = acceptedIids();
55  for (const QString &iid : iids)
56  {
57  if (metadata["IID"].toString() == iid) { return true; }
58  }
59 
60  return false;
61  }
62 
63  QString IPluginManager::pluginIdentifier(const QJsonObject &metadata) const
64  {
65  Q_ASSERT(isValid(metadata));
66  return metadata.value("MetaData").toObject().value("identifier").toString();
67  }
68 
69  QString IPluginManager::getIdByPlugin(const QObject *instance) const
70  {
71  return m_instanceIds.value(instance, QString());
72  }
73 
74  bool IPluginManager::tryLoad(const QString &path)
75  {
76  if (!QLibrary::isLibrary(path)) { return false; }
77 
78  CLogMessage(this).debug() << "Try loading plugin:" << path;
79  QPluginLoader loader(path);
80  const QJsonObject json = loader.metaData();
81  if (!isValid(json))
82  {
83  CLogMessage(this).warning(u"Plugin '%1' invalid, not loading it") << path;
84  return false;
85  }
86 
87  const QString identifier = pluginIdentifier(json);
88  m_paths.insert(identifier, path);
89  m_metadata.push_back(json);
90 
91  if (json.value("MetaData").toObject().contains("config"))
92  {
93  const QString configId = json.value("MetaData").toObject().value("config").toString();
94  if (!configId.isEmpty()) { m_configs.insert(identifier, configId); }
95  }
96 
97  return true;
98  }
99 
100  QObject *IPluginManager::getPluginByIdImpl(const QString &identifier)
101  {
102  if (m_instances.contains(identifier)) { return m_instances.value(identifier); }
103 
104  if (!m_paths.contains(identifier))
105  {
106  CLogMessage(this).warning(u"Plugin with id '%1' does not exist") << identifier;
107  return nullptr;
108  }
109 
110  QString path = m_paths.value(identifier);
111  QPluginLoader loader(path);
112  QObject *instance = loader.instance();
113  if (instance)
114  {
115  m_instances.insert(identifier, instance);
116  m_instanceIds.insert(instance, identifier);
117  return instance;
118  }
119  else
120  {
121  CLogMessage(this).error(loader.errorString());
122  return nullptr;
123  }
124  }
125 } // namespace swift::core
QString pluginIdentifier(const QJsonObject &metadata) const
Gets the plugin identifier from the metadata.
QString getPluginConfigId(const QString &identifier)
If the plugin specifies its config plugin, its identifier can be obtained using this method....
QString getIdByPlugin(const QObject *instance) const
Gets plugin identifier by its instance.
virtual bool isValid(const QJsonObject &metadata) const
Defines whether the given plugin is valid or not, based on its metadata. The default implementation c...
virtual void collectPlugins()
Looks for all available plugins.
virtual swift::misc::CSequence< QString > acceptedIids() const =0
Returns the list of valid IIDs for the implementation.
virtual const QString & pluginDirectory() const
Where to look for plugins, absolute path. Default implementation returns plugins in the application d...
Class for emitting a log message.
Definition: logmessage.h:27
Derived & warning(const char16_t(&format)[N])
Set the severity to warning, providing a format string.
Derived & error(const char16_t(&format)[N])
Set the severity to error, providing a format string.
Derived & debug()
Set the severity to debug.
void push_back(const T &value)
Appends an element at the end of the sequence.
Definition: sequence.h:305
static const QString & pluginsDirectory()
Plugins directory.
Backend services of the swift project, like dealing with the network or the simulators.
Definition: actionbind.cpp:7
Free functions in swift::misc.