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();
QTextCodec *m_codec = QTextCodec::codecForLocale();
QtcProcess m_process;
QTimer m_timer;
QEventLoop m_eventLoop;
SynchronousProcessResponse m_result;
@@ -2072,25 +2071,23 @@ SynchronousProcess::SynchronousProcess() :
{
d->m_timer.setInterval(1000);
connect(&d->m_timer, &QTimer::timeout, this, &SynchronousProcess::slotTimeout);
connect(&d->m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &SynchronousProcess::finished);
connect(&d->m_process, &QProcess::errorOccurred, this, &SynchronousProcess::error);
connect(&d->m_process, &QProcess::readyReadStandardOutput,
this, [this]() {
d->m_hangTimerCount = 0;
processStdOut(true);
});
connect(&d->m_process, &QProcess::readyReadStandardError,
this, [this]() {
d->m_hangTimerCount = 0;
processStdErr(true);
});
connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &SynchronousProcess::slotFinished);
connect(this, &QProcess::errorOccurred, this, &SynchronousProcess::error);
connect(this, &QProcess::readyReadStandardOutput, this, [this] {
d->m_hangTimerCount = 0;
processStdOut(true);
});
connect(this, &QProcess::readyReadStandardError, this, [this] {
d->m_hangTimerCount = 0;
processStdErr(true);
});
}
SynchronousProcess::~SynchronousProcess()
{
disconnect(&d->m_timer, nullptr, this, nullptr);
disconnect(&d->m_process, nullptr, this, nullptr);
disconnect(this, nullptr, this, nullptr);
delete d;
}
@@ -2102,78 +2099,23 @@ void SynchronousProcess::setTimeoutS(int timeoutS)
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)
{
QTC_ASSERT(c, return);
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)
{
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)
{
QTC_ASSERT(interpreter, return);
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
static bool isGuiThread()
{
@@ -2187,8 +2129,8 @@ SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
// FIXME: Implement properly
if (cmd.executable().needsDevice()) {
QtcProcess proc;
proc.setEnvironment(Environment(d->m_process.environment()));
proc.setWorkingDirectory(d->m_process.workingDirectory());
proc.setEnvironment(Environment(environment()));
proc.setWorkingDirectory(workingDirectory());
proc.setCommand(cmd);
// writeData ?
@@ -2215,15 +2157,15 @@ SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
// using QProcess::start() and passing program, args and OpenMode results in a different
// quoting of arguments than using QProcess::setArguments() beforehand and calling start()
// only with the OpenMode
d->m_process.setCommand(cmd);
setCommand(cmd);
if (!writeData.isEmpty()) {
connect(&d->m_process, &QProcess::started, this, [this, writeData] {
d->m_process.write(writeData);
d->m_process.closeWriteChannel();
connect(this, &QProcess::started, this, [this, writeData] {
write(writeData);
closeWriteChannel();
});
}
d->m_process.setOpenMode(writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
d->m_process.start();
setOpenMode(writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
start();
// On Windows, start failure is triggered immediately if 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
if (cmd.executable().needsDevice()) {
QtcProcess proc;
proc.setEnvironment(Environment(d->m_process.environment()));
proc.setWorkingDirectory(d->m_process.workingDirectory());
proc.setEnvironment(Environment(environment()));
proc.setWorkingDirectory(workingDirectory());
proc.setCommand(cmd);
// writeData ?
@@ -2281,32 +2223,32 @@ SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cm
d->clearForRun();
d->m_binary = cmd.executable();
d->m_process.setOpenMode(QIODevice::ReadOnly);
d->m_process.setCommand(cmd);
d->m_process.start();
if (!d->m_process.waitForStarted(d->m_maxHangTimerCount * 1000)) {
setOpenMode(QIODevice::ReadOnly);
setCommand(cmd);
start();
if (!waitForStarted(d->m_maxHangTimerCount * 1000)) {
d->m_result.result = SynchronousProcessResponse::StartFailed;
return d->m_result;
}
d->m_process.closeWriteChannel();
if (!d->m_process.waitForFinished(d->m_maxHangTimerCount * 1000)) {
closeWriteChannel();
if (!waitForFinished(d->m_maxHangTimerCount * 1000)) {
d->m_result.result = SynchronousProcessResponse::Hang;
d->m_process.terminate();
if (!d->m_process.waitForFinished(1000)) {
d->m_process.kill();
d->m_process.waitForFinished(1000);
terminate();
if (!waitForFinished(1000)) {
kill();
waitForFinished(1000);
}
}
if (d->m_process.state() != QProcess::NotRunning)
if (state() != QProcess::NotRunning)
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_process.exitStatus() != QProcess::NormalExit)
if (exitStatus() != QProcess::NormalExit)
d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
else
d->m_result.result = (exitCodeInterpreter())(d->m_result.exitCode);
d->m_result.result = d->m_exitCodeInterpreter(d->m_result.exitCode);
}
processStdOut(false);
processStdErr(false);
@@ -2327,11 +2269,6 @@ void SynchronousProcess::setStdErrCallback(const std::function<void (const QStri
d->m_stdErr.outputCallback = callback;
}
bool SynchronousProcess::stopProcess()
{
return d->m_process.stopProcess();
}
void SynchronousProcess::slotTimeout()
{
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());
d->m_waitingForUser = false;
if (terminate) {
d->m_process.stopProcess();
stopProcess();
d->m_result.result = SynchronousProcessResponse::Hang;
} else {
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)
qDebug() << Q_FUNC_INFO << exitCode << e;
@@ -2388,13 +2325,13 @@ void SynchronousProcess::error(QProcess::ProcessError e)
void SynchronousProcess::processStdOut(bool emitSignals)
{
// Handle binary data
d->m_stdOut.append(d->m_process.readAllStandardOutput(), emitSignals);
d->m_stdOut.append(readAllStandardOutput(), emitSignals);
}
void SynchronousProcess::processStdErr(bool emitSignals)
{
// Handle binary data
d->m_stdErr.append(d->m_process.readAllStandardError(), emitSignals);
d->m_stdErr.append(readAllStandardError(), emitSignals);
}
} // 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*/)>;
QTCREATOR_UTILS_EXPORT SynchronousProcessResponse::Result defaultExitCodeInterpreter(int code);
class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QObject
class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QtcProcess
{
Q_OBJECT
public:
@@ -240,28 +240,10 @@ public:
/* Timeout for hanging processes (triggers after no more output
* occurs on stderr/stdout). */
void setTimeoutS(int timeoutS);
int timeoutS() const;
void setCodec(QTextCodec *c);
QTextCodec *codec() const;
QProcess::ProcessChannelMode processChannelMode () const;
void setProcessChannelMode(QProcess::ProcessChannelMode m);
bool timeOutMessageBoxEnabled() const;
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);
ExitCodeInterpreter exitCodeInterpreter() const;
// Starts a nested event loop and runs the command
SynchronousProcessResponse run(const CommandLine &cmd, const QByteArray &writeData = {});
@@ -271,11 +253,9 @@ public:
void setStdOutCallback(const std::function<void(const QString &)> &callback);
void setStdErrCallback(const std::function<void(const QString &)> &callback);
bool stopProcess();
private:
void slotTimeout();
void finished(int exitCode, QProcess::ExitStatus e);
void slotFinished(int exitCode, QProcess::ExitStatus e);
void error(QProcess::ProcessError);
void processStdOut(bool emitSignals);
void processStdErr(bool emitSignals);