QtPass  1.3.3
Multi-platform GUI for pass, the standard unix password manager.
executor.cpp
Go to the documentation of this file.
1 #include "executor.h"
2 #include <QCoreApplication>
3 #include <QDir>
4 #include <QTextCodec>
5 
6 #ifdef QT_DEBUG
7 #include "debughelper.h"
8 #endif
9 
14 Executor::Executor(QObject *parent) : QObject(parent), running(false) {
15  connect(&m_process,
16  static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(
17  &QProcess::finished),
18  this,
19  static_cast<void (Executor::*)(int, QProcess::ExitStatus)>(
20  &Executor::finished));
21  connect(&m_process, &QProcess::started, this, &Executor::starting);
22 }
23 
27 void Executor::executeNext() {
28  if (!running) {
29  if (!m_execQueue.isEmpty()) {
30  const execQueueItem &i = m_execQueue.head();
31  running = true;
32  if (!i.workingDir.isEmpty())
33  m_process.setWorkingDirectory(i.workingDir);
34  if (i.app.startsWith("wsl ")) {
35  QStringList tmp = i.args;
36  QString app = i.app;
37  tmp.prepend(app.remove(0, 4));
38  m_process.start("wsl", tmp);
39  } else
40  m_process.start(i.app, i.args);
41  if (!i.input.isEmpty()) {
42  m_process.waitForStarted(-1);
43  QByteArray data = i.input.toUtf8();
44  if (m_process.write(data) != data.length()) {
45 #ifdef QT_DEBUG
46  dbg() << "Not all data written to process:" << i.id << " " << i.app;
47 #endif
48  }
49  }
50  m_process.closeWriteChannel();
51  }
52  }
53 }
54 
63 void Executor::execute(int id, const QString &app, const QStringList &args,
64  bool readStdout, bool readStderr) {
65  execute(id, QString(), app, args, QString(), readStdout, readStderr);
66 }
67 
77 void Executor::execute(int id, const QString &workDir, const QString &app,
78  const QStringList &args, bool readStdout,
79  bool readStderr) {
80  execute(id, workDir, app, args, QString(), readStdout, readStderr);
81 }
82 
92 void Executor::execute(int id, const QString &app, const QStringList &args,
93  QString input, bool readStdout, bool readStderr) {
94  execute(id, QString(), app, args, input, readStdout, readStderr);
95 }
96 
108 void Executor::execute(int id, const QString &workDir, const QString &app,
109  const QStringList &args, QString input, bool readStdout,
110  bool readStderr) {
111  // Happens a lot if e.g. git binary is not set.
112  // This will result in bogus "QProcess::FailedToStart" messages,
113  // also hiding legitimate errors from the gpg commands.
114  if (app.isEmpty()) {
115 #ifdef QT_DEBUG
116  dbg() << "Trying to execute nothing...";
117 #endif
118  return;
119  }
120  QString appPath = app;
121  if (!appPath.startsWith("wsl "))
122  appPath =
123  QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(app);
124  m_execQueue.push_back(
125  {id, appPath, args, input, readStdout, readStderr, workDir});
126  executeNext();
127 }
128 
138 static QString decodeAssumingUtf8(QByteArray in) {
139  QTextCodec *codec = QTextCodec::codecForName("UTF-8");
140  QTextCodec::ConverterState state;
141  QString out = codec->toUnicode(in.constData(), in.size(), &state);
142  if (!state.invalidChars)
143  return out;
144  codec = QTextCodec::codecForUtfText(in);
145  return codec->toUnicode(in);
146 }
147 
160 int Executor::executeBlocking(QString app, const QStringList &args,
161  QString input, QString *process_out,
162  QString *process_err) {
163  QProcess internal;
164  if (app.startsWith("wsl ")) {
165  QStringList tmp = args;
166  tmp.prepend(app.remove(0, 4));
167  internal.start("wsl", tmp);
168  } else
169  internal.start(app, args);
170  if (!input.isEmpty()) {
171  QByteArray data = input.toUtf8();
172  internal.waitForStarted(-1);
173  if (internal.write(data) != data.length()) {
174 #ifdef QT_DEBUG
175  dbg() << "Not all input written:" << app;
176 #endif
177  }
178  internal.closeWriteChannel();
179  }
180  internal.waitForFinished(-1);
181  if (internal.exitStatus() == QProcess::NormalExit) {
182  QString pout = decodeAssumingUtf8(internal.readAllStandardOutput());
183  QString perr = decodeAssumingUtf8(internal.readAllStandardError());
184  if (process_out != Q_NULLPTR)
185  *process_out = pout;
186  if (process_err != Q_NULLPTR)
187  *process_err = perr;
188  return internal.exitCode();
189  }
190  // TODO(bezet): emit error() ?
191  return -1; // QProcess error code + qDebug error?
192 }
193 
202 int Executor::executeBlocking(QString app, const QStringList &args,
203  QString *process_out, QString *process_err) {
204  return executeBlocking(app, args, QString(), process_out, process_err);
205 }
206 
212 void Executor::setEnvironment(const QStringList &env) {
213  m_process.setEnvironment(env);
214 }
215 
223  if (running || m_execQueue.isEmpty())
224  return -1; // TODO(bezet): definitely throw here
225  return m_execQueue.dequeue().id;
226 }
227 
233 void Executor::finished(int exitCode, QProcess::ExitStatus exitStatus) {
234  execQueueItem i = m_execQueue.dequeue();
235  running = false;
236  if (exitStatus == QProcess::NormalExit) {
237  QString output, err;
238  if (i.readStdout)
239  output = decodeAssumingUtf8(m_process.readAllStandardOutput());
240  if (i.readStderr || exitCode != 0) {
241  err = decodeAssumingUtf8(m_process.readAllStandardError());
242  if (exitCode != 0) {
243 #ifdef QT_DEBUG
244  dbg() << exitCode << err;
245 #endif
246  }
247  }
248  emit finished(i.id, exitCode, output, err);
249  }
250  // else: emit crashed with ID, which may give a chance to recover ?
251  executeNext();
252 }
Executor
Executes external commands for handleing password, git and other data.
Definition: executor.h:12
Executor::execute
void execute(int id, const QString &app, const QStringList &args, bool readStdout, bool readStderr=true)
Executor::execute execute an app.
Definition: executor.cpp:63
Executor::executeBlocking
static int executeBlocking(QString app, const QStringList &args, QString input=QString(), QString *process_out=Q_NULLPTR, QString *process_err=Q_NULLPTR)
Executor::executeBlocking blocking version of the executor, takes input and presents it as stdin.
Definition: executor.cpp:160
debughelper.h
Executor::setEnvironment
void setEnvironment(const QStringList &env)
Executor::setEnvironment set environment variables for executor processes.
Definition: executor.cpp:212
executor.h
Executor::Executor
Executor(QObject *parent=0)
Executor::Executor executes external applications.
Definition: executor.cpp:14
Executor::cancelNext
int cancelNext()
Executor::cancelNext cancels execution of first process in queue if it's not already running.
Definition: executor.cpp:222
dbg
#define dbg()
Definition: debughelper.h:7
Executor::starting
void starting()
starting signal that is emited when process starts