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 }
133 return ret;
134}
135
137{
138 if (!isReady()) {
139 return nullptr;
140 }
141
142 Q_D(const Configuration);
143
144 Purpose::Job *job = d->internalCreateJob(this);
145 if (!job) {
146 return job;
147 }
148
149 job->setData(d->m_inputData);
150 job->setProperty("outputArgs", d->m_pluginType.value(QLatin1String("X-Purpose-OutboundArguments")));
151
152 connect(job, &Purpose::Job::finished, &ConfigurationPrivate::checkJobFinish);
153 return job;
154}
155
157{
158 Q_D(const Configuration);
159 if (d->m_pluginData.fileName().contains(QLatin1String("contents/code/main."))) {
160 const QFileInfo fi(d->m_pluginData.fileName());
161 QDir conentsDir = fi.dir();
162 conentsDir.cdUp();
163 return QUrl::fromLocalFile(conentsDir.filePath(QStringLiteral("config/config.qml")));
164 } else {
165 const QString configFile =
166 QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf6/purpose/%1_config.qml").arg(d->m_pluginData.pluginId()));
167 if (configFile.isEmpty()) {
168 return QUrl();
169 }
170
171 return QUrl::fromLocalFile(configFile);
172 }
173}
174
176{
177 Q_D(const Configuration);
178 return d->m_useSeparateProcess;
179}
180
182{
184 d->m_useSeparateProcess = use;
185}
186
188{
189 Q_D(const Configuration);
190 KPluginMetaData md(d->m_pluginType, {});
191 return md.name();
192}
193
195{
196 Q_D(const Configuration);
197 return d->m_pluginData.name();
198}
199
200#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 Fri Oct 11 2024 12:19:52 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.