File indexing completed on 2025-03-09 03:56:12
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2015-04-13 0007 * Description : Generic process launcher with a capture of console output 0008 * 0009 * SPDX-FileCopyrightText: 2011-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0010 * 0011 * SPDX-License-Identifier: GPL-2.0-or-later 0012 * 0013 * ============================================================ */ 0014 0015 #include "processlauncher.h" 0016 0017 // Qt includes 0018 0019 #include <QByteArray> 0020 #include <QProcess> 0021 #include <QSharedPointer> 0022 #include <QElapsedTimer> 0023 #include <QProcessEnvironment> 0024 0025 // Local includes 0026 0027 #include "digikam_globals.h" 0028 #include "digikam_debug.h" 0029 0030 namespace Digikam 0031 { 0032 0033 class Q_DECL_HIDDEN ProcessLauncher::Private 0034 { 0035 public: 0036 0037 Private() = default; 0038 0039 public: 0040 0041 QSharedPointer<QProcess> process = nullptr; 0042 QStringList args; 0043 QString prog; 0044 QString dir; 0045 bool consoleTraces = true; 0046 bool successFlag = false; 0047 int exitCode = 0; 0048 int timeOut = 30000; ///< in milli-seconds; 0049 qint64 elapsed = 0; 0050 QString output; 0051 }; 0052 0053 ProcessLauncher::ProcessLauncher(QObject* const parent) 0054 : QThread(parent), 0055 d (new Private) 0056 { 0057 } 0058 0059 ProcessLauncher::~ProcessLauncher() 0060 { 0061 if (!d->process.isNull()) 0062 { 0063 d->process->kill(); 0064 } 0065 0066 delete d; 0067 } 0068 0069 void ProcessLauncher::setProgram(const QString& prog) 0070 { 0071 d->prog = prog; 0072 } 0073 0074 void ProcessLauncher::setArguments(const QStringList& args) 0075 { 0076 d->args = args; 0077 } 0078 0079 void ProcessLauncher::setWorkingDirectory(const QString& dir) 0080 { 0081 d->dir = dir; 0082 } 0083 0084 void ProcessLauncher::setTimeOut(int msecs) 0085 { 0086 d->timeOut = msecs; 0087 } 0088 0089 int ProcessLauncher::exitCode() const 0090 { 0091 return d->exitCode; 0092 } 0093 0094 QString ProcessLauncher::output() const 0095 { 0096 return d->output; 0097 } 0098 0099 bool ProcessLauncher::success() const 0100 { 0101 return d->successFlag; 0102 } 0103 0104 qint64 ProcessLauncher::elapsedTime() const 0105 { 0106 return d->elapsed; 0107 } 0108 0109 void ProcessLauncher::setConsoleTraces(bool b) 0110 { 0111 d->consoleTraces = b; 0112 } 0113 0114 void ProcessLauncher::startProcess() 0115 { 0116 start(); 0117 } 0118 0119 void ProcessLauncher::run() 0120 { 0121 QString prog; 0122 QStringList args; 0123 0124 d->process.reset(new QProcess()); 0125 d->process->setProcessChannelMode(QProcess::MergedChannels); 0126 d->process->setWorkingDirectory(d->dir); 0127 0128 QProcessEnvironment env = adjustedEnvironmentForAppImage(); 0129 d->process->setProcessEnvironment(env); 0130 0131 connect(d->process.data(), SIGNAL(readyRead()), 0132 this, SLOT(slotReadyRead())); 0133 0134 QElapsedTimer etimer; 0135 etimer.start(); 0136 0137 #ifdef Q_OS_WIN 0138 0139 prog = QLatin1String("cmd"); 0140 args = QStringList() << QLatin1String("/c") << d->prog << d->args; 0141 0142 #else // Linux and MacOS 0143 0144 prog = d->prog; 0145 args = d->args; 0146 0147 #endif 0148 0149 qCInfo(DIGIKAM_GENERAL_LOG) << "=== Starting process:" << prog << args; 0150 0151 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0152 0153 d->process->start(prog, args); 0154 0155 #else 0156 0157 d->process->setProgram(prog); 0158 d->process->setArguments(args); 0159 d->process->start(); 0160 0161 #endif 0162 0163 if (d->process->waitForStarted(d->timeOut)) 0164 { 0165 d->successFlag = d->process->waitForFinished(-1) && (d->process->exitStatus() == QProcess::NormalExit); 0166 d->elapsed = etimer.elapsed(); 0167 d->exitCode = d->process->exitCode(); 0168 0169 msleep(500); // Wait a little bit to flush the event loop. 0170 0171 qCInfo(DIGIKAM_GENERAL_LOG) << "=== Process execution is complete!"; 0172 qCInfo(DIGIKAM_GENERAL_LOG) << "> Process exit code :" << d->exitCode; 0173 qCInfo(DIGIKAM_GENERAL_LOG) << "> Process elasped time (ms):" << d->elapsed; 0174 } 0175 else 0176 { 0177 qCWarning(DIGIKAM_GENERAL_LOG) << "=== Process execution failed!"; 0178 } 0179 0180 Q_EMIT signalComplete(d->successFlag, d->exitCode); 0181 } 0182 0183 void ProcessLauncher::slotReadyRead() 0184 { 0185 QByteArray data = d->process->readAll(); 0186 0187 if (!data.isEmpty()) 0188 { 0189 QString txt = QString::fromLocal8Bit(data.data(), data.size()); 0190 d->output.append(txt); 0191 0192 if (d->consoleTraces) 0193 { 0194 Q_FOREACH (const QString& str, txt.split(QLatin1Char('\n'))) 0195 { 0196 if (!str.isEmpty()) 0197 { 0198 qCDebug(DIGIKAM_GENERAL_LOG) 0199 0200 #if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) 0201 0202 .noquote() 0203 0204 #endif 0205 0206 << str; 0207 } 0208 } 0209 } 0210 } 0211 } 0212 0213 } // namespace Digikam 0214 0215 #include "moc_processlauncher.cpp"