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 
37  while (it.hasNext()) { tryLoad(it.next()); }
38  }
39 
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 
64  {
65  Q_ASSERT(isValid(metadata));
66  return metadata.value("MetaData").toObject().value("identifier").toString();
67  }
68 
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.
bool exists() const const
QString path() const const
bool hasNext() const const
QString next()
bool contains(QLatin1StringView key) const const
QJsonValue value(QLatin1StringView key) const const
QJsonObject toObject() const const
QString toString() const const
bool isLibrary(const QString &fileName)
bool contains(const Key &key) const const
QMap< Key, T >::iterator insert(QMap< Key, T >::const_iterator pos, const Key &key, const T &value)
T value(const Key &key, const T &defaultValue) const const
bool isEmpty() const const