forked from qt-creator/qt-creator
Utils: Move most of SynchronousProcess to QtcProcess
Merge the pimpls, move the remaining functions to the base. This leaves SynchronousProcess as a QtcProcess with an internal special setup. Plan is still to unify this completely. Change-Id: Ie95d35ace23a1b7e078174ea37b9fd70a3ebe178 Reviewed-by: Christian Stenger <christian.stenger@qt.io> Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
@@ -89,6 +89,13 @@ using namespace Utils::Internal;
|
|||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
|
enum { debug = 0 };
|
||||||
|
enum { syncDebug = 0 };
|
||||||
|
|
||||||
|
enum { defaultMaxHangTimerCount = 10 };
|
||||||
|
|
||||||
|
static Q_LOGGING_CATEGORY(processLog, "qtc.utils.synchronousprocess", QtWarningMsg);
|
||||||
|
|
||||||
static std::function<void(QtcProcess &)> s_remoteRunProcessHook;
|
static std::function<void(QtcProcess &)> s_remoteRunProcessHook;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -700,9 +707,28 @@ bool QtcProcess::prepareCommand(const QString &command, const QString &arguments
|
|||||||
|
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
class QtcProcessPrivate
|
// Data for one channel buffer (stderr/stdout)
|
||||||
|
class ChannelBuffer : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
void clearForRun();
|
||||||
|
|
||||||
|
QString linesRead();
|
||||||
|
void append(const QByteArray &text, bool emitSignals);
|
||||||
|
|
||||||
|
QByteArray rawData;
|
||||||
|
QString incompleteLineBuffer; // lines not yet signaled
|
||||||
|
QTextCodec *codec = nullptr; // Not owner
|
||||||
|
std::unique_ptr<QTextCodec::ConverterState> codecState;
|
||||||
|
int rawDataPos = 0;
|
||||||
|
std::function<void(const QString &lines)> outputCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
class QtcProcessPrivate : public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit QtcProcessPrivate(QtcProcess *parent) : q(parent) {}
|
||||||
|
|
||||||
void setupChildProcess_impl();
|
void setupChildProcess_impl();
|
||||||
|
|
||||||
CommandLine m_commandLine;
|
CommandLine m_commandLine;
|
||||||
@@ -714,12 +740,49 @@ public:
|
|||||||
|
|
||||||
bool m_synchronous = false;
|
bool m_synchronous = false;
|
||||||
QProcess::OpenMode m_openMode = QProcess::ReadWrite;
|
QProcess::OpenMode m_openMode = QProcess::ReadWrite;
|
||||||
|
|
||||||
|
// SynchronousProcess left overs:
|
||||||
|
void slotTimeout();
|
||||||
|
void slotFinished(int exitCode, QProcess::ExitStatus e);
|
||||||
|
void slotError(QProcess::ProcessError);
|
||||||
|
void processStdOut(bool emitSignals);
|
||||||
|
void processStdErr(bool emitSignals);
|
||||||
|
void clearForRun();
|
||||||
|
|
||||||
|
QtcProcess *q;
|
||||||
|
QTextCodec *m_codec = QTextCodec::codecForLocale();
|
||||||
|
QTimer m_timer;
|
||||||
|
QEventLoop m_eventLoop;
|
||||||
|
SynchronousProcessResponse m_result;
|
||||||
|
FilePath m_binary;
|
||||||
|
ChannelBuffer m_stdOut;
|
||||||
|
ChannelBuffer m_stdErr;
|
||||||
|
ExitCodeInterpreter m_exitCodeInterpreter = defaultExitCodeInterpreter;
|
||||||
|
|
||||||
|
int m_hangTimerCount = 0;
|
||||||
|
int m_maxHangTimerCount = defaultMaxHangTimerCount;
|
||||||
|
bool m_startFailure = false;
|
||||||
|
bool m_timeOutMessageBoxEnabled = false;
|
||||||
|
bool m_waitingForUser = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void QtcProcessPrivate::clearForRun()
|
||||||
|
{
|
||||||
|
m_hangTimerCount = 0;
|
||||||
|
m_stdOut.clearForRun();
|
||||||
|
m_stdOut.codec = m_codec;
|
||||||
|
m_stdErr.clearForRun();
|
||||||
|
m_stdErr.codec = m_codec;
|
||||||
|
m_result.clear();
|
||||||
|
m_result.codec = m_codec;
|
||||||
|
m_startFailure = false;
|
||||||
|
m_binary = {};
|
||||||
|
}
|
||||||
|
|
||||||
} // Internal
|
} // Internal
|
||||||
|
|
||||||
QtcProcess::QtcProcess(QObject *parent)
|
QtcProcess::QtcProcess(QObject *parent)
|
||||||
: QProcess(parent), d(new QtcProcessPrivate)
|
: QProcess(parent), d(new QtcProcessPrivate(this))
|
||||||
{
|
{
|
||||||
static int qProcessExitStatusMeta = qRegisterMetaType<QProcess::ExitStatus>();
|
static int qProcessExitStatusMeta = qRegisterMetaType<QProcess::ExitStatus>();
|
||||||
static int qProcessProcessErrorMeta = qRegisterMetaType<QProcess::ProcessError>();
|
static int qProcessProcessErrorMeta = qRegisterMetaType<QProcess::ProcessError>();
|
||||||
@@ -1882,13 +1945,6 @@ QString QtcProcess::locateBinary(const QString &binary)
|
|||||||
as this will cause event loop problems.
|
as this will cause event loop problems.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum { debug = 0 };
|
|
||||||
enum { syncDebug = 0 };
|
|
||||||
|
|
||||||
enum { defaultMaxHangTimerCount = 10 };
|
|
||||||
|
|
||||||
static Q_LOGGING_CATEGORY(processLog, "qtc.utils.synchronousprocess", QtWarningMsg);
|
|
||||||
|
|
||||||
// ----------- SynchronousProcessResponse
|
// ----------- SynchronousProcessResponse
|
||||||
void SynchronousProcessResponse::clear()
|
void SynchronousProcessResponse::clear()
|
||||||
{
|
{
|
||||||
@@ -1902,15 +1958,15 @@ QString SynchronousProcessResponse::exitMessage(const QString &binary, int timeo
|
|||||||
{
|
{
|
||||||
switch (result) {
|
switch (result) {
|
||||||
case Finished:
|
case Finished:
|
||||||
return SynchronousProcess::tr("The command \"%1\" finished successfully.").arg(QDir::toNativeSeparators(binary));
|
return QtcProcess::tr("The command \"%1\" finished successfully.").arg(QDir::toNativeSeparators(binary));
|
||||||
case FinishedError:
|
case FinishedError:
|
||||||
return SynchronousProcess::tr("The command \"%1\" terminated with exit code %2.").arg(QDir::toNativeSeparators(binary)).arg(exitCode);
|
return QtcProcess::tr("The command \"%1\" terminated with exit code %2.").arg(QDir::toNativeSeparators(binary)).arg(exitCode);
|
||||||
case TerminatedAbnormally:
|
case TerminatedAbnormally:
|
||||||
return SynchronousProcess::tr("The command \"%1\" terminated abnormally.").arg(QDir::toNativeSeparators(binary));
|
return QtcProcess::tr("The command \"%1\" terminated abnormally.").arg(QDir::toNativeSeparators(binary));
|
||||||
case StartFailed:
|
case StartFailed:
|
||||||
return SynchronousProcess::tr("The command \"%1\" could not be started.").arg(QDir::toNativeSeparators(binary));
|
return QtcProcess::tr("The command \"%1\" could not be started.").arg(QDir::toNativeSeparators(binary));
|
||||||
case Hang:
|
case Hang:
|
||||||
return SynchronousProcess::tr("The command \"%1\" did not respond within the timeout limit (%2 s).")
|
return QtcProcess::tr("The command \"%1\" did not respond within the timeout limit (%2 s).")
|
||||||
.arg(QDir::toNativeSeparators(binary)).arg(timeoutS);
|
.arg(QDir::toNativeSeparators(binary)).arg(timeoutS);
|
||||||
}
|
}
|
||||||
return QString();
|
return QString();
|
||||||
@@ -1967,23 +2023,6 @@ SynchronousProcessResponse::Result defaultExitCodeInterpreter(int code)
|
|||||||
: SynchronousProcessResponse::Finished;
|
: SynchronousProcessResponse::Finished;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Data for one channel buffer (stderr/stdout)
|
|
||||||
class ChannelBuffer : public QObject
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
void clearForRun();
|
|
||||||
|
|
||||||
QString linesRead();
|
|
||||||
void append(const QByteArray &text, bool emitSignals);
|
|
||||||
|
|
||||||
QByteArray rawData;
|
|
||||||
QString incompleteLineBuffer; // lines not yet signaled
|
|
||||||
QTextCodec *codec = nullptr; // Not owner
|
|
||||||
std::unique_ptr<QTextCodec::ConverterState> codecState;
|
|
||||||
int rawDataPos = 0;
|
|
||||||
std::function<void(const QString &lines)> outputCallback;
|
|
||||||
};
|
|
||||||
|
|
||||||
void ChannelBuffer::clearForRun()
|
void ChannelBuffer::clearForRun()
|
||||||
{
|
{
|
||||||
rawDataPos = 0;
|
rawDataPos = 0;
|
||||||
@@ -2031,56 +2070,22 @@ void ChannelBuffer::append(const QByteArray &text, bool emitSignals)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------- SynchronousProcessPrivate
|
|
||||||
class SynchronousProcessPrivate {
|
|
||||||
public:
|
|
||||||
void clearForRun();
|
|
||||||
|
|
||||||
QTextCodec *m_codec = QTextCodec::codecForLocale();
|
|
||||||
QTimer m_timer;
|
|
||||||
QEventLoop m_eventLoop;
|
|
||||||
SynchronousProcessResponse m_result;
|
|
||||||
FilePath m_binary;
|
|
||||||
ChannelBuffer m_stdOut;
|
|
||||||
ChannelBuffer m_stdErr;
|
|
||||||
ExitCodeInterpreter m_exitCodeInterpreter = defaultExitCodeInterpreter;
|
|
||||||
|
|
||||||
int m_hangTimerCount = 0;
|
|
||||||
int m_maxHangTimerCount = defaultMaxHangTimerCount;
|
|
||||||
bool m_startFailure = false;
|
|
||||||
bool m_timeOutMessageBoxEnabled = false;
|
|
||||||
bool m_waitingForUser = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
void SynchronousProcessPrivate::clearForRun()
|
|
||||||
{
|
|
||||||
m_hangTimerCount = 0;
|
|
||||||
m_stdOut.clearForRun();
|
|
||||||
m_stdOut.codec = m_codec;
|
|
||||||
m_stdErr.clearForRun();
|
|
||||||
m_stdErr.codec = m_codec;
|
|
||||||
m_result.clear();
|
|
||||||
m_result.codec = m_codec;
|
|
||||||
m_startFailure = false;
|
|
||||||
m_binary = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------- SynchronousProcess
|
// ----------- SynchronousProcess
|
||||||
SynchronousProcess::SynchronousProcess() :
|
SynchronousProcess::SynchronousProcess()
|
||||||
d(new SynchronousProcessPrivate)
|
|
||||||
{
|
{
|
||||||
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, d, &QtcProcessPrivate::slotTimeout);
|
||||||
connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
connect(this, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||||
this, &SynchronousProcess::slotFinished);
|
d, &QtcProcessPrivate::slotFinished);
|
||||||
connect(this, &QProcess::errorOccurred, this, &SynchronousProcess::error);
|
connect(this, &QProcess::errorOccurred, d, &QtcProcessPrivate::slotError);
|
||||||
connect(this, &QProcess::readyReadStandardOutput, this, [this] {
|
connect(this, &QProcess::readyReadStandardOutput, d, [this] {
|
||||||
d->m_hangTimerCount = 0;
|
d->m_hangTimerCount = 0;
|
||||||
processStdOut(true);
|
d->processStdOut(true);
|
||||||
});
|
});
|
||||||
connect(this, &QProcess::readyReadStandardError, this, [this] {
|
connect(this, &QProcess::readyReadStandardError, d, [this] {
|
||||||
d->m_hangTimerCount = 0;
|
d->m_hangTimerCount = 0;
|
||||||
processStdErr(true);
|
d->processStdErr(true);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2088,10 +2093,9 @@ SynchronousProcess::~SynchronousProcess()
|
|||||||
{
|
{
|
||||||
disconnect(&d->m_timer, nullptr, this, nullptr);
|
disconnect(&d->m_timer, nullptr, this, nullptr);
|
||||||
disconnect(this, nullptr, this, nullptr);
|
disconnect(this, nullptr, this, nullptr);
|
||||||
delete d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::setTimeoutS(int timeoutS)
|
void QtcProcess::setTimeoutS(int timeoutS)
|
||||||
{
|
{
|
||||||
if (timeoutS > 0)
|
if (timeoutS > 0)
|
||||||
d->m_maxHangTimerCount = qMax(2, timeoutS);
|
d->m_maxHangTimerCount = qMax(2, timeoutS);
|
||||||
@@ -2099,18 +2103,18 @@ void SynchronousProcess::setTimeoutS(int timeoutS)
|
|||||||
d->m_maxHangTimerCount = INT_MAX / 1000;
|
d->m_maxHangTimerCount = INT_MAX / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::setCodec(QTextCodec *c)
|
void QtcProcess::setCodec(QTextCodec *c)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(c, return);
|
QTC_ASSERT(c, return);
|
||||||
d->m_codec = c;
|
d->m_codec = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::setTimeOutMessageBoxEnabled(bool v)
|
void QtcProcess::setTimeOutMessageBoxEnabled(bool v)
|
||||||
{
|
{
|
||||||
d->m_timeOutMessageBoxEnabled = v;
|
d->m_timeOutMessageBoxEnabled = v;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter)
|
void QtcProcess::setExitCodeInterpreter(const ExitCodeInterpreter &interpreter)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(interpreter, return);
|
QTC_ASSERT(interpreter, return);
|
||||||
d->m_exitCodeInterpreter = interpreter;
|
d->m_exitCodeInterpreter = interpreter;
|
||||||
@@ -2123,8 +2127,7 @@ static bool isGuiThread()
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
|
SynchronousProcessResponse QtcProcess::run(const CommandLine &cmd, const QByteArray &writeData)
|
||||||
const QByteArray &writeData)
|
|
||||||
{
|
{
|
||||||
// FIXME: Implement properly
|
// FIXME: Implement properly
|
||||||
if (cmd.executable().needsDevice()) {
|
if (cmd.executable().needsDevice()) {
|
||||||
@@ -2177,8 +2180,8 @@ SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
|
|||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
#endif
|
#endif
|
||||||
d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
|
d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
processStdOut(false);
|
d->processStdOut(false);
|
||||||
processStdErr(false);
|
d->processStdErr(false);
|
||||||
|
|
||||||
d->m_result.rawStdOut = d->m_stdOut.rawData;
|
d->m_result.rawStdOut = d->m_stdOut.rawData;
|
||||||
d->m_result.rawStdErr = d->m_stdErr.rawData;
|
d->m_result.rawStdErr = d->m_stdErr.rawData;
|
||||||
@@ -2193,7 +2196,7 @@ SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
|
|||||||
return d->m_result;
|
return d->m_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cmd)
|
SynchronousProcessResponse QtcProcess::runBlocking(const CommandLine &cmd)
|
||||||
{
|
{
|
||||||
// FIXME: Implement properly
|
// FIXME: Implement properly
|
||||||
if (cmd.executable().needsDevice()) {
|
if (cmd.executable().needsDevice()) {
|
||||||
@@ -2250,8 +2253,8 @@ SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cm
|
|||||||
else
|
else
|
||||||
d->m_result.result = d->m_exitCodeInterpreter(d->m_result.exitCode);
|
d->m_result.result = d->m_exitCodeInterpreter(d->m_result.exitCode);
|
||||||
}
|
}
|
||||||
processStdOut(false);
|
d->processStdOut(false);
|
||||||
processStdErr(false);
|
d->processStdErr(false);
|
||||||
|
|
||||||
d->m_result.rawStdOut = d->m_stdOut.rawData;
|
d->m_result.rawStdOut = d->m_stdOut.rawData;
|
||||||
d->m_result.rawStdErr = d->m_stdErr.rawData;
|
d->m_result.rawStdErr = d->m_stdErr.rawData;
|
||||||
@@ -2259,79 +2262,79 @@ SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cm
|
|||||||
return d->m_result;
|
return d->m_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::setStdOutCallback(const std::function<void (const QString &)> &callback)
|
void QtcProcess::setStdOutCallback(const std::function<void (const QString &)> &callback)
|
||||||
{
|
{
|
||||||
d->m_stdOut.outputCallback = callback;
|
d->m_stdOut.outputCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::setStdErrCallback(const std::function<void (const QString &)> &callback)
|
void QtcProcess::setStdErrCallback(const std::function<void (const QString &)> &callback)
|
||||||
{
|
{
|
||||||
d->m_stdErr.outputCallback = callback;
|
d->m_stdErr.outputCallback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::slotTimeout()
|
void QtcProcessPrivate::slotTimeout()
|
||||||
{
|
{
|
||||||
if (!d->m_waitingForUser && (++d->m_hangTimerCount > d->m_maxHangTimerCount)) {
|
if (!m_waitingForUser && (++m_hangTimerCount > m_maxHangTimerCount)) {
|
||||||
if (debug)
|
if (debug)
|
||||||
qDebug() << Q_FUNC_INFO << "HANG detected, killing";
|
qDebug() << Q_FUNC_INFO << "HANG detected, killing";
|
||||||
d->m_waitingForUser = true;
|
m_waitingForUser = true;
|
||||||
const bool terminate = !d->m_timeOutMessageBoxEnabled || askToKill(d->m_binary.toString());
|
const bool terminate = !m_timeOutMessageBoxEnabled || askToKill(m_binary.toString());
|
||||||
d->m_waitingForUser = false;
|
m_waitingForUser = false;
|
||||||
if (terminate) {
|
if (terminate) {
|
||||||
stopProcess();
|
q->stopProcess();
|
||||||
d->m_result.result = SynchronousProcessResponse::Hang;
|
m_result.result = SynchronousProcessResponse::Hang;
|
||||||
} else {
|
} else {
|
||||||
d->m_hangTimerCount = 0;
|
m_hangTimerCount = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (debug)
|
if (debug)
|
||||||
qDebug() << Q_FUNC_INFO << d->m_hangTimerCount;
|
qDebug() << Q_FUNC_INFO << m_hangTimerCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::slotFinished(int exitCode, QProcess::ExitStatus e)
|
void QtcProcessPrivate::slotFinished(int exitCode, QProcess::ExitStatus e)
|
||||||
{
|
{
|
||||||
if (debug)
|
if (debug)
|
||||||
qDebug() << Q_FUNC_INFO << exitCode << e;
|
qDebug() << Q_FUNC_INFO << exitCode << e;
|
||||||
d->m_hangTimerCount = 0;
|
m_hangTimerCount = 0;
|
||||||
|
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case QProcess::NormalExit:
|
case QProcess::NormalExit:
|
||||||
d->m_result.result = d->m_exitCodeInterpreter(exitCode);
|
m_result.result = m_exitCodeInterpreter(exitCode);
|
||||||
d->m_result.exitCode = exitCode;
|
m_result.exitCode = exitCode;
|
||||||
break;
|
break;
|
||||||
case QProcess::CrashExit:
|
case QProcess::CrashExit:
|
||||||
// Was hang detected before and killed?
|
// Was hang detected before and killed?
|
||||||
if (d->m_result.result != SynchronousProcessResponse::Hang)
|
if (m_result.result != SynchronousProcessResponse::Hang)
|
||||||
d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
|
m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
|
||||||
d->m_result.exitCode = -1;
|
m_result.exitCode = -1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
d->m_eventLoop.quit();
|
m_eventLoop.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::error(QProcess::ProcessError e)
|
void QtcProcessPrivate::slotError(QProcess::ProcessError e)
|
||||||
{
|
{
|
||||||
d->m_hangTimerCount = 0;
|
m_hangTimerCount = 0;
|
||||||
if (debug)
|
if (debug)
|
||||||
qDebug() << Q_FUNC_INFO << e;
|
qDebug() << Q_FUNC_INFO << e;
|
||||||
// Was hang detected before and killed?
|
// Was hang detected before and killed?
|
||||||
if (d->m_result.result != SynchronousProcessResponse::Hang)
|
if (m_result.result != SynchronousProcessResponse::Hang)
|
||||||
d->m_result.result = SynchronousProcessResponse::StartFailed;
|
m_result.result = SynchronousProcessResponse::StartFailed;
|
||||||
d->m_startFailure = true;
|
m_startFailure = true;
|
||||||
d->m_eventLoop.quit();
|
m_eventLoop.quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::processStdOut(bool emitSignals)
|
void QtcProcessPrivate::processStdOut(bool emitSignals)
|
||||||
{
|
{
|
||||||
// Handle binary data
|
// Handle binary data
|
||||||
d->m_stdOut.append(readAllStandardOutput(), emitSignals);
|
m_stdOut.append(q->readAllStandardOutput(), emitSignals);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SynchronousProcess::processStdErr(bool emitSignals)
|
void QtcProcessPrivate::processStdErr(bool emitSignals)
|
||||||
{
|
{
|
||||||
// Handle binary data
|
// Handle binary data
|
||||||
d->m_stdErr.append(readAllStandardError(), emitSignals);
|
m_stdErr.append(q->readAllStandardError(), emitSignals);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
@@ -39,12 +39,11 @@ QT_FORWARD_DECLARE_CLASS(QDebug)
|
|||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
class AbstractMacroExpander;
|
class AbstractMacroExpander;
|
||||||
|
|
||||||
namespace Internal { class QtcProcessPrivate; }
|
|
||||||
class SynchronousProcessPrivate;
|
|
||||||
class CommandLine;
|
class CommandLine;
|
||||||
class Environment;
|
class Environment;
|
||||||
|
|
||||||
|
namespace Internal { class QtcProcessPrivate; }
|
||||||
|
|
||||||
/* Result of SynchronousProcess execution */
|
/* Result of SynchronousProcess execution */
|
||||||
class QTCREATOR_UTILS_EXPORT SynchronousProcessResponse
|
class QTCREATOR_UTILS_EXPORT SynchronousProcessResponse
|
||||||
{
|
{
|
||||||
@@ -80,6 +79,7 @@ public:
|
|||||||
QTextCodec *codec = QTextCodec::codecForLocale();
|
QTextCodec *codec = QTextCodec::codecForLocale();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using ExitCodeInterpreter = std::function<SynchronousProcessResponse::Result(int /*exitCode*/)>;
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT QtcProcess : public QProcess
|
class QTCREATOR_UTILS_EXPORT QtcProcess : public QProcess
|
||||||
{
|
{
|
||||||
@@ -103,6 +103,22 @@ public:
|
|||||||
void terminate();
|
void terminate();
|
||||||
void interrupt();
|
void interrupt();
|
||||||
|
|
||||||
|
/* Timeout for hanging processes (triggers after no more output
|
||||||
|
* occurs on stderr/stdout). */
|
||||||
|
void setTimeoutS(int timeoutS);
|
||||||
|
|
||||||
|
void setCodec(QTextCodec *c);
|
||||||
|
void setTimeOutMessageBoxEnabled(bool);
|
||||||
|
void setExitCodeInterpreter(const ExitCodeInterpreter &interpreter);
|
||||||
|
|
||||||
|
// Starts a nested event loop and runs the command
|
||||||
|
SynchronousProcessResponse run(const CommandLine &cmd, const QByteArray &writeData = {});
|
||||||
|
// Starts the command blocking the UI fully
|
||||||
|
SynchronousProcessResponse runBlocking(const CommandLine &cmd);
|
||||||
|
|
||||||
|
void setStdOutCallback(const std::function<void(const QString &)> &callback);
|
||||||
|
void setStdErrCallback(const std::function<void(const QString &)> &callback);
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT Arguments
|
class QTCREATOR_UTILS_EXPORT Arguments
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -219,6 +235,7 @@ private:
|
|||||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||||
void setupChildProcess() override;
|
void setupChildProcess() override;
|
||||||
#endif
|
#endif
|
||||||
|
friend class SynchronousProcess;
|
||||||
Internal::QtcProcessPrivate *d = nullptr;
|
Internal::QtcProcessPrivate *d = nullptr;
|
||||||
|
|
||||||
void setProcessEnvironment(const QProcessEnvironment &environment) = delete;
|
void setProcessEnvironment(const QProcessEnvironment &environment) = delete;
|
||||||
@@ -227,7 +244,6 @@ private:
|
|||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse &);
|
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse &);
|
||||||
|
|
||||||
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 QtcProcess
|
class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QtcProcess
|
||||||
@@ -236,31 +252,6 @@ class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QtcProcess
|
|||||||
public:
|
public:
|
||||||
SynchronousProcess();
|
SynchronousProcess();
|
||||||
~SynchronousProcess() override;
|
~SynchronousProcess() override;
|
||||||
|
|
||||||
/* Timeout for hanging processes (triggers after no more output
|
|
||||||
* occurs on stderr/stdout). */
|
|
||||||
void setTimeoutS(int timeoutS);
|
|
||||||
|
|
||||||
void setCodec(QTextCodec *c);
|
|
||||||
void setTimeOutMessageBoxEnabled(bool);
|
|
||||||
void setExitCodeInterpreter(const ExitCodeInterpreter &interpreter);
|
|
||||||
|
|
||||||
// Starts a nested event loop and runs the command
|
|
||||||
SynchronousProcessResponse run(const CommandLine &cmd, const QByteArray &writeData = {});
|
|
||||||
// Starts the command blocking the UI fully
|
|
||||||
SynchronousProcessResponse runBlocking(const CommandLine &cmd);
|
|
||||||
|
|
||||||
void setStdOutCallback(const std::function<void(const QString &)> &callback);
|
|
||||||
void setStdErrCallback(const std::function<void(const QString &)> &callback);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void slotTimeout();
|
|
||||||
void slotFinished(int exitCode, QProcess::ExitStatus e);
|
|
||||||
void error(QProcess::ProcessError);
|
|
||||||
void processStdOut(bool emitSignals);
|
|
||||||
void processStdErr(bool emitSignals);
|
|
||||||
|
|
||||||
SynchronousProcessPrivate *d;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
Reference in New Issue
Block a user