File indexing completed on 2024-04-28 05:26:46

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     qDebug() << "libs" << libraryPaths;
0078     for (const QString &dir : libraryPaths) {
0079         QDirIterator it(dir + QStringLiteral("/discover"), QDir::Files);
0080         while (it.hasNext()) {
0081             it.next();
0082             if (QLibrary::isLibrary(it.fileName()) && (allowDummy || it.fileName() != QLatin1String("dummy-backend.so"))) {
0083                 pluginNames += it.fileInfo().baseName();
0084             }
0085         }
0086     }
0087 
0088     pluginNames.removeDuplicates(); // will happen when discover is installed twice on the system
0089     return pluginNames;
0090 }
0091 
0092 QVector<AbstractResourcesBackend *> DiscoverBackendsFactory::allBackends() const
0093 {
0094     QStringList names = allBackendNames();
0095     auto ret = kTransform<QVector<AbstractResourcesBackend *>>(names, [this](const QString &name) {
0096         return backend(name);
0097     });
0098     ret.removeAll(nullptr);
0099 
0100     if (ret.isEmpty()) {
0101         qCWarning(LIBDISCOVER_LOG) << "Didn't find any Discover backend!";
0102     }
0103     return ret;
0104 }
0105 
0106 int DiscoverBackendsFactory::backendsCount() const
0107 {
0108     return allBackendNames().count();
0109 }
0110 
0111 void DiscoverBackendsFactory::setupCommandLine(QCommandLineParser *parser)
0112 {
0113     parser->addOption(QCommandLineOption(QStringLiteral("backends"),
0114                                          i18n("List all the backends we'll want to have loaded, separated by comma ','."),
0115                                          QStringLiteral("names")));
0116 }
0117 
0118 void DiscoverBackendsFactory::processCommandLine(QCommandLineParser *parser, bool test)
0119 {
0120     if (parser->isSet(QStringLiteral("feedback"))) {
0121         s_isFeedback = true;
0122         s_requestedBackends->clear();
0123         return;
0124     }
0125 
0126     QStringList backends = test //
0127         ? QStringList{QStringLiteral("dummy-backend")} //
0128         : parser->value(QStringLiteral("backends")).split(QLatin1Char(','), Qt::SkipEmptyParts);
0129     for (auto &backend : backends) {
0130         if (!backend.endsWith(QLatin1String("-backend"))) {
0131             backend.append(QLatin1String("-backend"));
0132         }
0133     }
0134     *s_requestedBackends = backends;
0135 }