Purpose

configuration.cpp
1/*
2 SPDX-FileCopyrightText: 2015 Aleix Pol Gonzalez <aleixpol@blue-systems.com>
3
4 SPDX-License-Identifier: LGPL-2.1-or-later
5*/
6
7#include "purpose/configuration.h"
8#include "externalprocess/processjob.h"
9#include <QFileInfo>
10
11#include <KPluginFactory>
12#include <KPluginMetaData>
13
14#include <QDebug>
15#include <QDir>
16#include <QStandardPaths>
17#include <qregularexpression.h>
18
19#include "helper.h"
20#include "pluginbase.h"
21
22using namespace Purpose;
23
24class Purpose::ConfigurationPrivate
25{
26public:
27 QJsonObject m_inputData;
28 QString m_pluginTypeName;
29 QJsonObject m_pluginType;
30 const KPluginMetaData m_pluginData;
31 bool m_useSeparateProcess;
32
33 static void checkJobFinish(KJob *job)
34 {
35 const QStringList outputArgs = job->property("outputArgs").toStringList();
36 const auto argsSet = QSet<QString>{outputArgs.cbegin(), outputArgs.cend()};
37
38 const QStringList outputKeys = job->property("output").toJsonObject().keys();
39 const auto keysSet = QSet<QString>{outputKeys.cbegin(), outputKeys.cend()};
40
41 if (!keysSet.contains(argsSet) && job->error() == 0) {
42 qWarning() << "missing output values for" << job->metaObject()->className() << ". Expected: " << outputArgs.join(QStringLiteral(", "))
43 << ". Got: " << outputKeys.join(QStringLiteral(", "));
44 }
45 }
46
47 Purpose::Job *internalCreateJob(QObject *parent) const
48 {
49 if (m_useSeparateProcess)
50 return new ProcessJob(m_pluginData.fileName(), m_pluginTypeName, m_inputData, parent);
51 else {
52 return createJob(parent);
53 }
54 }
55
56 Purpose::Job *createJob(QObject *parent) const
57 {
58 if (m_pluginData.fileName().contains(QLatin1String("contents/code/main."))) {
59 return new ProcessJob(m_pluginData.fileName(), m_pluginTypeName, m_inputData, parent);
60 } else {
61 auto pluginResult = KPluginFactory::instantiatePlugin<QObject>(m_pluginData, parent, QVariantList());
62
63 if (!pluginResult) {
64 qWarning() << "Couldn't load plugin:" << m_pluginData.fileName() << pluginResult.errorString;
65 return nullptr;
66 }
67
68 Purpose::PluginBase *plugin = dynamic_cast<Purpose::PluginBase *>(pluginResult.plugin);
69 return plugin->createJob();
70 }
71 }
72};
73
74Configuration::Configuration(const QJsonObject &inputData, const QString &pluginTypeName, const KPluginMetaData &pluginInformation, QObject *parent)
75 : Configuration(inputData, pluginTypeName, QJsonObject(), pluginInformation, parent)
76{
77}
78
79Configuration::Configuration(const QJsonObject &inputData,
80 const QString &pluginTypeName,
81 const QJsonObject &pluginType,
82 const KPluginMetaData &pluginInformation,
83 QObject *parent)
84 : QObject(parent)
85 , d_ptr(new ConfigurationPrivate{inputData, pluginTypeName, pluginType, pluginInformation, !qEnvironmentVariableIsSet("KDE_PURPOSE_LOCAL_JOBS")})
86{
87}
88
89Configuration::~Configuration()
90{
91 delete d_ptr;
92}
93
94void Configuration::setData(const QJsonObject &data)
95{
97
98 // qDebug() << "datachanged" << data;
99 if (d->m_inputData != data) {
100 d->m_inputData = data;
101 Q_EMIT dataChanged();
102 }
103}
104
106{
107 Q_D(const Configuration);
108 return d->m_inputData;
109}
110
111bool Configuration::isReady() const
112{
113 Q_D(const Configuration);
114 bool ok = true;
115 const auto arguments = neededArguments();
116 for (const QJsonValue &arg : arguments) {
117 if (!d->m_inputData.contains(arg.toString())) {
118 qDebug() << "missing mandatory argument" << arg.toString();
119 ok = false;
120 }
121 }
122 return ok;
123}
124
126{
127 Q_D(const Configuration);
128 QJsonArray ret = d->m_pluginType.value(QLatin1String("X-Purpose-InboundArguments")).toArray();
129 const QJsonArray arr = d->m_pluginData.rawData().value(QLatin1String("X-Purpose-Configuration")).toArray();
130 for (const QJsonValue &val : arr)
131 ret += val;
132 return ret;
133}
134
136{
137 if (!isReady())
138 return nullptr;
139
140 Q_D(const Configuration);
141
142 Purpose::Job *job = d->internalCreateJob(this);
143 if (!job)
144 return job;
145
146 job->setData(d->m_inputData);
147 job->setProperty("outputArgs", d->m_pluginType.value(QLatin1String("X-Purpose-OutboundArguments")));
148
149 connect(job, &Purpose::Job::finished, &ConfigurationPrivate::checkJobFinish);
150 return job;
151}
152
154{
155 Q_D(const Configuration);
156 if (d->m_pluginData.fileName().contains(QLatin1String("contents/code/main."))) {
157 const QFileInfo fi(d->m_pluginData.fileName());
158 QDir conentsDir = fi.dir();
159 conentsDir.cdUp();
160 return QUrl::fromLocalFile(conentsDir.filePath(QStringLiteral("config/config.qml")));
161 } else {
162 const QString configFile =
163 QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf6/purpose/%1_config.qml").arg(d->m_pluginData.pluginId()));
164 if (configFile.isEmpty())
165 return QUrl();
166
167 return QUrl::fromLocalFile(configFile);
168 }
169}
170
172{
173 Q_D(const Configuration);
174 return d->m_useSeparateProcess;
175}
176
178{
180 d->m_useSeparateProcess = use;
181}
182
184{
185 Q_D(const Configuration);
186 KPluginMetaData md(d->m_pluginType, {});
187 return md.name();
188}
189
191{
192 Q_D(const Configuration);
193 return d->m_pluginData.name();
194}
195
196#include "moc_configuration.cpp"
int error() const
void finished(KJob *job)
QString fileName() const
This class will be in charge of figuring out the job configuration.
bool useSeparateProcess() const
QJsonArray neededArguments
Specifies the arguments the config file and the job will be sharing.
QUrl configSourceCode
Specifies the qml source code to be used, to configure the current job.
QJsonObject data
Represents the data the job will have available to perform its task.
bool isReady
Tells whether there's still information to be provided, to be able to run the job.
void setUseSeparateProcess(bool separate)
separate will specify whether the process will be forced to execute in-process or in a separate proce...
Q_SCRIPTABLE Purpose::Job * createJob()
Job that will actually perform the sharing.
Definition job.h:34
void setData(const QJsonObject &data)
Should only be called after constructing.
Definition job.cpp:34
Base class to implement by plugins.
Definition pluginbase.h:29
virtual Job * createJob() const =0
bool cdUp()
QString filePath(const QString &fileName) const const
QStringList keys() const const
const_iterator cbegin() const const
const_iterator cend() const const
const char * className() const const
Q_EMITQ_EMIT
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
virtual const QMetaObject * metaObject() const const
QVariant property(const char *name) const const
bool setProperty(const char *name, QVariant &&value)
QString locate(StandardLocation type, const QString &fileName, LocateOptions options)
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString join(QChar separator) const const
QUrl fromLocalFile(const QString &localFile)
QJsonObject toJsonObject() const const
QStringList toStringList() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:05 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.