diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index acf9c6190d5..e08a8128565 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -95,6 +95,11 @@ QString CommandLine::toUserOutput() const return m_executable.toUserOutput() + ' ' + m_arguments; } +QStringList CommandLine::splitArguments(OsType osType) const +{ + return QtcProcess::splitArgs(m_arguments, osType); +} + /*! \class Utils::FileUtils \brief The FileUtils class contains file and directory related convenience diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index ec018b9c3b3..8193ae915f4 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -145,6 +145,7 @@ public: FilePath executable() const { return m_executable; } QString arguments() const { return m_arguments; } + QStringList splitArguments(OsType osType = HostOsInfo::hostOs()) const; private: FilePath m_executable; diff --git a/src/libs/utils/synchronousprocess.cpp b/src/libs/utils/synchronousprocess.cpp index bfb9d0d2964..d7e5c72c731 100644 --- a/src/libs/utils/synchronousprocess.cpp +++ b/src/libs/utils/synchronousprocess.cpp @@ -26,6 +26,7 @@ #include "synchronousprocess.h" #include "qtcassert.h" #include "hostosinfo.h" +#include "fileutils.h" #include #include @@ -266,7 +267,7 @@ public: QTimer m_timer; QEventLoop m_eventLoop; SynchronousProcessResponse m_result; - QString m_binary; + FilePath m_binary; ChannelBuffer m_stdOut; ChannelBuffer m_stdErr; ExitCodeInterpreter m_exitCodeInterpreter = defaultExitCodeInterpreter; @@ -288,7 +289,7 @@ void SynchronousProcessPrivate::clearForRun() m_result.clear(); m_result.codec = m_codec; m_startFailure = false; - m_binary.clear(); + m_binary = {}; } // ----------- SynchronousProcess @@ -444,21 +445,29 @@ static bool isGuiThread() SynchronousProcessResponse SynchronousProcess::run(const QString &binary, const QStringList &args, const QByteArray &writeData) +{ + CommandLine cmd(FilePath::fromString(binary), {}); + cmd.addArgs(args); + return run(cmd, writeData); +} + +SynchronousProcessResponse SynchronousProcess::run(const CommandLine &cmd, + const QByteArray &writeData) { if (debug) - qDebug() << '>' << Q_FUNC_INFO << binary << args; + qDebug() << '>' << Q_FUNC_INFO << cmd.toUserOutput(); d->clearForRun(); // On Windows, start failure is triggered immediately if the // executable cannot be found in the path. Do not start the // event loop in that case. - d->m_binary = binary; + d->m_binary = cmd.executable(); // using QProcess::start() and passing program, args and OpenMode results in a different // quoting of arguments than using QProcess::setArguments() beforehand and calling start() // only with the OpenMode - d->m_process.setProgram(binary); - d->m_process.setArguments(args); + d->m_process.setProgram(cmd.executable().toString()); + d->m_process.setArguments(cmd.splitArguments()); connect(&d->m_process, &QProcess::started, this, [this, writeData] { if (!writeData.isEmpty()) { int pos = 0; @@ -493,19 +502,27 @@ SynchronousProcessResponse SynchronousProcess::run(const QString &binary, } if (debug) - qDebug() << '<' << Q_FUNC_INFO << binary << d->m_result; + qDebug() << '<' << Q_FUNC_INFO << cmd.executable().toString() << d->m_result; return d->m_result; } -SynchronousProcessResponse SynchronousProcess::runBlocking(const QString &binary, const QStringList &args) +SynchronousProcessResponse + SynchronousProcess::runBlocking(const QString &binary, const QStringList &args) +{ + CommandLine cmd(FilePath::fromString(binary), {}); + cmd.addArgs(args); + return runBlocking(cmd); +} + +SynchronousProcessResponse SynchronousProcess::runBlocking(const CommandLine &cmd) { d->clearForRun(); // On Windows, start failure is triggered immediately if the // executable cannot be found in the path. Do not start the // event loop in that case. - d->m_binary = binary; - d->m_process.start(binary, args, QIODevice::ReadOnly); + d->m_binary = cmd.executable(); + d->m_process.start(cmd.executable().toString(), cmd.splitArguments(), QIODevice::ReadOnly); if (!d->m_process.waitForStarted(d->m_maxHangTimerCount * 1000) && d->m_process.state() == QProcess::NotRunning) { d->m_result.result = SynchronousProcessResponse::StartFailed; @@ -573,7 +590,7 @@ void SynchronousProcess::slotTimeout() if (debug) qDebug() << Q_FUNC_INFO << "HANG detected, killing"; d->m_waitingForUser = true; - const bool terminate = !d->m_timeOutMessageBoxEnabled || askToKill(d->m_binary); + const bool terminate = !d->m_timeOutMessageBoxEnabled || askToKill(d->m_binary.toString()); d->m_waitingForUser = false; if (terminate) { SynchronousProcess::stopProcess(d->m_process); diff --git a/src/libs/utils/synchronousprocess.h b/src/libs/utils/synchronousprocess.h index d8e3275030b..f13a7e2db8b 100644 --- a/src/libs/utils/synchronousprocess.h +++ b/src/libs/utils/synchronousprocess.h @@ -38,6 +38,7 @@ QT_FORWARD_DECLARE_CLASS(QDebug) namespace Utils { class SynchronousProcessPrivate; +class CommandLine; /* Result of SynchronousProcess execution */ class QTCREATOR_UTILS_EXPORT SynchronousProcessResponse @@ -126,10 +127,16 @@ public: void setExitCodeInterpreter(const ExitCodeInterpreter &interpreter); ExitCodeInterpreter exitCodeInterpreter() const; - // Starts an nested event loop and runs the binary with the arguments + // Starts a nested event loop and runs the binary with the arguments + // FIXME: Use the CommandLine overload below. SynchronousProcessResponse run(const QString &binary, const QStringList &args, const QByteArray &writeData = {}); + // Starts a nested event loop and runs the command + SynchronousProcessResponse run(const CommandLine &cmd, const QByteArray &writeData = {}); // Starts the binary with the arguments blocking the UI fully + // FIXME: Use the CommandLine overload below. SynchronousProcessResponse runBlocking(const QString &binary, const QStringList &args); + // Starts the command blocking the UI fully + SynchronousProcessResponse runBlocking(const CommandLine &cmd); // Create a (derived) processes with flags applied. static QSharedPointer createProcess(unsigned flags);