Implement readyRead inside process launcher

Change-Id: I3a27edef2307053b8c4c7d8f1dbf7e0400e27416
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Jarek Kobus
2021-08-02 13:26:33 +02:00
parent 48c1f56ebe
commit ba037a707e
7 changed files with 131 additions and 14 deletions

View File

@@ -118,6 +118,17 @@ void ProcessErrorPacket::doDeserialize(QDataStream &stream)
} }
void ReadyReadPacket::doSerialize(QDataStream &stream) const
{
stream << standardChannel;
}
void ReadyReadPacket::doDeserialize(QDataStream &stream)
{
stream >> standardChannel;
}
ProcessFinishedPacket::ProcessFinishedPacket(quintptr token) ProcessFinishedPacket::ProcessFinishedPacket(quintptr token)
: LauncherPacket(LauncherPacketType::ProcessFinished, token) : LauncherPacket(LauncherPacketType::ProcessFinished, token)
{ {

View File

@@ -37,7 +37,16 @@ namespace Utils {
namespace Internal { namespace Internal {
enum class LauncherPacketType { enum class LauncherPacketType {
Shutdown, StartProcess, ProcessStarted, StopProcess, ProcessError, ProcessFinished // client -> launcher packets:
Shutdown,
StartProcess,
StopProcess,
// launcher -> client packets:
ProcessError,
ProcessStarted,
ReadyReadStandardOutput,
ReadyReadStandardError,
ProcessFinished
}; };
class PacketParser class PacketParser
@@ -153,6 +162,33 @@ private:
void doDeserialize(QDataStream &stream) override; void doDeserialize(QDataStream &stream) override;
}; };
class ReadyReadPacket : public LauncherPacket
{
public:
QByteArray standardChannel;
protected:
ReadyReadPacket(LauncherPacketType type, quintptr token) : LauncherPacket(type, token) { }
private:
void doSerialize(QDataStream &stream) const override;
void doDeserialize(QDataStream &stream) override;
};
class ReadyReadStandardOutputPacket : public ReadyReadPacket
{
public:
ReadyReadStandardOutputPacket(quintptr token)
: ReadyReadPacket(LauncherPacketType::ReadyReadStandardOutput, token) { }
};
class ReadyReadStandardErrorPacket : public ReadyReadPacket
{
public:
ReadyReadStandardErrorPacket(quintptr token)
: ReadyReadPacket(LauncherPacketType::ReadyReadStandardError, token) { }
};
class ProcessFinishedPacket : public LauncherPacket class ProcessFinishedPacket : public LauncherPacket
{ {
public: public:

View File

@@ -103,6 +103,12 @@ void LauncherHandle::handlePacket(LauncherPacketType type, const QByteArray &pay
case LauncherPacketType::ProcessStarted: case LauncherPacketType::ProcessStarted:
handleStartedPacket(payload); handleStartedPacket(payload);
break; break;
case LauncherPacketType::ReadyReadStandardOutput:
handleReadyReadStandardOutput(payload);
break;
case LauncherPacketType::ReadyReadStandardError:
handleReadyReadStandardError(payload);
break;
case LauncherPacketType::ProcessFinished: case LauncherPacketType::ProcessFinished:
handleFinishedPacket(payload); handleFinishedPacket(payload);
break; break;
@@ -165,10 +171,47 @@ void LauncherHandle::handleStartedPacket(const QByteArray &packetData)
m_processState = QProcess::Running; m_processState = QProcess::Running;
const auto packet = LauncherPacket::extractPacket<ProcessStartedPacket>(m_token, packetData); const auto packet = LauncherPacket::extractPacket<ProcessStartedPacket>(m_token, packetData);
m_processId = packet.processId; m_processId = packet.processId;
if (m_callerHandle) { if (!m_callerHandle)
return;
m_callerHandle->appendSignal(SignalType::Started); m_callerHandle->appendSignal(SignalType::Started);
flushCaller(); flushCaller();
} }
void LauncherHandle::handleReadyReadStandardOutput(const QByteArray &packetData)
{
QMutexLocker locker(&m_mutex);
wakeUpIfWaitingFor(SignalType::ReadyRead);
if (m_canceled)
return;
const auto packet = LauncherPacket::extractPacket<ReadyReadStandardOutputPacket>(m_token, packetData);
if (packet.standardChannel.isEmpty())
return;
m_stdout += packet.standardChannel;
if (!m_callerHandle)
return;
m_callerHandle->appendSignal(SignalType::ReadyRead);
flushCaller();
}
void LauncherHandle::handleReadyReadStandardError(const QByteArray &packetData)
{
QMutexLocker locker(&m_mutex);
wakeUpIfWaitingFor(SignalType::ReadyRead);
if (m_canceled)
return;
const auto packet = LauncherPacket::extractPacket<ReadyReadStandardErrorPacket>(m_token, packetData);
if (packet.standardChannel.isEmpty())
return;
m_stderr += packet.standardChannel;
if (!m_callerHandle)
return;
m_callerHandle->appendSignal(SignalType::ReadyRead);
flushCaller();
} }
void LauncherHandle::handleFinishedPacket(const QByteArray &packetData) void LauncherHandle::handleFinishedPacket(const QByteArray &packetData)
@@ -180,17 +223,18 @@ void LauncherHandle::handleFinishedPacket(const QByteArray &packetData)
m_processState = QProcess::NotRunning; m_processState = QProcess::NotRunning;
const auto packet = LauncherPacket::extractPacket<ProcessFinishedPacket>(m_token, packetData); const auto packet = LauncherPacket::extractPacket<ProcessFinishedPacket>(m_token, packetData);
m_exitCode = packet.exitCode; m_exitCode = packet.exitCode;
m_stdout = packet.stdOut; m_stdout += packet.stdOut;
m_stderr = packet.stdErr; m_stderr += packet.stdErr;
m_errorString = packet.errorString; m_errorString = packet.errorString;
m_exitStatus = packet.exitStatus; m_exitStatus = packet.exitStatus;
if (m_callerHandle) { if (!m_callerHandle)
return;
if (!m_stdout.isEmpty() || !m_stderr.isEmpty()) if (!m_stdout.isEmpty() || !m_stderr.isEmpty())
m_callerHandle->appendSignal(SignalType::ReadyRead); m_callerHandle->appendSignal(SignalType::ReadyRead);
m_callerHandle->appendSignal(SignalType::Finished); m_callerHandle->appendSignal(SignalType::Finished);
flushCaller(); flushCaller();
} }
}
void LauncherHandle::handleSocketReady() void LauncherHandle::handleSocketReady()
{ {
@@ -476,6 +520,8 @@ void LauncherSocket::handleSocketDataAvailable()
switch (m_packetParser.type()) { switch (m_packetParser.type()) {
case LauncherPacketType::ProcessError: case LauncherPacketType::ProcessError:
case LauncherPacketType::ProcessStarted: case LauncherPacketType::ProcessStarted:
case LauncherPacketType::ReadyReadStandardOutput:
case LauncherPacketType::ReadyReadStandardError:
case LauncherPacketType::ProcessFinished: case LauncherPacketType::ProcessFinished:
handle->handlePacket(m_packetParser.type(), m_packetParser.packetData()); handle->handlePacket(m_packetParser.type(), m_packetParser.packetData());
break; break;

View File

@@ -139,6 +139,8 @@ private:
void handlePacket(LauncherPacketType type, const QByteArray &payload); void handlePacket(LauncherPacketType type, const QByteArray &payload);
void handleErrorPacket(const QByteArray &packetData); void handleErrorPacket(const QByteArray &packetData);
void handleStartedPacket(const QByteArray &packetData); void handleStartedPacket(const QByteArray &packetData);
void handleReadyReadStandardOutput(const QByteArray &packetData);
void handleReadyReadStandardError(const QByteArray &packetData);
void handleFinishedPacket(const QByteArray &packetData); void handleFinishedPacket(const QByteArray &packetData);
void handleSocketReady(); void handleSocketReady();

View File

@@ -332,7 +332,7 @@ public:
void setErrorString(const QString &str) override { m_handle->setErrorString(str); } void setErrorString(const QString &str) override { m_handle->setErrorString(str); }
bool waitForStarted(int msecs) override { return m_handle->waitForStarted(msecs); } bool waitForStarted(int msecs) override { return m_handle->waitForStarted(msecs); }
bool waitForReadyRead(int msecs) override { QTC_CHECK(false); return false; } bool waitForReadyRead(int msecs) override { return m_handle->waitForReadyRead(msecs); }
bool waitForFinished(int msecs) override { return m_handle->waitForFinished(msecs); } bool waitForFinished(int msecs) override { return m_handle->waitForFinished(msecs); }
void setLowPriority() override { QTC_CHECK(false); } void setLowPriority() override { QTC_CHECK(false); }

View File

@@ -186,6 +186,22 @@ void LauncherSocketHandler::handleProcessStarted()
sendPacket(packet); sendPacket(packet);
} }
void LauncherSocketHandler::handleReadyReadStandardOutput()
{
Process * proc = senderProcess();
ReadyReadStandardOutputPacket packet(proc->token());
packet.standardChannel = proc->readAllStandardOutput();
sendPacket(packet);
}
void LauncherSocketHandler::handleReadyReadStandardError()
{
Process * proc = senderProcess();
ReadyReadStandardErrorPacket packet(proc->token());
packet.standardChannel = proc->readAllStandardError();
sendPacket(packet);
}
void LauncherSocketHandler::handleProcessFinished() void LauncherSocketHandler::handleProcessFinished()
{ {
Process * proc = senderProcess(); Process * proc = senderProcess();
@@ -276,6 +292,10 @@ 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::errorOccurred, this, &LauncherSocketHandler::handleProcessError);
connect(p, &QProcess::started, this, &LauncherSocketHandler::handleProcessStarted); connect(p, &QProcess::started, this, &LauncherSocketHandler::handleProcessStarted);
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, &LauncherSocketHandler::handleProcessFinished);
connect(p, &Process::failedToStop, this, &LauncherSocketHandler::handleStopFailure); connect(p, &Process::failedToStop, this, &LauncherSocketHandler::handleStopFailure);

View File

@@ -54,6 +54,8 @@ private:
void handleSocketClosed(); void handleSocketClosed();
void handleProcessError(); void handleProcessError();
void handleProcessStarted(); void handleProcessStarted();
void handleReadyReadStandardOutput();
void handleReadyReadStandardError();
void handleProcessFinished(); void handleProcessFinished();
void handleStopFailure(); void handleStopFailure();