diff --git a/src/libs/utils/launcherpackets.cpp b/src/libs/utils/launcherpackets.cpp index 7e7bbfd86ae..c971f1494ba 100644 --- a/src/libs/utils/launcherpackets.cpp +++ b/src/libs/utils/launcherpackets.cpp @@ -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) : LauncherPacket(LauncherPacketType::ProcessFinished, token) { diff --git a/src/libs/utils/launcherpackets.h b/src/libs/utils/launcherpackets.h index cd5a8a35ec2..27ce9d2cc4d 100644 --- a/src/libs/utils/launcherpackets.h +++ b/src/libs/utils/launcherpackets.h @@ -37,7 +37,16 @@ namespace Utils { namespace Internal { 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 @@ -153,6 +162,33 @@ private: 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 { public: diff --git a/src/libs/utils/launchersocket.cpp b/src/libs/utils/launchersocket.cpp index 20b1ca0148c..ae4193c3f52 100644 --- a/src/libs/utils/launchersocket.cpp +++ b/src/libs/utils/launchersocket.cpp @@ -103,6 +103,12 @@ void LauncherHandle::handlePacket(LauncherPacketType type, const QByteArray &pay case LauncherPacketType::ProcessStarted: handleStartedPacket(payload); break; + case LauncherPacketType::ReadyReadStandardOutput: + handleReadyReadStandardOutput(payload); + break; + case LauncherPacketType::ReadyReadStandardError: + handleReadyReadStandardError(payload); + break; case LauncherPacketType::ProcessFinished: handleFinishedPacket(payload); break; @@ -165,10 +171,47 @@ void LauncherHandle::handleStartedPacket(const QByteArray &packetData) m_processState = QProcess::Running; const auto packet = LauncherPacket::extractPacket(m_token, packetData); m_processId = packet.processId; - if (m_callerHandle) { - m_callerHandle->appendSignal(SignalType::Started); - flushCaller(); - } + if (!m_callerHandle) + return; + + m_callerHandle->appendSignal(SignalType::Started); + flushCaller(); +} + +void LauncherHandle::handleReadyReadStandardOutput(const QByteArray &packetData) +{ + QMutexLocker locker(&m_mutex); + wakeUpIfWaitingFor(SignalType::ReadyRead); + if (m_canceled) + return; + const auto packet = LauncherPacket::extractPacket(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(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) @@ -180,16 +223,17 @@ void LauncherHandle::handleFinishedPacket(const QByteArray &packetData) m_processState = QProcess::NotRunning; const auto packet = LauncherPacket::extractPacket(m_token, packetData); m_exitCode = packet.exitCode; - m_stdout = packet.stdOut; - m_stderr = packet.stdErr; + m_stdout += packet.stdOut; + m_stderr += packet.stdErr; m_errorString = packet.errorString; m_exitStatus = packet.exitStatus; - if (m_callerHandle) { - if (!m_stdout.isEmpty() || !m_stderr.isEmpty()) - m_callerHandle->appendSignal(SignalType::ReadyRead); - m_callerHandle->appendSignal(SignalType::Finished); - flushCaller(); - } + if (!m_callerHandle) + return; + + if (!m_stdout.isEmpty() || !m_stderr.isEmpty()) + m_callerHandle->appendSignal(SignalType::ReadyRead); + m_callerHandle->appendSignal(SignalType::Finished); + flushCaller(); } void LauncherHandle::handleSocketReady() @@ -476,6 +520,8 @@ void LauncherSocket::handleSocketDataAvailable() switch (m_packetParser.type()) { case LauncherPacketType::ProcessError: case LauncherPacketType::ProcessStarted: + case LauncherPacketType::ReadyReadStandardOutput: + case LauncherPacketType::ReadyReadStandardError: case LauncherPacketType::ProcessFinished: handle->handlePacket(m_packetParser.type(), m_packetParser.packetData()); break; diff --git a/src/libs/utils/launchersocket.h b/src/libs/utils/launchersocket.h index f6a0b9d5418..1bf50938ffd 100644 --- a/src/libs/utils/launchersocket.h +++ b/src/libs/utils/launchersocket.h @@ -139,6 +139,8 @@ private: void handlePacket(LauncherPacketType type, const QByteArray &payload); void handleErrorPacket(const QByteArray &packetData); void handleStartedPacket(const QByteArray &packetData); + void handleReadyReadStandardOutput(const QByteArray &packetData); + void handleReadyReadStandardError(const QByteArray &packetData); void handleFinishedPacket(const QByteArray &packetData); void handleSocketReady(); diff --git a/src/libs/utils/qtcprocess.cpp b/src/libs/utils/qtcprocess.cpp index 36f0c6abe8e..434655b013f 100644 --- a/src/libs/utils/qtcprocess.cpp +++ b/src/libs/utils/qtcprocess.cpp @@ -332,7 +332,7 @@ public: void setErrorString(const QString &str) override { m_handle->setErrorString(str); } 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); } void setLowPriority() override { QTC_CHECK(false); } diff --git a/src/tools/processlauncher/launchersockethandler.cpp b/src/tools/processlauncher/launchersockethandler.cpp index bfe08d26fc8..e8dcc4f9785 100644 --- a/src/tools/processlauncher/launchersockethandler.cpp +++ b/src/tools/processlauncher/launchersockethandler.cpp @@ -186,6 +186,22 @@ void LauncherSocketHandler::handleProcessStarted() 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() { Process * proc = senderProcess(); @@ -276,6 +292,10 @@ Process *LauncherSocketHandler::setupProcess(quintptr token) const auto p = new Process(token, this); connect(p, &QProcess::errorOccurred, this, &LauncherSocketHandler::handleProcessError); 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(&QProcess::finished), this, &LauncherSocketHandler::handleProcessFinished); connect(p, &Process::failedToStop, this, &LauncherSocketHandler::handleStopFailure); diff --git a/src/tools/processlauncher/launchersockethandler.h b/src/tools/processlauncher/launchersockethandler.h index 2f67d51528f..54a0e3429f2 100644 --- a/src/tools/processlauncher/launchersockethandler.h +++ b/src/tools/processlauncher/launchersockethandler.h @@ -54,6 +54,8 @@ private: void handleSocketClosed(); void handleProcessError(); void handleProcessStarted(); + void handleReadyReadStandardOutput(); + void handleReadyReadStandardError(); void handleProcessFinished(); void handleStopFailure();