Utils: Base SynchronousProcess on QtcProcess

This is the last intermediate step before unification to keep the
merge small.

Change-Id: I5b320f9db4c467c49a384f665cea5e16bfef4f60
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
hjk
2021-05-06 10:06:45 +02:00
parent eb99d1bc6c
commit a4b5479695
2 changed files with 42 additions and 125 deletions

View File

@@ -2037,7 +2037,6 @@ public:
void clearForRun(); void clearForRun();
QTextCodec *m_codec = QTextCodec::codecForLocale(); QTextCodec *m_codec = QTextCodec::codecForLocale();
QtcProcess m_process;
QTimer m_timer; QTimer m_timer;
QEventLoop m_eventLoop; QEventLoop m_eventLoop;
SynchronousProcessResponse m_result; SynchronousProcessResponse m_result;
@@ -2072,25 +2071,23 @@ SynchronousProcess::SynchronousProcess() :
{ {
d->m_timer.setInterval(1000); d->m_timer.setInterval(1000);
connect(&d->m_timer, &QTimer::timeout, this, &SynchronousProcess::slotTimeout); connect(&d->m_timer, &QTimer::timeout, this, &SynchronousProcess::slotTimeout);
connect(&d->m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &SynchronousProcess::finished); this, &SynchronousProcess::slotFinished);
connect(&d->m_process, &QProcess::errorOccurred, this, &SynchronousProcess::error); connect(this, &QProcess::errorOccurred, this, &SynchronousProcess::error);
connect(&d->m_process, &QProcess::readyReadStandardOutput, connect(this, &QProcess::readyReadStandardOutput, this, [this] {
this, [this]() { d->m_hangTimerCount = 0;
d->m_hangTimerCount = 0; processStdOut(true);
processStdOut(true); });
}); connect(this, &QProcess::readyReadStandardError, this, [this] {
connect(&d->m_process, &QProcess::readyReadStandardError, d->m_hangTimerCount = 0;
this, [this]() { processStdErr(true);
d->m_hangTimerCount = 0; });
processStdErr(true);
});
} }
SynchronousProcess::~SynchronousProcess() SynchronousProcess::~SynchronousProcess()
{ {
disconnect(&d->m_timer, nullptr, this, nullptr); disconnect(&d->m_timer, nullptr, this, nullptr);
disconnect(&d->m_process, nullptr, this, nullptr); disconnect(this, nullptr, this, nullptr);
delete d; delete d;
} }
@@ -2102,78 +2099,23 @@ void SynchronousProcess::setTimeoutS(int timeoutS)
d->m_maxHangTimerCount = INT_MAX / 1000; d->m_maxHangTimerCount = INT_MAX / 1000;
} }
int SynchronousProcess::timeoutS() const
{
return d->m_maxHangTimerCount == (INT_MAX / 1000) ? -1 : d->m_maxHangTimerCount;
}
void SynchronousProcess::setCodec(QTextCodec *c) void SynchronousProcess::setCodec(QTextCodec *c)
{ {
QTC_ASSERT(c, return); QTC_ASSERT(c, return);
d->m_codec = c; d->m_codec = c;
} }
QTextCodec *SynchronousProcess::codec() const
{
return d->m_codec;
}
Environment SynchronousProcess::environment() const
{
return d->m_process.environment();
}
bool SynchronousProcess::timeOutMessageBoxEnabled() const
{
return d->m_timeOutMessageBoxEnabled;
}
void SynchronousProcess::setTimeOutMessageBoxEnabled(bool v) void SynchronousProcess::setTimeOutMessageBoxEnabled(bool v)
{ {
d->m_timeOutMessageBoxEnabled = v; d->m_timeOutMessageBoxEnabled = v;
} }
void SynchronousProcess::setEnvironment(const Environment &e)
{
d->m_process.setEnvironment(Environment(e));
}
void SynchronousProcess::setDisableUnixTerminal()
{
d->m_process.setDisableUnixTerminal();
}
void SynchronousProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter) void SynchronousProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter)
{ {
QTC_ASSERT(interpreter, return); QTC_ASSERT(interpreter, return);
d->m_exitCodeInterpreter = interpreter; d->m_exitCodeInterpreter = interpreter;
} }
ExitCodeInterpreter SynchronousProcess::exitCodeInterpreter() const
{
return d->m_exitCodeInterpreter;
}
void SynchronousProcess::setWorkingDirectory(const QString &workingDirectory)
{
d->m_process.setWorkingDirectory(workingDirectory);
}
QString SynchronousProcess::workingDirectory() const
{
return d->m_process.workingDirectory();
}
QProcess::ProcessChannelMode SynchronousProcess::processChannelMode () const
{
return d->m_process.processChannelMode();
}
void SynchronousProcess::setProcessChannelMode(QProcess::ProcessChannelMode m)
{
d->m_process.setProcessChannelMode(m);
}
#ifdef QT_GUI_LIB #ifdef QT_GUI_LIB
static bool isGuiThread() static bool isGuiThread()
{ {
@@ -2187,8 +2129,8 @@ SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
// FIXME: Implement properly // FIXME: Implement properly
if (cmd.executable().needsDevice()) { if (cmd.executable().needsDevice()) {
QtcProcess proc; QtcProcess proc;
proc.setEnvironment(Environment(d->m_process.environment())); proc.setEnvironment(Environment(environment()));
proc.setWorkingDirectory(d->m_process.workingDirectory()); proc.setWorkingDirectory(workingDirectory());
proc.setCommand(cmd); proc.setCommand(cmd);
// writeData ? // writeData ?
@@ -2215,15 +2157,15 @@ SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
// using QProcess::start() and passing program, args and OpenMode results in a different // using QProcess::start() and passing program, args and OpenMode results in a different
// quoting of arguments than using QProcess::setArguments() beforehand and calling start() // quoting of arguments than using QProcess::setArguments() beforehand and calling start()
// only with the OpenMode // only with the OpenMode
d->m_process.setCommand(cmd); setCommand(cmd);
if (!writeData.isEmpty()) { if (!writeData.isEmpty()) {
connect(&d->m_process, &QProcess::started, this, [this, writeData] { connect(this, &QProcess::started, this, [this, writeData] {
d->m_process.write(writeData); write(writeData);
d->m_process.closeWriteChannel(); closeWriteChannel();
}); });
} }
d->m_process.setOpenMode(writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite); setOpenMode(writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
d->m_process.start(); start();
// On Windows, start failure is triggered immediately if the // On Windows, start failure is triggered immediately if the
// executable cannot be found in the path. Do not start the // executable cannot be found in the path. Do not start the
@@ -2256,8 +2198,8 @@ SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cm
// FIXME: Implement properly // FIXME: Implement properly
if (cmd.executable().needsDevice()) { if (cmd.executable().needsDevice()) {
QtcProcess proc; QtcProcess proc;
proc.setEnvironment(Environment(d->m_process.environment())); proc.setEnvironment(Environment(environment()));
proc.setWorkingDirectory(d->m_process.workingDirectory()); proc.setWorkingDirectory(workingDirectory());
proc.setCommand(cmd); proc.setCommand(cmd);
// writeData ? // writeData ?
@@ -2281,32 +2223,32 @@ SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cm
d->clearForRun(); d->clearForRun();
d->m_binary = cmd.executable(); d->m_binary = cmd.executable();
d->m_process.setOpenMode(QIODevice::ReadOnly); setOpenMode(QIODevice::ReadOnly);
d->m_process.setCommand(cmd); setCommand(cmd);
d->m_process.start(); start();
if (!d->m_process.waitForStarted(d->m_maxHangTimerCount * 1000)) { if (!waitForStarted(d->m_maxHangTimerCount * 1000)) {
d->m_result.result = SynchronousProcessResponse::StartFailed; d->m_result.result = SynchronousProcessResponse::StartFailed;
return d->m_result; return d->m_result;
} }
d->m_process.closeWriteChannel(); closeWriteChannel();
if (!d->m_process.waitForFinished(d->m_maxHangTimerCount * 1000)) { if (!waitForFinished(d->m_maxHangTimerCount * 1000)) {
d->m_result.result = SynchronousProcessResponse::Hang; d->m_result.result = SynchronousProcessResponse::Hang;
d->m_process.terminate(); terminate();
if (!d->m_process.waitForFinished(1000)) { if (!waitForFinished(1000)) {
d->m_process.kill(); kill();
d->m_process.waitForFinished(1000); waitForFinished(1000);
} }
} }
if (d->m_process.state() != QProcess::NotRunning) if (state() != QProcess::NotRunning)
return d->m_result; return d->m_result;
d->m_result.exitCode = d->m_process.exitCode(); d->m_result.exitCode = exitCode();
if (d->m_result.result == SynchronousProcessResponse::StartFailed) { if (d->m_result.result == SynchronousProcessResponse::StartFailed) {
if (d->m_process.exitStatus() != QProcess::NormalExit) if (exitStatus() != QProcess::NormalExit)
d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally; d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
else else
d->m_result.result = (exitCodeInterpreter())(d->m_result.exitCode); d->m_result.result = d->m_exitCodeInterpreter(d->m_result.exitCode);
} }
processStdOut(false); processStdOut(false);
processStdErr(false); processStdErr(false);
@@ -2327,11 +2269,6 @@ void SynchronousProcess::setStdErrCallback(const std::function<void (const QStri
d->m_stdErr.outputCallback = callback; d->m_stdErr.outputCallback = callback;
} }
bool SynchronousProcess::stopProcess()
{
return d->m_process.stopProcess();
}
void SynchronousProcess::slotTimeout() void SynchronousProcess::slotTimeout()
{ {
if (!d->m_waitingForUser && (++d->m_hangTimerCount > d->m_maxHangTimerCount)) { if (!d->m_waitingForUser && (++d->m_hangTimerCount > d->m_maxHangTimerCount)) {
@@ -2341,7 +2278,7 @@ void SynchronousProcess::slotTimeout()
const bool terminate = !d->m_timeOutMessageBoxEnabled || askToKill(d->m_binary.toString()); const bool terminate = !d->m_timeOutMessageBoxEnabled || askToKill(d->m_binary.toString());
d->m_waitingForUser = false; d->m_waitingForUser = false;
if (terminate) { if (terminate) {
d->m_process.stopProcess(); stopProcess();
d->m_result.result = SynchronousProcessResponse::Hang; d->m_result.result = SynchronousProcessResponse::Hang;
} else { } else {
d->m_hangTimerCount = 0; d->m_hangTimerCount = 0;
@@ -2352,7 +2289,7 @@ void SynchronousProcess::slotTimeout()
} }
} }
void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e) void SynchronousProcess::slotFinished(int exitCode, QProcess::ExitStatus e)
{ {
if (debug) if (debug)
qDebug() << Q_FUNC_INFO << exitCode << e; qDebug() << Q_FUNC_INFO << exitCode << e;
@@ -2388,13 +2325,13 @@ void SynchronousProcess::error(QProcess::ProcessError e)
void SynchronousProcess::processStdOut(bool emitSignals) void SynchronousProcess::processStdOut(bool emitSignals)
{ {
// Handle binary data // Handle binary data
d->m_stdOut.append(d->m_process.readAllStandardOutput(), emitSignals); d->m_stdOut.append(readAllStandardOutput(), emitSignals);
} }
void SynchronousProcess::processStdErr(bool emitSignals) void SynchronousProcess::processStdErr(bool emitSignals)
{ {
// Handle binary data // Handle binary data
d->m_stdErr.append(d->m_process.readAllStandardError(), emitSignals); d->m_stdErr.append(readAllStandardError(), emitSignals);
} }
} // namespace Utils } // namespace Utils

View File

@@ -230,7 +230,7 @@ QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessRes
using ExitCodeInterpreter = std::function<SynchronousProcessResponse::Result(int /*exitCode*/)>; using ExitCodeInterpreter = std::function<SynchronousProcessResponse::Result(int /*exitCode*/)>;
QTCREATOR_UTILS_EXPORT SynchronousProcessResponse::Result defaultExitCodeInterpreter(int code); QTCREATOR_UTILS_EXPORT SynchronousProcessResponse::Result defaultExitCodeInterpreter(int code);
class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QObject class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QtcProcess
{ {
Q_OBJECT Q_OBJECT
public: public:
@@ -240,28 +240,10 @@ public:
/* Timeout for hanging processes (triggers after no more output /* Timeout for hanging processes (triggers after no more output
* occurs on stderr/stdout). */ * occurs on stderr/stdout). */
void setTimeoutS(int timeoutS); void setTimeoutS(int timeoutS);
int timeoutS() const;
void setCodec(QTextCodec *c); void setCodec(QTextCodec *c);
QTextCodec *codec() const;
QProcess::ProcessChannelMode processChannelMode () const;
void setProcessChannelMode(QProcess::ProcessChannelMode m);
bool timeOutMessageBoxEnabled() const;
void setTimeOutMessageBoxEnabled(bool); void setTimeOutMessageBoxEnabled(bool);
Environment environment() const;
void setEnvironment(const Environment &);
void setWorkingDirectory(const QString &workingDirectory);
QString workingDirectory() const;
// Unix: Do not give the child process a terminal for input prompting.
void setDisableUnixTerminal();
void setExitCodeInterpreter(const ExitCodeInterpreter &interpreter); void setExitCodeInterpreter(const ExitCodeInterpreter &interpreter);
ExitCodeInterpreter exitCodeInterpreter() const;
// Starts a nested event loop and runs the command // Starts a nested event loop and runs the command
SynchronousProcessResponse run(const CommandLine &cmd, const QByteArray &writeData = {}); SynchronousProcessResponse run(const CommandLine &cmd, const QByteArray &writeData = {});
@@ -271,11 +253,9 @@ public:
void setStdOutCallback(const std::function<void(const QString &)> &callback); void setStdOutCallback(const std::function<void(const QString &)> &callback);
void setStdErrCallback(const std::function<void(const QString &)> &callback); void setStdErrCallback(const std::function<void(const QString &)> &callback);
bool stopProcess();
private: private:
void slotTimeout(); void slotTimeout();
void finished(int exitCode, QProcess::ExitStatus e); void slotFinished(int exitCode, QProcess::ExitStatus e);
void error(QProcess::ProcessError); void error(QProcess::ProcessError);
void processStdOut(bool emitSignals); void processStdOut(bool emitSignals);
void processStdErr(bool emitSignals); void processStdErr(bool emitSignals);