From f1f5a7412a124ec011c5563a1120faf8343d3e8e Mon Sep 17 00:00:00 2001 From: Marcus Tillmanns Date: Fri, 24 Mar 2023 09:26:42 +0100 Subject: [PATCH] Utils: Send __qtc marker from stub Docker and ssh devices need the real process id on the remote device. The process stub now send this if it receives it as the first line of output. Change-Id: I5d3af39651958fc88d21c3854a0fa1d7f51547a6 Reviewed-by: Reviewed-by: David Schulz --- src/libs/utils/processinterface.cpp | 6 ++-- src/libs/utils/terminalinterface.cpp | 2 ++ src/plugins/docker/dockerdevice.cpp | 27 ++++++--------- src/tools/process_stub/main.cpp | 52 +++++++++++++++++++++++++++- 4 files changed, 68 insertions(+), 19 deletions(-) diff --git a/src/libs/utils/processinterface.cpp b/src/libs/utils/processinterface.cpp index a5e60c97a31..a2dc746905c 100644 --- a/src/libs/utils/processinterface.cpp +++ b/src/libs/utils/processinterface.cpp @@ -29,8 +29,10 @@ int ProcessInterface::controlSignalToInt(ControlSignal controlSignal) case ControlSignal::Terminate: return 15; case ControlSignal::Kill: return 9; case ControlSignal::Interrupt: return 2; - case ControlSignal::KickOff: QTC_CHECK(false); return 0; - case ControlSignal::CloseWriteChannel: QTC_CHECK(false); return 0; + case ControlSignal::KickOff: return 19; + case ControlSignal::CloseWriteChannel: + QTC_CHECK(false); + return 0; } return 0; } diff --git a/src/libs/utils/terminalinterface.cpp b/src/libs/utils/terminalinterface.cpp index 58d48cb910a..74831723296 100644 --- a/src/libs/utils/terminalinterface.cpp +++ b/src/libs/utils/terminalinterface.cpp @@ -183,6 +183,8 @@ void TerminalInterface::onStubReadyRead() emitFinished(out.mid(5).toInt(), QProcess::NormalExit); } else if (out.startsWith("crash ")) { emitFinished(out.mid(6).toInt(), QProcess::CrashExit); + } else if (out.startsWith("qtc: ")) { + emit readyRead(out.mid(5) + "\n", {}); } else { emitError(QProcess::UnknownError, msgUnexpectedOutput(out)); break; diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index fa66c344492..b7ff64ab9e3 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -164,7 +164,6 @@ public: const std::optional &env = std::nullopt, const std::optional &workDir = std::nullopt, bool interactive = false, - bool includeMarker = true, bool withPty = false); bool prepareForBuild(const Target *target); @@ -315,16 +314,17 @@ void DockerProcessImpl::start() if (m_setup.m_lowPriority) m_process.setLowPriority(); + const bool inTerminal = m_setup.m_terminalMode != TerminalMode::Off; + const bool interactive = m_setup.m_processMode == ProcessMode::Writer - || !m_setup.m_writeData.isEmpty(); + || !m_setup.m_writeData.isEmpty() || inTerminal; const CommandLine fullCommandLine = m_devicePrivate->withDockerExecCmd(m_setup.m_commandLine, m_setup.m_environment, m_setup.m_workingDirectory, interactive, - true, - m_setup.m_ptyData.has_value()); + inTerminal); m_process.setCommand(fullCommandLine); m_process.start(); @@ -472,7 +472,6 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, const std::optional &env, const std::optional &workDir, bool interactive, - bool includeMarker, bool withPty) { if (!m_settings) @@ -501,20 +500,16 @@ CommandLine DockerDevicePrivate::withDockerExecCmd(const CommandLine &cmd, dockerCmd.addArg(m_container); - if (includeMarker) { - dockerCmd.addArgs({"/bin/sh", "-c"}); + dockerCmd.addArgs({"/bin/sh", "-c"}); - CommandLine exec("exec"); - exec.addCommandLineAsArgs(cmd, CommandLine::Raw); + CommandLine exec("exec"); + exec.addCommandLineAsArgs(cmd, CommandLine::Raw); - CommandLine echo("echo"); - echo.addArgs("__qtc$$qtc__", CommandLine::Raw); - echo.addCommandLineWithAnd(exec); + CommandLine echo("echo"); + echo.addArgs("__qtc$$qtc__", CommandLine::Raw); + echo.addCommandLineWithAnd(exec); - dockerCmd.addCommandLineAsSingleArg(echo); - } else { - dockerCmd.addCommandLineAsArgs(cmd, CommandLine::Raw); - } + dockerCmd.addCommandLineAsSingleArg(echo); return dockerCmd; } diff --git a/src/tools/process_stub/main.cpp b/src/tools/process_stub/main.cpp index 45ac9c41f9b..3a3dd8af33b 100644 --- a/src/tools/process_stub/main.cpp +++ b/src/tools/process_stub/main.cpp @@ -137,6 +137,11 @@ void sendMsg(const QByteArray &msg) } } +void sendQtcMarker(const QByteArray &marker) +{ + sendMsg(QByteArray("qtc: ") + marker + "\n"); +} + void sendPid(int inferiorPid) { sendMsg(QString("pid %1\n").arg(inferiorPid).toUtf8()); @@ -273,6 +278,26 @@ void setupPidPollTimer() pollPidTimer.start(); #endif } + +enum class Out { StdOut, StdErr }; + +void writeToOut(const QByteArray &data, Out out) +{ +#ifdef Q_OS_WIN + static const HANDLE outHandle = GetStdHandle(STD_OUTPUT_HANDLE); + static const HANDLE errHandle = GetStdHandle(STD_ERROR_HANDLE); + WriteFile(out == Out::StdOut ? outHandle : errHandle, + data.constData(), + data.size(), + nullptr, + nullptr); +#else + auto fp = out == Out::StdOut ? stdout : stderr; + ::fwrite(data.constData(), 1, data.size(), fp); + ::fflush(fp); +#endif +} + void startProcess(const QString &executable, const QStringList &arguments, const QString &workingDir) { setupPidPollTimer(); @@ -292,7 +317,32 @@ void startProcess(const QString &executable, const QStringList &arguments, const QCoreApplication::instance(), &onInferiorStarted); - inferiorProcess.setProcessChannelMode(QProcess::ForwardedChannels); + inferiorProcess.setProcessChannelMode(QProcess::SeparateChannels); + + QObject::connect(&inferiorProcess, + &QProcess::readyReadStandardOutput, + QCoreApplication::instance(), + [] { + const QByteArray data = inferiorProcess.readAllStandardOutput(); + static bool isFirst = true; + if (isFirst) { + isFirst = false; + if (data.startsWith("__qtc")) { + int lineBreak = data.indexOf("\r\n"); + sendQtcMarker(data.mid(0, lineBreak)); + if (lineBreak != -1) + writeToOut(data.mid(lineBreak + 2), Out::StdOut); + return; + } + } + writeToOut(data, Out::StdOut); + }); + + QObject::connect(&inferiorProcess, + &QProcess::readyReadStandardError, + QCoreApplication::instance(), + [] { writeToOut(inferiorProcess.readAllStandardOutput(), Out::StdErr); }); + if (!(testMode && debugMode)) inferiorProcess.setInputChannelMode(QProcess::ForwardedInputChannel); inferiorProcess.setWorkingDirectory(workingDir);