diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 31894b5..39a745e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,59 +1,60 @@ +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake-paths.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/cmake-paths.h) + add_library(KF5Purpose pluginbase.cpp job.cpp alternativesmodel.cpp configuration.cpp helper.cpp externalprocess/processjob.cpp ) -set_source_files_properties(externalprocess/processjob.cpp PROPERTIES COMPILE_FLAGS "-DCMAKE_INSTALL_FULL_LIBEXECDIR_KF5='\"${CMAKE_INSTALL_FULL_LIBEXECDIR_KF5}\"'") target_include_directories(KF5Purpose PUBLIC "$" "$" INTERFACE "$" ) target_link_libraries(KF5Purpose PUBLIC KF5::CoreAddons Qt5::Gui PRIVATE Qt5::Network #QLocalSocket KF5::ConfigCore ) set_target_properties(KF5Purpose PROPERTIES VERSION ${PURPOSE_VERSION_STRING} SOVERSION ${PURPOSE_SOVERSION} EXPORT_NAME Purpose ) install(TARGETS KF5Purpose EXPORT KDEExperimentalPurposeTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) add_library(KF5::Purpose ALIAS KF5Purpose) generate_export_header(KF5Purpose EXPORT_FILE_NAME ${Purpose_BINARY_DIR}/purpose/purpose_export.h BASE_NAME Purpose) ecm_generate_headers(Purpose_CamelCase_HEADERS HEADER_NAMES PluginBase AlternativesModel Job Configuration REQUIRED_HEADERS Purpose_HEADERS PREFIX Purpose ) install(FILES ${Purpose_CamelCase_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/purpose/Purpose/ COMPONENT Devel) install(FILES ${Purpose_BINARY_DIR}/purpose/purpose_export.h ${Purpose_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/purpose/purpose COMPONENT Devel ) add_executable(purposeprocess externalprocess/purposeprocess_main.cpp helper.cpp) ecm_mark_nongui_executable(purposeprocess) target_link_libraries(purposeprocess KF5::Purpose Qt5::Network Qt5::Widgets) install(TARGETS purposeprocess DESTINATION ${KDE_INSTALL_LIBEXECDIR_KF5}) add_subdirectory(plugins) add_subdirectory(quick) add_subdirectory(widgets) diff --git a/src/cmake-paths.h.cmake b/src/cmake-paths.h.cmake new file mode 100644 index 0000000..92f4926 --- /dev/null +++ b/src/cmake-paths.h.cmake @@ -0,0 +1 @@ +#define CMAKE_INSTALL_FULL_LIBEXECDIR_KF5 "@CMAKE_INSTALL_FULL_LIBEXECDIR_KF5@" diff --git a/src/externalprocess/processjob.cpp b/src/externalprocess/processjob.cpp index 2360059..1969139 100644 --- a/src/externalprocess/processjob.cpp +++ b/src/externalprocess/processjob.cpp @@ -1,137 +1,138 @@ /* Copyright 2015 Aleix Pol Gonzalez This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . */ #include "processjob.h" +#include "cmake-paths.h" #include #include #include #include #include #include #include #include using namespace Purpose; ProcessJob::ProcessJob(const QString &pluginPath, const QString &pluginType, const QJsonObject& data, QObject* parent) : Job(parent) , m_process(new QProcess(this)) , m_pluginPath(pluginPath) , m_pluginType(pluginType) , m_data(data) , m_localSocket(nullptr) { if (QLibrary::isLibrary(pluginPath)) { QString exec = QStandardPaths::findExecutable(QStringLiteral("purposeprocess"), QStringList(QStringLiteral(CMAKE_INSTALL_FULL_LIBEXECDIR_KF5))); Q_ASSERT(!exec.isEmpty()); m_process->setProgram(exec); } else { Q_ASSERT(QFile::exists(pluginPath)); Q_ASSERT(QFileInfo(pluginPath).permission(QFile::ExeOther | QFile::ExeGroup | QFile::ExeUser)); m_process->setProgram(pluginPath); } m_process->setProcessChannelMode(QProcess::ForwardedChannels); #if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) connect(static_cast(m_process), &QProcess::errorOccurred, this, [](QProcess::ProcessError error) { qWarning() << "error!" << error; } ); #endif connect(static_cast(m_process), &QProcess::stateChanged, this, &ProcessJob::processStateChanged); m_socket.setMaxPendingConnections(1); m_socket.setSocketOptions(QLocalServer::UserAccessOption); bool b = m_socket.listen(QStringLiteral("randomname-%1").arg(KRandom::random())); Q_ASSERT(b); connect(&m_socket, &QLocalServer::newConnection, this, &ProcessJob::writeSocket); } ProcessJob::~ProcessJob() { m_process->kill(); delete m_process; } void ProcessJob::writeSocket() { m_localSocket = m_socket.nextPendingConnection(); connect(static_cast(m_localSocket), &QIODevice::readyRead, this, &ProcessJob::readSocket); m_socket.removeServer(m_socket.serverName()); const QJsonDocument doc(m_data); const QByteArray data = doc.toBinaryData(); m_localSocket->write(QByteArray::number(data.size()) + '\n'); const auto ret = m_localSocket->write(data); Q_ASSERT(ret == data.size()); m_localSocket->flush(); } void ProcessJob::readSocket() { QJsonParseError error; while(m_localSocket && m_localSocket->canReadLine()) { const QByteArray json = m_localSocket->readLine(); const QJsonObject object = QJsonDocument::fromJson(json, &error).object(); if (error.error != QJsonParseError::NoError) { qWarning() << "error!" << error.errorString() << json; continue; } for(auto it=object.constBegin(), itEnd=object.constEnd(); it!=itEnd; ++it) { const QByteArray propName = it.key().toLatin1(); if (propName == "percent") { setPercent(it->toInt()); } else if (propName == "error") { setError(it->toInt()); } else if (propName == "errorText") { setErrorText(it->toString()); } else if (propName == "output") { setOutput(it->toObject()); } } } } void ProcessJob::start() { m_process->setArguments({ QStringLiteral("--server"), m_socket.fullServerName(), QStringLiteral("--pluginType"), m_pluginType, QStringLiteral("--pluginPath"), m_pluginPath }); qDebug() << "launching..." << m_process->program() << m_process->arguments().join(QLatin1Char(' ')).constData(); m_process->start(); } void Purpose::ProcessJob::processStateChanged(QProcess::ProcessState state) { if (state == QProcess::NotRunning) { Q_ASSERT(m_process->exitCode()!=0 || m_localSocket); if (m_process->exitCode()!=0) { qWarning() << "process exited with code:" << m_process->exitCode(); } do { readSocket(); } while (m_localSocket->waitForReadyRead()); emitResult(); } }