File indexing completed on 2024-04-14 03:58:03
0001 /* 0002 SPDX-FileCopyrightText: 2015 Aleix Pol Gonzalez <aleixpol@blue-systems.com> 0003 0004 SPDX-License-Identifier: LGPL-2.1-or-later 0005 */ 0006 0007 #include "purpose/configuration.h" 0008 #include "externalprocess/processjob.h" 0009 #include <QFileInfo> 0010 0011 #include <KPluginFactory> 0012 #include <KPluginMetaData> 0013 0014 #include <QDebug> 0015 #include <QDir> 0016 #include <QStandardPaths> 0017 #include <qregularexpression.h> 0018 0019 #include "helper.h" 0020 #include "pluginbase.h" 0021 0022 using namespace Purpose; 0023 0024 class Purpose::ConfigurationPrivate 0025 { 0026 public: 0027 QJsonObject m_inputData; 0028 QString m_pluginTypeName; 0029 QJsonObject m_pluginType; 0030 const KPluginMetaData m_pluginData; 0031 bool m_useSeparateProcess; 0032 0033 static void checkJobFinish(KJob *job) 0034 { 0035 const QStringList outputArgs = job->property("outputArgs").toStringList(); 0036 const auto argsSet = QSet<QString>{outputArgs.cbegin(), outputArgs.cend()}; 0037 0038 const QStringList outputKeys = job->property("output").toJsonObject().keys(); 0039 const auto keysSet = QSet<QString>{outputKeys.cbegin(), outputKeys.cend()}; 0040 0041 if (!keysSet.contains(argsSet) && job->error() == 0) { 0042 qWarning() << "missing output values for" << job->metaObject()->className() << ". Expected: " << outputArgs.join(QStringLiteral(", ")) 0043 << ". Got: " << outputKeys.join(QStringLiteral(", ")); 0044 } 0045 } 0046 0047 Purpose::Job *internalCreateJob(QObject *parent) const 0048 { 0049 if (m_useSeparateProcess) 0050 return new ProcessJob(m_pluginData.fileName(), m_pluginTypeName, m_inputData, parent); 0051 else { 0052 return createJob(parent); 0053 } 0054 } 0055 0056 Purpose::Job *createJob(QObject *parent) const 0057 { 0058 if (m_pluginData.fileName().contains(QLatin1String("contents/code/main."))) { 0059 return new ProcessJob(m_pluginData.fileName(), m_pluginTypeName, m_inputData, parent); 0060 } else { 0061 auto pluginResult = KPluginFactory::instantiatePlugin<QObject>(m_pluginData, parent, QVariantList()); 0062 0063 if (!pluginResult) { 0064 qWarning() << "Couldn't load plugin:" << m_pluginData.fileName() << pluginResult.errorString; 0065 return nullptr; 0066 } 0067 0068 Purpose::PluginBase *plugin = dynamic_cast<Purpose::PluginBase *>(pluginResult.plugin); 0069 return plugin->createJob(); 0070 } 0071 } 0072 }; 0073 0074 Configuration::Configuration(const QJsonObject &inputData, const QString &pluginTypeName, const KPluginMetaData &pluginInformation, QObject *parent) 0075 : Configuration(inputData, pluginTypeName, QJsonObject(), pluginInformation, parent) 0076 { 0077 } 0078 0079 Configuration::Configuration(const QJsonObject &inputData, 0080 const QString &pluginTypeName, 0081 const QJsonObject &pluginType, 0082 const KPluginMetaData &pluginInformation, 0083 QObject *parent) 0084 : QObject(parent) 0085 , d_ptr(new ConfigurationPrivate{inputData, pluginTypeName, pluginType, pluginInformation, !qEnvironmentVariableIsSet("KDE_PURPOSE_LOCAL_JOBS")}) 0086 { 0087 } 0088 0089 Configuration::~Configuration() 0090 { 0091 delete d_ptr; 0092 } 0093 0094 void Configuration::setData(const QJsonObject &data) 0095 { 0096 Q_D(Configuration); 0097 0098 // qDebug() << "datachanged" << data; 0099 if (d->m_inputData != data) { 0100 d->m_inputData = data; 0101 Q_EMIT dataChanged(); 0102 } 0103 } 0104 0105 QJsonObject Configuration::data() const 0106 { 0107 Q_D(const Configuration); 0108 return d->m_inputData; 0109 } 0110 0111 bool Configuration::isReady() const 0112 { 0113 Q_D(const Configuration); 0114 bool ok = true; 0115 const auto arguments = neededArguments(); 0116 for (const QJsonValue &arg : arguments) { 0117 if (!d->m_inputData.contains(arg.toString())) { 0118 qDebug() << "missing mandatory argument" << arg.toString(); 0119 ok = false; 0120 } 0121 } 0122 return ok; 0123 } 0124 0125 QJsonArray Configuration::neededArguments() const 0126 { 0127 Q_D(const Configuration); 0128 QJsonArray ret = d->m_pluginType.value(QLatin1String("X-Purpose-InboundArguments")).toArray(); 0129 const QJsonArray arr = d->m_pluginData.rawData().value(QLatin1String("X-Purpose-Configuration")).toArray(); 0130 for (const QJsonValue &val : arr) 0131 ret += val; 0132 return ret; 0133 } 0134 0135 Purpose::Job *Configuration::createJob() 0136 { 0137 if (!isReady()) 0138 return nullptr; 0139 0140 Q_D(const Configuration); 0141 0142 Purpose::Job *job = d->internalCreateJob(this); 0143 if (!job) 0144 return job; 0145 0146 job->setData(d->m_inputData); 0147 job->setProperty("outputArgs", d->m_pluginType.value(QLatin1String("X-Purpose-OutboundArguments"))); 0148 0149 connect(job, &Purpose::Job::finished, &ConfigurationPrivate::checkJobFinish); 0150 return job; 0151 } 0152 0153 QUrl Configuration::configSourceCode() const 0154 { 0155 Q_D(const Configuration); 0156 if (d->m_pluginData.fileName().contains(QLatin1String("contents/code/main."))) { 0157 const QFileInfo fi(d->m_pluginData.fileName()); 0158 QDir conentsDir = fi.dir(); 0159 conentsDir.cdUp(); 0160 return QUrl::fromLocalFile(conentsDir.filePath(QStringLiteral("config/config.qml"))); 0161 } else { 0162 const QString configFile = 0163 QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kf6/purpose/%1_config.qml").arg(d->m_pluginData.pluginId())); 0164 if (configFile.isEmpty()) 0165 return QUrl(); 0166 0167 return QUrl::fromLocalFile(configFile); 0168 } 0169 } 0170 0171 bool Configuration::useSeparateProcess() const 0172 { 0173 Q_D(const Configuration); 0174 return d->m_useSeparateProcess; 0175 } 0176 0177 void Configuration::setUseSeparateProcess(bool use) 0178 { 0179 Q_D(Configuration); 0180 d->m_useSeparateProcess = use; 0181 } 0182 0183 QString Configuration::pluginTypeName() const 0184 { 0185 Q_D(const Configuration); 0186 KPluginMetaData md(d->m_pluginType, {}); 0187 return md.name(); 0188 } 0189 0190 QString Configuration::pluginName() const 0191 { 0192 Q_D(const Configuration); 0193 return d->m_pluginData.name(); 0194 } 0195 0196 #include "moc_configuration.cpp"