1 /*
2 * SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
5 */
6
7 #include "DiscoverBackendsFactory.h"
8 #include "libdiscover_debug.h"
9 #include "resources/AbstractResourcesBackend.h"
10 #include "resources/ResourcesModel.h"
11 #include "utils.h"
12 #include <KConfigGroup>
13 #include <KDesktopFile>
14 #include <KLocalizedString>
15 #include <KSharedConfig>
16 #include <QCommandLineParser>
17 #include <QDir>
18 #include <QDirIterator>
19 #include <QPluginLoader>
20 #include <QStandardPaths>
21
Q_GLOBAL_STATIC(QStringList,s_requestedBackends)22 Q_GLOBAL_STATIC(QStringList, s_requestedBackends)
23
24 void DiscoverBackendsFactory::setRequestedBackends(const QStringList &backends)
25 {
26 *s_requestedBackends = backends;
27 }
28
hasRequestedBackends()29 bool DiscoverBackendsFactory::hasRequestedBackends()
30 {
31 return !s_requestedBackends->isEmpty();
32 }
33
DiscoverBackendsFactory()34 DiscoverBackendsFactory::DiscoverBackendsFactory()
35 {
36 }
37
backend(const QString & name) const38 QVector<AbstractResourcesBackend *> DiscoverBackendsFactory::backend(const QString &name) const
39 {
40 if (QDir::isAbsolutePath(name) && QStandardPaths::isTestModeEnabled()) {
41 return backendForFile(name, QFileInfo(name).fileName());
42 } else {
43 return backendForFile(name, name);
44 }
45 }
46
backendForFile(const QString & libname,const QString & name) const47 QVector<AbstractResourcesBackend *> DiscoverBackendsFactory::backendForFile(const QString &libname, const QString &name) const
48 {
49 QPluginLoader *loader = new QPluginLoader(QLatin1String("discover/") + libname, ResourcesModel::global());
50
51 // qCDebug(LIBDISCOVER_LOG) << "trying to load plugin:" << loader->fileName();
52 AbstractResourcesBackendFactory *f = qobject_cast<AbstractResourcesBackendFactory *>(loader->instance());
53 if (!f) {
54 qCWarning(LIBDISCOVER_LOG) << "error loading" << libname << loader->errorString() << loader->metaData();
55 return {};
56 }
57 auto instances = f->newInstance(ResourcesModel::global(), name);
58 if (instances.isEmpty()) {
59 qCWarning(LIBDISCOVER_LOG) << "Couldn't find the backend: " << libname << "among" << allBackendNames(false, true);
60 return instances;
61 }
62
63 return instances;
64 }
65
allBackendNames(bool whitelist,bool allowDummy) const66 QStringList DiscoverBackendsFactory::allBackendNames(bool whitelist, bool allowDummy) const
67 {
68 if (whitelist) {
69 QStringList whitelistNames = *s_requestedBackends;
70 if (!whitelistNames.isEmpty())
71 return whitelistNames;
72 }
73
74 QStringList pluginNames;
75 const auto libraryPaths = QCoreApplication::libraryPaths();
76 for (const QString &dir : libraryPaths) {
77 QDirIterator it(dir + QStringLiteral("/discover"), QDir::Files);
78 while (it.hasNext()) {
79 it.next();
80 if (QLibrary::isLibrary(it.fileName()) && (allowDummy || it.fileName() != QLatin1String("dummy-backend.so"))) {
81 pluginNames += it.fileInfo().baseName();
82 }
83 }
84 }
85
86 pluginNames.removeDuplicates(); // will happen when discover is installed twice on the system
87 return pluginNames;
88 }
89
allBackends() const90 QVector<AbstractResourcesBackend *> DiscoverBackendsFactory::allBackends() const
91 {
92 QStringList names = allBackendNames();
93 auto ret = kTransform<QVector<AbstractResourcesBackend *>>(names, [this](const QString &name) {
94 return backend(name);
95 });
96 ret.removeAll(nullptr);
97
98 if (ret.isEmpty())
99 qCWarning(LIBDISCOVER_LOG) << "Didn't find any Discover backend!";
100 return ret;
101 }
102
backendsCount() const103 int DiscoverBackendsFactory::backendsCount() const
104 {
105 return allBackendNames().count();
106 }
107
setupCommandLine(QCommandLineParser * parser)108 void DiscoverBackendsFactory::setupCommandLine(QCommandLineParser *parser)
109 {
110 parser->addOption(QCommandLineOption(QStringLiteral("backends"),
111 i18n("List all the backends we'll want to have loaded, separated by comma ','."),
112 QStringLiteral("names")));
113 }
114
processCommandLine(QCommandLineParser * parser,bool test)115 void DiscoverBackendsFactory::processCommandLine(QCommandLineParser *parser, bool test)
116 {
117 QStringList backends = test //
118 ? QStringList{QStringLiteral("dummy-backend")} //
119 : parser->value(QStringLiteral("backends")).split(QLatin1Char(','), Qt::SkipEmptyParts);
120 for (auto &backend : backends) {
121 if (!backend.endsWith(QLatin1String("-backend")))
122 backend.append(QLatin1String("-backend"));
123 }
124 *s_requestedBackends = backends;
125 }
126