LCOV - code coverage report
Current view: top level - src - executor.cpp (source / functions) Hit Total Coverage
Test: .lcov.total Lines: 4 85 4.7 %
Date: 2018-06-12 11:27:04 Functions: 2 12 16.7 %

          Line data    Source code
       1             : #include "executor.h"
       2             : #include "debughelper.h"
       3             : #include <QCoreApplication>
       4             : #include <QDir>
       5             : #include <QTextCodec>
       6             : 
       7             : /**
       8             :  * @brief Executor::Executor executes external applications
       9             :  * @param parent
      10             :  */
      11          20 : Executor::Executor(QObject *parent) : QObject(parent), running(false) {
      12           8 :   connect(&m_process,
      13             :           static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(
      14             :               &QProcess::finished),
      15             :           this,
      16             :           static_cast<void (Executor::*)(int, QProcess::ExitStatus)>(
      17             :               &Executor::finished));
      18           8 :   connect(&m_process, &QProcess::started, this, &Executor::starting);
      19           8 : }
      20             : 
      21             : /**
      22             :  * @brief Executor::executeNext consumes executable tasks from the queue
      23             :  */
      24           0 : void Executor::executeNext() {
      25           0 :   if (!running) {
      26           0 :     if (!m_execQueue.isEmpty()) {
      27           0 :       const execQueueItem &i = m_execQueue.head();
      28           0 :       running = true;
      29           0 :       if (!i.workingDir.isEmpty())
      30           0 :         m_process.setWorkingDirectory(i.workingDir);
      31           0 :       m_process.start(i.app, i.args);
      32           0 :       if (!i.input.isEmpty()) {
      33           0 :         m_process.waitForStarted(-1);
      34           0 :         QByteArray data = i.input.toUtf8();
      35           0 :         if (m_process.write(data) != data.length())
      36             :           dbg() << "Not all data written to process:" << i.id << " " << i.app;
      37           0 :       }
      38           0 :       m_process.closeWriteChannel();
      39           0 :     }
      40             :   }
      41           0 : }
      42             : 
      43             : /**
      44             :  * @brief Executor::execute execute an app
      45             :  * @param id
      46             :  * @param app
      47             :  * @param args
      48             :  * @param readStdout
      49             :  * @param readStderr
      50             :  */
      51           0 : void Executor::execute(int id, const QString &app, const QStringList &args,
      52             :                        bool readStdout, bool readStderr) {
      53           0 :   execute(id, QString(), app, args, QString(), readStdout, readStderr);
      54           0 : }
      55             : 
      56             : /**
      57             :  * @brief Executor::execute executes an app from a workDir
      58             :  * @param id
      59             :  * @param workDir
      60             :  * @param app
      61             :  * @param args
      62             :  * @param readStdout
      63             :  * @param readStderr
      64             :  */
      65           0 : void Executor::execute(int id, const QString &workDir, const QString &app,
      66             :                        const QStringList &args, bool readStdout,
      67             :                        bool readStderr) {
      68           0 :   execute(id, workDir, app, args, QString(), readStdout, readStderr);
      69           0 : }
      70             : 
      71             : /**
      72             :  * @brief Executor::execute an app, takes input and presents it as stdin
      73             :  * @param id
      74             :  * @param app
      75             :  * @param args
      76             :  * @param input
      77             :  * @param readStdout
      78             :  * @param readStderr
      79             :  */
      80           0 : void Executor::execute(int id, const QString &app, const QStringList &args,
      81             :                        QString input, bool readStdout, bool readStderr) {
      82           0 :   execute(id, QString(), app, args, input, readStdout, readStderr);
      83           0 : }
      84             : 
      85             : /**
      86             :  * @brief Executor::execute  executes an app from a workDir, takes input and
      87             :  * presents it as stdin
      88             :  * @param id
      89             :  * @param workDir
      90             :  * @param app
      91             :  * @param args
      92             :  * @param input
      93             :  * @param readStdout
      94             :  * @param readStderr
      95             :  */
      96           0 : void Executor::execute(int id, const QString &workDir, const QString &app,
      97             :                        const QStringList &args, QString input, bool readStdout,
      98             :                        bool readStderr) {
      99             :   // Happens a lot if e.g. git binary is not set.
     100             :   // This will result in bogus "QProcess::FailedToStart" messages,
     101             :   // also hiding legitimate errors from the gpg commands.
     102           0 :   if (app.isEmpty()) {
     103             :     dbg() << "Trying to execute nothing...";
     104             :     return;
     105             :   }
     106           0 :   QString appPath =
     107           0 :       QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(app);
     108           0 :   m_execQueue.push_back(
     109           0 :       {id, appPath, args, input, readStdout, readStderr, workDir});
     110           0 :   executeNext();
     111           0 : }
     112             : 
     113             : /**
     114             :  * @brief Executor::executeBlocking blocking version of the executor,
     115             :  * takes input and presents it as stdin
     116             :  * @param app
     117             :  * @param args
     118             :  * @param input
     119             :  * @param process_out
     120             :  * @param process_err
     121             :  * @return
     122             :  *
     123             :  * TODO(bezet): it might make sense to throw here, a lot of possible errors
     124             :  */
     125           0 : int Executor::executeBlocking(QString app, const QStringList &args,
     126             :                               QString input, QString *process_out,
     127             :                               QString *process_err) {
     128           0 :   QProcess internal;
     129           0 :   internal.start(app, args);
     130           0 :   if (!input.isEmpty()) {
     131           0 :     QByteArray data = input.toUtf8();
     132           0 :     internal.waitForStarted(-1);
     133           0 :     if (internal.write(data) != data.length()) {
     134             :       dbg() << "Not all input written:" << app;
     135             :     }
     136           0 :     internal.closeWriteChannel();
     137           0 :   }
     138           0 :   internal.waitForFinished(-1);
     139           0 :   if (internal.exitStatus() == QProcess::NormalExit) {
     140           0 :     QTextCodec *codec = QTextCodec::codecForLocale();
     141           0 :     QString pout = codec->toUnicode(internal.readAllStandardOutput());
     142           0 :     QString perr = codec->toUnicode(internal.readAllStandardError());
     143           0 :     if (process_out != Q_NULLPTR)
     144           0 :       *process_out = pout;
     145           0 :     if (process_err != Q_NULLPTR)
     146           0 :       *process_err = perr;
     147           0 :     return internal.exitCode();
     148           0 :   } else {
     149             :     //  TODO(bezet): emit error() ?
     150           0 :     return -1; //    QProcess error code + qDebug error?
     151             :   }
     152           0 : }
     153             : 
     154             : /**
     155             :  * @brief Executor::executeBlocking blocking version of the executor
     156             :  * @param app
     157             :  * @param args
     158             :  * @param process_out
     159             :  * @param process_err
     160             :  * @return
     161             :  */
     162           0 : int Executor::executeBlocking(QString app, const QStringList &args,
     163             :                               QString *process_out, QString *process_err) {
     164           0 :   return executeBlocking(app, args, QString(), process_out, process_err);
     165           0 : }
     166             : 
     167             : /**
     168             :  * @brief Executor::setEnvironment set environment variables
     169             :  * for executor processes
     170             :  * @param env
     171             :  */
     172           0 : void Executor::setEnvironment(const QStringList &env) {
     173           0 :   m_process.setEnvironment(env);
     174           0 : }
     175             : 
     176             : /**
     177             :  * @brief Executor::cancelNext  cancels execution of first process in queue
     178             :  *                              if it's not already running
     179             :  *
     180             :  * @return  id of the cancelled process or -1 on error
     181             :  */
     182           0 : int Executor::cancelNext() {
     183           0 :   if (running || m_execQueue.isEmpty())
     184           0 :     return -1; //  TODO(bezet): definitely throw here
     185           0 :   return m_execQueue.dequeue().id;
     186           0 : }
     187             : 
     188             : /**
     189             :  * @brief Executor::finished called when an executed process finishes
     190             :  * @param exitCode
     191             :  * @param exitStatus
     192             :  */
     193           0 : void Executor::finished(int exitCode, QProcess::ExitStatus exitStatus) {
     194           0 :   execQueueItem i = m_execQueue.dequeue();
     195           0 :   running = false;
     196           0 :   if (exitStatus == QProcess::NormalExit) {
     197           0 :     QString output, err;
     198           0 :     QTextCodec *codec = QTextCodec::codecForLocale();
     199           0 :     if (i.readStdout)
     200           0 :       output = codec->toUnicode(m_process.readAllStandardOutput());
     201           0 :     if (i.readStderr or exitCode != 0) {
     202           0 :       err = codec->toUnicode(m_process.readAllStandardError());
     203             :       if (exitCode != 0)
     204             :         dbg() << exitCode << err;
     205           0 :     }
     206           0 :     emit finished(i.id, exitCode, output, err);
     207           0 :   }
     208             :   //    else: emit crashed with ID, which may give a chance to recover ?
     209           0 :   executeNext();
     210           0 : }

Generated by: LCOV version 1.13