QtPass  1.2.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  } else {
190  // TODO(bezet): emit error() ?
191  return -1; // QProcess error code + qDebug error?
192  }
193 }
194 
203 int Executor::executeBlocking(QString app, const QStringList &args,
204  QString *process_out, QString *process_err) {
205  return executeBlocking(app, args, QString(), process_out, process_err);
206 }
207 
213 void Executor::setEnvironment(const QStringList &env) {
214  m_process.setEnvironment(env);
215 }
216 
224  if (running || m_execQueue.isEmpty())
225  return -1; // TODO(bezet): definitely throw here
226  return m_execQueue.dequeue().id;
227 }
228 
234 void Executor::finished(int exitCode, QProcess::ExitStatus exitStatus) {
235  execQueueItem i = m_execQueue.dequeue();
236  running = false;
237  if (exitStatus == QProcess::NormalExit) {
238  QString output, err;
239  if (i.readStdout)
240  output = decodeAssumingUtf8(m_process.readAllStandardOutput());
241  if (i.readStderr || exitCode != 0) {
242  err = decodeAssumingUtf8(m_process.readAllStandardError());
243  if (exitCode != 0) {
244 #ifdef QT_DEBUG
245  dbg() << exitCode << err;
246 #endif
247  }
248  }
249  emit finished(i.id, exitCode, output, err);
250  }
251  // else: emit crashed with ID, which may give a chance to recover ?
252  executeNext();
253 }
int cancelNext()
Executor::cancelNext cancels execution of first process in queue if it&#39;s not already running...
Definition: executor.cpp:223
#define dbg()
Definition: debughelper.h:7
void setEnvironment(const QStringList &env)
Executor::setEnvironment set environment variables for executor processes.
Definition: executor.cpp:213
Executes external commands for handleing password, git and other data.
Definition: executor.h:12
def data
Definition: avatars.py:87
void execute(int id, const QString &app, const QStringList &args, bool readStdout, bool readStderr=true)
Executor::execute execute an app.
Definition: executor.cpp:63
void starting()
starting signal that is emited when process starts
Executor(QObject *parent=0)
Executor::Executor executes external applications.
Definition: executor.cpp:14
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