forked from qt-creator/qt-creator
ProcessInterface: Add done() signal
And get rid of errorOccurred() and finished() signals. Get rid of resultData() accessor, as this data is passed with done() signal. Task-number: QTCREATORBUG-27358 Change-Id: I677bbd174cceea6d8f5a989f961222c417992b60 Reviewed-by: hjk <hjk@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -74,12 +74,12 @@ void StartProcessPacket::doSerialize(QDataStream &stream) const
|
|||||||
|
|
||||||
void StartProcessPacket::doDeserialize(QDataStream &stream)
|
void StartProcessPacket::doDeserialize(QDataStream &stream)
|
||||||
{
|
{
|
||||||
int pm;
|
int processModeInt;
|
||||||
stream >> command
|
stream >> command
|
||||||
>> arguments
|
>> arguments
|
||||||
>> workingDir
|
>> workingDir
|
||||||
>> env
|
>> env
|
||||||
>> pm
|
>> processModeInt
|
||||||
>> writeData
|
>> writeData
|
||||||
>> standardInputFile
|
>> standardInputFile
|
||||||
>> belowNormalPriority
|
>> belowNormalPriority
|
||||||
@@ -87,7 +87,7 @@ void StartProcessPacket::doDeserialize(QDataStream &stream)
|
|||||||
>> lowPriority
|
>> lowPriority
|
||||||
>> unixTerminalDisabled
|
>> unixTerminalDisabled
|
||||||
>> useCtrlCStub;
|
>> useCtrlCStub;
|
||||||
processMode = Utils::ProcessMode(pm);
|
processMode = Utils::ProcessMode(processModeInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -119,9 +119,9 @@ void StopProcessPacket::doSerialize(QDataStream &stream) const
|
|||||||
|
|
||||||
void StopProcessPacket::doDeserialize(QDataStream &stream)
|
void StopProcessPacket::doDeserialize(QDataStream &stream)
|
||||||
{
|
{
|
||||||
int sig;
|
int signalTypeInt;
|
||||||
stream >> sig;
|
stream >> signalTypeInt;
|
||||||
signalType = SignalType(sig);
|
signalType = SignalType(signalTypeInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WritePacket::doSerialize(QDataStream &stream) const
|
void WritePacket::doSerialize(QDataStream &stream) const
|
||||||
@@ -134,25 +134,6 @@ void WritePacket::doDeserialize(QDataStream &stream)
|
|||||||
stream >> inputData;
|
stream >> inputData;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessErrorPacket::ProcessErrorPacket(quintptr token)
|
|
||||||
: LauncherPacket(LauncherPacketType::ProcessError, token)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessErrorPacket::doSerialize(QDataStream &stream) const
|
|
||||||
{
|
|
||||||
stream << static_cast<quint8>(error) << errorString;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessErrorPacket::doDeserialize(QDataStream &stream)
|
|
||||||
{
|
|
||||||
quint8 e;
|
|
||||||
stream >> e;
|
|
||||||
error = static_cast<QProcess::ProcessError>(e);
|
|
||||||
stream >> errorString;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ReadyReadPacket::doSerialize(QDataStream &stream) const
|
void ReadyReadPacket::doSerialize(QDataStream &stream) const
|
||||||
{
|
{
|
||||||
stream << standardChannel;
|
stream << standardChannel;
|
||||||
@@ -164,27 +145,32 @@ void ReadyReadPacket::doDeserialize(QDataStream &stream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ProcessFinishedPacket::ProcessFinishedPacket(quintptr token)
|
ProcessDonePacket::ProcessDonePacket(quintptr token)
|
||||||
: LauncherPacket(LauncherPacketType::ProcessFinished, token)
|
: LauncherPacket(LauncherPacketType::ProcessDone, token)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessFinishedPacket::doSerialize(QDataStream &stream) const
|
void ProcessDonePacket::doSerialize(QDataStream &stream) const
|
||||||
{
|
{
|
||||||
stream << errorString << stdOut << stdErr
|
stream << exitCode
|
||||||
<< static_cast<quint8>(exitStatus) << static_cast<quint8>(error)
|
<< int(exitStatus)
|
||||||
<< exitCode;
|
<< int(error)
|
||||||
|
<< errorString
|
||||||
|
<< stdOut
|
||||||
|
<< stdErr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessFinishedPacket::doDeserialize(QDataStream &stream)
|
void ProcessDonePacket::doDeserialize(QDataStream &stream)
|
||||||
{
|
{
|
||||||
stream >> errorString >> stdOut >> stdErr;
|
int exitStatusInt, errorInt;
|
||||||
quint8 val;
|
stream >> exitCode
|
||||||
stream >> val;
|
>> exitStatusInt
|
||||||
exitStatus = static_cast<QProcess::ExitStatus>(val);
|
>> errorInt
|
||||||
stream >> val;
|
>> errorString
|
||||||
error = static_cast<QProcess::ProcessError>(val);
|
>> stdOut
|
||||||
stream >> exitCode;
|
>> stdErr;
|
||||||
|
exitStatus = QProcess::ExitStatus(exitStatusInt);
|
||||||
|
error = QProcess::ProcessError(errorInt);
|
||||||
}
|
}
|
||||||
|
|
||||||
ShutdownPacket::ShutdownPacket() : LauncherPacket(LauncherPacketType::Shutdown, 0) { }
|
ShutdownPacket::ShutdownPacket() : LauncherPacket(LauncherPacketType::Shutdown, 0) { }
|
||||||
|
|||||||
@@ -45,11 +45,10 @@ enum class LauncherPacketType {
|
|||||||
WriteIntoProcess,
|
WriteIntoProcess,
|
||||||
StopProcess,
|
StopProcess,
|
||||||
// launcher -> client packets:
|
// launcher -> client packets:
|
||||||
ProcessError,
|
|
||||||
ProcessStarted,
|
ProcessStarted,
|
||||||
ReadyReadStandardOutput,
|
ReadyReadStandardOutput,
|
||||||
ReadyReadStandardError,
|
ReadyReadStandardError,
|
||||||
ProcessFinished
|
ProcessDone
|
||||||
};
|
};
|
||||||
|
|
||||||
class PacketParser
|
class PacketParser
|
||||||
@@ -176,19 +175,6 @@ private:
|
|||||||
void doDeserialize(QDataStream &stream) override;
|
void doDeserialize(QDataStream &stream) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProcessErrorPacket : public LauncherPacket
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ProcessErrorPacket(quintptr token);
|
|
||||||
|
|
||||||
QProcess::ProcessError error = QProcess::UnknownError;
|
|
||||||
QString errorString;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void doSerialize(QDataStream &stream) const override;
|
|
||||||
void doDeserialize(QDataStream &stream) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ReadyReadPacket : public LauncherPacket
|
class ReadyReadPacket : public LauncherPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -216,17 +202,18 @@ public:
|
|||||||
: ReadyReadPacket(LauncherPacketType::ReadyReadStandardError, token) { }
|
: ReadyReadPacket(LauncherPacketType::ReadyReadStandardError, token) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProcessFinishedPacket : public LauncherPacket
|
class ProcessDonePacket : public LauncherPacket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ProcessFinishedPacket(quintptr token);
|
ProcessDonePacket(quintptr token);
|
||||||
|
|
||||||
QString errorString;
|
|
||||||
QByteArray stdOut;
|
QByteArray stdOut;
|
||||||
QByteArray stdErr;
|
QByteArray stdErr;
|
||||||
|
|
||||||
|
int exitCode = 0;
|
||||||
QProcess::ExitStatus exitStatus = QProcess::NormalExit;
|
QProcess::ExitStatus exitStatus = QProcess::NormalExit;
|
||||||
QProcess::ProcessError error = QProcess::UnknownError;
|
QProcess::ProcessError error = QProcess::UnknownError;
|
||||||
int exitCode = 0;
|
QString errorString;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void doSerialize(QDataStream &stream) const override;
|
void doSerialize(QDataStream &stream) const override;
|
||||||
|
|||||||
@@ -49,20 +49,6 @@ private:
|
|||||||
const CallerHandle::SignalType m_signalType;
|
const CallerHandle::SignalType m_signalType;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ErrorSignal : public LauncherSignal
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ErrorSignal(QProcess::ProcessError error, const QString &errorString)
|
|
||||||
: LauncherSignal(CallerHandle::SignalType::Error)
|
|
||||||
, m_error(error)
|
|
||||||
, m_errorString(errorString) {}
|
|
||||||
QProcess::ProcessError error() const { return m_error; }
|
|
||||||
QString errorString() const { return m_errorString; }
|
|
||||||
private:
|
|
||||||
const QProcess::ProcessError m_error;
|
|
||||||
const QString m_errorString;
|
|
||||||
};
|
|
||||||
|
|
||||||
class StartedSignal : public LauncherSignal
|
class StartedSignal : public LauncherSignal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -92,19 +78,15 @@ private:
|
|||||||
QByteArray m_stdErr;
|
QByteArray m_stdErr;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FinishedSignal : public LauncherSignal
|
class DoneSignal : public LauncherSignal
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FinishedSignal(QProcess::ExitStatus exitStatus,
|
DoneSignal(const ProcessResultData &resultData)
|
||||||
int exitCode)
|
: LauncherSignal(CallerHandle::SignalType::Done)
|
||||||
: LauncherSignal(CallerHandle::SignalType::Finished)
|
, m_resultData(resultData) {}
|
||||||
, m_exitStatus(exitStatus)
|
ProcessResultData resultData() const { return m_resultData; }
|
||||||
, m_exitCode(exitCode) {}
|
|
||||||
QProcess::ExitStatus exitStatus() const { return m_exitStatus; }
|
|
||||||
int exitCode() const { return m_exitCode; }
|
|
||||||
private:
|
private:
|
||||||
const QProcess::ExitStatus m_exitStatus;
|
const ProcessResultData m_resultData;
|
||||||
const int m_exitCode;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
CallerHandle::~CallerHandle()
|
CallerHandle::~CallerHandle()
|
||||||
@@ -124,38 +106,28 @@ bool CallerHandle::waitForReadyRead(int msces)
|
|||||||
|
|
||||||
bool CallerHandle::waitForFinished(int msecs)
|
bool CallerHandle::waitForFinished(int msecs)
|
||||||
{
|
{
|
||||||
return waitForSignal(msecs, SignalType::Finished);
|
return waitForSignal(msecs, SignalType::Done);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<CallerHandle::SignalType> CallerHandle::flush()
|
void CallerHandle::flush()
|
||||||
{
|
{
|
||||||
return flushFor(SignalType::NoSignal);
|
flushFor(SignalType::NoSignal);
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<CallerHandle::SignalType> CallerHandle::flushFor(SignalType signalType)
|
bool CallerHandle::flushFor(SignalType signalType)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromCallersThread(), return {});
|
QTC_ASSERT(isCalledFromCallersThread(), return {});
|
||||||
QList<LauncherSignal *> oldSignals;
|
QList<LauncherSignal *> oldSignals;
|
||||||
QList<SignalType> flushedSignals;
|
QList<SignalType> flushedSignals;
|
||||||
{
|
{
|
||||||
// 1. If signalType is no signal - flush all
|
|
||||||
// 2. Flush all if we have any error
|
|
||||||
// 3. If we are flushing for Finished or ReadyRead, flush all, too
|
|
||||||
// 4. If we are flushing for Started, flush Started only
|
|
||||||
|
|
||||||
// In short: only when we are flushing for Started, flush started only signal,
|
|
||||||
// otherwise flush always all. (note: we can't flush for Error, since we don't have
|
|
||||||
// waitForError() method).
|
|
||||||
|
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
|
|
||||||
const QList<SignalType> storedSignals =
|
const QList<SignalType> storedSignals =
|
||||||
Utils::transform(qAsConst(m_signals), [](const LauncherSignal *launcherSignal) {
|
Utils::transform(qAsConst(m_signals), [](const LauncherSignal *launcherSignal) {
|
||||||
return launcherSignal->signalType();
|
return launcherSignal->signalType();
|
||||||
});
|
});
|
||||||
|
|
||||||
const bool flushAll = (signalType != SignalType::Started)
|
// If we are flushing for Started, flush Started only
|
||||||
|| storedSignals.contains(SignalType::Error);
|
const bool flushAll = (signalType != SignalType::Started);
|
||||||
if (flushAll) {
|
if (flushAll) {
|
||||||
oldSignals = m_signals;
|
oldSignals = m_signals;
|
||||||
m_signals = {};
|
m_signals = {};
|
||||||
@@ -169,27 +141,28 @@ QList<CallerHandle::SignalType> CallerHandle::flushFor(SignalType signalType)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
bool signalMatched = false;
|
||||||
for (const LauncherSignal *storedSignal : qAsConst(oldSignals)) {
|
for (const LauncherSignal *storedSignal : qAsConst(oldSignals)) {
|
||||||
const SignalType storedSignalType = storedSignal->signalType();
|
const SignalType storedSignalType = storedSignal->signalType();
|
||||||
|
if (storedSignalType == signalType)
|
||||||
|
signalMatched = true;
|
||||||
switch (storedSignalType) {
|
switch (storedSignalType) {
|
||||||
case SignalType::NoSignal:
|
case SignalType::NoSignal:
|
||||||
break;
|
break;
|
||||||
case SignalType::Error:
|
|
||||||
handleError(static_cast<const ErrorSignal *>(storedSignal));
|
|
||||||
break;
|
|
||||||
case SignalType::Started:
|
case SignalType::Started:
|
||||||
handleStarted(static_cast<const StartedSignal *>(storedSignal));
|
handleStarted(static_cast<const StartedSignal *>(storedSignal));
|
||||||
break;
|
break;
|
||||||
case SignalType::ReadyRead:
|
case SignalType::ReadyRead:
|
||||||
handleReadyRead(static_cast<const ReadyReadSignal *>(storedSignal));
|
handleReadyRead(static_cast<const ReadyReadSignal *>(storedSignal));
|
||||||
break;
|
break;
|
||||||
case SignalType::Finished:
|
case SignalType::Done:
|
||||||
handleFinished(static_cast<const FinishedSignal *>(storedSignal));
|
signalMatched = true;
|
||||||
|
handleDone(static_cast<const DoneSignal *>(storedSignal));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
delete storedSignal;
|
delete storedSignal;
|
||||||
}
|
}
|
||||||
return flushedSignals;
|
return signalMatched;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from caller's thread exclusively.
|
// Called from caller's thread exclusively.
|
||||||
@@ -200,18 +173,6 @@ bool CallerHandle::shouldFlush() const
|
|||||||
return !m_signals.isEmpty();
|
return !m_signals.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallerHandle::handleError(const ErrorSignal *launcherSignal)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(isCalledFromCallersThread(), return);
|
|
||||||
m_processState = QProcess::NotRunning;
|
|
||||||
m_result.m_error = launcherSignal->error();
|
|
||||||
if (!launcherSignal->errorString().isEmpty())
|
|
||||||
m_result.m_errorString = launcherSignal->errorString();
|
|
||||||
if (m_result.m_error == QProcess::FailedToStart)
|
|
||||||
m_result.m_exitCode = 255; // This code is being returned by QProcess when FailedToStart error occurred
|
|
||||||
emit errorOccurred(m_result.m_error);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CallerHandle::handleStarted(const StartedSignal *launcherSignal)
|
void CallerHandle::handleStarted(const StartedSignal *launcherSignal)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromCallersThread(), return);
|
QTC_ASSERT(isCalledFromCallersThread(), return);
|
||||||
@@ -248,13 +209,11 @@ void CallerHandle::handleReadyRead(const ReadyReadSignal *launcherSignal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CallerHandle::handleFinished(const FinishedSignal *launcherSignal)
|
void CallerHandle::handleDone(const DoneSignal *launcherSignal)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromCallersThread(), return);
|
QTC_ASSERT(isCalledFromCallersThread(), return);
|
||||||
m_processState = QProcess::NotRunning;
|
m_processState = QProcess::NotRunning;
|
||||||
m_result.m_exitStatus = launcherSignal->exitStatus();
|
emit done(launcherSignal->resultData());
|
||||||
m_result.m_exitCode = launcherSignal->exitCode();
|
|
||||||
emit finished();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from launcher's thread exclusively.
|
// Called from launcher's thread exclusively.
|
||||||
@@ -276,19 +235,9 @@ void CallerHandle::appendSignal(LauncherSignal *newSignal)
|
|||||||
if (!m_signals.isEmpty()) {
|
if (!m_signals.isEmpty()) {
|
||||||
LauncherSignal *lastSignal = m_signals.last();
|
LauncherSignal *lastSignal = m_signals.last();
|
||||||
|
|
||||||
QTC_ASSERT(lastSignal->signalType() != SignalType::Finished,
|
QTC_ASSERT(lastSignal->signalType() != SignalType::Done,
|
||||||
qWarning() << "Buffering new signal for process" << m_command
|
qWarning() << "Buffering new signal for process" << m_command
|
||||||
<< "while the last finished() signal wasn't flushed yet.");
|
<< "while the last done() signal wasn't flushed yet.");
|
||||||
|
|
||||||
if (lastSignal->signalType() == SignalType::Error) {
|
|
||||||
ErrorSignal *lastError = static_cast<ErrorSignal *>(lastSignal);
|
|
||||||
QTC_ASSERT(lastError->error() != QProcess::FailedToStart,
|
|
||||||
qWarning() << "Buffering new signal for process" << m_command
|
|
||||||
<< "while the last FailedToStart error signal wasn't flushed yet.");
|
|
||||||
QTC_ASSERT(newSignal->signalType() == SignalType::Finished,
|
|
||||||
qWarning() << "Buffering non finished signal for process" << m_command
|
|
||||||
<< "while the last buffered signal was an error.");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Merge ReadyRead signals into one.
|
// Merge ReadyRead signals into one.
|
||||||
if (lastSignal->signalType() == SignalType::ReadyRead
|
if (lastSignal->signalType() == SignalType::ReadyRead
|
||||||
@@ -329,13 +278,13 @@ void CallerHandle::sendStopPacket(StopProcessPacket::SignalType signalType)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_processState.store(QProcess::NotRunning);
|
m_processState.store(QProcess::NotRunning);
|
||||||
m_result.m_errorString = QCoreApplication::translate("Utils::LauncherHandle",
|
const QString errorString = QCoreApplication::translate("Utils::LauncherHandle",
|
||||||
"Process was canceled before it was started.");
|
"Process was canceled before it was started.");
|
||||||
m_result.m_error = QProcess::FailedToStart;
|
const ProcessResultData result = { 0, QProcess::NormalExit, QProcess::FailedToStart,
|
||||||
emit errorOccurred(m_result.m_error);
|
errorString };
|
||||||
|
emit done(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CallerHandle::terminate()
|
void CallerHandle::terminate()
|
||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromCallersThread(), return);
|
QTC_ASSERT(isCalledFromCallersThread(), return);
|
||||||
@@ -366,24 +315,15 @@ qint64 CallerHandle::processId() const
|
|||||||
return m_processId;
|
return m_processId;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessResultData CallerHandle::resultData() const
|
|
||||||
{
|
|
||||||
QTC_ASSERT(isCalledFromCallersThread(), return {});
|
|
||||||
return m_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CallerHandle::setErrorString(const QString &str)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(isCalledFromCallersThread(), return);
|
|
||||||
m_result.m_errorString = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CallerHandle::start(const QString &program, const QStringList &arguments)
|
void CallerHandle::start(const QString &program, const QStringList &arguments)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromCallersThread(), return);
|
QTC_ASSERT(isCalledFromCallersThread(), return);
|
||||||
if (!m_launcherHandle || m_launcherHandle->isSocketError()) {
|
if (!m_launcherHandle || m_launcherHandle->isSocketError()) {
|
||||||
m_result.m_error = QProcess::FailedToStart;
|
const QString errorString = QCoreApplication::translate("Utils::LauncherHandle",
|
||||||
emit errorOccurred(m_result.m_error);
|
"Process launcher socket error.");
|
||||||
|
const ProcessResultData result = { 0, QProcess::NormalExit, QProcess::FailedToStart,
|
||||||
|
errorString };
|
||||||
|
emit done(result);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -492,7 +432,7 @@ bool CallerHandle::canWaitFor(SignalType newSignal) const
|
|||||||
case SignalType::Started:
|
case SignalType::Started:
|
||||||
return m_processState == QProcess::Starting;
|
return m_processState == QProcess::Starting;
|
||||||
case SignalType::ReadyRead:
|
case SignalType::ReadyRead:
|
||||||
case SignalType::Finished:
|
case SignalType::Done:
|
||||||
return m_processState != QProcess::NotRunning;
|
return m_processState != QProcess::NotRunning;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -524,16 +464,10 @@ bool LauncherHandle::waitForSignal(int msecs, CallerHandle::SignalType newSignal
|
|||||||
break;
|
break;
|
||||||
if (!doWaitForSignal(deadline, newSignal))
|
if (!doWaitForSignal(deadline, newSignal))
|
||||||
break;
|
break;
|
||||||
const QList<CallerHandle::SignalType> flushedSignals = m_callerHandle->flushFor(newSignal);
|
// Matching (or Done) signal was flushed
|
||||||
const bool errorOccurred = flushedSignals.contains(CallerHandle::SignalType::Error);
|
if (m_callerHandle->flushFor(newSignal))
|
||||||
if (errorOccurred)
|
|
||||||
return true; // apparently QProcess behaves like this in case of error
|
|
||||||
const bool newSignalFlushed = flushedSignals.contains(newSignal);
|
|
||||||
if (newSignalFlushed) // so we don't continue waiting
|
|
||||||
return true;
|
return true;
|
||||||
const bool finishedSignalFlushed = flushedSignals.contains(CallerHandle::SignalType::Finished);
|
// Otherwise continue awaiting (e.g. when ReadyRead came while waitForFinished())
|
||||||
if (finishedSignalFlushed)
|
|
||||||
return true; // finish has appeared but we were waiting for other signal
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -557,30 +491,6 @@ bool LauncherHandle::doWaitForSignal(QDeadlineTimer deadline, CallerHandle::Sign
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called from launcher's thread exclusively. Call me with mutex locked.
|
|
||||||
void LauncherHandle::wakeUpIfWaitingFor(CallerHandle::SignalType newSignal)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
|
||||||
// TODO: should we always wake up in case m_waitingFor != NoSignal?
|
|
||||||
// The matching signal came
|
|
||||||
const bool signalMatched = (m_waitingFor == newSignal);
|
|
||||||
// E.g. if we are waiting for ReadyRead and we got Finished or Error signal instead -> wake it, too.
|
|
||||||
const bool finishedOrErrorWhileWaiting =
|
|
||||||
(m_waitingFor != CallerHandle::SignalType::NoSignal)
|
|
||||||
&& ((newSignal == CallerHandle::SignalType::Finished) || (newSignal == CallerHandle::SignalType::Error));
|
|
||||||
// Wake up, flush and continue waiting.
|
|
||||||
// E.g. when being in waitingForFinished() state and Started or ReadyRead signal came.
|
|
||||||
const bool continueWaitingAfterFlushing =
|
|
||||||
((m_waitingFor == CallerHandle::SignalType::Finished) && (newSignal != CallerHandle::SignalType::Finished))
|
|
||||||
|| ((m_waitingFor == CallerHandle::SignalType::ReadyRead) && (newSignal == CallerHandle::SignalType::Started));
|
|
||||||
const bool shouldWake = signalMatched
|
|
||||||
|| finishedOrErrorWhileWaiting
|
|
||||||
|| continueWaitingAfterFlushing;
|
|
||||||
|
|
||||||
if (shouldWake)
|
|
||||||
m_waitCondition.wakeOne();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Called from launcher's thread exclusively. Call me with mutex locked.
|
// Called from launcher's thread exclusively. Call me with mutex locked.
|
||||||
void LauncherHandle::flushCaller()
|
void LauncherHandle::flushCaller()
|
||||||
{
|
{
|
||||||
@@ -588,6 +498,8 @@ void LauncherHandle::flushCaller()
|
|||||||
if (!m_callerHandle)
|
if (!m_callerHandle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
m_waitCondition.wakeOne();
|
||||||
|
|
||||||
// call in callers thread
|
// call in callers thread
|
||||||
QMetaObject::invokeMethod(m_callerHandle, &CallerHandle::flush);
|
QMetaObject::invokeMethod(m_callerHandle, &CallerHandle::flush);
|
||||||
}
|
}
|
||||||
@@ -596,9 +508,6 @@ void LauncherHandle::handlePacket(LauncherPacketType type, const QByteArray &pay
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case LauncherPacketType::ProcessError:
|
|
||||||
handleErrorPacket(payload);
|
|
||||||
break;
|
|
||||||
case LauncherPacketType::ProcessStarted:
|
case LauncherPacketType::ProcessStarted:
|
||||||
handleStartedPacket(payload);
|
handleStartedPacket(payload);
|
||||||
break;
|
break;
|
||||||
@@ -608,32 +517,18 @@ void LauncherHandle::handlePacket(LauncherPacketType type, const QByteArray &pay
|
|||||||
case LauncherPacketType::ReadyReadStandardError:
|
case LauncherPacketType::ReadyReadStandardError:
|
||||||
handleReadyReadStandardError(payload);
|
handleReadyReadStandardError(payload);
|
||||||
break;
|
break;
|
||||||
case LauncherPacketType::ProcessFinished:
|
case LauncherPacketType::ProcessDone:
|
||||||
handleFinishedPacket(payload);
|
handleDonePacket(payload);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
QTC_ASSERT(false, break);
|
QTC_ASSERT(false, break);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherHandle::handleErrorPacket(const QByteArray &packetData)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
|
||||||
QMutexLocker locker(&m_mutex);
|
|
||||||
wakeUpIfWaitingFor(CallerHandle::SignalType::Error);
|
|
||||||
if (!m_callerHandle)
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto packet = LauncherPacket::extractPacket<ProcessErrorPacket>(m_token, packetData);
|
|
||||||
m_callerHandle->appendSignal(new ErrorSignal(packet.error, packet.errorString));
|
|
||||||
flushCaller();
|
|
||||||
}
|
|
||||||
|
|
||||||
void LauncherHandle::handleStartedPacket(const QByteArray &packetData)
|
void LauncherHandle::handleStartedPacket(const QByteArray &packetData)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
wakeUpIfWaitingFor(CallerHandle::SignalType::Started);
|
|
||||||
if (!m_callerHandle)
|
if (!m_callerHandle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -646,7 +541,6 @@ void LauncherHandle::handleReadyReadStandardOutput(const QByteArray &packetData)
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
wakeUpIfWaitingFor(CallerHandle::SignalType::ReadyRead);
|
|
||||||
if (!m_callerHandle)
|
if (!m_callerHandle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -662,7 +556,6 @@ void LauncherHandle::handleReadyReadStandardError(const QByteArray &packetData)
|
|||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
wakeUpIfWaitingFor(CallerHandle::SignalType::ReadyRead);
|
|
||||||
if (!m_callerHandle)
|
if (!m_callerHandle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -674,27 +567,22 @@ void LauncherHandle::handleReadyReadStandardError(const QByteArray &packetData)
|
|||||||
flushCaller();
|
flushCaller();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherHandle::handleFinishedPacket(const QByteArray &packetData)
|
void LauncherHandle::handleDonePacket(const QByteArray &packetData)
|
||||||
{
|
{
|
||||||
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
wakeUpIfWaitingFor(CallerHandle::SignalType::Finished);
|
|
||||||
if (!m_callerHandle)
|
if (!m_callerHandle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const auto packet = LauncherPacket::extractPacket<ProcessFinishedPacket>(m_token, packetData);
|
const auto packet = LauncherPacket::extractPacket<ProcessDonePacket>(m_token, packetData);
|
||||||
const QByteArray stdOut = packet.stdOut;
|
const QByteArray stdOut = packet.stdOut;
|
||||||
const QByteArray stdErr = packet.stdErr;
|
const QByteArray stdErr = packet.stdErr;
|
||||||
const QProcess::ProcessError error = packet.error;
|
const ProcessResultData result = { packet.exitCode, packet.exitStatus,
|
||||||
const QString errorString = packet.errorString;
|
packet.error, packet.errorString };
|
||||||
|
|
||||||
// We assume that if error is UnknownError, everything went fine.
|
|
||||||
// By default QProcess returns "Unknown error" for errorString()
|
|
||||||
if (error != QProcess::UnknownError)
|
|
||||||
m_callerHandle->appendSignal(new ErrorSignal(error, errorString));
|
|
||||||
if (!stdOut.isEmpty() || !stdErr.isEmpty())
|
if (!stdOut.isEmpty() || !stdErr.isEmpty())
|
||||||
m_callerHandle->appendSignal(new ReadyReadSignal(stdOut, stdErr));
|
m_callerHandle->appendSignal(new ReadyReadSignal(stdOut, stdErr));
|
||||||
m_callerHandle->appendSignal(new FinishedSignal(packet.exitStatus, packet.exitCode));
|
m_callerHandle->appendSignal(new DoneSignal(result));
|
||||||
flushCaller();
|
flushCaller();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -712,13 +600,15 @@ void LauncherHandle::handleSocketError(const QString &message)
|
|||||||
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
QTC_ASSERT(isCalledFromLaunchersThread(), return);
|
||||||
m_socketError = true; // TODO: ???
|
m_socketError = true; // TODO: ???
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
wakeUpIfWaitingFor(CallerHandle::SignalType::Error);
|
|
||||||
if (!m_callerHandle)
|
if (!m_callerHandle)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// TODO: FailedToStart may be wrong in case process has already started
|
||||||
const QString errorString = QCoreApplication::translate("Utils::QtcProcess",
|
const QString errorString = QCoreApplication::translate("Utils::QtcProcess",
|
||||||
"Internal socket error: %1").arg(message);
|
"Internal socket error: %1").arg(message);
|
||||||
m_callerHandle->appendSignal(new ErrorSignal(QProcess::FailedToStart, errorString));
|
const ProcessResultData result = { 0, QProcess::NormalExit, QProcess::FailedToStart,
|
||||||
|
errorString };
|
||||||
|
m_callerHandle->appendSignal(new DoneSignal(result));
|
||||||
flushCaller();
|
flushCaller();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -874,11 +764,10 @@ void LauncherSocket::handleSocketDataAvailable()
|
|||||||
LauncherHandle *handle = handleForToken(m_packetParser.token());
|
LauncherHandle *handle = handleForToken(m_packetParser.token());
|
||||||
if (handle) {
|
if (handle) {
|
||||||
switch (m_packetParser.type()) {
|
switch (m_packetParser.type()) {
|
||||||
case LauncherPacketType::ProcessError:
|
|
||||||
case LauncherPacketType::ProcessStarted:
|
case LauncherPacketType::ProcessStarted:
|
||||||
case LauncherPacketType::ReadyReadStandardOutput:
|
case LauncherPacketType::ReadyReadStandardOutput:
|
||||||
case LauncherPacketType::ReadyReadStandardError:
|
case LauncherPacketType::ReadyReadStandardError:
|
||||||
case LauncherPacketType::ProcessFinished:
|
case LauncherPacketType::ProcessDone:
|
||||||
handle->handlePacket(m_packetParser.type(), m_packetParser.packetData());
|
handle->handlePacket(m_packetParser.type(), m_packetParser.packetData());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
|||||||
@@ -51,10 +51,9 @@ namespace Internal {
|
|||||||
class LauncherInterfacePrivate;
|
class LauncherInterfacePrivate;
|
||||||
class LauncherHandle;
|
class LauncherHandle;
|
||||||
class LauncherSignal;
|
class LauncherSignal;
|
||||||
class ErrorSignal;
|
|
||||||
class StartedSignal;
|
class StartedSignal;
|
||||||
class ReadyReadSignal;
|
class ReadyReadSignal;
|
||||||
class FinishedSignal;
|
class DoneSignal;
|
||||||
|
|
||||||
// All the methods and data fields in this class are called / accessed from the caller's thread.
|
// All the methods and data fields in this class are called / accessed from the caller's thread.
|
||||||
// Exceptions are explicitly marked.
|
// Exceptions are explicitly marked.
|
||||||
@@ -64,10 +63,9 @@ class CallerHandle : public QObject
|
|||||||
public:
|
public:
|
||||||
enum class SignalType {
|
enum class SignalType {
|
||||||
NoSignal,
|
NoSignal,
|
||||||
Error,
|
|
||||||
Started,
|
Started,
|
||||||
ReadyRead,
|
ReadyRead,
|
||||||
Finished
|
Done
|
||||||
};
|
};
|
||||||
Q_ENUM(SignalType)
|
Q_ENUM(SignalType)
|
||||||
CallerHandle(QObject *parent, quintptr token)
|
CallerHandle(QObject *parent, quintptr token)
|
||||||
@@ -82,8 +80,8 @@ public:
|
|||||||
bool waitForFinished(int msecs);
|
bool waitForFinished(int msecs);
|
||||||
|
|
||||||
// Returns the list of flushed signals.
|
// Returns the list of flushed signals.
|
||||||
QList<SignalType> flush();
|
void flush();
|
||||||
QList<SignalType> flushFor(SignalType signalType);
|
bool flushFor(SignalType signalType);
|
||||||
bool shouldFlush() const;
|
bool shouldFlush() const;
|
||||||
// Called from launcher's thread exclusively.
|
// Called from launcher's thread exclusively.
|
||||||
void appendSignal(LauncherSignal *launcherSignal);
|
void appendSignal(LauncherSignal *launcherSignal);
|
||||||
@@ -99,9 +97,6 @@ public:
|
|||||||
QByteArray readAllStandardError();
|
QByteArray readAllStandardError();
|
||||||
|
|
||||||
qint64 processId() const;
|
qint64 processId() const;
|
||||||
ProcessResultData resultData() const;
|
|
||||||
|
|
||||||
void setErrorString(const QString &str);
|
|
||||||
|
|
||||||
void start(const QString &program, const QStringList &arguments);
|
void start(const QString &program, const QStringList &arguments);
|
||||||
// Called from caller's or launcher's thread.
|
// Called from caller's or launcher's thread.
|
||||||
@@ -116,9 +111,8 @@ public:
|
|||||||
void setProcessSetupData(const ProcessSetupData::Ptr &setup);
|
void setProcessSetupData(const ProcessSetupData::Ptr &setup);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void errorOccurred(QProcess::ProcessError error);
|
|
||||||
void started();
|
void started();
|
||||||
void finished();
|
void done(const Utils::ProcessResultData &resultData);
|
||||||
void readyReadStandardOutput();
|
void readyReadStandardOutput();
|
||||||
void readyReadStandardError();
|
void readyReadStandardError();
|
||||||
|
|
||||||
@@ -142,10 +136,9 @@ private:
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void handleError(const ErrorSignal *launcherSignal);
|
|
||||||
void handleStarted(const StartedSignal *launcherSignal);
|
void handleStarted(const StartedSignal *launcherSignal);
|
||||||
void handleReadyRead(const ReadyReadSignal *launcherSignal);
|
void handleReadyRead(const ReadyReadSignal *launcherSignal);
|
||||||
void handleFinished(const FinishedSignal *launcherSignal);
|
void handleDone(const DoneSignal *launcherSignal);
|
||||||
|
|
||||||
// Lives in launcher's thread. Modified from caller's thread.
|
// Lives in launcher's thread. Modified from caller's thread.
|
||||||
LauncherHandle *m_launcherHandle = nullptr;
|
LauncherHandle *m_launcherHandle = nullptr;
|
||||||
@@ -162,7 +155,6 @@ private:
|
|||||||
int m_processId = 0;
|
int m_processId = 0;
|
||||||
QByteArray m_stdout;
|
QByteArray m_stdout;
|
||||||
QByteArray m_stderr;
|
QByteArray m_stderr;
|
||||||
ProcessResultData m_result;
|
|
||||||
|
|
||||||
QString m_command;
|
QString m_command;
|
||||||
QStringList m_arguments;
|
QStringList m_arguments;
|
||||||
@@ -195,17 +187,13 @@ public:
|
|||||||
private:
|
private:
|
||||||
// Called from caller's thread exclusively.
|
// Called from caller's thread exclusively.
|
||||||
bool doWaitForSignal(QDeadlineTimer deadline, CallerHandle::SignalType newSignal);
|
bool doWaitForSignal(QDeadlineTimer deadline, CallerHandle::SignalType newSignal);
|
||||||
// Called from launcher's thread exclusively. Call me with mutex locked.
|
|
||||||
void wakeUpIfWaitingFor(CallerHandle::SignalType newSignal);
|
|
||||||
|
|
||||||
// Called from launcher's thread exclusively. Call me with mutex locked.
|
// Called from launcher's thread exclusively. Call me with mutex locked.
|
||||||
void flushCaller();
|
void flushCaller();
|
||||||
// Called from launcher's thread exclusively.
|
// Called from launcher's thread exclusively.
|
||||||
void handleErrorPacket(const QByteArray &packetData);
|
|
||||||
void handleStartedPacket(const QByteArray &packetData);
|
void handleStartedPacket(const QByteArray &packetData);
|
||||||
void handleReadyReadStandardOutput(const QByteArray &packetData);
|
void handleReadyReadStandardOutput(const QByteArray &packetData);
|
||||||
void handleReadyReadStandardError(const QByteArray &packetData);
|
void handleReadyReadStandardError(const QByteArray &packetData);
|
||||||
void handleFinishedPacket(const QByteArray &packetData);
|
void handleDonePacket(const QByteArray &packetData);
|
||||||
|
|
||||||
// Called from caller's or launcher's thread.
|
// Called from caller's or launcher's thread.
|
||||||
bool isCalledFromLaunchersThread() const;
|
bool isCalledFromLaunchersThread() const;
|
||||||
|
|||||||
@@ -93,8 +93,6 @@ public:
|
|||||||
virtual qint64 processId() const = 0;
|
virtual qint64 processId() const = 0;
|
||||||
virtual QProcess::ProcessState state() const = 0;
|
virtual QProcess::ProcessState state() const = 0;
|
||||||
|
|
||||||
virtual ProcessResultData resultData() const = 0;
|
|
||||||
|
|
||||||
virtual bool waitForStarted(int msecs) = 0;
|
virtual bool waitForStarted(int msecs) = 0;
|
||||||
virtual bool waitForReadyRead(int msecs) = 0;
|
virtual bool waitForReadyRead(int msecs) = 0;
|
||||||
virtual bool waitForFinished(int msecs) = 0;
|
virtual bool waitForFinished(int msecs) = 0;
|
||||||
@@ -104,8 +102,7 @@ public:
|
|||||||
|
|
||||||
signals:
|
signals:
|
||||||
void started();
|
void started();
|
||||||
void finished();
|
void done(const Utils::ProcessResultData &resultData);
|
||||||
void errorOccurred(QProcess::ProcessError error);
|
|
||||||
void readyReadStandardOutput();
|
void readyReadStandardOutput();
|
||||||
void readyReadStandardError();
|
void readyReadStandardError();
|
||||||
|
|
||||||
@@ -126,8 +123,7 @@ public:
|
|||||||
{
|
{
|
||||||
m_target->setParent(this);
|
m_target->setParent(this);
|
||||||
connect(m_target, &ProcessInterface::started, this, &ProcessInterface::started);
|
connect(m_target, &ProcessInterface::started, this, &ProcessInterface::started);
|
||||||
connect(m_target, &ProcessInterface::finished, this, &ProcessInterface::finished);
|
connect(m_target, &ProcessInterface::done, this, &ProcessInterface::done);
|
||||||
connect(m_target, &ProcessInterface::errorOccurred, this, &ProcessInterface::errorOccurred);
|
|
||||||
connect(m_target, &ProcessInterface::readyReadStandardOutput,
|
connect(m_target, &ProcessInterface::readyReadStandardOutput,
|
||||||
this, &ProcessInterface::readyReadStandardOutput);
|
this, &ProcessInterface::readyReadStandardOutput);
|
||||||
connect(m_target, &ProcessInterface::readyReadStandardError,
|
connect(m_target, &ProcessInterface::readyReadStandardError,
|
||||||
@@ -147,8 +143,6 @@ public:
|
|||||||
qint64 processId() const override { return m_target->processId(); }
|
qint64 processId() const override { return m_target->processId(); }
|
||||||
QProcess::ProcessState state() const override { return m_target->state(); }
|
QProcess::ProcessState state() const override { return m_target->state(); }
|
||||||
|
|
||||||
ProcessResultData resultData() const override { return m_target->resultData(); };
|
|
||||||
|
|
||||||
bool waitForStarted(int msecs) override { return m_target->waitForStarted(msecs); }
|
bool waitForStarted(int msecs) override { return m_target->waitForStarted(msecs); }
|
||||||
bool waitForReadyRead(int msecs) override { return m_target->waitForReadyRead(msecs); }
|
bool waitForReadyRead(int msecs) override { return m_target->waitForReadyRead(msecs); }
|
||||||
bool waitForFinished(int msecs) override { return m_target->waitForFinished(msecs); }
|
bool waitForFinished(int msecs) override { return m_target->waitForFinished(msecs); }
|
||||||
|
|||||||
@@ -221,7 +221,6 @@ protected:
|
|||||||
void defaultStart();
|
void defaultStart();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void setErrorString(const QString &str) = 0;
|
|
||||||
virtual void doDefaultStart(const QString &program, const QStringList &arguments) = 0;
|
virtual void doDefaultStart(const QString &program, const QStringList &arguments) = 0;
|
||||||
bool dissolveCommand(QString *program, QStringList *arguments);
|
bool dissolveCommand(QString *program, QStringList *arguments);
|
||||||
bool ensureProgramExists(const QString &program);
|
bool ensureProgramExists(const QString &program);
|
||||||
@@ -290,9 +289,9 @@ bool DefaultImpl::dissolveCommand(QString *program, QStringList *arguments)
|
|||||||
*arguments = QStringList();
|
*arguments = QStringList();
|
||||||
} else {
|
} else {
|
||||||
if (!success) {
|
if (!success) {
|
||||||
setErrorString(tr("Error in command line."));
|
const ProcessResultData result = { 0, QProcess::NormalExit, QProcess::FailedToStart,
|
||||||
// TODO: in fact it's WrongArgumentsFailure
|
tr("Error in command line.") };
|
||||||
emit errorOccurred(QProcess::FailedToStart);
|
emit done(result);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
*arguments = processArgs.toUnixArgs();
|
*arguments = processArgs.toUnixArgs();
|
||||||
@@ -319,9 +318,11 @@ bool DefaultImpl::ensureProgramExists(const QString &program)
|
|||||||
if (programFilePath.exists() && programFilePath.isExecutableFile())
|
if (programFilePath.exists() && programFilePath.isExecutableFile())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
setErrorString(QLatin1String("The program \"%1\" does not exist or is not executable.")
|
const QString errorString = tr("The program \"%1\" does not exist or is not executable.")
|
||||||
.arg(program));
|
.arg(program);
|
||||||
emit errorOccurred(QProcess::FailedToStart);
|
const ProcessResultData result = { 0, QProcess::NormalExit, QProcess::FailedToStart,
|
||||||
|
errorString };
|
||||||
|
emit done(result);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,9 +334,9 @@ public:
|
|||||||
connect(m_process, &QProcess::started,
|
connect(m_process, &QProcess::started,
|
||||||
this, &QProcessImpl::handleStarted);
|
this, &QProcessImpl::handleStarted);
|
||||||
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||||
this, &ProcessInterface::finished);
|
this, &QProcessImpl::handleFinished);
|
||||||
connect(m_process, &QProcess::errorOccurred,
|
connect(m_process, &QProcess::errorOccurred,
|
||||||
this, &ProcessInterface::errorOccurred);
|
this, &QProcessImpl::handleError);
|
||||||
connect(m_process, &QProcess::readyReadStandardOutput,
|
connect(m_process, &QProcess::readyReadStandardOutput,
|
||||||
this, &ProcessInterface::readyReadStandardOutput);
|
this, &ProcessInterface::readyReadStandardOutput);
|
||||||
connect(m_process, &QProcess::readyReadStandardError,
|
connect(m_process, &QProcess::readyReadStandardError,
|
||||||
@@ -352,12 +353,6 @@ public:
|
|||||||
void close() final { m_process->close(); }
|
void close() final { m_process->close(); }
|
||||||
qint64 write(const QByteArray &data) final { return m_process->write(data); }
|
qint64 write(const QByteArray &data) final { return m_process->write(data); }
|
||||||
|
|
||||||
ProcessResultData resultData() const final {
|
|
||||||
return { m_process->exitCode(), m_process->exitStatus(),
|
|
||||||
m_process->error(), m_process->errorString() };
|
|
||||||
};
|
|
||||||
void setErrorString(const QString &str) final { m_process->setErrorString(str); }
|
|
||||||
|
|
||||||
QProcess::ProcessState state() const final { return m_process->state(); }
|
QProcess::ProcessState state() const final { return m_process->state(); }
|
||||||
qint64 processId() const final { return m_process->processId(); }
|
qint64 processId() const final { return m_process->processId(); }
|
||||||
|
|
||||||
@@ -392,6 +387,23 @@ private:
|
|||||||
m_process->processStartHandler()->handleProcessStarted();
|
m_process->processStartHandler()->handleProcessStarted();
|
||||||
emit started();
|
emit started();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void handleError(QProcess::ProcessError error)
|
||||||
|
{
|
||||||
|
if (error != QProcess::FailedToStart)
|
||||||
|
return;
|
||||||
|
const ProcessResultData result = { m_process->exitCode(), m_process->exitStatus(),
|
||||||
|
error, m_process->errorString() };
|
||||||
|
emit done(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
|
{
|
||||||
|
const ProcessResultData result = { exitCode, exitStatus,
|
||||||
|
m_process->error(), m_process->errorString() };
|
||||||
|
emit done(result);
|
||||||
|
}
|
||||||
|
|
||||||
ProcessHelper *m_process;
|
ProcessHelper *m_process;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -409,12 +421,10 @@ public:
|
|||||||
{
|
{
|
||||||
m_handle = LauncherInterface::registerHandle(this, token());
|
m_handle = LauncherInterface::registerHandle(this, token());
|
||||||
m_handle->setProcessSetupData(m_setup);
|
m_handle->setProcessSetupData(m_setup);
|
||||||
connect(m_handle, &CallerHandle::errorOccurred,
|
|
||||||
this, &ProcessInterface::errorOccurred);
|
|
||||||
connect(m_handle, &CallerHandle::started,
|
connect(m_handle, &CallerHandle::started,
|
||||||
this, &ProcessInterface::started);
|
this, &ProcessInterface::started);
|
||||||
connect(m_handle, &CallerHandle::finished,
|
connect(m_handle, &CallerHandle::done,
|
||||||
this, &ProcessInterface::finished);
|
this, &ProcessInterface::done);
|
||||||
connect(m_handle, &CallerHandle::readyReadStandardOutput,
|
connect(m_handle, &CallerHandle::readyReadStandardOutput,
|
||||||
this, &ProcessInterface::readyReadStandardOutput);
|
this, &ProcessInterface::readyReadStandardOutput);
|
||||||
connect(m_handle, &CallerHandle::readyReadStandardError,
|
connect(m_handle, &CallerHandle::readyReadStandardError,
|
||||||
@@ -440,9 +450,6 @@ public:
|
|||||||
void close() final { m_handle->kill(); } // TODO: is it more like terminate or kill?
|
void close() final { m_handle->kill(); } // TODO: is it more like terminate or kill?
|
||||||
qint64 write(const QByteArray &data) final { return m_handle->write(data); }
|
qint64 write(const QByteArray &data) final { return m_handle->write(data); }
|
||||||
|
|
||||||
ProcessResultData resultData() const final { return m_handle->resultData(); };
|
|
||||||
void setErrorString(const QString &str) final { m_handle->setErrorString(str); }
|
|
||||||
|
|
||||||
QProcess::ProcessState state() const final { return m_handle->state(); }
|
QProcess::ProcessState state() const final { return m_handle->state(); }
|
||||||
qint64 processId() const final { return m_handle->processId(); }
|
qint64 processId() const final { return m_handle->processId(); }
|
||||||
|
|
||||||
@@ -473,12 +480,6 @@ static ProcessImpl defaultProcessImpl()
|
|||||||
class QtcProcessPrivate : public QObject
|
class QtcProcessPrivate : public QObject
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum StartFailure {
|
|
||||||
NoFailure,
|
|
||||||
WrongCommandFailure,
|
|
||||||
OtherFailure
|
|
||||||
};
|
|
||||||
|
|
||||||
explicit QtcProcessPrivate(QtcProcess *parent)
|
explicit QtcProcessPrivate(QtcProcess *parent)
|
||||||
: QObject(parent)
|
: QObject(parent)
|
||||||
, q(parent)
|
, q(parent)
|
||||||
@@ -503,10 +504,8 @@ public:
|
|||||||
|
|
||||||
connect(m_process.get(), &ProcessInterface::started,
|
connect(m_process.get(), &ProcessInterface::started,
|
||||||
this, &QtcProcessPrivate::emitStarted);
|
this, &QtcProcessPrivate::emitStarted);
|
||||||
connect(m_process.get(), &ProcessInterface::finished,
|
connect(m_process.get(), &ProcessInterface::done,
|
||||||
this, &QtcProcessPrivate::slotFinished);
|
this, &QtcProcessPrivate::handleDone);
|
||||||
connect(m_process.get(), &ProcessInterface::errorOccurred,
|
|
||||||
this, &QtcProcessPrivate::handleError);
|
|
||||||
connect(m_process.get(), &ProcessInterface::readyReadStandardOutput,
|
connect(m_process.get(), &ProcessInterface::readyReadStandardOutput,
|
||||||
this, &QtcProcessPrivate::handleReadyReadStandardOutput);
|
this, &QtcProcessPrivate::handleReadyReadStandardOutput);
|
||||||
connect(m_process.get(), &ProcessInterface::readyReadStandardError,
|
connect(m_process.get(), &ProcessInterface::readyReadStandardError,
|
||||||
@@ -559,9 +558,8 @@ public:
|
|||||||
ProcessSetupData m_setup;
|
ProcessSetupData m_setup;
|
||||||
|
|
||||||
void slotTimeout();
|
void slotTimeout();
|
||||||
void slotFinished();
|
void handleDone(const ProcessResultData &data);
|
||||||
void handleFinished(int exitCode, QProcess::ExitStatus status);
|
void handleError();
|
||||||
void handleError(QProcess::ProcessError error);
|
|
||||||
void clearForRun();
|
void clearForRun();
|
||||||
|
|
||||||
void emitStarted();
|
void emitStarted();
|
||||||
@@ -572,6 +570,8 @@ public:
|
|||||||
|
|
||||||
ProcessResult interpretExitCode(int exitCode);
|
ProcessResult interpretExitCode(int exitCode);
|
||||||
|
|
||||||
|
ProcessResultData m_resultData;
|
||||||
|
|
||||||
QTextCodec *m_codec = QTextCodec::codecForLocale();
|
QTextCodec *m_codec = QTextCodec::codecForLocale();
|
||||||
QEventLoop *m_eventLoop = nullptr;
|
QEventLoop *m_eventLoop = nullptr;
|
||||||
ProcessResult m_result = ProcessResult::StartFailed;
|
ProcessResult m_result = ProcessResult::StartFailed;
|
||||||
@@ -581,7 +581,6 @@ public:
|
|||||||
|
|
||||||
int m_hangTimerCount = 0;
|
int m_hangTimerCount = 0;
|
||||||
int m_maxHangTimerCount = defaultMaxHangTimerCount;
|
int m_maxHangTimerCount = defaultMaxHangTimerCount;
|
||||||
StartFailure m_startFailure = NoFailure;
|
|
||||||
bool m_timeOutMessageBoxEnabled = false;
|
bool m_timeOutMessageBoxEnabled = false;
|
||||||
bool m_waitingForUser = false;
|
bool m_waitingForUser = false;
|
||||||
|
|
||||||
@@ -605,7 +604,7 @@ void QtcProcessPrivate::clearForRun()
|
|||||||
m_stdErr.clearForRun();
|
m_stdErr.clearForRun();
|
||||||
m_stdErr.codec = m_codec;
|
m_stdErr.codec = m_codec;
|
||||||
m_result = ProcessResult::StartFailed;
|
m_result = ProcessResult::StartFailed;
|
||||||
m_startFailure = NoFailure;
|
m_resultData = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessResult QtcProcessPrivate::interpretExitCode(int exitCode)
|
ProcessResult QtcProcessPrivate::interpretExitCode(int exitCode)
|
||||||
@@ -1028,12 +1027,7 @@ void QtcProcess::setResult(const ProcessResult &result)
|
|||||||
|
|
||||||
ProcessResultData QtcProcess::resultData() const
|
ProcessResultData QtcProcess::resultData() const
|
||||||
{
|
{
|
||||||
const ProcessResultData result = d->m_process ? d->m_process->resultData()
|
return d->m_resultData;
|
||||||
: ProcessResultData();
|
|
||||||
// This code (255) is being returned by QProcess when FailedToStart error occurred
|
|
||||||
if (d->m_startFailure == QtcProcessPrivate::WrongCommandFailure)
|
|
||||||
return { 255, result.m_exitStatus, QProcess::FailedToStart, result.m_errorString };
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int QtcProcess::exitCode() const
|
int QtcProcess::exitCode() const
|
||||||
@@ -1478,10 +1472,10 @@ void QtcProcess::runBlocking(EventLoopMode eventLoopMode)
|
|||||||
setProperty(QTC_PROCESS_BLOCKING_TYPE, QVariant());
|
setProperty(QTC_PROCESS_BLOCKING_TYPE, QVariant());
|
||||||
}
|
}
|
||||||
if (eventLoopMode == EventLoopMode::On) {
|
if (eventLoopMode == EventLoopMode::On) {
|
||||||
// On Windows, start failure is triggered immediately if the
|
// Start failure is triggered immediately if the executable cannot be found in the path.
|
||||||
// executable cannot be found in the path. Do not start the
|
// In this case the process is left in NotRunning state.
|
||||||
// event loop in that case.
|
// Do not start the event loop in that case.
|
||||||
if (d->m_startFailure == QtcProcessPrivate::NoFailure) {
|
if (state() == QProcess::Starting) {
|
||||||
QTimer timer(this);
|
QTimer timer(this);
|
||||||
connect(&timer, &QTimer::timeout, d, &QtcProcessPrivate::slotTimeout);
|
connect(&timer, &QTimer::timeout, d, &QtcProcessPrivate::slotTimeout);
|
||||||
timer.setInterval(1000);
|
timer.setInterval(1000);
|
||||||
@@ -1573,21 +1567,28 @@ void QtcProcessPrivate::slotTimeout()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtcProcessPrivate::slotFinished()
|
void QtcProcessPrivate::handleDone(const ProcessResultData &data)
|
||||||
{
|
{
|
||||||
handleFinished(m_process->resultData().m_exitCode, m_process->resultData().m_exitStatus);
|
m_resultData = data;
|
||||||
emitFinished();
|
|
||||||
}
|
// This code (255) is being returned by QProcess when FailedToStart error occurred
|
||||||
|
if (m_resultData.m_error == QProcess::FailedToStart)
|
||||||
|
m_resultData.m_exitCode = 0xFF;
|
||||||
|
|
||||||
|
// HACK: See QIODevice::errorString() implementation.
|
||||||
|
if (m_resultData.m_error == QProcess::UnknownError)
|
||||||
|
m_resultData.m_errorString.clear();
|
||||||
|
|
||||||
|
if (m_resultData.m_error != QProcess::UnknownError)
|
||||||
|
handleError();
|
||||||
|
|
||||||
void QtcProcessPrivate::handleFinished(int exitCode, QProcess::ExitStatus status)
|
|
||||||
{
|
|
||||||
if (debug)
|
if (debug)
|
||||||
qDebug() << Q_FUNC_INFO << exitCode << status;
|
qDebug() << Q_FUNC_INFO << m_resultData.m_exitCode << m_resultData.m_exitStatus;
|
||||||
m_hangTimerCount = 0;
|
m_hangTimerCount = 0;
|
||||||
|
|
||||||
switch (status) {
|
switch (m_resultData.m_exitStatus) {
|
||||||
case QProcess::NormalExit:
|
case QProcess::NormalExit:
|
||||||
m_result = interpretExitCode(exitCode);
|
m_result = interpretExitCode(m_resultData.m_exitCode);
|
||||||
break;
|
break;
|
||||||
case QProcess::CrashExit:
|
case QProcess::CrashExit:
|
||||||
// Was hang detected before and killed?
|
// Was hang detected before and killed?
|
||||||
@@ -1600,21 +1601,25 @@ void QtcProcessPrivate::handleFinished(int exitCode, QProcess::ExitStatus status
|
|||||||
|
|
||||||
m_stdOut.handleRest();
|
m_stdOut.handleRest();
|
||||||
m_stdErr.handleRest();
|
m_stdErr.handleRest();
|
||||||
|
|
||||||
|
if (m_resultData.m_error != QProcess::FailedToStart)
|
||||||
|
emitFinished();
|
||||||
|
|
||||||
|
emit q->done();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtcProcessPrivate::handleError(QProcess::ProcessError error)
|
void QtcProcessPrivate::handleError()
|
||||||
{
|
{
|
||||||
m_hangTimerCount = 0;
|
m_hangTimerCount = 0;
|
||||||
if (debug)
|
if (debug)
|
||||||
qDebug() << Q_FUNC_INFO << error;
|
qDebug() << Q_FUNC_INFO << m_resultData.m_error;
|
||||||
// Was hang detected before and killed?
|
// Was hang detected before and killed?
|
||||||
if (m_result != ProcessResult::Hang)
|
if (m_result != ProcessResult::Hang)
|
||||||
m_result = ProcessResult::StartFailed;
|
m_result = ProcessResult::StartFailed;
|
||||||
m_startFailure = (error == QProcess::FailedToStart) ? WrongCommandFailure : OtherFailure;
|
|
||||||
if (m_eventLoop)
|
if (m_eventLoop)
|
||||||
m_eventLoop->quit();
|
m_eventLoop->quit();
|
||||||
|
|
||||||
emitErrorOccurred(error);
|
emitErrorOccurred(m_resultData.m_error);
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtcProcessPrivate::emitStarted()
|
void QtcProcessPrivate::emitStarted()
|
||||||
@@ -1627,15 +1632,12 @@ void QtcProcessPrivate::emitFinished()
|
|||||||
{
|
{
|
||||||
CALL_STACK_GUARD();
|
CALL_STACK_GUARD();
|
||||||
q->emitFinished();
|
q->emitFinished();
|
||||||
emit q->done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtcProcessPrivate::emitErrorOccurred(QProcess::ProcessError error)
|
void QtcProcessPrivate::emitErrorOccurred(QProcess::ProcessError error)
|
||||||
{
|
{
|
||||||
CALL_STACK_GUARD();
|
CALL_STACK_GUARD();
|
||||||
emit q->errorOccurred(error);
|
emit q->errorOccurred(error);
|
||||||
if (error == QProcess::FailedToStart)
|
|
||||||
emit q->done();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QtcProcessPrivate::emitReadyReadStandardOutput()
|
void QtcProcessPrivate::emitReadyReadStandardOutput()
|
||||||
|
|||||||
@@ -442,14 +442,6 @@ void TerminalImpl::cleanupAfterStartFailure(const QString &errorMessage)
|
|||||||
d->m_tempFile = nullptr;
|
d->m_tempFile = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalImpl::finish(int exitCode, QProcess::ExitStatus exitStatus)
|
|
||||||
{
|
|
||||||
d->m_processId = 0;
|
|
||||||
d->m_result.m_exitCode = exitCode;
|
|
||||||
d->m_result.m_exitStatus = exitStatus;
|
|
||||||
emit finished();
|
|
||||||
}
|
|
||||||
|
|
||||||
void TerminalImpl::kickoffProcess()
|
void TerminalImpl::kickoffProcess()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN
|
#ifdef Q_OS_WIN
|
||||||
@@ -652,7 +644,7 @@ void TerminalImpl::readStubOutput()
|
|||||||
emitError(QProcess::UnknownError, tr("Cannot obtain exit status from inferior: %1")
|
emitError(QProcess::UnknownError, tr("Cannot obtain exit status from inferior: %1")
|
||||||
.arg(winErrorMessage(GetLastError())));
|
.arg(winErrorMessage(GetLastError())));
|
||||||
cleanupInferior();
|
cleanupInferior();
|
||||||
finish(chldStatus, QProcess::NormalExit);
|
emitFinished(chldStatus, QProcess::NormalExit);
|
||||||
});
|
});
|
||||||
|
|
||||||
emit started();
|
emit started();
|
||||||
@@ -676,9 +668,9 @@ void TerminalImpl::readStubOutput()
|
|||||||
d->m_processId = out.mid(4).toInt();
|
d->m_processId = out.mid(4).toInt();
|
||||||
emit started();
|
emit started();
|
||||||
} else if (out.startsWith("exit ")) {
|
} else if (out.startsWith("exit ")) {
|
||||||
finish(out.mid(5).toInt(), QProcess::NormalExit);
|
emitFinished(out.mid(5).toInt(), QProcess::NormalExit);
|
||||||
} else if (out.startsWith("crash ")) {
|
} else if (out.startsWith("crash ")) {
|
||||||
finish(out.mid(6).toInt(), QProcess::CrashExit);
|
emitFinished(out.mid(6).toInt(), QProcess::CrashExit);
|
||||||
} else {
|
} else {
|
||||||
emitError(QProcess::UnknownError, msgUnexpectedOutput(out));
|
emitError(QProcess::UnknownError, msgUnexpectedOutput(out));
|
||||||
d->m_process.terminate();
|
d->m_process.terminate();
|
||||||
@@ -700,14 +692,14 @@ void TerminalImpl::stubExited()
|
|||||||
if (d->m_hInferior != NULL) {
|
if (d->m_hInferior != NULL) {
|
||||||
TerminateProcess(d->m_hInferior, (unsigned)-1);
|
TerminateProcess(d->m_hInferior, (unsigned)-1);
|
||||||
cleanupInferior();
|
cleanupInferior();
|
||||||
finish(-1, QProcess::CrashExit);
|
emitFinished(-1, QProcess::CrashExit);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
stubServerShutdown();
|
stubServerShutdown();
|
||||||
delete d->m_tempFile;
|
delete d->m_tempFile;
|
||||||
d->m_tempFile = nullptr;
|
d->m_tempFile = nullptr;
|
||||||
if (d->m_processId)
|
if (d->m_processId)
|
||||||
finish(-1, QProcess::CrashExit);
|
emitFinished(-1, QProcess::CrashExit);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -741,17 +733,22 @@ qint64 TerminalImpl::processId() const
|
|||||||
return d->m_processId;
|
return d->m_processId;
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessResultData TerminalImpl::resultData() const
|
void TerminalImpl::emitError(QProcess::ProcessError error, const QString &errorString)
|
||||||
{
|
{
|
||||||
return d->m_result;
|
d->m_result.m_error = error;
|
||||||
|
d->m_result.m_errorString = errorString;
|
||||||
|
if (error == QProcess::FailedToStart)
|
||||||
|
emit done(d->m_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalImpl::emitError(QProcess::ProcessError err, const QString &errorString)
|
void TerminalImpl::emitFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
||||||
{
|
{
|
||||||
d->m_result.m_error = err;
|
d->m_processId = 0;
|
||||||
d->m_result.m_errorString = errorString;
|
d->m_result.m_exitCode = exitCode;
|
||||||
emit errorOccurred(err);
|
d->m_result.m_exitStatus = exitStatus;
|
||||||
|
emit done(d->m_result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} // Internal
|
} // Internal
|
||||||
} // Utils
|
} // Utils
|
||||||
|
|||||||
@@ -64,7 +64,6 @@ public:
|
|||||||
|
|
||||||
QProcess::ProcessState state() const final;
|
QProcess::ProcessState state() const final;
|
||||||
qint64 processId() const final;
|
qint64 processId() const final;
|
||||||
ProcessResultData resultData() const final;
|
|
||||||
|
|
||||||
void kickoffProcess() final; // only debugger terminal, only non-windows
|
void kickoffProcess() final; // only debugger terminal, only non-windows
|
||||||
void interrupt() final; // only debugger terminal, only non-windows
|
void interrupt() final; // only debugger terminal, only non-windows
|
||||||
@@ -80,10 +79,10 @@ private:
|
|||||||
void readStubOutput();
|
void readStubOutput();
|
||||||
void stubExited();
|
void stubExited();
|
||||||
void cleanupAfterStartFailure(const QString &errorMessage);
|
void cleanupAfterStartFailure(const QString &errorMessage);
|
||||||
void finish(int exitCode, QProcess::ExitStatus exitStatus);
|
|
||||||
void killProcess();
|
void killProcess();
|
||||||
void killStub();
|
void killStub();
|
||||||
void emitError(QProcess::ProcessError err, const QString &errorString);
|
void emitError(QProcess::ProcessError error, const QString &errorString);
|
||||||
|
void emitFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||||
QString stubServerListen();
|
QString stubServerListen();
|
||||||
void stubServerShutdown();
|
void stubServerShutdown();
|
||||||
void cleanupStub();
|
void cleanupStub();
|
||||||
|
|||||||
@@ -133,61 +133,49 @@ void LauncherSocketHandler::handleSocketClosed()
|
|||||||
qApp->quit();
|
qApp->quit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherSocketHandler::handleProcessError()
|
void LauncherSocketHandler::handleProcessError(Process *process)
|
||||||
{
|
{
|
||||||
Process * proc = senderProcess();
|
|
||||||
|
|
||||||
// In case of FailedToStart we won't receive finished signal, so we send the error
|
// In case of FailedToStart we won't receive finished signal, so we send the error
|
||||||
// packet and remove the process here and now. For all other errors we should expect
|
// packet and remove the process here and now. For all other errors we should expect
|
||||||
// corresponding finished signal to appear, so we will send the error data together with
|
// corresponding finished signal to appear, so we will send the error data together with
|
||||||
// the finished packet later on.
|
// the finished packet later on.
|
||||||
if (proc->error() != QProcess::FailedToStart)
|
if (process->error() == QProcess::FailedToStart)
|
||||||
return;
|
handleProcessFinished(process);
|
||||||
|
|
||||||
ProcessErrorPacket packet(proc->token());
|
|
||||||
packet.error = proc->error();
|
|
||||||
packet.errorString = proc->errorString();
|
|
||||||
sendPacket(packet);
|
|
||||||
removeProcess(proc->token());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherSocketHandler::handleProcessStarted()
|
void LauncherSocketHandler::handleProcessStarted(Process *process)
|
||||||
{
|
{
|
||||||
Process *proc = senderProcess();
|
ProcessStartedPacket packet(process->token());
|
||||||
ProcessStartedPacket packet(proc->token());
|
packet.processId = process->processId();
|
||||||
packet.processId = proc->processId();
|
process->processStartHandler()->handleProcessStarted();
|
||||||
proc->processStartHandler()->handleProcessStarted();
|
|
||||||
sendPacket(packet);
|
sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherSocketHandler::handleReadyReadStandardOutput()
|
void LauncherSocketHandler::handleReadyReadStandardOutput(Process *process)
|
||||||
{
|
{
|
||||||
Process * proc = senderProcess();
|
ReadyReadStandardOutputPacket packet(process->token());
|
||||||
ReadyReadStandardOutputPacket packet(proc->token());
|
packet.standardChannel = process->readAllStandardOutput();
|
||||||
packet.standardChannel = proc->readAllStandardOutput();
|
|
||||||
sendPacket(packet);
|
sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherSocketHandler::handleReadyReadStandardError()
|
void LauncherSocketHandler::handleReadyReadStandardError(Process *process)
|
||||||
{
|
{
|
||||||
Process * proc = senderProcess();
|
ReadyReadStandardErrorPacket packet(process->token());
|
||||||
ReadyReadStandardErrorPacket packet(proc->token());
|
packet.standardChannel = process->readAllStandardError();
|
||||||
packet.standardChannel = proc->readAllStandardError();
|
|
||||||
sendPacket(packet);
|
sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherSocketHandler::handleProcessFinished()
|
void LauncherSocketHandler::handleProcessFinished(Process *process)
|
||||||
{
|
{
|
||||||
Process * proc = senderProcess();
|
ProcessDonePacket packet(process->token());
|
||||||
ProcessFinishedPacket packet(proc->token());
|
packet.exitCode = process->exitCode();
|
||||||
packet.error = proc->error();
|
packet.exitStatus = process->exitStatus();
|
||||||
packet.errorString = proc->errorString();
|
packet.error = process->error();
|
||||||
packet.exitCode = proc->exitCode();
|
packet.errorString = process->errorString();
|
||||||
packet.exitStatus = proc->exitStatus();
|
packet.stdErr = process->readAllStandardError();
|
||||||
packet.stdErr = proc->readAllStandardError();
|
packet.stdOut = process->readAllStandardOutput();
|
||||||
packet.stdOut = proc->readAllStandardOutput();
|
|
||||||
sendPacket(packet);
|
sendPacket(packet);
|
||||||
removeProcess(proc->token());
|
removeProcess(process->token());
|
||||||
}
|
}
|
||||||
|
|
||||||
void LauncherSocketHandler::handleStartPacket()
|
void LauncherSocketHandler::handleStartPacket()
|
||||||
@@ -263,7 +251,7 @@ void LauncherSocketHandler::handleStopPacket()
|
|||||||
} else {
|
} else {
|
||||||
// We got the client request to stop the starting / running process.
|
// We got the client request to stop the starting / running process.
|
||||||
// We report process exit to the client.
|
// We report process exit to the client.
|
||||||
ProcessFinishedPacket packet(process->token());
|
ProcessDonePacket packet(process->token());
|
||||||
packet.error = QProcess::Crashed;
|
packet.error = QProcess::Crashed;
|
||||||
packet.exitCode = -1;
|
packet.exitCode = -1;
|
||||||
packet.exitStatus = QProcess::CrashExit;
|
packet.exitStatus = QProcess::CrashExit;
|
||||||
@@ -289,14 +277,14 @@ void LauncherSocketHandler::sendPacket(const LauncherPacket &packet)
|
|||||||
Process *LauncherSocketHandler::setupProcess(quintptr token)
|
Process *LauncherSocketHandler::setupProcess(quintptr token)
|
||||||
{
|
{
|
||||||
const auto p = new Process(token, this);
|
const auto p = new Process(token, this);
|
||||||
connect(p, &QProcess::errorOccurred, this, &LauncherSocketHandler::handleProcessError);
|
connect(p, &QProcess::started, this, [this, p] { handleProcessStarted(p); });
|
||||||
connect(p, &QProcess::started, this, &LauncherSocketHandler::handleProcessStarted);
|
connect(p, &QProcess::errorOccurred, this, [this, p] { handleProcessError(p); });
|
||||||
connect(p, &QProcess::readyReadStandardOutput,
|
|
||||||
this, &LauncherSocketHandler::handleReadyReadStandardOutput);
|
|
||||||
connect(p, &QProcess::readyReadStandardError,
|
|
||||||
this, &LauncherSocketHandler::handleReadyReadStandardError);
|
|
||||||
connect(p, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
connect(p, static_cast<void (QProcess::*)(int, QProcess::ExitStatus)>(&QProcess::finished),
|
||||||
this, &LauncherSocketHandler::handleProcessFinished);
|
this, [this, p] { handleProcessFinished(p); });
|
||||||
|
connect(p, &QProcess::readyReadStandardOutput,
|
||||||
|
this, [this, p] { handleReadyReadStandardOutput(p); });
|
||||||
|
connect(p, &QProcess::readyReadStandardError,
|
||||||
|
this, [this, p] { handleReadyReadStandardError(p); });
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -311,11 +299,6 @@ void LauncherSocketHandler::removeProcess(quintptr token)
|
|||||||
ProcessReaper::reap(process);
|
ProcessReaper::reap(process);
|
||||||
}
|
}
|
||||||
|
|
||||||
Process *LauncherSocketHandler::senderProcess() const
|
|
||||||
{
|
|
||||||
return static_cast<Process *>(sender());
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
|
|||||||
@@ -52,11 +52,12 @@ private:
|
|||||||
void handleSocketData();
|
void handleSocketData();
|
||||||
void handleSocketError();
|
void handleSocketError();
|
||||||
void handleSocketClosed();
|
void handleSocketClosed();
|
||||||
void handleProcessError();
|
|
||||||
void handleProcessStarted();
|
void handleProcessStarted(Process *process);
|
||||||
void handleReadyReadStandardOutput();
|
void handleProcessError(Process *process);
|
||||||
void handleReadyReadStandardError();
|
void handleProcessFinished(Process *process);
|
||||||
void handleProcessFinished();
|
void handleReadyReadStandardOutput(Process *process);
|
||||||
|
void handleReadyReadStandardError(Process *process);
|
||||||
|
|
||||||
void handleStartPacket();
|
void handleStartPacket();
|
||||||
void handleWritePacket();
|
void handleWritePacket();
|
||||||
@@ -67,7 +68,6 @@ private:
|
|||||||
|
|
||||||
Process *setupProcess(quintptr token);
|
Process *setupProcess(quintptr token);
|
||||||
void removeProcess(quintptr token);
|
void removeProcess(quintptr token);
|
||||||
Process *senderProcess() const;
|
|
||||||
|
|
||||||
const QString m_serverPath;
|
const QString m_serverPath;
|
||||||
QLocalSocket * const m_socket;
|
QLocalSocket * const m_socket;
|
||||||
|
|||||||
Reference in New Issue
Block a user