#include "command.h" #include <QProcess> #include <QDebug> #include <QDir> #include <QRegularExpression> #include <QDateTime> Command::Command(QString const &command, int start_timeout, int finish_timeout) : m_command(command.trimmed()) , m_commandResult("") , m_waitForStartTimeout(start_timeout) , m_waitForFinishTimeout(finish_timeout) , m_exitCode(-1) { } QString Command::getCommandResult() const { return m_commandResult; } void Command::readyReadStandardOutput() { QProcess *p = (QProcess *)sender(); m_commandResult += p->readAllStandardOutput(); // qCritical() << m_commandResult; } void Command::readyReadStandardError() { QProcess *p = (QProcess *)sender(); QByteArray buf = p->readAllStandardError(); qCritical() << buf; } void Command::finished(int /*exitCode*/, QProcess::ExitStatus /*exitStatus*/) { QProcess *p = (QProcess *)sender(); // read all remaining data sent to the process, just in case QString d = p->readAllStandardOutput(); if (!d.isEmpty()) { m_commandResult += d; } disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardOutput())); disconnect(p, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(readyReadStandardError())); } bool Command::execute(QString workingDirectory, QStringList args) { if (!QDir::setCurrent(workingDirectory)) { qCritical() << "SET WORKING_DIRECTORY" << workingDirectory << "FAILED FOR" << m_command; return false; } QScopedPointer<QProcess> p(new QProcess(this)); p->setWorkingDirectory(workingDirectory); p->setProcessChannelMode(QProcess::MergedChannels); connect(&(*p), SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput())); connect(&(*p), SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError())); if (!args.isEmpty()) { qDebug() << "START COMMAND" << m_command << "WITH ARGS" << args << "IN" << p->workingDirectory(); p->start(m_command, args); } else { qDebug() << "START COMMAND" << m_command << "IN" << p->workingDirectory(); p->start(m_command); } qint64 const start = QDateTime::currentDateTime().toMSecsSinceEpoch(); if (p->waitForStarted(m_waitForStartTimeout)) { qDebug() << "PROCESS" << m_command << "STARTED IN" << p->workingDirectory(); if (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 = p->waitForFinished(wait); if (no_timeout) { qDebug() << "PROCESS" << m_command << "FINISHED IN" << p->workingDirectory(); if (p->exitStatus() == QProcess::NormalExit) { if ((m_exitCode = p->exitCode()) == 0) { qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); qDebug() << "EXECUTED" << m_command << QString("(runtime %1ms)").arg(end-start) << "with code" << m_exitCode << "IN" << 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" << p->workingDirectory(); } } else { qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); qCritical() << "PROCESS" << m_command << "CRASHED with code" << p->exitCode() << QString("(after %1ms)").arg(end-start) << "IN" << p->workingDirectory(); } } else { qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); qCritical() << "PROCESS" << m_command << "DID NOT FINISH WITH" << wait << "MS IN" << p->workingDirectory() << QString("(runtime %1ms)").arg(end-start); } } else { qCritical() << "WRONG PROCESS STATE" << p->state() << "IN" << p->workingDirectory(); } } else { qint64 const end = QDateTime::currentDateTime().toMSecsSinceEpoch(); qCritical() << "PROCESS" << m_command << "TIMEOUT AT START" << QString("(runtime %1ms)").arg(end-start) << "IN" << p->workingDirectory(); } return false; }