From 47e7e1e796dc19afd1165695a8578aadaf659f15 Mon Sep 17 00:00:00 2001 From: Siegfried Siegert Date: Thu, 5 Feb 2026 13:59:13 +0100 Subject: [PATCH] Add common/command --- common/include/command.h | 49 +++++++++++++++ common/src/command.cpp | 128 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 177 insertions(+) create mode 100644 common/include/command.h create mode 100644 common/src/command.cpp diff --git a/common/include/command.h b/common/include/command.h new file mode 100644 index 0000000..33b155f --- /dev/null +++ b/common/include/command.h @@ -0,0 +1,49 @@ +#ifndef COMMAND_H_INCLUDED +#define COMMAND_H_INCLUDED + +#include +#include +#include +#include +#include +#include + +class Command : public QObject { + Q_OBJECT + + QString m_command; + QString m_commandResult; + + int m_waitForStartTimeout; + int m_waitForFinishTimeout; + bool m_verbose; + int m_exitCode; + QString m_workingDirectory; + + QScopedPointer m_p; + + QStringList m_args; + +public: + Command(QString command, + QStringList args, + QString workingDirectory, + bool verbose = true, + int start_timeout = 100000, + int finish_timeout = 100000); + + void resetCommandResult() { m_commandResult.clear(); } + QString getCommandResult(bool reset = false); + QString const &command() const { return m_command; } + QString const &commandResult() const { return m_commandResult; } + QStringList const &args() const { return m_args; } + + bool exec(); + int exitCode() const { return m_exitCode; } + +private slots: + virtual void readyReadStandardOutput(); + virtual void readyReadStandardError(); +}; + +#endif // COMMAND_H_INCLUDED diff --git a/common/src/command.cpp b/common/src/command.cpp new file mode 100644 index 0000000..28b8c19 --- /dev/null +++ b/common/src/command.cpp @@ -0,0 +1,128 @@ +#include "command.h" + +#include +#include +#include +#include +#include + +Command::Command(QString command, QStringList args, QString workingDirectory, + bool verbose, int start_timeout, int finish_timeout) + : m_command(command.trimmed()) + , m_commandResult("") + , m_waitForStartTimeout(start_timeout) + , m_waitForFinishTimeout(finish_timeout) + , m_verbose(verbose) + , m_exitCode(-1) + , m_workingDirectory(workingDirectory) + , m_args(args) { + m_p.reset(new QProcess(this)); + if (m_p) { + m_p->setWorkingDirectory(workingDirectory); + m_p->setProcessChannelMode(QProcess::MergedChannels); + + connect(m_p.get(), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput())); + connect(m_p.get(), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError())); + } +} + +void Command::readyReadStandardOutput() { + QProcess *p = (QProcess *)sender(); + if (p) { + QString s = p->readAllStandardOutput(); + if (m_verbose) { +// qCritical().noquote() << s; + m_commandResult += s; + } + } +} + +void Command::readyReadStandardError() { + QProcess *p = (QProcess *)sender(); + if (p) { + QString s = p->readAllStandardError(); +// qCritical().noquote() << s; + m_commandResult += s; + } +} + + +QString Command::getCommandResult(bool reset) { + if (reset == false) { + return m_commandResult; + } + + QString commandResult = m_commandResult; + m_commandResult.clear(); + + return commandResult; +} + +bool Command::exec() { + + if (!m_args.isEmpty()) { + m_p->start(m_command, m_args); + } else { + m_p->start(m_command); + } + + qint64 const start = QDateTime::currentDateTime().toMSecsSinceEpoch(); + + bool started = false; + if ((started = m_p->waitForStarted(m_waitForStartTimeout)) == true) { + // qCritical() << "PROCESS" << m_command << "STARTED IN" << m_p->workingDirectory(); + if (m_p->state() == QProcess::ProcessState::Running) { + // qDebug() << "PROCESS" << m_command << "RUNNING IN" << p->workingDirectory(); + // wait forever for git/opkg-commands to finish + int wait = m_waitForFinishTimeout; + if (m_command.trimmed().startsWith("git", Qt::CaseInsensitive) || + m_command.trimmed().startsWith("opkg", Qt::CaseInsensitive)) { + wait = -1; + } + bool const no_timeout = m_p->waitForFinished(wait); + if (no_timeout) { + // qDebug() << "PROCESS" << m_command << "FINISHED IN" << p->workingDirectory(); + if (m_p->exitStatus() == QProcess::NormalExit) { + if ((m_exitCode = m_p->exitCode()) == 0) { + qCritical().noquote() << m_p->readAllStandardOutput(); + //qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); + //qDebug() << "EXECUTED" << m_command + // << QString("(runtime %1ms)").arg(end-start) + // << "with code" << m_exitCode + // << "IN" << m_p->workingDirectory(); + return true; + } else { + qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); + qCritical() << "EXECUTED" << m_command + << QString("(runtime %1ms)").arg(end-start) + << "with code" << m_exitCode + << "IN" << m_p->workingDirectory(); + } + } else { + qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); + qCritical() << "PROCESS" << m_command << "CRASHED with code" + << m_p->exitCode() + << QString("(after %1ms)").arg(end-start) + << "IN" << m_p->workingDirectory(); + } + } else { + qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); + qCritical() << "PROCESS" << m_command + << "DID NOT FINISH WITH" << wait + << "MS IN" << m_p->workingDirectory() + << QString("(runtime %1ms)").arg(end-start); + } + } else { + qCritical() << "WRONG PROCESS STATE" << m_p->state() + << "IN" << m_p->workingDirectory(); + } + } else { + qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); + qCritical() << "PROCESS" << m_command << "TIMEOUT AT START" + << QString("(runtime %1ms)").arg(end-start) + << "IN" << m_p->workingDirectory() << m_waitForStartTimeout; + } + + return false; +} +