forked from qt-creator/qt-creator
Utils: Merge {synchronous,qtc}process.{h,cpp} file pairs
Mechanical to prepare merging the actual classes. Adapting #includes. Change-Id: I77a2c28129287778bc870c30cb890cd26bc2e62b Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -55,8 +55,8 @@
|
|||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/mimetypes/mimedatabase.h>
|
#include <utils/mimetypes/mimedatabase.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/qtcsettings.h>
|
#include <utils/qtcsettings.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#ifdef WITH_TESTS
|
#ifdef WITH_TESTS
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
|||||||
@@ -151,7 +151,6 @@ add_qtc_library(Utils
|
|||||||
stringutils.cpp stringutils.h
|
stringutils.cpp stringutils.h
|
||||||
styledbar.cpp styledbar.h
|
styledbar.cpp styledbar.h
|
||||||
stylehelper.cpp stylehelper.h
|
stylehelper.cpp stylehelper.h
|
||||||
synchronousprocess.cpp synchronousprocess.h
|
|
||||||
templateengine.cpp templateengine.h
|
templateengine.cpp templateengine.h
|
||||||
temporarydirectory.cpp temporarydirectory.h
|
temporarydirectory.cpp temporarydirectory.h
|
||||||
temporaryfile.cpp temporaryfile.h
|
temporaryfile.cpp temporaryfile.h
|
||||||
|
|||||||
@@ -25,7 +25,6 @@
|
|||||||
|
|
||||||
#include "buildablehelperlibrary.h"
|
#include "buildablehelperlibrary.h"
|
||||||
#include "hostosinfo.h"
|
#include "hostosinfo.h"
|
||||||
#include "synchronousprocess.h"
|
|
||||||
#include "qtcprocess.h"
|
#include "qtcprocess.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
|
|||||||
@@ -26,11 +26,10 @@
|
|||||||
#include "pathchooser.h"
|
#include "pathchooser.h"
|
||||||
|
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
#include "qtcassert.h"
|
|
||||||
#include "macroexpander.h"
|
|
||||||
|
|
||||||
#include "synchronousprocess.h"
|
|
||||||
#include "hostosinfo.h"
|
#include "hostosinfo.h"
|
||||||
|
#include "macroexpander.h"
|
||||||
|
#include "qtcassert.h"
|
||||||
|
#include "qtcprocess.h"
|
||||||
#include "theme/theme.h"
|
#include "theme/theme.h"
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|||||||
@@ -24,17 +24,22 @@
|
|||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "qtcprocess.h"
|
#include "qtcprocess.h"
|
||||||
#include "stringutils.h"
|
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include "stringutils.h"
|
||||||
#include <utils/hostosinfo.h>
|
#include "executeondestruction.h"
|
||||||
|
#include "hostosinfo.h"
|
||||||
|
#include "qtcassert.h"
|
||||||
|
#include "qtcprocess.h"
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QDir>
|
||||||
|
#include <QLoggingCategory>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QStack>
|
#include <QStack>
|
||||||
|
#include <QTextCodec>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
#ifdef QT_GUI_LIB
|
#ifdef QT_GUI_LIB
|
||||||
// qmlpuppet does not use that.
|
// qmlpuppet does not use that.
|
||||||
@@ -42,6 +47,10 @@
|
|||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <limits.h>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
#define CALLBACK WINAPI
|
#define CALLBACK WINAPI
|
||||||
#include <qt_windows.h>
|
#include <qt_windows.h>
|
||||||
@@ -1845,4 +1854,575 @@ QString QtcProcess::locateBinary(const QString &binary)
|
|||||||
return locateBinary(QString::fromLocal8Bit(path), binary);
|
return locateBinary(QString::fromLocal8Bit(path), binary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\class Utils::SynchronousProcess
|
||||||
|
|
||||||
|
\brief The SynchronousProcess class runs a synchronous process in its own
|
||||||
|
event loop that blocks only user input events. Thus, it allows for the GUI to
|
||||||
|
repaint and append output to log windows.
|
||||||
|
|
||||||
|
The stdOut(), stdErr() signals are emitted unbuffered as the process
|
||||||
|
writes them.
|
||||||
|
|
||||||
|
The stdOutBuffered(), stdErrBuffered() signals are emitted with complete
|
||||||
|
lines based on the '\\n' marker if they are enabled using
|
||||||
|
stdOutBufferedSignalsEnabled()/setStdErrBufferedSignalsEnabled().
|
||||||
|
They would typically be used for log windows.
|
||||||
|
|
||||||
|
There is a timeout handling that takes effect after the last data have been
|
||||||
|
read from stdout/stdin (as opposed to waitForFinished(), which measures time
|
||||||
|
since it was invoked). It is thus also suitable for slow processes that
|
||||||
|
continuously output data (like version system operations).
|
||||||
|
|
||||||
|
The property timeOutMessageBoxEnabled influences whether a message box is
|
||||||
|
shown asking the user if they want to kill the process on timeout (default: false).
|
||||||
|
|
||||||
|
There are also static utility functions for dealing with fully synchronous
|
||||||
|
processes, like reading the output with correct timeout handling.
|
||||||
|
|
||||||
|
Caution: This class should NOT be used if there is a chance that the process
|
||||||
|
triggers opening dialog boxes (for example, by file watchers triggering),
|
||||||
|
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
|
||||||
|
void SynchronousProcessResponse::clear()
|
||||||
|
{
|
||||||
|
result = StartFailed;
|
||||||
|
exitCode = -1;
|
||||||
|
rawStdOut.clear();
|
||||||
|
rawStdErr.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SynchronousProcessResponse::exitMessage(const QString &binary, int timeoutS) const
|
||||||
|
{
|
||||||
|
switch (result) {
|
||||||
|
case Finished:
|
||||||
|
return SynchronousProcess::tr("The command \"%1\" finished successfully.").arg(QDir::toNativeSeparators(binary));
|
||||||
|
case FinishedError:
|
||||||
|
return SynchronousProcess::tr("The command \"%1\" terminated with exit code %2.").arg(QDir::toNativeSeparators(binary)).arg(exitCode);
|
||||||
|
case TerminatedAbnormally:
|
||||||
|
return SynchronousProcess::tr("The command \"%1\" terminated abnormally.").arg(QDir::toNativeSeparators(binary));
|
||||||
|
case StartFailed:
|
||||||
|
return SynchronousProcess::tr("The command \"%1\" could not be started.").arg(QDir::toNativeSeparators(binary));
|
||||||
|
case Hang:
|
||||||
|
return SynchronousProcess::tr("The command \"%1\" did not respond within the timeout limit (%2 s).")
|
||||||
|
.arg(QDir::toNativeSeparators(binary)).arg(timeoutS);
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
QByteArray SynchronousProcessResponse::allRawOutput() const
|
||||||
|
{
|
||||||
|
if (!rawStdOut.isEmpty() && !rawStdErr.isEmpty()) {
|
||||||
|
QByteArray result = rawStdOut;
|
||||||
|
if (!result.endsWith('\n'))
|
||||||
|
result += '\n';
|
||||||
|
result += rawStdErr;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return !rawStdOut.isEmpty() ? rawStdOut : rawStdErr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SynchronousProcessResponse::allOutput() const
|
||||||
|
{
|
||||||
|
const QString out = stdOut();
|
||||||
|
const QString err = stdErr();
|
||||||
|
|
||||||
|
if (!out.isEmpty() && !err.isEmpty()) {
|
||||||
|
QString result = out;
|
||||||
|
if (!result.endsWith('\n'))
|
||||||
|
result += '\n';
|
||||||
|
result += err;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
return !out.isEmpty() ? out : err;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SynchronousProcessResponse::stdOut() const
|
||||||
|
{
|
||||||
|
return QtcProcess::normalizeNewlines(codec->toUnicode(rawStdOut));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString SynchronousProcessResponse::stdErr() const
|
||||||
|
{
|
||||||
|
return QtcProcess::normalizeNewlines(codec->toUnicode(rawStdErr));
|
||||||
|
}
|
||||||
|
|
||||||
|
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse& r)
|
||||||
|
{
|
||||||
|
QDebug nsp = str.nospace();
|
||||||
|
nsp << "SynchronousProcessResponse: result=" << r.result << " ex=" << r.exitCode << '\n'
|
||||||
|
<< r.rawStdOut.size() << " bytes stdout, stderr=" << r.rawStdErr << '\n';
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
SynchronousProcessResponse::Result defaultExitCodeInterpreter(int code)
|
||||||
|
{
|
||||||
|
return code ? SynchronousProcessResponse::FinishedError
|
||||||
|
: SynchronousProcessResponse::Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Data for one channel buffer (stderr/stdout)
|
||||||
|
class ChannelBuffer : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
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;
|
||||||
|
bool bufferedSignalsEnabled = false;
|
||||||
|
bool firstBuffer = true;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void outputBuffered(const QString &text, bool firstTime);
|
||||||
|
};
|
||||||
|
|
||||||
|
void ChannelBuffer::clearForRun()
|
||||||
|
{
|
||||||
|
firstBuffer = true;
|
||||||
|
rawDataPos = 0;
|
||||||
|
rawData.clear();
|
||||||
|
codecState.reset(new QTextCodec::ConverterState);
|
||||||
|
incompleteLineBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check for complete lines read from the device and return them, moving the
|
||||||
|
* buffer position. */
|
||||||
|
QString ChannelBuffer::linesRead()
|
||||||
|
{
|
||||||
|
// Convert and append the new input to the buffer of incomplete lines
|
||||||
|
const char *start = rawData.constData() + rawDataPos;
|
||||||
|
const int len = rawData.size() - rawDataPos;
|
||||||
|
incompleteLineBuffer.append(codec->toUnicode(start, len, codecState.get()));
|
||||||
|
rawDataPos = rawData.size();
|
||||||
|
|
||||||
|
// Any completed lines in the incompleteLineBuffer?
|
||||||
|
const int lastLineIndex = qMax(incompleteLineBuffer.lastIndexOf('\n'),
|
||||||
|
incompleteLineBuffer.lastIndexOf('\r'));
|
||||||
|
if (lastLineIndex == -1)
|
||||||
|
return QString();
|
||||||
|
|
||||||
|
// Get completed lines and remove them from the incompleteLinesBuffer:
|
||||||
|
const QString lines = QtcProcess::normalizeNewlines(incompleteLineBuffer.left(lastLineIndex + 1));
|
||||||
|
incompleteLineBuffer = incompleteLineBuffer.mid(lastLineIndex + 1);
|
||||||
|
|
||||||
|
return lines;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChannelBuffer::append(const QByteArray &text, bool emitSignals)
|
||||||
|
{
|
||||||
|
if (text.isEmpty())
|
||||||
|
return;
|
||||||
|
rawData += text;
|
||||||
|
if (!emitSignals)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Buffered. Emit complete lines?
|
||||||
|
if (bufferedSignalsEnabled) {
|
||||||
|
const QString lines = linesRead();
|
||||||
|
if (!lines.isEmpty()) {
|
||||||
|
emit outputBuffered(lines, firstBuffer);
|
||||||
|
firstBuffer = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ----------- SynchronousProcessPrivate
|
||||||
|
class SynchronousProcessPrivate {
|
||||||
|
public:
|
||||||
|
void clearForRun();
|
||||||
|
|
||||||
|
QTextCodec *m_codec = QTextCodec::codecForLocale();
|
||||||
|
QtcProcess m_process;
|
||||||
|
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() :
|
||||||
|
d(new SynchronousProcessPrivate)
|
||||||
|
{
|
||||||
|
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(&d->m_stdOut, &ChannelBuffer::outputBuffered, this, &SynchronousProcess::stdOutBuffered);
|
||||||
|
connect(&d->m_stdErr, &ChannelBuffer::outputBuffered, this, &SynchronousProcess::stdErrBuffered);
|
||||||
|
}
|
||||||
|
|
||||||
|
SynchronousProcess::~SynchronousProcess()
|
||||||
|
{
|
||||||
|
disconnect(&d->m_timer, nullptr, this, nullptr);
|
||||||
|
disconnect(&d->m_process, nullptr, this, nullptr);
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronousProcess::setTimeoutS(int timeoutS)
|
||||||
|
{
|
||||||
|
if (timeoutS > 0)
|
||||||
|
d->m_maxHangTimerCount = qMax(2, timeoutS);
|
||||||
|
else
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SynchronousProcess::stdOutBufferedSignalsEnabled() const
|
||||||
|
{
|
||||||
|
return d->m_stdOut.bufferedSignalsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronousProcess::setStdOutBufferedSignalsEnabled(bool v)
|
||||||
|
{
|
||||||
|
d->m_stdOut.bufferedSignalsEnabled = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SynchronousProcess::stdErrBufferedSignalsEnabled() const
|
||||||
|
{
|
||||||
|
return d->m_stdErr.bufferedSignalsEnabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronousProcess::setStdErrBufferedSignalsEnabled(bool v)
|
||||||
|
{
|
||||||
|
d->m_stdErr.bufferedSignalsEnabled = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
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()
|
||||||
|
{
|
||||||
|
return QThread::currentThread() == QCoreApplication::instance()->thread();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
|
||||||
|
const QByteArray &writeData)
|
||||||
|
{
|
||||||
|
// FIXME: Implement properly
|
||||||
|
if (cmd.executable().needsDevice()) {
|
||||||
|
QtcProcess proc;
|
||||||
|
proc.setEnvironment(Environment(d->m_process.environment()));
|
||||||
|
proc.setWorkingDirectory(d->m_process.workingDirectory());
|
||||||
|
proc.setCommand(cmd);
|
||||||
|
|
||||||
|
// writeData ?
|
||||||
|
proc.start();
|
||||||
|
|
||||||
|
proc.waitForFinished();
|
||||||
|
|
||||||
|
SynchronousProcessResponse res;
|
||||||
|
res.result = SynchronousProcessResponse::Finished;
|
||||||
|
res.exitCode = proc.exitCode();
|
||||||
|
res.rawStdOut = proc.readAllStandardOutput();
|
||||||
|
res.rawStdErr = proc.readAllStandardError();
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
qCDebug(processLog).noquote() << "Starting:" << cmd.toUserOutput();
|
||||||
|
ExecuteOnDestruction logResult([this] {
|
||||||
|
qCDebug(processLog) << d->m_result;
|
||||||
|
});
|
||||||
|
|
||||||
|
d->clearForRun();
|
||||||
|
|
||||||
|
d->m_binary = cmd.executable();
|
||||||
|
// 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);
|
||||||
|
if (!writeData.isEmpty()) {
|
||||||
|
connect(&d->m_process, &QProcess::started, this, [this, writeData] {
|
||||||
|
d->m_process.write(writeData);
|
||||||
|
d->m_process.closeWriteChannel();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
d->m_process.setOpenMode(writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
|
||||||
|
d->m_process.start();
|
||||||
|
|
||||||
|
// On Windows, start failure is triggered immediately if the
|
||||||
|
// executable cannot be found in the path. Do not start the
|
||||||
|
// event loop in that case.
|
||||||
|
if (!d->m_startFailure) {
|
||||||
|
d->m_timer.start();
|
||||||
|
#ifdef QT_GUI_LIB
|
||||||
|
if (isGuiThread())
|
||||||
|
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||||
|
#endif
|
||||||
|
d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
|
||||||
|
processStdOut(false);
|
||||||
|
processStdErr(false);
|
||||||
|
|
||||||
|
d->m_result.rawStdOut = d->m_stdOut.rawData;
|
||||||
|
d->m_result.rawStdErr = d->m_stdErr.rawData;
|
||||||
|
|
||||||
|
d->m_timer.stop();
|
||||||
|
#ifdef QT_GUI_LIB
|
||||||
|
if (isGuiThread())
|
||||||
|
QApplication::restoreOverrideCursor();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
return d->m_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
SynchronousProcessResponse SynchronousProcess::runBlocking(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.setCommand(cmd);
|
||||||
|
|
||||||
|
// writeData ?
|
||||||
|
proc.start();
|
||||||
|
|
||||||
|
proc.waitForFinished();
|
||||||
|
|
||||||
|
SynchronousProcessResponse res;
|
||||||
|
res.result = SynchronousProcessResponse::Finished;
|
||||||
|
res.exitCode = proc.exitCode();
|
||||||
|
res.rawStdOut = proc.readAllStandardOutput();
|
||||||
|
res.rawStdErr = proc.readAllStandardError();
|
||||||
|
return res;
|
||||||
|
};
|
||||||
|
|
||||||
|
qCDebug(processLog).noquote() << "Starting blocking:" << cmd.toUserOutput();
|
||||||
|
ExecuteOnDestruction logResult([this] {
|
||||||
|
qCDebug(processLog) << d->m_result;
|
||||||
|
});
|
||||||
|
|
||||||
|
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)) {
|
||||||
|
d->m_result.result = SynchronousProcessResponse::StartFailed;
|
||||||
|
return d->m_result;
|
||||||
|
}
|
||||||
|
d->m_process.closeWriteChannel();
|
||||||
|
if (!d->m_process.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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (d->m_process.state() != QProcess::NotRunning)
|
||||||
|
return d->m_result;
|
||||||
|
|
||||||
|
d->m_result.exitCode = d->m_process.exitCode();
|
||||||
|
if (d->m_result.result == SynchronousProcessResponse::StartFailed) {
|
||||||
|
if (d->m_process.exitStatus() != QProcess::NormalExit)
|
||||||
|
d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
|
||||||
|
else
|
||||||
|
d->m_result.result = (exitCodeInterpreter())(d->m_result.exitCode);
|
||||||
|
}
|
||||||
|
processStdOut(false);
|
||||||
|
processStdErr(false);
|
||||||
|
|
||||||
|
d->m_result.rawStdOut = d->m_stdOut.rawData;
|
||||||
|
d->m_result.rawStdErr = d->m_stdErr.rawData;
|
||||||
|
|
||||||
|
return d->m_result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SynchronousProcess::terminate()
|
||||||
|
{
|
||||||
|
return d->m_process.stopProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronousProcess::slotTimeout()
|
||||||
|
{
|
||||||
|
if (!d->m_waitingForUser && (++d->m_hangTimerCount > d->m_maxHangTimerCount)) {
|
||||||
|
if (debug)
|
||||||
|
qDebug() << Q_FUNC_INFO << "HANG detected, killing";
|
||||||
|
d->m_waitingForUser = true;
|
||||||
|
const bool terminate = !d->m_timeOutMessageBoxEnabled || askToKill(d->m_binary.toString());
|
||||||
|
d->m_waitingForUser = false;
|
||||||
|
if (terminate) {
|
||||||
|
d->m_process.stopProcess();
|
||||||
|
d->m_result.result = SynchronousProcessResponse::Hang;
|
||||||
|
} else {
|
||||||
|
d->m_hangTimerCount = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (debug)
|
||||||
|
qDebug() << Q_FUNC_INFO << d->m_hangTimerCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e)
|
||||||
|
{
|
||||||
|
if (debug)
|
||||||
|
qDebug() << Q_FUNC_INFO << exitCode << e;
|
||||||
|
d->m_hangTimerCount = 0;
|
||||||
|
|
||||||
|
switch (e) {
|
||||||
|
case QProcess::NormalExit:
|
||||||
|
d->m_result.result = d->m_exitCodeInterpreter(exitCode);
|
||||||
|
d->m_result.exitCode = exitCode;
|
||||||
|
break;
|
||||||
|
case QProcess::CrashExit:
|
||||||
|
// Was hang detected before and killed?
|
||||||
|
if (d->m_result.result != SynchronousProcessResponse::Hang)
|
||||||
|
d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
|
||||||
|
d->m_result.exitCode = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
d->m_eventLoop.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronousProcess::error(QProcess::ProcessError e)
|
||||||
|
{
|
||||||
|
d->m_hangTimerCount = 0;
|
||||||
|
if (debug)
|
||||||
|
qDebug() << Q_FUNC_INFO << e;
|
||||||
|
// Was hang detected before and killed?
|
||||||
|
if (d->m_result.result != SynchronousProcessResponse::Hang)
|
||||||
|
d->m_result.result = SynchronousProcessResponse::StartFailed;
|
||||||
|
d->m_startFailure = true;
|
||||||
|
d->m_eventLoop.quit();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronousProcess::processStdOut(bool emitSignals)
|
||||||
|
{
|
||||||
|
// Handle binary data
|
||||||
|
d->m_stdOut.append(d->m_process.readAllStandardOutput(), emitSignals);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SynchronousProcess::processStdErr(bool emitSignals)
|
||||||
|
{
|
||||||
|
// Handle binary data
|
||||||
|
d->m_stdErr.append(d->m_process.readAllStandardError(), emitSignals);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
|
#include "qtcprocess.moc"
|
||||||
|
|
||||||
|
|||||||
@@ -25,14 +25,61 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "utils_global.h"
|
||||||
|
|
||||||
#include "environment.h"
|
#include "environment.h"
|
||||||
|
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
#include <QTextCodec>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QDebug)
|
||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
class AbstractMacroExpander;
|
class AbstractMacroExpander;
|
||||||
|
|
||||||
namespace Internal { class QtcProcessPrivate; }
|
namespace Internal { class QtcProcessPrivate; }
|
||||||
|
class SynchronousProcessPrivate;
|
||||||
|
class CommandLine;
|
||||||
|
class Environment;
|
||||||
|
|
||||||
|
/* Result of SynchronousProcess execution */
|
||||||
|
class QTCREATOR_UTILS_EXPORT SynchronousProcessResponse
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Result {
|
||||||
|
// Finished with return code 0
|
||||||
|
Finished,
|
||||||
|
// Finished with return code != 0
|
||||||
|
FinishedError,
|
||||||
|
// Process terminated abnormally (kill)
|
||||||
|
TerminatedAbnormally,
|
||||||
|
// Executable could not be started
|
||||||
|
StartFailed,
|
||||||
|
// Hang, no output after time out
|
||||||
|
Hang };
|
||||||
|
|
||||||
|
void clear();
|
||||||
|
|
||||||
|
// Helper to format an exit message.
|
||||||
|
QString exitMessage(const QString &binary, int timeoutS) const;
|
||||||
|
|
||||||
|
QByteArray allRawOutput() const;
|
||||||
|
QString allOutput() const;
|
||||||
|
|
||||||
|
QString stdOut() const;
|
||||||
|
QString stdErr() const;
|
||||||
|
|
||||||
|
Result result = StartFailed;
|
||||||
|
int exitCode = -1;
|
||||||
|
|
||||||
|
QByteArray rawStdOut;
|
||||||
|
QByteArray rawStdErr;
|
||||||
|
QTextCodec *codec = QTextCodec::codecForLocale();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT QtcProcess : public QProcess
|
class QTCREATOR_UTILS_EXPORT QtcProcess : public QProcess
|
||||||
{
|
{
|
||||||
@@ -178,4 +225,70 @@ private:
|
|||||||
QProcessEnvironment processEnvironment() const = delete;
|
QProcessEnvironment processEnvironment() const = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
SynchronousProcess();
|
||||||
|
~SynchronousProcess() override;
|
||||||
|
|
||||||
|
/* 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 stdOutBufferedSignalsEnabled() const;
|
||||||
|
void setStdOutBufferedSignalsEnabled(bool);
|
||||||
|
|
||||||
|
bool stdErrBufferedSignalsEnabled() const;
|
||||||
|
void setStdErrBufferedSignalsEnabled(bool);
|
||||||
|
|
||||||
|
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 = {});
|
||||||
|
// Starts the command blocking the UI fully
|
||||||
|
SynchronousProcessResponse runBlocking(const CommandLine &cmd);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void stdOutBuffered(const QString &lines, bool firstTime);
|
||||||
|
void stdErrBuffered(const QString &lines, bool firstTime);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
bool terminate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void slotTimeout();
|
||||||
|
void finished(int exitCode, QProcess::ExitStatus e);
|
||||||
|
void error(QProcess::ProcessError);
|
||||||
|
void processStdOut(bool emitSignals);
|
||||||
|
void processStdErr(bool emitSignals);
|
||||||
|
|
||||||
|
SynchronousProcessPrivate *d;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|||||||
@@ -27,16 +27,13 @@
|
|||||||
|
|
||||||
#include "utils_global.h"
|
#include "utils_global.h"
|
||||||
|
|
||||||
#include "synchronousprocess.h"
|
#include "qtcprocess.h"
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
class QMutex;
|
class QMutex;
|
||||||
class QVariant;
|
class QVariant;
|
||||||
class QProcessEnvironment;
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class QFutureInterface;
|
class QFutureInterface;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -45,7 +42,6 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
class CommandLine;
|
|
||||||
namespace Internal { class ShellCommandPrivate; }
|
namespace Internal { class ShellCommandPrivate; }
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT ProgressParser
|
class QTCREATOR_UTILS_EXPORT ProgressParser
|
||||||
|
|||||||
@@ -1,591 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
** Contact: https://www.qt.io/licensing/
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator.
|
|
||||||
**
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and The Qt Company. For licensing terms
|
|
||||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
||||||
** information use the contact form at https://www.qt.io/contact-us.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3 as published by the Free Software
|
|
||||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
||||||
** included in the packaging of this file. Please review the following
|
|
||||||
** information to ensure the GNU General Public License requirements will
|
|
||||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#include "synchronousprocess.h"
|
|
||||||
#include "executeondestruction.h"
|
|
||||||
#include "hostosinfo.h"
|
|
||||||
#include "qtcassert.h"
|
|
||||||
#include "qtcprocess.h"
|
|
||||||
|
|
||||||
#include <QDebug>
|
|
||||||
#include <QDir>
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
#include <QMessageBox>
|
|
||||||
#include <QTextCodec>
|
|
||||||
#include <QThread>
|
|
||||||
#include <QTimer>
|
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
|
|
||||||
#include <algorithm>
|
|
||||||
#include <limits.h>
|
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\class Utils::SynchronousProcess
|
|
||||||
|
|
||||||
\brief The SynchronousProcess class runs a synchronous process in its own
|
|
||||||
event loop that blocks only user input events. Thus, it allows for the GUI to
|
|
||||||
repaint and append output to log windows.
|
|
||||||
|
|
||||||
The stdOut(), stdErr() signals are emitted unbuffered as the process
|
|
||||||
writes them.
|
|
||||||
|
|
||||||
The stdOutBuffered(), stdErrBuffered() signals are emitted with complete
|
|
||||||
lines based on the '\\n' marker if they are enabled using
|
|
||||||
stdOutBufferedSignalsEnabled()/setStdErrBufferedSignalsEnabled().
|
|
||||||
They would typically be used for log windows.
|
|
||||||
|
|
||||||
There is a timeout handling that takes effect after the last data have been
|
|
||||||
read from stdout/stdin (as opposed to waitForFinished(), which measures time
|
|
||||||
since it was invoked). It is thus also suitable for slow processes that continously
|
|
||||||
output data (like version system operations).
|
|
||||||
|
|
||||||
The property timeOutMessageBoxEnabled influences whether a message box is
|
|
||||||
shown asking the user if they want to kill the process on timeout (default: false).
|
|
||||||
|
|
||||||
There are also static utility functions for dealing with fully synchronous
|
|
||||||
processes, like reading the output with correct timeout handling.
|
|
||||||
|
|
||||||
Caution: This class should NOT be used if there is a chance that the process
|
|
||||||
triggers opening dialog boxes (for example, by file watchers triggering),
|
|
||||||
as this will cause event loop problems.
|
|
||||||
*/
|
|
||||||
|
|
||||||
enum { debug = 0 };
|
|
||||||
enum { syncDebug = 0 };
|
|
||||||
|
|
||||||
enum { defaultMaxHangTimerCount = 10 };
|
|
||||||
|
|
||||||
namespace Utils {
|
|
||||||
|
|
||||||
static Q_LOGGING_CATEGORY(processLog, "qtc.utils.synchronousprocess", QtWarningMsg);
|
|
||||||
|
|
||||||
// ----------- SynchronousProcessResponse
|
|
||||||
void SynchronousProcessResponse::clear()
|
|
||||||
{
|
|
||||||
result = StartFailed;
|
|
||||||
exitCode = -1;
|
|
||||||
rawStdOut.clear();
|
|
||||||
rawStdErr.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SynchronousProcessResponse::exitMessage(const QString &binary, int timeoutS) const
|
|
||||||
{
|
|
||||||
switch (result) {
|
|
||||||
case Finished:
|
|
||||||
return SynchronousProcess::tr("The command \"%1\" finished successfully.").arg(QDir::toNativeSeparators(binary));
|
|
||||||
case FinishedError:
|
|
||||||
return SynchronousProcess::tr("The command \"%1\" terminated with exit code %2.").arg(QDir::toNativeSeparators(binary)).arg(exitCode);
|
|
||||||
case TerminatedAbnormally:
|
|
||||||
return SynchronousProcess::tr("The command \"%1\" terminated abnormally.").arg(QDir::toNativeSeparators(binary));
|
|
||||||
case StartFailed:
|
|
||||||
return SynchronousProcess::tr("The command \"%1\" could not be started.").arg(QDir::toNativeSeparators(binary));
|
|
||||||
case Hang:
|
|
||||||
return SynchronousProcess::tr("The command \"%1\" did not respond within the timeout limit (%2 s).")
|
|
||||||
.arg(QDir::toNativeSeparators(binary)).arg(timeoutS);
|
|
||||||
}
|
|
||||||
return QString();
|
|
||||||
}
|
|
||||||
|
|
||||||
QByteArray SynchronousProcessResponse::allRawOutput() const
|
|
||||||
{
|
|
||||||
if (!rawStdOut.isEmpty() && !rawStdErr.isEmpty()) {
|
|
||||||
QByteArray result = rawStdOut;
|
|
||||||
if (!result.endsWith('\n'))
|
|
||||||
result += '\n';
|
|
||||||
result += rawStdErr;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return !rawStdOut.isEmpty() ? rawStdOut : rawStdErr;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SynchronousProcessResponse::allOutput() const
|
|
||||||
{
|
|
||||||
const QString out = stdOut();
|
|
||||||
const QString err = stdErr();
|
|
||||||
|
|
||||||
if (!out.isEmpty() && !err.isEmpty()) {
|
|
||||||
QString result = out;
|
|
||||||
if (!result.endsWith('\n'))
|
|
||||||
result += '\n';
|
|
||||||
result += err;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
return !out.isEmpty() ? out : err;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SynchronousProcessResponse::stdOut() const
|
|
||||||
{
|
|
||||||
return QtcProcess::normalizeNewlines(codec->toUnicode(rawStdOut));
|
|
||||||
}
|
|
||||||
|
|
||||||
QString SynchronousProcessResponse::stdErr() const
|
|
||||||
{
|
|
||||||
return QtcProcess::normalizeNewlines(codec->toUnicode(rawStdErr));
|
|
||||||
}
|
|
||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse& r)
|
|
||||||
{
|
|
||||||
QDebug nsp = str.nospace();
|
|
||||||
nsp << "SynchronousProcessResponse: result=" << r.result << " ex=" << r.exitCode << '\n'
|
|
||||||
<< r.rawStdOut.size() << " bytes stdout, stderr=" << r.rawStdErr << '\n';
|
|
||||||
return str;
|
|
||||||
}
|
|
||||||
|
|
||||||
SynchronousProcessResponse::Result defaultExitCodeInterpreter(int code)
|
|
||||||
{
|
|
||||||
return code ? SynchronousProcessResponse::FinishedError
|
|
||||||
: SynchronousProcessResponse::Finished;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Data for one channel buffer (stderr/stdout)
|
|
||||||
class ChannelBuffer : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
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;
|
|
||||||
bool bufferedSignalsEnabled = false;
|
|
||||||
bool firstBuffer = true;
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void outputBuffered(const QString &text, bool firstTime);
|
|
||||||
};
|
|
||||||
|
|
||||||
void ChannelBuffer::clearForRun()
|
|
||||||
{
|
|
||||||
firstBuffer = true;
|
|
||||||
rawDataPos = 0;
|
|
||||||
rawData.clear();
|
|
||||||
codecState.reset(new QTextCodec::ConverterState);
|
|
||||||
incompleteLineBuffer.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Check for complete lines read from the device and return them, moving the
|
|
||||||
* buffer position. */
|
|
||||||
QString ChannelBuffer::linesRead()
|
|
||||||
{
|
|
||||||
// Convert and append the new input to the buffer of incomplete lines
|
|
||||||
const char *start = rawData.constData() + rawDataPos;
|
|
||||||
const int len = rawData.size() - rawDataPos;
|
|
||||||
incompleteLineBuffer.append(codec->toUnicode(start, len, codecState.get()));
|
|
||||||
rawDataPos = rawData.size();
|
|
||||||
|
|
||||||
// Any completed lines in the incompleteLineBuffer?
|
|
||||||
const int lastLineIndex = qMax(incompleteLineBuffer.lastIndexOf('\n'),
|
|
||||||
incompleteLineBuffer.lastIndexOf('\r'));
|
|
||||||
if (lastLineIndex == -1)
|
|
||||||
return QString();
|
|
||||||
|
|
||||||
// Get completed lines and remove them from the incompleteLinesBuffer:
|
|
||||||
const QString lines = QtcProcess::normalizeNewlines(incompleteLineBuffer.left(lastLineIndex + 1));
|
|
||||||
incompleteLineBuffer = incompleteLineBuffer.mid(lastLineIndex + 1);
|
|
||||||
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChannelBuffer::append(const QByteArray &text, bool emitSignals)
|
|
||||||
{
|
|
||||||
if (text.isEmpty())
|
|
||||||
return;
|
|
||||||
rawData += text;
|
|
||||||
if (!emitSignals)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Buffered. Emit complete lines?
|
|
||||||
if (bufferedSignalsEnabled) {
|
|
||||||
const QString lines = linesRead();
|
|
||||||
if (!lines.isEmpty()) {
|
|
||||||
emit outputBuffered(lines, firstBuffer);
|
|
||||||
firstBuffer = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ----------- SynchronousProcessPrivate
|
|
||||||
class SynchronousProcessPrivate {
|
|
||||||
public:
|
|
||||||
void clearForRun();
|
|
||||||
|
|
||||||
QTextCodec *m_codec = QTextCodec::codecForLocale();
|
|
||||||
QtcProcess m_process;
|
|
||||||
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() :
|
|
||||||
d(new SynchronousProcessPrivate)
|
|
||||||
{
|
|
||||||
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(&d->m_stdOut, &ChannelBuffer::outputBuffered, this, &SynchronousProcess::stdOutBuffered);
|
|
||||||
connect(&d->m_stdErr, &ChannelBuffer::outputBuffered, this, &SynchronousProcess::stdErrBuffered);
|
|
||||||
}
|
|
||||||
|
|
||||||
SynchronousProcess::~SynchronousProcess()
|
|
||||||
{
|
|
||||||
disconnect(&d->m_timer, nullptr, this, nullptr);
|
|
||||||
disconnect(&d->m_process, nullptr, this, nullptr);
|
|
||||||
delete d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronousProcess::setTimeoutS(int timeoutS)
|
|
||||||
{
|
|
||||||
if (timeoutS > 0)
|
|
||||||
d->m_maxHangTimerCount = qMax(2, timeoutS);
|
|
||||||
else
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SynchronousProcess::stdOutBufferedSignalsEnabled() const
|
|
||||||
{
|
|
||||||
return d->m_stdOut.bufferedSignalsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronousProcess::setStdOutBufferedSignalsEnabled(bool v)
|
|
||||||
{
|
|
||||||
d->m_stdOut.bufferedSignalsEnabled = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SynchronousProcess::stdErrBufferedSignalsEnabled() const
|
|
||||||
{
|
|
||||||
return d->m_stdErr.bufferedSignalsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronousProcess::setStdErrBufferedSignalsEnabled(bool v)
|
|
||||||
{
|
|
||||||
d->m_stdErr.bufferedSignalsEnabled = v;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isGuiThread()
|
|
||||||
{
|
|
||||||
return QThread::currentThread() == QCoreApplication::instance()->thread();
|
|
||||||
}
|
|
||||||
|
|
||||||
SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd,
|
|
||||||
const QByteArray &writeData)
|
|
||||||
{
|
|
||||||
qCDebug(processLog).noquote() << "Starting:" << cmd.toUserOutput();
|
|
||||||
ExecuteOnDestruction logResult([this] {
|
|
||||||
qCDebug(processLog) << d->m_result;
|
|
||||||
});
|
|
||||||
|
|
||||||
d->clearForRun();
|
|
||||||
|
|
||||||
d->m_binary = cmd.executable();
|
|
||||||
// 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);
|
|
||||||
if (!writeData.isEmpty()) {
|
|
||||||
connect(&d->m_process, &QProcess::started, this, [this, writeData] {
|
|
||||||
d->m_process.write(writeData);
|
|
||||||
d->m_process.closeWriteChannel();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
d->m_process.setOpenMode(writeData.isEmpty() ? QIODevice::ReadOnly : QIODevice::ReadWrite);
|
|
||||||
d->m_process.start();
|
|
||||||
|
|
||||||
// On Windows, start failure is triggered immediately if the
|
|
||||||
// executable cannot be found in the path. Do not start the
|
|
||||||
// event loop in that case.
|
|
||||||
if (!d->m_startFailure) {
|
|
||||||
d->m_timer.start();
|
|
||||||
if (isGuiThread())
|
|
||||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
|
||||||
d->m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
|
|
||||||
processStdOut(false);
|
|
||||||
processStdErr(false);
|
|
||||||
|
|
||||||
d->m_result.rawStdOut = d->m_stdOut.rawData;
|
|
||||||
d->m_result.rawStdErr = d->m_stdErr.rawData;
|
|
||||||
|
|
||||||
d->m_timer.stop();
|
|
||||||
if (isGuiThread())
|
|
||||||
QApplication::restoreOverrideCursor();
|
|
||||||
}
|
|
||||||
|
|
||||||
return d->m_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cmd)
|
|
||||||
{
|
|
||||||
qCDebug(processLog).noquote() << "Starting blocking:" << cmd.toUserOutput();
|
|
||||||
ExecuteOnDestruction logResult([this] {
|
|
||||||
qCDebug(processLog) << d->m_result;
|
|
||||||
});
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
d->m_result.result = SynchronousProcessResponse::StartFailed;
|
|
||||||
return d->m_result;
|
|
||||||
}
|
|
||||||
d->m_process.closeWriteChannel();
|
|
||||||
if (!d->m_process.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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (d->m_process.state() != QProcess::NotRunning)
|
|
||||||
return d->m_result;
|
|
||||||
|
|
||||||
d->m_result.exitCode = d->m_process.exitCode();
|
|
||||||
if (d->m_result.result == SynchronousProcessResponse::StartFailed) {
|
|
||||||
if (d->m_process.exitStatus() != QProcess::NormalExit)
|
|
||||||
d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
|
|
||||||
else
|
|
||||||
d->m_result.result = (exitCodeInterpreter())(d->m_result.exitCode);
|
|
||||||
}
|
|
||||||
processStdOut(false);
|
|
||||||
processStdErr(false);
|
|
||||||
|
|
||||||
d->m_result.rawStdOut = d->m_stdOut.rawData;
|
|
||||||
d->m_result.rawStdErr = d->m_stdErr.rawData;
|
|
||||||
|
|
||||||
return d->m_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SynchronousProcess::terminate()
|
|
||||||
{
|
|
||||||
return d->m_process.stopProcess();
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline bool askToKill(const QString &binary = QString())
|
|
||||||
{
|
|
||||||
if (!isGuiThread())
|
|
||||||
return true;
|
|
||||||
const QString title = SynchronousProcess::tr("Process not Responding");
|
|
||||||
QString msg = binary.isEmpty() ?
|
|
||||||
SynchronousProcess::tr("The process is not responding.") :
|
|
||||||
SynchronousProcess::tr("The process \"%1\" is not responding.").arg(QDir::toNativeSeparators(binary));
|
|
||||||
msg += QLatin1Char(' ');
|
|
||||||
msg += SynchronousProcess::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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronousProcess::slotTimeout()
|
|
||||||
{
|
|
||||||
if (!d->m_waitingForUser && (++d->m_hangTimerCount > d->m_maxHangTimerCount)) {
|
|
||||||
if (debug)
|
|
||||||
qDebug() << Q_FUNC_INFO << "HANG detected, killing";
|
|
||||||
d->m_waitingForUser = true;
|
|
||||||
const bool terminate = !d->m_timeOutMessageBoxEnabled || askToKill(d->m_binary.toString());
|
|
||||||
d->m_waitingForUser = false;
|
|
||||||
if (terminate) {
|
|
||||||
d->m_process.stopProcess();
|
|
||||||
d->m_result.result = SynchronousProcessResponse::Hang;
|
|
||||||
} else {
|
|
||||||
d->m_hangTimerCount = 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (debug)
|
|
||||||
qDebug() << Q_FUNC_INFO << d->m_hangTimerCount;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronousProcess::finished(int exitCode, QProcess::ExitStatus e)
|
|
||||||
{
|
|
||||||
if (debug)
|
|
||||||
qDebug() << Q_FUNC_INFO << exitCode << e;
|
|
||||||
d->m_hangTimerCount = 0;
|
|
||||||
|
|
||||||
switch (e) {
|
|
||||||
case QProcess::NormalExit:
|
|
||||||
d->m_result.result = d->m_exitCodeInterpreter(exitCode);
|
|
||||||
d->m_result.exitCode = exitCode;
|
|
||||||
break;
|
|
||||||
case QProcess::CrashExit:
|
|
||||||
// Was hang detected before and killed?
|
|
||||||
if (d->m_result.result != SynchronousProcessResponse::Hang)
|
|
||||||
d->m_result.result = SynchronousProcessResponse::TerminatedAbnormally;
|
|
||||||
d->m_result.exitCode = -1;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
d->m_eventLoop.quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronousProcess::error(QProcess::ProcessError e)
|
|
||||||
{
|
|
||||||
d->m_hangTimerCount = 0;
|
|
||||||
if (debug)
|
|
||||||
qDebug() << Q_FUNC_INFO << e;
|
|
||||||
// Was hang detected before and killed?
|
|
||||||
if (d->m_result.result != SynchronousProcessResponse::Hang)
|
|
||||||
d->m_result.result = SynchronousProcessResponse::StartFailed;
|
|
||||||
d->m_startFailure = true;
|
|
||||||
d->m_eventLoop.quit();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronousProcess::processStdOut(bool emitSignals)
|
|
||||||
{
|
|
||||||
// Handle binary data
|
|
||||||
d->m_stdOut.append(d->m_process.readAllStandardOutput(), emitSignals);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SynchronousProcess::processStdErr(bool emitSignals)
|
|
||||||
{
|
|
||||||
// Handle binary data
|
|
||||||
d->m_stdErr.append(d->m_process.readAllStandardError(), emitSignals);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Utils
|
|
||||||
|
|
||||||
#include "synchronousprocess.moc"
|
|
||||||
@@ -1,144 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
** Contact: https://www.qt.io/licensing/
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator.
|
|
||||||
**
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and The Qt Company. For licensing terms
|
|
||||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
||||||
** information use the contact form at https://www.qt.io/contact-us.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3 as published by the Free Software
|
|
||||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
||||||
** included in the packaging of this file. Please review the following
|
|
||||||
** information to ensure the GNU General Public License requirements will
|
|
||||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "utils_global.h"
|
|
||||||
|
|
||||||
#include <QProcess>
|
|
||||||
#include <QTextCodec>
|
|
||||||
|
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QDebug)
|
|
||||||
|
|
||||||
namespace Utils {
|
|
||||||
|
|
||||||
class SynchronousProcessPrivate;
|
|
||||||
class CommandLine;
|
|
||||||
class Environment;
|
|
||||||
|
|
||||||
/* Result of SynchronousProcess execution */
|
|
||||||
class QTCREATOR_UTILS_EXPORT SynchronousProcessResponse
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum Result {
|
|
||||||
// Finished with return code 0
|
|
||||||
Finished,
|
|
||||||
// Finished with return code != 0
|
|
||||||
FinishedError,
|
|
||||||
// Process terminated abnormally (kill)
|
|
||||||
TerminatedAbnormally,
|
|
||||||
// Executable could not be started
|
|
||||||
StartFailed,
|
|
||||||
// Hang, no output after time out
|
|
||||||
Hang };
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
|
|
||||||
// Helper to format an exit message.
|
|
||||||
QString exitMessage(const QString &binary, int timeoutS) const;
|
|
||||||
|
|
||||||
QByteArray allRawOutput() const;
|
|
||||||
QString allOutput() const;
|
|
||||||
|
|
||||||
QString stdOut() const;
|
|
||||||
QString stdErr() const;
|
|
||||||
|
|
||||||
Result result = StartFailed;
|
|
||||||
int exitCode = -1;
|
|
||||||
|
|
||||||
QByteArray rawStdOut;
|
|
||||||
QByteArray rawStdErr;
|
|
||||||
QTextCodec *codec = QTextCodec::codecForLocale();
|
|
||||||
};
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT SynchronousProcess : public QObject
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
public:
|
|
||||||
SynchronousProcess();
|
|
||||||
~SynchronousProcess() override;
|
|
||||||
|
|
||||||
/* 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 stdOutBufferedSignalsEnabled() const;
|
|
||||||
void setStdOutBufferedSignalsEnabled(bool);
|
|
||||||
|
|
||||||
bool stdErrBufferedSignalsEnabled() const;
|
|
||||||
void setStdErrBufferedSignalsEnabled(bool);
|
|
||||||
|
|
||||||
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 = {});
|
|
||||||
// Starts the command blocking the UI fully
|
|
||||||
SynchronousProcessResponse runBlocking(const CommandLine &cmd);
|
|
||||||
|
|
||||||
signals:
|
|
||||||
void stdOutBuffered(const QString &lines, bool firstTime);
|
|
||||||
void stdErrBuffered(const QString &lines, bool firstTime);
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
bool terminate();
|
|
||||||
|
|
||||||
private:
|
|
||||||
void slotTimeout();
|
|
||||||
void finished(int exitCode, QProcess::ExitStatus e);
|
|
||||||
void error(QProcess::ProcessError);
|
|
||||||
void processStdOut(bool emitSignals);
|
|
||||||
void processStdErr(bool emitSignals);
|
|
||||||
|
|
||||||
SynchronousProcessPrivate *d;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Utils
|
|
||||||
@@ -60,7 +60,6 @@ SOURCES += \
|
|||||||
$$PWD/classnamevalidatinglineedit.cpp \
|
$$PWD/classnamevalidatinglineedit.cpp \
|
||||||
$$PWD/fancylineedit.cpp \
|
$$PWD/fancylineedit.cpp \
|
||||||
$$PWD/qtcolorbutton.cpp \
|
$$PWD/qtcolorbutton.cpp \
|
||||||
$$PWD/synchronousprocess.cpp \
|
|
||||||
$$PWD/savefile.cpp \
|
$$PWD/savefile.cpp \
|
||||||
$$PWD/fileutils.cpp \
|
$$PWD/fileutils.cpp \
|
||||||
$$PWD/textfileformat.cpp \
|
$$PWD/textfileformat.cpp \
|
||||||
@@ -188,7 +187,6 @@ HEADERS += \
|
|||||||
$$PWD/fancylineedit.h \
|
$$PWD/fancylineedit.h \
|
||||||
$$PWD/qtcolorbutton.h \
|
$$PWD/qtcolorbutton.h \
|
||||||
$$PWD/consoleprocess.h \
|
$$PWD/consoleprocess.h \
|
||||||
$$PWD/synchronousprocess.h \
|
|
||||||
$$PWD/savefile.h \
|
$$PWD/savefile.h \
|
||||||
$$PWD/fileutils.h \
|
$$PWD/fileutils.h \
|
||||||
$$PWD/textfileformat.h \
|
$$PWD/textfileformat.h \
|
||||||
|
|||||||
@@ -263,8 +263,6 @@ Project {
|
|||||||
"styledbar.h",
|
"styledbar.h",
|
||||||
"stylehelper.cpp",
|
"stylehelper.cpp",
|
||||||
"stylehelper.h",
|
"stylehelper.h",
|
||||||
"synchronousprocess.cpp",
|
|
||||||
"synchronousprocess.h",
|
|
||||||
"templateengine.cpp",
|
"templateengine.cpp",
|
||||||
"templateengine.h",
|
"templateengine.h",
|
||||||
"temporarydirectory.cpp",
|
"temporarydirectory.cpp",
|
||||||
|
|||||||
@@ -22,16 +22,19 @@
|
|||||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "androidavdmanager.h"
|
#include "androidavdmanager.h"
|
||||||
|
|
||||||
#include "avdmanageroutputparser.h"
|
#include "avdmanageroutputparser.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|||||||
@@ -59,7 +59,6 @@
|
|||||||
#include <utils/infolabel.h>
|
#include <utils/infolabel.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
|||||||
@@ -57,9 +57,9 @@
|
|||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/persistentsettings.h>
|
#include <utils/persistentsettings.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@
|
|||||||
#include "androidconfigurations.h"
|
#include "androidconfigurations.h"
|
||||||
#include "ui_androidcreatekeystorecertificate.h"
|
#include "ui_androidcreatekeystorecertificate.h"
|
||||||
|
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
|
|||||||
@@ -55,7 +55,6 @@
|
|||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|||||||
@@ -53,8 +53,8 @@
|
|||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -47,7 +47,6 @@
|
|||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/temporaryfile.h>
|
#include <utils/temporaryfile.h>
|
||||||
#include <utils/url.h>
|
#include <utils/url.h>
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@
|
|||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|||||||
@@ -45,7 +45,6 @@
|
|||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -38,7 +38,6 @@
|
|||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@
|
|||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
|
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|||||||
@@ -53,8 +53,8 @@
|
|||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/mimetypes/mimedatabase.h>
|
#include <utils/mimetypes/mimedatabase.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
#include <utils/textutils.h>
|
#include <utils/textutils.h>
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
|||||||
@@ -34,8 +34,8 @@
|
|||||||
#include <cpptools/compileroptionsbuilder.h>
|
#include <cpptools/compileroptionsbuilder.h>
|
||||||
#include <cpptools/cpptoolsreuse.h>
|
#include <cpptools/cpptoolsreuse.h>
|
||||||
|
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/temporaryfile.h>
|
#include <utils/temporaryfile.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
|||||||
@@ -35,11 +35,10 @@
|
|||||||
#include <cpptools/cpptoolsreuse.h>
|
#include <cpptools/cpptoolsreuse.h>
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
#include <utils/qtcprocess.h>
|
|
||||||
#include <utils/checkablemessagebox.h>
|
#include <utils/checkablemessagebox.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
|
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|||||||
@@ -60,9 +60,9 @@
|
|||||||
#include <utils/infobar.h>
|
#include <utils/infobar.h>
|
||||||
#include <utils/parameteraction.h>
|
#include <utils/parameteraction.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
|
|
||||||
#include <vcsbase/basevcseditorfactory.h>
|
#include <vcsbase/basevcseditorfactory.h>
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/id.h>
|
#include <utils/id.h>
|
||||||
#include <utils/optional.h>
|
#include <utils/optional.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
QT_FORWARD_DECLARE_CLASS(QProcess)
|
QT_FORWARD_DECLARE_CLASS(QProcess)
|
||||||
|
|
||||||
|
|||||||
@@ -36,8 +36,8 @@
|
|||||||
#include <utils/infolabel.h>
|
#include <utils/infolabel.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
#include <utils/wizard.h>
|
#include <utils/wizard.h>
|
||||||
#include <utils/wizardpage.h>
|
#include <utils/wizardpage.h>
|
||||||
|
|||||||
@@ -42,9 +42,9 @@
|
|||||||
|
|
||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
|
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/parameteraction.h>
|
#include <utils/parameteraction.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
|
|||||||
@@ -35,8 +35,8 @@
|
|||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/macroexpander.h>
|
#include <utils/macroexpander.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/utilsicons.h>
|
#include <utils/utilsicons.h>
|
||||||
#include <utils/winutils.h>
|
#include <utils/winutils.h>
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/persistentsettings.h>
|
#include <utils/persistentsettings.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/treemodel.h>
|
#include <utils/treemodel.h>
|
||||||
#include <utils/winutils.h>
|
#include <utils/winutils.h>
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,6 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/temporaryfile.h>
|
#include <utils/temporaryfile.h>
|
||||||
|
|
||||||
#include <QDirIterator>
|
#include <QDirIterator>
|
||||||
|
|||||||
@@ -31,8 +31,9 @@
|
|||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/shellcommand.h>
|
#include <coreplugin/shellcommand.h>
|
||||||
|
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QJsonDocument>
|
#include <QJsonDocument>
|
||||||
|
|||||||
@@ -50,7 +50,6 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/temporaryfile.h>
|
#include <utils/temporaryfile.h>
|
||||||
#include <utils/theme/theme.h>
|
#include <utils/theme/theme.h>
|
||||||
|
|
||||||
|
|||||||
@@ -39,8 +39,8 @@
|
|||||||
#include <utils/filesearch.h>
|
#include <utils/filesearch.h>
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/textfileformat.h>
|
#include <utils/textfileformat.h>
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
|||||||
@@ -31,10 +31,7 @@
|
|||||||
#include "iosprobe.h"
|
#include "iosprobe.h"
|
||||||
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <utils/algorithm.h>
|
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <projectexplorer/kitmanager.h>
|
#include <projectexplorer/kitmanager.h>
|
||||||
#include <projectexplorer/kitinformation.h>
|
#include <projectexplorer/kitinformation.h>
|
||||||
#include <projectexplorer/devicesupport/devicemanager.h>
|
#include <projectexplorer/devicesupport/devicemanager.h>
|
||||||
@@ -42,14 +39,20 @@
|
|||||||
#include <projectexplorer/toolchain.h>
|
#include <projectexplorer/toolchain.h>
|
||||||
#include <projectexplorer/gcctoolchain.h>
|
#include <projectexplorer/gcctoolchain.h>
|
||||||
#include <projectexplorer/projectexplorerconstants.h>
|
#include <projectexplorer/projectexplorerconstants.h>
|
||||||
|
|
||||||
#include <debugger/debuggeritemmanager.h>
|
#include <debugger/debuggeritemmanager.h>
|
||||||
#include <debugger/debuggeritem.h>
|
#include <debugger/debuggeritem.h>
|
||||||
#include <debugger/debuggerkitinformation.h>
|
#include <debugger/debuggerkitinformation.h>
|
||||||
|
|
||||||
#include <qtsupport/baseqtversion.h>
|
#include <qtsupport/baseqtversion.h>
|
||||||
#include <qtsupport/qtkitinformation.h>
|
#include <qtsupport/qtkitinformation.h>
|
||||||
#include <qtsupport/qtversionmanager.h>
|
#include <qtsupport/qtversionmanager.h>
|
||||||
#include <qtsupport/qtversionfactory.h>
|
#include <qtsupport/qtversionfactory.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDomDocument>
|
#include <QDomDocument>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "iosprobe.h"
|
#include "iosprobe.h"
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|||||||
@@ -29,12 +29,14 @@
|
|||||||
#include "iossimulator.h"
|
#include "iossimulator.h"
|
||||||
#include "simulatorcontrol.h"
|
#include "simulatorcontrol.h"
|
||||||
|
|
||||||
#include "debugger/debuggerconstants.h"
|
|
||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
|
#include <debugger/debuggerconstants.h>
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#ifdef Q_OS_MAC
|
#ifdef Q_OS_MAC
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
|||||||
@@ -34,6 +34,8 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/idocument.h>
|
#include <coreplugin/idocument.h>
|
||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
|
#include <coreplugin/progressmanager/progressmanager.h>
|
||||||
|
|
||||||
#include <languageserverprotocol/completion.h>
|
#include <languageserverprotocol/completion.h>
|
||||||
#include <languageserverprotocol/diagnostics.h>
|
#include <languageserverprotocol/diagnostics.h>
|
||||||
#include <languageserverprotocol/languagefeatures.h>
|
#include <languageserverprotocol/languagefeatures.h>
|
||||||
@@ -41,8 +43,10 @@
|
|||||||
#include <languageserverprotocol/servercapabilities.h>
|
#include <languageserverprotocol/servercapabilities.h>
|
||||||
#include <languageserverprotocol/workspace.h>
|
#include <languageserverprotocol/workspace.h>
|
||||||
#include <languageserverprotocol/progresssupport.h>
|
#include <languageserverprotocol/progresssupport.h>
|
||||||
|
|
||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
|
|
||||||
#include <texteditor/codeassist/documentcontentcompletion.h>
|
#include <texteditor/codeassist/documentcontentcompletion.h>
|
||||||
#include <texteditor/codeassist/iassistprocessor.h>
|
#include <texteditor/codeassist/iassistprocessor.h>
|
||||||
#include <texteditor/ioutlinewidget.h>
|
#include <texteditor/ioutlinewidget.h>
|
||||||
@@ -52,10 +56,10 @@
|
|||||||
#include <texteditor/texteditor.h>
|
#include <texteditor/texteditor.h>
|
||||||
#include <texteditor/texteditoractionhandler.h>
|
#include <texteditor/texteditoractionhandler.h>
|
||||||
#include <texteditor/texteditorsettings.h>
|
#include <texteditor/texteditorsettings.h>
|
||||||
|
|
||||||
#include <utils/mimetypes/mimedatabase.h>
|
#include <utils/mimetypes/mimedatabase.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <coreplugin/progressmanager/progressmanager.h>
|
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QLoggingCategory>
|
#include <QLoggingCategory>
|
||||||
|
|||||||
@@ -35,10 +35,11 @@
|
|||||||
#include <vcsbase/vcsbaseeditor.h>
|
#include <vcsbase/vcsbaseeditor.h>
|
||||||
#include <vcsbase/vcsbaseeditorconfig.h>
|
#include <vcsbase/vcsbaseeditorconfig.h>
|
||||||
#include <vcsbase/vcsbasediffeditorcontroller.h>
|
#include <vcsbase/vcsbasediffeditorcontroller.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -41,11 +41,13 @@
|
|||||||
#include <coreplugin/icore.h>
|
#include <coreplugin/icore.h>
|
||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
#include <coreplugin/locator/commandlocator.h>
|
#include <coreplugin/locator/commandlocator.h>
|
||||||
|
|
||||||
#include <texteditor/textdocument.h>
|
#include <texteditor/textdocument.h>
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/parameteraction.h>
|
#include <utils/parameteraction.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
|
|
||||||
#include <vcsbase/basevcseditorfactory.h>
|
#include <vcsbase/basevcseditorfactory.h>
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|||||||
@@ -37,11 +37,9 @@
|
|||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QBuffer>
|
#include <QBuffer>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
|
|||||||
@@ -40,7 +40,6 @@
|
|||||||
#include <utils/optional.h>
|
#include <utils/optional.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
#include "pythonconstants.h"
|
#include "pythonconstants.h"
|
||||||
|
|
||||||
#include <coreplugin/dialogs/ioptionspage.h>
|
#include <coreplugin/dialogs/ioptionspage.h>
|
||||||
#include "coreplugin/icore.h"
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
#include <utils/listmodel.h>
|
#include <utils/listmodel.h>
|
||||||
#include <utils/layoutbuilder.h>
|
#include <utils/layoutbuilder.h>
|
||||||
#include <utils/pathchooser.h>
|
#include <utils/pathchooser.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/treemodel.h>
|
#include <utils/treemodel.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -48,7 +48,6 @@
|
|||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
|
|||||||
@@ -28,20 +28,22 @@
|
|||||||
#include "subversionplugin.h"
|
#include "subversionplugin.h"
|
||||||
#include "subversionsettings.h"
|
#include "subversionsettings.h"
|
||||||
|
|
||||||
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
|
|
||||||
#include <vcsbase/vcscommand.h>
|
#include <vcsbase/vcscommand.h>
|
||||||
#include <vcsbase/vcsbaseconstants.h>
|
#include <vcsbase/vcsbaseconstants.h>
|
||||||
#include <vcsbase/vcsbasediffeditorcontroller.h>
|
#include <vcsbase/vcsbasediffeditorcontroller.h>
|
||||||
#include <vcsbase/vcsbaseeditor.h>
|
#include <vcsbase/vcsbaseeditor.h>
|
||||||
#include <vcsbase/vcsbaseeditorconfig.h>
|
#include <vcsbase/vcsbaseeditorconfig.h>
|
||||||
#include <vcsbase/vcsbaseplugin.h>
|
#include <vcsbase/vcsbaseplugin.h>
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <diffeditor/diffeditorcontroller.h>
|
#include <diffeditor/diffeditorcontroller.h>
|
||||||
#include <diffeditor/diffutils.h>
|
#include <diffeditor/diffutils.h>
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
|
||||||
|
|
||||||
#include <utils/algorithm.h>
|
#include <utils/algorithm.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
|||||||
@@ -57,8 +57,8 @@
|
|||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
#include <utils/parameteraction.h>
|
#include <utils/parameteraction.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -32,11 +32,11 @@
|
|||||||
#include <coreplugin/messagemanager.h>
|
#include <coreplugin/messagemanager.h>
|
||||||
|
|
||||||
#include <utils/differ.h>
|
#include <utils/differ.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <utils/temporarydirectory.h>
|
#include <utils/temporarydirectory.h>
|
||||||
#include <utils/textutils.h>
|
#include <utils/textutils.h>
|
||||||
#include <utils/qtcassert.h>
|
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
|
|||||||
@@ -31,8 +31,8 @@
|
|||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/hostosinfo.h>
|
#include <utils/hostosinfo.h>
|
||||||
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/stringutils.h>
|
#include <utils/stringutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
|
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <QLatin1String>
|
#include <QLatin1String>
|
||||||
|
|||||||
@@ -36,7 +36,7 @@
|
|||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#include <vcsbase/vcsbaseeditor.h>
|
#include <vcsbase/vcsbaseeditor.h>
|
||||||
#include <vcsbase/vcsoutputwindow.h>
|
#include <vcsbase/vcsoutputwindow.h>
|
||||||
#include <vcsbase/vcsbaseplugin.h>
|
#include <vcsbase/vcsbaseplugin.h>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/id.h>
|
#include <utils/id.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
#include <projectexplorer/project.h>
|
#include <projectexplorer/project.h>
|
||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|||||||
@@ -32,12 +32,6 @@
|
|||||||
#include <utils/environment.h>
|
#include <utils/environment.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
#ifdef Q_CC_MSVC
|
|
||||||
#include <utils/synchronousprocess.h>
|
|
||||||
#endif // Q_CC_MSVC
|
|
||||||
#endif // Q_OS_WIN
|
|
||||||
|
|
||||||
#include <QtTest>
|
#include <QtTest>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
#include <utils/synchronousprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
|
|
||||||
#include <QPlainTextEdit>
|
#include <QPlainTextEdit>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|||||||
Reference in New Issue
Block a user