QtPass 1.4.0
Multi-platform GUI for pass, the standard unix password manager.
Loading...
Searching...
No Matches
executor.cpp
Go to the documentation of this file.
1#include "executor.h"
2#include <QCoreApplication>
3#include <QDir>
4#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
5#include <QTextCodec>
6#endif
7#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
8#include <QStringDecoder>
9#endif
10
11#ifdef QT_DEBUG
12#include "debughelper.h"
13#endif
14
19Executor::Executor(QObject *parent) : QObject(parent), running(false) {
20 connect(&m_process,
21 static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(
22 &QProcess::finished),
23 this,
24 static_cast<void (Executor::*)(int, QProcess::ExitStatus)>(
25 &Executor::finished));
26 connect(&m_process, &QProcess::started, this, &Executor::starting);
27}
28
32void Executor::executeNext() {
33 if (!running) {
34 if (!m_execQueue.isEmpty()) {
35 const execQueueItem &i = m_execQueue.head();
36 running = true;
37 if (!i.workingDir.isEmpty())
38 m_process.setWorkingDirectory(i.workingDir);
39 if (i.app.startsWith("wsl ")) {
40 QStringList tmp = i.args;
41 QString app = i.app;
42 tmp.prepend(app.remove(0, 4));
43 m_process.start("wsl", tmp);
44 } else
45 m_process.start(i.app, i.args);
46 if (!i.input.isEmpty()) {
47 m_process.waitForStarted(-1);
48 QByteArray data = i.input.toUtf8();
49 if (m_process.write(data) != data.length()) {
50#ifdef QT_DEBUG
51 dbg() << "Not all data written to process:" << i.id << " " << i.app;
52#endif
53 }
54 }
55 m_process.closeWriteChannel();
56 }
57 }
58}
59
68void Executor::execute(int id, const QString &app, const QStringList &args,
69 bool readStdout, bool readStderr) {
70 execute(id, QString(), app, args, QString(), readStdout, readStderr);
71}
72
82void Executor::execute(int id, const QString &workDir, const QString &app,
83 const QStringList &args, bool readStdout,
84 bool readStderr) {
85 execute(id, workDir, app, args, QString(), readStdout, readStderr);
86}
87
97void Executor::execute(int id, const QString &app, const QStringList &args,
98 QString input, bool readStdout, bool readStderr) {
99 execute(id, QString(), app, args, input, readStdout, readStderr);
100}
101
113void Executor::execute(int id, const QString &workDir, const QString &app,
114 const QStringList &args, QString input, bool readStdout,
115 bool readStderr) {
116 // Happens a lot if e.g. git binary is not set.
117 // This will result in bogus "QProcess::FailedToStart" messages,
118 // also hiding legitimate errors from the gpg commands.
119 if (app.isEmpty()) {
120#ifdef QT_DEBUG
121 dbg() << "Trying to execute nothing...";
122#endif
123 return;
124 }
125 QString appPath = app;
126 if (!appPath.startsWith("wsl "))
127 appPath =
128 QDir(QCoreApplication::applicationDirPath()).absoluteFilePath(app);
129 m_execQueue.push_back(
130 {id, appPath, args, input, readStdout, readStderr, workDir});
131 executeNext();
132}
133
144static QString decodeAssumingUtf8(QByteArray in) {
145#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
146 QTextCodec *codec = QTextCodec::codecForName("UTF-8");
147 QTextCodec::ConverterState state;
148 QString out = codec->toUnicode(in.constData(), in.size(), &state);
149 if (!state.invalidChars)
150 return out;
151 codec = QTextCodec::codecForUtfText(in);
152 return codec->toUnicode(in);
153#else
154 auto converter = QStringDecoder(QStringDecoder::Utf8);
155 return converter(in);
156#endif
157}
158
171int Executor::executeBlocking(QString app, const QStringList &args,
172 QString input, QString *process_out,
173 QString *process_err) {
174 QProcess internal;
175 if (app.startsWith("wsl ")) {
176 QStringList tmp = args;
177 tmp.prepend(app.remove(0, 4));
178 internal.start("wsl", tmp);
179 } else
180 internal.start(app, args);
181 if (!input.isEmpty()) {
182 QByteArray data = input.toUtf8();
183 internal.waitForStarted(-1);
184 if (internal.write(data) != data.length()) {
185#ifdef QT_DEBUG
186 dbg() << "Not all input written:" << app;
187#endif
188 }
189 internal.closeWriteChannel();
190 }
191 internal.waitForFinished(-1);
192 if (internal.exitStatus() == QProcess::NormalExit) {
193 QString pout = decodeAssumingUtf8(internal.readAllStandardOutput());
194 QString perr = decodeAssumingUtf8(internal.readAllStandardError());
195 if (process_out != Q_NULLPTR)
196 *process_out = pout;
197 if (process_err != Q_NULLPTR)
198 *process_err = perr;
199 return internal.exitCode();
200 }
201 // TODO(bezet): emit error() ?
202 return -1; // QProcess error code + qDebug error?
203}
204
213int Executor::executeBlocking(QString app, const QStringList &args,
214 QString *process_out, QString *process_err) {
215 return executeBlocking(app, args, QString(), process_out, process_err);
216}
217
223void Executor::setEnvironment(const QStringList &env) {
224 m_process.setEnvironment(env);
225}
226
234 if (running || m_execQueue.isEmpty())
235 return -1; // TODO(bezet): definitely throw here
236 return m_execQueue.dequeue().id;
237}
238
244void Executor::finished(int exitCode, QProcess::ExitStatus exitStatus) {
245 execQueueItem i = m_execQueue.dequeue();
246 running = false;
247 if (exitStatus == QProcess::NormalExit) {
248 QString output, err;
249 if (i.readStdout)
250 output = decodeAssumingUtf8(m_process.readAllStandardOutput());
251 if (i.readStderr || exitCode != 0) {
252 err = decodeAssumingUtf8(m_process.readAllStandardError());
253 if (exitCode != 0) {
254#ifdef QT_DEBUG
255 dbg() << exitCode << err;
256#endif
257 }
258 }
259 emit finished(i.id, exitCode, output, err);
260 }
261 // else: emit crashed with ID, which may give a chance to recover ?
262 executeNext();
263}
Executes external commands for handleing password, git and other data.
Definition: executor.h:12
Executor(QObject *parent=0)
Executor::Executor executes external applications.
Definition: executor.cpp:19
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:171
void execute(int id, const QString &app, const QStringList &args, bool readStdout, bool readStderr=true)
Executor::execute execute an app.
Definition: executor.cpp:68
int cancelNext()
Executor::cancelNext cancels execution of first process in queue if it's not already running.
Definition: executor.cpp:233
void setEnvironment(const QStringList &env)
Executor::setEnvironment set environment variables for executor processes.
Definition: executor.cpp:223
void starting()
starting signal that is emited when process starts
#define dbg()
Definition: debughelper.h:7