File indexing completed on 2024-04-21 16:12:11

0001 /*
0002  *   SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
0003  *
0004  *   SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "DiscoverBackendsFactory.h"
0008 #include "libdiscover_debug.h"
0009 #include "resources/AbstractResourcesBackend.h"
0010 #include "resources/ResourcesModel.h"
0011 #include "utils.h"
0012 #include <KConfigGroup>
0013 #include <KDesktopFile>
0014 #include <KLocalizedString>
0015 #include <KSharedConfig>
0016 #include <QCommandLineParser>
0017 #include <QDir>
0018 #include <QDirIterator>
0019 #include <QPluginLoader>
0020 #include <QStandardPaths>
0021 
0022 Q_GLOBAL_STATIC(QStringList, s_requestedBackends)
0023 static bool s_isFeedback = false;
0024 
0025 void DiscoverBackendsFactory::setRequestedBackends(const QStringList &backends)
0026 {
0027     *s_requestedBackends = backends;
0028 }
0029 
0030 bool DiscoverBackendsFactory::hasRequestedBackends()
0031 {
0032     return !s_requestedBackends->isEmpty();
0033 }
0034 
0035 DiscoverBackendsFactory::DiscoverBackendsFactory()
0036 {
0037 }
0038 
0039 QVector<AbstractResourcesBackend *> DiscoverBackendsFactory::backend(const QString &name) const
0040 {
0041     if (QDir::isAbsolutePath(name) && QStandardPaths::isTestModeEnabled()) {
0042         return backendForFile(name, QFileInfo(name).fileName());
0043     } else {
0044         return backendForFile(name, name);
0045     }
0046 }
0047 
0048 QVector<AbstractResourcesBackend *> DiscoverBackendsFactory::backendForFile(const QString &libname, const QString &name) const
0049 {
0050     QPluginLoader *loader = new QPluginLoader(QLatin1String("discover/") + libname, QCoreApplication::instance());
0051 
0052     // qCDebug(LIBDISCOVER_LOG) << "trying to load plugin:" << loader->fileName();
0053     AbstractResourcesBackendFactory *f = qobject_cast<AbstractResourcesBackendFactory *>(loader->instance());
0054     if (!f) {
0055         qCWarning(LIBDISCOVER_LOG) << "error loading" << libname << loader->errorString() << loader->metaData();
0056         return {};
0057     }
0058     auto instances = f->newInstance(QCoreApplication::instance(), name);
0059     if (instances.isEmpty()) {
0060         qCWarning(LIBDISCOVER_LOG) << "Couldn't find the backend: " << libname << "among" << allBackendNames(false, true);
0061         return instances;
0062     }
0063 
0064     return instances;
0065 }
0066 
0067 QStringList DiscoverBackendsFactory::allBackendNames(bool whitelist, bool allowDummy) const
0068 {
0069     if (whitelist) {
0070         QStringList whitelistNames = *s_requestedBackends;
0071         if (s_isFeedback || !whitelistNames.isEmpty())
0072             return whitelistNames;
0073     }
0074 
0075     QStringList pluginNames;
0076     const auto libraryPaths = QCoreApplication::libraryPaths();
0077     for (const QString &dir : libraryPaths) {
0078         QDirIterator it(dir + QStringLiteral("/discover"), QDir::Files);
0079         while (it.hasNext()) {
0080             it.next();
0081             if (QLibrary::isLibrary(it.fileName()) && (allowDummy || it.fileName() != QLatin1String("dummy-backend.so"))) {
0082                 pluginNames += it.fileInfo().baseName();
0083             }
0084         }
0085     }
0086 
0087     pluginNames.removeDuplicates(); // will happen when discover is installed twice on the system
0088     return pluginNames;
0089 }
0090 
0091 QVector<AbstractResourcesBackend *> DiscoverBackendsFactory::allBackends() const
0092 {
0093     QStringList names = allBackendNames();
0094     auto ret = kTransform<QVector<AbstractResourcesBackend *>>(names, [this](const QString &name) {
0095         return backend(name);
0096     });
0097     ret.removeAll(nullptr);
0098 
0099     if (ret.isEmpty())
0100         qCWarning(LIBDISCOVER_LOG) << "Didn't find any Discover backend!";
0101     return ret;
0102 }
0103 
0104 int DiscoverBackendsFactory::backendsCount() const
0105 {
0106     return allBackendNames().count();
0107 }
0108 
0109 void DiscoverBackendsFactory::setupCommandLine(QCommandLineParser *parser)
0110 {
0111     parser->addOption(QCommandLineOption(QStringLiteral("backends"),
0112                                          i18n("List all the backends we'll want to have loaded, separated by comma ','."),
0113                                          QStringLiteral("names")));
0114 }
0115 
0116 void DiscoverBackendsFactory::processCommandLine(QCommandLineParser *parser, bool test)
0117 {
0118     if (parser->isSet(QStringLiteral("feedback"))) {
0119         s_isFeedback = true;
0120         s_requestedBackends->clear();
0121         return;
0122     }
0123 
0124     QStringList backends = test //
0125         ? QStringList{QStringLiteral("dummy-backend")} //
0126         : parser->value(QStringLiteral("backends")).split(QLatin1Char(','), Qt::SkipEmptyParts);
0127     for (auto &backend : backends) {
0128         if (!backend.endsWith(QLatin1String("-backend")))
0129             backend.append(QLatin1String("-backend"));
0130     }
0131     *s_requestedBackends = backends;
0132 }