Utils: Shift more code from SynchronousProcess to QtcProcess

Copy for now, original will vanish once all is ported.

Idea is still to reduce the number of process related classes.

To avoid a new dependency for qmlpuppet, handle questions to
the user only inside #ifdef.

Change-Id: Ib1354fc0370a87052b4f9c8460dfcf5d762a6c4e
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2021-04-30 12:31:36 +02:00
parent f3e4c7112b
commit ecc5c042ab
2 changed files with 80 additions and 1 deletions

View File

@@ -29,11 +29,18 @@
#include <utils/qtcassert.h>
#include <utils/hostosinfo.h>
#include <QCoreApplication>
#include <QDir>
#include <QDebug>
#include <QCoreApplication>
#include <QRegularExpression>
#include <QStack>
#include <QThread>
#ifdef QT_GUI_LIB
// qmlpuppet does not use that.
#include <QApplication>
#include <QMessageBox>
#endif
#ifdef Q_OS_WIN
#define CALLBACK WINAPI
@@ -1292,6 +1299,76 @@ bool QtcProcess::stopProcess()
return waitForFinished(300);
}
static bool askToKill(const QString &command)
{
#ifdef QT_GUI_LIB
if (QThread::currentThread() != QCoreApplication::instance()->thread())
return true;
const QString title = QtcProcess::tr("Process not Responding");
QString msg = command.isEmpty() ?
QtcProcess::tr("The process is not responding.") :
QtcProcess::tr("The process \"%1\" is not responding.").arg(command);
msg += ' ';
msg += QtcProcess::tr("Would you like to terminate it?");
// Restore the cursor that is set to wait while running.
const bool hasOverrideCursor = QApplication::overrideCursor() != nullptr;
if (hasOverrideCursor)
QApplication::restoreOverrideCursor();
QMessageBox::StandardButton answer = QMessageBox::question(nullptr, title, msg, QMessageBox::Yes|QMessageBox::No);
if (hasOverrideCursor)
QApplication::setOverrideCursor(Qt::WaitCursor);
return answer == QMessageBox::Yes;
#else
Q_UNUSED(command)
return true;
#endif
}
bool QtcProcess::readDataFromProcess(int timeoutS,
QByteArray *stdOut,
QByteArray *stdErr,
bool showTimeOutMessageBox)
{
enum { syncDebug = 0 };
if (syncDebug)
qDebug() << ">readDataFromProcess" << timeoutS;
if (state() != QProcess::Running) {
qWarning("readDataFromProcess: Process in non-running state passed in.");
return false;
}
QTC_ASSERT(readChannel() == QProcess::StandardOutput, return false);
// Keep the process running until it has no longer has data
bool finished = false;
bool hasData = false;
do {
finished = waitForFinished(timeoutS > 0 ? timeoutS * 1000 : -1)
|| state() == QProcess::NotRunning;
// First check 'stdout'
if (bytesAvailable()) { // applies to readChannel() only
hasData = true;
const QByteArray newStdOut = readAllStandardOutput();
if (stdOut)
stdOut->append(newStdOut);
}
// Check 'stderr' separately. This is a special handling
// for 'git pull' and the like which prints its progress on stderr.
const QByteArray newStdErr = readAllStandardError();
if (!newStdErr.isEmpty()) {
hasData = true;
if (stdErr)
stdErr->append(newStdErr);
}
// Prompt user, pretend we have data if says 'No'.
const bool hang = !hasData && !finished;
hasData = hang && showTimeOutMessageBox && !askToKill(program());
} while (hasData && !finished);
if (syncDebug)
qDebug() << "<readDataFromProcess" << finished;
return finished;
}
bool QtcProcess::ArgIterator::next()
{
// We delay the setting of m_prev so we can still delete the last argument