From 5efd82468b0802fd0f6993b8a430acc09c6293a9 Mon Sep 17 00:00:00 2001 From: Tobias Hunger Date: Tue, 5 Jul 2016 12:00:59 +0200 Subject: [PATCH] SynchronousProcess: Store raw bytes from stdout/stderr of the process Only convert the raw output later in a stdOut() and stdErr() method of the SynchronousProcessResponse. This is necessary since we have processes that use different encodings for different sections of the file (I am looking at you, git). Also remove the signals for raw data on stdout/stderr, leaving only the signals returning buffered QString lines. This should be safe, even with UTF-16 output. Change-Id: Ida613fa86d1468cbd33bc6b3a1506a849c2d1c0a Reviewed-by: Tobias Hunger --- src/libs/utils/buildablehelperlibrary.cpp | 2 +- src/libs/utils/shellcommand.cpp | 17 +- src/libs/utils/synchronousprocess.cpp | 153 ++++++++++-------- src/libs/utils/synchronousprocess.h | 23 +-- src/plugins/android/androidbuildapkstep.cpp | 2 +- .../artisticstyle/artisticstylesettings.cpp | 6 +- src/plugins/beautifier/beautifierplugin.cpp | 2 +- src/plugins/clearcase/clearcaseplugin.cpp | 4 +- src/plugins/cmakeprojectmanager/cmaketool.cpp | 10 +- src/plugins/cvs/cvsplugin.cpp | 4 +- src/plugins/debugger/gdb/coregdbadapter.cpp | 2 +- src/plugins/git/gitclient.cpp | 8 +- src/plugins/ios/iosprobe.cpp | 2 +- src/plugins/mercurial/mercurialclient.cpp | 2 +- src/plugins/perforce/perforceplugin.cpp | 4 +- .../projectexplorer/abstractmsvctoolchain.cpp | 2 +- .../customwizardscriptgenerator.cpp | 8 +- src/plugins/projectexplorer/msvctoolchain.cpp | 21 ++- src/plugins/subversion/subversionplugin.cpp | 4 +- .../highlightersettings.cpp | 2 +- tests/manual/process/mainwindow.cpp | 4 +- 21 files changed, 149 insertions(+), 133 deletions(-) diff --git a/src/libs/utils/buildablehelperlibrary.cpp b/src/libs/utils/buildablehelperlibrary.cpp index 357bc2fea21..6e56ef97887 100644 --- a/src/libs/utils/buildablehelperlibrary.cpp +++ b/src/libs/utils/buildablehelperlibrary.cpp @@ -46,7 +46,7 @@ QString BuildableHelperLibrary::qtChooserToQmakePath(const QString &path) SynchronousProcessResponse response = proc.runBlocking(path, QStringList(QLatin1String("-print-env"))); if (response.result != SynchronousProcessResponse::Finished) return QString(); - const QString output = response.stdOut; + const QString output = response.stdOut(); int pos = output.indexOf(toolDir); if (pos == -1) return QString(); diff --git a/src/libs/utils/shellcommand.cpp b/src/libs/utils/shellcommand.cpp index 335142c0ef6..dfb58e17ff2 100644 --- a/src/libs/utils/shellcommand.cpp +++ b/src/libs/utils/shellcommand.cpp @@ -277,8 +277,8 @@ void ShellCommand::run(QFutureInterface &future) Utils::SynchronousProcessResponse resp = runCommand(job.binary, job.arguments, job.timeoutS, job.workingDirectory, job.exitCodeInterpreter); - stdOut += resp.stdOut; - stdErr += resp.stdErr; + stdOut += resp.stdOut(); + stdErr += resp.stdErr(); d->m_lastExecExitCode = resp.exitCode; d->m_lastExecSuccess = resp.result == Utils::SynchronousProcessResponse::Finished; if (!d->m_lastExecSuccess) @@ -427,21 +427,20 @@ Utils::SynchronousProcessResponse ShellCommand::runSynchronous(const Utils::File &stdOut, &stdErr, true); if (!d->m_aborted) { + response.codec = d->m_codec ? d->m_codec : QTextCodec::codecForLocale(); if (!stdErr.isEmpty()) { - response.stdErr = Utils::SynchronousProcess::normalizeNewlines( - d->m_codec ? d->m_codec->toUnicode(stdErr) : QString::fromLocal8Bit(stdErr)); + response.rawStdErr = stdErr; if (!(d->m_flags & SuppressStdErr)) - proxy->append(response.stdErr); + proxy->append(response.stdErr()); } if (!stdOut.isEmpty()) { - response.stdOut = Utils::SynchronousProcess::normalizeNewlines( - d->m_codec ? d->m_codec->toUnicode(stdOut) : QString::fromLocal8Bit(stdOut)); + response.rawStdOut = stdOut; if (d->m_flags & ShowStdOut) { if (d->m_flags & SilentOutput) - proxy->appendSilently(response.stdOut); + proxy->appendSilently(response.stdOut()); else - proxy->append(response.stdOut); + proxy->append(response.stdOut()); } } } diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp index 9f6210869db..fdbf05c17e7 100644 --- a/src/libs/utils/synchronousprocess.cpp +++ b/src/libs/utils/synchronousprocess.cpp @@ -37,6 +37,7 @@ #include #include +#include #ifdef Q_OS_UNIX # include @@ -115,8 +116,8 @@ void SynchronousProcessResponse::clear() { result = StartFailed; exitCode = -1; - stdOut.clear(); - stdErr.clear(); + rawStdOut.clear(); + rawStdErr.clear(); } QString SynchronousProcessResponse::exitMessage(const QString &binary, int timeoutS) const @@ -137,22 +138,49 @@ QString SynchronousProcessResponse::exitMessage(const QString &binary, int timeo return QString(); } +QByteArray SynchronousProcessResponse::allRawOutput() const +{ + if (!rawStdOut.isEmpty() && !rawStdErr.isEmpty()) { + QByteArray result; + result.reserve(rawStdOut.size() + rawStdErr.size() + 1); + result = rawStdOut; + if (!result.endsWith('\n')) + result += '\n'; + result += rawStdErr; + return result; + } + return !rawStdOut.isEmpty() ? rawStdOut : rawStdErr; +} + QString SynchronousProcessResponse::allOutput() const { - if (!stdOut.isEmpty() && !stdErr.isEmpty()) { - if (stdOut.endsWith(QLatin1Char('\n'))) - return stdOut + stdErr; - else - return stdOut + QLatin1Char('\n') + stdErr; - } - return !stdOut.isEmpty() ? stdOut : stdErr; + const QString out = stdOut(); + const QString err = stdErr(); + + QString result; + result.reserve(out.size() + err.size() + 1); + result = out; + if (!result.endsWith('\n')) + result += '\n'; + result += err; + return result; +} + +QString SynchronousProcessResponse::stdOut() const +{ + return SynchronousProcess::normalizeNewlines(codec->toUnicode(rawStdOut)); +} + +QString SynchronousProcessResponse::stdErr() const +{ + return SynchronousProcess::normalizeNewlines(codec->toUnicode(rawStdErr)); } QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse& r) { QDebug nsp = str.nospace(); nsp << "SynchronousProcessResponse: result=" << r.result << " ex=" << r.exitCode << '\n' - << r.stdOut.size() << " bytes stdout, stderr=" << r.stdErr << '\n'; + << r.rawStdOut.size() << " bytes stdout, stderr=" << r.rawStdErr << '\n'; return str; } @@ -169,52 +197,62 @@ class ChannelBuffer : public QObject public: void clearForRun(); - QString linesRead(); - void append(const QString &text, bool emitSignals); - QString data; - int bufferPos = 0; - bool firstData = true; + QString linesRead(); + void append(const QByteArray &text, bool emitSignals); + + QByteArray rawData; + QString incompleteLineBuffer; // lines not yet signaled + QTextCodec *codec = nullptr; // Not owner + std::unique_ptr codecState; + int rawDataPos = 0; bool bufferedSignalsEnabled = false; bool firstBuffer = true; signals: - void output(const QString &text, bool firstTime); void outputBuffered(const QString &text, bool firstTime); }; void ChannelBuffer::clearForRun() { - firstData = true; firstBuffer = true; - bufferPos = 0; + rawDataPos = 0; + rawData.clear(); + codecState.reset(new QTextCodec::ConverterState); + incompleteLineBuffer.clear(); } /* Check for complete lines read from the device and return them, moving the * buffer position. */ QString ChannelBuffer::linesRead() { - // Any new lines? - const int lastLineIndex = qMax(data.lastIndexOf(QLatin1Char('\n')), - data.lastIndexOf(QLatin1Char('\r'))); - if (lastLineIndex == -1 || lastLineIndex <= bufferPos) + // Convert and append the new input to the buffer of incomplete lines + const char *start = rawData.constData() + rawDataPos; + const int len = rawData.size() - rawDataPos; + incompleteLineBuffer.append(codec->toUnicode(start, len, codecState.get())); + rawDataPos = rawData.size(); + + // Any completed lines in the incompleteLineBuffer? + const int lastLineIndex = qMax(incompleteLineBuffer.lastIndexOf('\n'), + incompleteLineBuffer.lastIndexOf('\r')); + if (lastLineIndex == -1) return QString(); - const int nextBufferPos = lastLineIndex + 1; - const QString lines = data.mid(bufferPos, nextBufferPos - bufferPos); - bufferPos = nextBufferPos; + + // Get completed lines and remove them from the incompleteLinesBuffer: + const QString lines = SynchronousProcess::normalizeNewlines(incompleteLineBuffer.left(lastLineIndex)); + incompleteLineBuffer = incompleteLineBuffer.mid(lastLineIndex + 1); + return lines; } -void ChannelBuffer::append(const QString &text, bool emitSignals) +void ChannelBuffer::append(const QByteArray &text, bool emitSignals) { if (text.isEmpty()) return; - data += text; + rawData += text; if (!emitSignals) return; - // Emit binary signals - emit output(text, firstData); - firstData = false; + // Buffered. Emit complete lines? if (bufferedSignalsEnabled) { const QString lines = linesRead(); @@ -231,8 +269,6 @@ struct SynchronousProcessPrivate { void clearForRun(); QTextCodec *m_codec; - QTextCodec::ConverterState m_stdOutState; - QTextCodec::ConverterState m_stdErrState; TerminalControllingProcess m_process; QTimer m_timer; QEventLoop m_eventLoop; @@ -258,8 +294,11 @@ void SynchronousProcessPrivate::clearForRun() { m_hangTimerCount = 0; m_stdOut.clearForRun(); + m_stdOut.codec = m_codec; m_stdErr.clearForRun(); + m_stdErr.codec = m_codec; m_result.clear(); + m_result.codec = m_codec; m_startFailure = false; m_binary.clear(); } @@ -276,12 +315,16 @@ SynchronousProcess::SynchronousProcess() : connect(&d->m_process, static_cast(&QProcess::error), this, &SynchronousProcess::error); connect(&d->m_process, &QProcess::readyReadStandardOutput, - this, &SynchronousProcess::stdOutReady); + this, [this]() { + d->m_hangTimerCount = 0; + processStdOut(true); + }); connect(&d->m_process, &QProcess::readyReadStandardError, - this, &SynchronousProcess::stdErrReady); - connect(&d->m_stdOut, &ChannelBuffer::output, this, &SynchronousProcess::stdOut); + this, [this]() { + d->m_hangTimerCount = 0; + processStdErr(true); + }); connect(&d->m_stdOut, &ChannelBuffer::outputBuffered, this, &SynchronousProcess::stdOutBuffered); - connect(&d->m_stdErr, &ChannelBuffer::output, this, &SynchronousProcess::stdErr); connect(&d->m_stdErr, &ChannelBuffer::outputBuffered, this, &SynchronousProcess::stdErrBuffered); } @@ -436,8 +479,8 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, processStdErr(false); } - d->m_result.stdOut = d->m_stdOut.data; - d->m_result.stdErr = d->m_stdErr.data; + d->m_result.rawStdOut = d->m_stdOut.rawData; + d->m_result.rawStdErr = d->m_stdErr.rawData; d->m_timer.stop(); if (isGuiThread()) @@ -485,8 +528,8 @@ SynchronousProcessResponse SynchronousProcess::runBlocking(const QString &binary processStdOut(false); processStdErr(false); - d->m_result.stdOut = d->m_stdOut.data; - d->m_result.stdErr = d->m_stdErr.data; + d->m_result.rawStdOut = d->m_stdOut.rawData; + d->m_result.rawStdErr = d->m_stdErr.rawData; return d->m_result; } @@ -569,42 +612,16 @@ void SynchronousProcess::error(QProcess::ProcessError e) d->m_eventLoop.quit(); } -void SynchronousProcess::stdOutReady() -{ - d->m_hangTimerCount = 0; - processStdOut(true); -} - -void SynchronousProcess::stdErrReady() -{ - d->m_hangTimerCount = 0; - processStdErr(true); -} - -QString SynchronousProcess::convertOutput(const QByteArray &ba, - QTextCodec::ConverterState *state) const -{ - return normalizeNewlines(d->m_codec->toUnicode(ba, ba.size(), state)); -} - void SynchronousProcess::processStdOut(bool emitSignals) { // Handle binary data - const QString stdOutput = convertOutput(d->m_process.readAllStandardOutput(), - &d->m_stdOutState); - if (debug > 1) - qDebug() << Q_FUNC_INFO << emitSignals << stdOutput; - d->m_stdOut.append(stdOutput, emitSignals); + d->m_stdOut.append(d->m_process.readAllStandardOutput(), emitSignals); } void SynchronousProcess::processStdErr(bool emitSignals) { // Handle binary data - const QString stdError = convertOutput(d->m_process.readAllStandardError(), - &d->m_stdErrState); - if (debug > 1) - qDebug() << Q_FUNC_INFO << emitSignals << stdError; - d->m_stdErr.append(stdError, emitSignals); + d->m_stdErr.append(d->m_process.readAllStandardError(), emitSignals); } QSharedPointer SynchronousProcess::createProcess(unsigned flags) diff --git a/src/libs/utils/synchronousprocess.h b/src/libs/utils/synchronousprocess.h index 5c4f8bc7608..a8772233644 100644 --- a/src/libs/utils/synchronousprocess.h +++ b/src/libs/utils/synchronousprocess.h @@ -59,12 +59,19 @@ struct QTCREATOR_UTILS_EXPORT SynchronousProcessResponse // Helper to format an exit message. QString exitMessage(const QString &binary, int timeoutS) const; + + QByteArray allRawOutput() const; QString allOutput() const; + QString stdOut() const; + QString stdErr() const; + Result result; int exitCode; - QString stdOut; - QString stdErr; + + QTextCodec *codec = nullptr; + QByteArray rawStdOut; + QByteArray rawStdErr; }; QTCREATOR_UTILS_EXPORT QDebug operator<<(QDebug str, const SynchronousProcessResponse &); @@ -132,7 +139,7 @@ public: // occurs on stderr/stdout as opposed to waitForFinished()). Returns false if a timeout // occurs. Checking of the process' exit state/code still has to be done. static bool readDataFromProcess(QProcess &p, int timeoutS, - QByteArray *stdOut = 0, QByteArray *stdErr = 0, + QByteArray *rawStdOut = 0, QByteArray *rawStdErr = 0, bool timeOutMessageBox = false); // Stop a process by first calling terminate() (allowing for signal handling) and // then kill(). @@ -146,11 +153,8 @@ public: static QString normalizeNewlines(const QString &text); signals: - void stdOut(const QString &text, bool firstTime); - void stdErr(const QString &text, bool firstTime); - - void stdOutBuffered(const QString &data, bool firstTime); - void stdErrBuffered(const QString &data, bool firstTime); + void stdOutBuffered(const QString &lines, bool firstTime); + void stdErrBuffered(const QString &lines, bool firstTime); public slots: bool terminate(); @@ -159,11 +163,8 @@ private: void slotTimeout(); void finished(int exitCode, QProcess::ExitStatus e); void error(QProcess::ProcessError); - void stdOutReady(); - void stdErrReady(); void processStdOut(bool emitSignals); void processStdErr(bool emitSignals); - QString convertOutput(const QByteArray &, QTextCodec::ConverterState *state) const; SynchronousProcessPrivate *d; }; diff --git a/src/plugins/android/androidbuildapkstep.cpp b/src/plugins/android/androidbuildapkstep.cpp index 698dc98aa08..e5593b567c9 100644 --- a/src/plugins/android/androidbuildapkstep.cpp +++ b/src/plugins/android/androidbuildapkstep.cpp @@ -305,7 +305,7 @@ QAbstractItemModel *AndroidBuildApkStep::keystoreCertificates() QMessageBox::critical(0, tr("Error"), tr("Invalid password.")); m_keystorePasswd.clear(); } - rawCerts = response.stdOut; + rawCerts = response.stdOut(); } return new CertificatesModel(rawCerts, this); } diff --git a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp index 52a546860cd..b0014036791 100644 --- a/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp +++ b/src/plugins/beautifier/artisticstyle/artisticstylesettings.cpp @@ -85,10 +85,10 @@ static int updateVersionHelper(const QString &command) return 0; // Astyle prints the version on stdout or stderr, depending on platform - const int version = parseVersion(response.stdOut.trimmed()); + const int version = parseVersion(response.stdOut().trimmed()); if (version != 0) return version; - return parseVersion(response.stdErr.trimmed()); + return parseVersion(response.stdErr().trimmed()); } void ArtisticStyleSettings::updateVersion() @@ -176,7 +176,7 @@ void ArtisticStyleSettings::createDocumentationFile() const stream.writeStartElement(Constants::DOCUMENTATION_XMLROOT); // astyle writes its output to 'error'... - const QStringList lines = response.stdErr.split(QLatin1Char('\n')); + const QStringList lines = response.stdErr().split(QLatin1Char('\n')); QStringList keys; QStringList docu; for (QString line : lines) { diff --git a/src/plugins/beautifier/beautifierplugin.cpp b/src/plugins/beautifier/beautifierplugin.cpp index ee9bbf650f3..043881b2196 100644 --- a/src/plugins/beautifier/beautifierplugin.cpp +++ b/src/plugins/beautifier/beautifierplugin.cpp @@ -104,7 +104,7 @@ FormatTask format(FormatTask task) task.error = BeautifierPlugin::tr("Failed to format: %1.").arg(response.exitMessage(executable, 5)); return task; } - const QString output = response.stdErr; + const QString output = response.stdErr(); if (!output.isEmpty()) task.error = executable + QLatin1String(": ") + output; diff --git a/src/plugins/clearcase/clearcaseplugin.cpp b/src/plugins/clearcase/clearcaseplugin.cpp index 8071365aa8c..2351e6bbb21 100644 --- a/src/plugins/clearcase/clearcaseplugin.cpp +++ b/src/plugins/clearcase/clearcaseplugin.cpp @@ -1480,8 +1480,8 @@ ClearCasePlugin::runCleartool(const QString &workingDir, response.error = sp_resp.result != SynchronousProcessResponse::Finished; if (response.error) response.message = sp_resp.exitMessage(executable, timeOutS); - response.stdErr = sp_resp.stdErr; - response.stdOut = sp_resp.stdOut; + response.stdErr = sp_resp.stdErr(); + response.stdOut = sp_resp.stdOut(); return response; } diff --git a/src/plugins/cmakeprojectmanager/cmaketool.cpp b/src/plugins/cmakeprojectmanager/cmaketool.cpp index 55685b08895..5f140ac84f7 100644 --- a/src/plugins/cmakeprojectmanager/cmaketool.cpp +++ b/src/plugins/cmakeprojectmanager/cmaketool.cpp @@ -153,7 +153,7 @@ QStringList CMakeTool::supportedGenerators() const Utils::SynchronousProcessResponse response = run(QLatin1String("--help")); if (response.result == Utils::SynchronousProcessResponse::Finished) { bool inGeneratorSection = false; - const QStringList lines = response.stdOut.split(QLatin1Char('\n')); + const QStringList lines = response.stdOut().split(QLatin1Char('\n')); foreach (const QString &line, lines) { if (line.isEmpty()) continue; @@ -188,19 +188,19 @@ TextEditor::Keywords CMakeTool::keywords() Utils::SynchronousProcessResponse response; response = run(QLatin1String("--help-command-list")); if (response.result == Utils::SynchronousProcessResponse::Finished) - m_functions = response.stdOut.split(QLatin1Char('\n')); + m_functions = response.stdOut().split(QLatin1Char('\n')); response = run(QLatin1String("--help-commands")); if (response.result == Utils::SynchronousProcessResponse::Finished) - parseFunctionDetailsOutput(response.stdOut); + parseFunctionDetailsOutput(response.stdOut()); response = run(QLatin1String("--help-property-list")); if (response.result == Utils::SynchronousProcessResponse::Finished) - m_variables = parseVariableOutput(response.stdOut); + m_variables = parseVariableOutput(response.stdOut()); response = run(QLatin1String("--help-variable-list")); if (response.result == Utils::SynchronousProcessResponse::Finished) { - m_variables.append(parseVariableOutput(response.stdOut)); + m_variables.append(parseVariableOutput(response.stdOut())); m_variables = Utils::filteredUnique(m_variables); Utils::sort(m_variables); } diff --git a/src/plugins/cvs/cvsplugin.cpp b/src/plugins/cvs/cvsplugin.cpp index 9f4097ebb13..336a45f6a80 100644 --- a/src/plugins/cvs/cvsplugin.cpp +++ b/src/plugins/cvs/cvsplugin.cpp @@ -1140,8 +1140,8 @@ CvsResponse CvsPlugin::runCvs(const QString &workingDirectory, timeOutS, flags, outputCodec); response.result = CvsResponse::OtherError; - response.stdErr = sp_resp.stdErr; - response.stdOut = sp_resp.stdOut; + response.stdErr = sp_resp.stdErr(); + response.stdOut = sp_resp.stdOut(); switch (sp_resp.result) { case SynchronousProcessResponse::Finished: response.result = CvsResponse::Ok; diff --git a/src/plugins/debugger/gdb/coregdbadapter.cpp b/src/plugins/debugger/gdb/coregdbadapter.cpp index b7a54285719..4534c295a55 100644 --- a/src/plugins/debugger/gdb/coregdbadapter.cpp +++ b/src/plugins/debugger/gdb/coregdbadapter.cpp @@ -142,7 +142,7 @@ GdbCoreEngine::readExecutableNameFromCore(const QString &debuggerCommand, const SynchronousProcessResponse response = proc.runBlocking(debuggerCommand, args); if (response.result == SynchronousProcessResponse::Finished) { - QString output = response.stdOut; + QString output = response.stdOut(); // Core was generated by `/data/dev/creator-2.6/bin/qtcreator'. // Program terminated with signal 11, Segmentation fault. int pos1 = output.indexOf("Core was generated by"); diff --git a/src/plugins/git/gitclient.cpp b/src/plugins/git/gitclient.cpp index e903a58d072..b526fb980e4 100644 --- a/src/plugins/git/gitclient.cpp +++ b/src/plugins/git/gitclient.cpp @@ -473,8 +473,8 @@ public: // No conflicts => do nothing if (response.result == SynchronousProcessResponse::Finished) return; - handler.readStdOut(response.stdOut); - handler.readStdErr(response.stdErr); + handler.readStdOut(response.stdOut()); + handler.readStdErr(response.stdErr()); } private: @@ -1543,7 +1543,7 @@ bool GitClient::executeSynchronousStash(const QString &workingDirectory, const SynchronousProcessResponse response = vcsSynchronousExec(workingDirectory, arguments, flags); const bool rc = response.result == SynchronousProcessResponse::Finished; if (!rc) - msgCannotRun(arguments, workingDirectory, response.stdErr.toLocal8Bit(), errorMessage); + msgCannotRun(arguments, workingDirectory, response.rawStdErr, errorMessage); return rc; } @@ -2119,7 +2119,7 @@ QStringList GitClient::synchronousRepositoryBranches(const QString &repositoryUR QString headSha; // split "82bfad2f51d34e98b18982211c82220b8db049brefs/heads/master" bool headFound = false; - foreach (const QString &line, resp.stdOut.split('\n')) { + foreach (const QString &line, resp.stdOut().split('\n')) { if (line.endsWith("\tHEAD")) { QTC_CHECK(headSha.isNull()); headSha = line.left(line.indexOf('\t')); diff --git a/src/plugins/ios/iosprobe.cpp b/src/plugins/ios/iosprobe.cpp index 47c4e2c7a7d..a8be1f7b2a5 100644 --- a/src/plugins/ios/iosprobe.cpp +++ b/src/plugins/ios/iosprobe.cpp @@ -104,7 +104,7 @@ void IosProbe::detectDeveloperPaths() if (response.result != Utils::SynchronousProcessResponse::Finished) { qCWarning(probeLog) << QString::fromLatin1("Could not detect selected xcode with /usr/bin/xcode-select"); } else { - QString path = response.stdOut; + QString path = response.stdOut(); path.chop(1); addDeveloperPath(path); } diff --git a/src/plugins/mercurial/mercurialclient.cpp b/src/plugins/mercurial/mercurialclient.cpp index 30af8ba98e5..abc4835ed89 100644 --- a/src/plugins/mercurial/mercurialclient.cpp +++ b/src/plugins/mercurial/mercurialclient.cpp @@ -157,7 +157,7 @@ bool MercurialClient::synchronousPull(const QString &workingDir, const QString & workingDir, vcsBinary(), args, vcsTimeoutS(), flags, 0, env); const bool ok = resp.result == SynchronousProcessResponse::Finished; - parsePullOutput(resp.stdOut.trimmed()); + parsePullOutput(resp.stdOut().trimmed()); return ok; } diff --git a/src/plugins/perforce/perforceplugin.cpp b/src/plugins/perforce/perforceplugin.cpp index 5696e55760b..a351014293d 100644 --- a/src/plugins/perforce/perforceplugin.cpp +++ b/src/plugins/perforce/perforceplugin.cpp @@ -1016,8 +1016,8 @@ PerforceResponse PerforcePlugin::synchronousProcess(const QString &workingDir, PerforceResponse response; response.error = true; response.exitCode = sp_resp.exitCode; - response.stdErr = sp_resp.stdErr; - response.stdOut = sp_resp.stdOut; + response.stdErr = sp_resp.stdErr(); + response.stdOut = sp_resp.stdOut(); switch (sp_resp.result) { case SynchronousProcessResponse::Finished: response.error = false; diff --git a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp index d7eb341d5b0..34436b892c8 100644 --- a/src/plugins/projectexplorer/abstractmsvctoolchain.cpp +++ b/src/plugins/projectexplorer/abstractmsvctoolchain.cpp @@ -286,7 +286,7 @@ bool AbstractMsvcToolChain::generateEnvironmentSettings(Utils::Environment &env, } // The SDK/MSVC scripts do not return exit codes != 0. Check on stdout. - const QString stdOut = response.stdOut; + const QString stdOut = response.stdOut(); // // Now parse the file to get the environment settings diff --git a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp index 59487384c1c..25d009908bb 100644 --- a/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp +++ b/src/plugins/projectexplorer/customwizard/customwizardscriptgenerator.cpp @@ -116,15 +116,15 @@ static bool if (response.result != Utils::SynchronousProcessResponse::Finished) { *errorMessage = QString::fromLatin1("Generator script failed: %1") .arg(response.exitMessage(binary, 30)); - if (!response.stdErr.isEmpty()) { + const QString stdErr = response.stdErr(); + if (!stdErr.isEmpty()) { errorMessage->append(QLatin1Char('\n')); - errorMessage->append(response.stdErr); + errorMessage->append(stdErr); } return false; } if (stdOut) { - *stdOut = response.stdOut; - stdOut->remove(QLatin1Char('\r')); + *stdOut = response.stdOut(); if (CustomWizard::verbose()) qDebug("Output: '%s'\n", qPrintable(*stdOut)); } diff --git a/src/plugins/projectexplorer/msvctoolchain.cpp b/src/plugins/projectexplorer/msvctoolchain.cpp index bb084b644e9..6398ef87ad5 100644 --- a/src/plugins/projectexplorer/msvctoolchain.cpp +++ b/src/plugins/projectexplorer/msvctoolchain.cpp @@ -253,18 +253,17 @@ QByteArray MsvcToolChain::msvcPredefinedMacros(const QStringList cxxflags, response.exitCode != 0) return predefinedMacros; - const QStringList output = response.stdOut.split('\n'); + const QStringList output = Utils::filtered(response.stdOut().split('\n'), + [](const QString &s) { return s.startsWith('V'); }); foreach (const QString& line, output) { - if (line.startsWith('V')) { - QStringList split = line.split('='); - const QString key = split.at(0).mid(1); - QString value = split.at(1); - predefinedMacros += "#define "; - predefinedMacros += key.toUtf8(); - predefinedMacros += ' '; - predefinedMacros += value.toUtf8(); - predefinedMacros += '\n'; - } + QStringList split = line.split('='); + const QString key = split.at(0).mid(1); + QString value = split.at(1); + predefinedMacros += "#define "; + predefinedMacros += key.toUtf8(); + predefinedMacros += ' '; + predefinedMacros += value.toUtf8(); + predefinedMacros += '\n'; } if (debug) qDebug() << "msvcPredefinedMacros" << predefinedMacros; diff --git a/src/plugins/subversion/subversionplugin.cpp b/src/plugins/subversion/subversionplugin.cpp index 96c66229eb3..d5b0f90e4be 100644 --- a/src/plugins/subversion/subversionplugin.cpp +++ b/src/plugins/subversion/subversionplugin.cpp @@ -892,8 +892,8 @@ SubversionResponse SubversionPlugin::runSvn(const QString &workingDir, response.error = sp_resp.result != SynchronousProcessResponse::Finished; if (response.error) response.message = sp_resp.exitMessage(executable.toString(), timeOutS); - response.stdErr = sp_resp.stdErr; - response.stdOut = sp_resp.stdOut; + response.stdErr = sp_resp.stdErr(); + response.stdOut = sp_resp.stdOut(); return response; } diff --git a/src/plugins/texteditor/generichighlighter/highlightersettings.cpp b/src/plugins/texteditor/generichighlighter/highlightersettings.cpp index dcfa90593f4..42e9ca3c26d 100644 --- a/src/plugins/texteditor/generichighlighter/highlightersettings.cpp +++ b/src/plugins/texteditor/generichighlighter/highlightersettings.cpp @@ -74,7 +74,7 @@ QString findFallbackDefinitionsLocation() Utils::SynchronousProcessResponse response = process.runBlocking(program, QStringList(QLatin1String("--prefix"))); if (response.result == Utils::SynchronousProcessResponse::Finished) { - QString output = response.stdOut; + QString output = response.stdOut(); output.remove(QLatin1Char('\n')); for (int i = 0; i < kateSyntaxCount; ++i) { dir.setPath(output + kateSyntax[i]); diff --git a/tests/manual/process/mainwindow.cpp b/tests/manual/process/mainwindow.cpp index bd89d935cf8..7a99e8a8724 100644 --- a/tests/manual/process/mainwindow.cpp +++ b/tests/manual/process/mainwindow.cpp @@ -54,8 +54,8 @@ void MainWindow::test() Utils::SynchronousProcess process; process.setTimeoutS(2); qDebug() << "Async: " << cmd << args; - connect(&process, &Utils::SynchronousProcess::stdOut, this, &MainWindow::append); - connect(&process, &Utils::SynchronousProcess::stdErr, this, &MainWindow::append); + connect(&process, &Utils::SynchronousProcess::stdOutBuffered, this, &MainWindow::append); + connect(&process, &Utils::SynchronousProcess::stdErrBuffered, this, &MainWindow::append); const Utils::SynchronousProcessResponse resp = process.run(cmd, args); qDebug() << resp; }