diff options
author | hjk <hjk@qt.io> | 2022-05-23 11:43:10 +0200 |
---|---|---|
committer | hjk <hjk@qt.io> | 2022-05-23 11:13:27 +0000 |
commit | 1f022735d4c0d66adcf78887ffb29247f0870c7d (patch) | |
tree | bfe442ccd69ea263b9e06595325a601742867072 | |
parent | 21d0175dabff43eaf35658f1153187553019444f (diff) | |
download | qt-creator-1f022735d4c0d66adcf78887ffb29247f0870c7d.tar.gz |
ProjectExplorer: Move ApplicationLauncher to runcontrol.cpp
It's the only remaining use.
Change-Id: Id631981945b4d1850ea880a583d99dbb1e3cf25c
Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
-rw-r--r-- | src/plugins/projectexplorer/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/plugins/projectexplorer/applicationlauncher.cpp | 355 | ||||
-rw-r--r-- | src/plugins/projectexplorer/applicationlauncher.h | 76 | ||||
-rw-r--r-- | src/plugins/projectexplorer/projectexplorer.qbs | 1 | ||||
-rw-r--r-- | src/plugins/projectexplorer/runcontrol.cpp | 367 |
5 files changed, 356 insertions, 444 deletions
diff --git a/src/plugins/projectexplorer/CMakeLists.txt b/src/plugins/projectexplorer/CMakeLists.txt index f24aba8244..0bfdec0dc5 100644 --- a/src/plugins/projectexplorer/CMakeLists.txt +++ b/src/plugins/projectexplorer/CMakeLists.txt @@ -9,7 +9,6 @@ add_qtc_plugin(ProjectExplorer addrunconfigdialog.cpp addrunconfigdialog.h allprojectsfilter.cpp allprojectsfilter.h allprojectsfind.cpp allprojectsfind.h - applicationlauncher.cpp applicationlauncher.h appoutputpane.cpp appoutputpane.h baseprojectwizarddialog.cpp baseprojectwizarddialog.h buildaspects.cpp buildaspects.h diff --git a/src/plugins/projectexplorer/applicationlauncher.cpp b/src/plugins/projectexplorer/applicationlauncher.cpp deleted file mode 100644 index 8e913fff6c..0000000000 --- a/src/plugins/projectexplorer/applicationlauncher.cpp +++ /dev/null @@ -1,355 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#include "applicationlauncher.h" - -#include "devicesupport/desktopdevice.h" -#include "projectexplorer.h" -#include "projectexplorersettings.h" -#include "runcontrol.h" -#include "windebuginterface.h" - -#include <coreplugin/icore.h> - -#include <utils/fileutils.h> -#include <utils/processinterface.h> -#include <utils/qtcassert.h> -#include <utils/qtcprocess.h> - -#include <QTextCodec> -#include <QTimer> - -/*! - \class ProjectExplorer::ApplicationLauncher - - \brief The ApplicationLauncher class is the application launcher of the - ProjectExplorer plugin. - - Encapsulates processes running in a console or as GUI processes, - captures debug output of GUI processes on Windows (outputDebugString()). - - \sa Utils::QtcProcess -*/ - -using namespace Utils; - -namespace ProjectExplorer { - -using namespace Internal; - -namespace Internal { - -class ApplicationLauncherPrivate : public QObject -{ -public: - enum State { Inactive, Run }; - explicit ApplicationLauncherPrivate(ApplicationLauncher *parent); - - ~ApplicationLauncherPrivate() override { - if (m_state == Run) - emit q->done(); - } - - void start(); - void stop(); - - void handleStandardOutput(); - void handleStandardError(); - void handleDone(); - - // Local - qint64 applicationPID() const; - bool isRunning() const; - -public: - ApplicationLauncher *q; - - bool m_isLocal = true; - bool m_runAsRoot = false; - - QtcProcess m_process; - - QTextCodec *m_outputCodec = nullptr; - QTextCodec::ConverterState m_outputCodecState; - QTextCodec::ConverterState m_errorCodecState; - - // Keep track whether we need to emit a finished signal - bool m_processRunning = false; - - // Remote - State m_state = Inactive; - bool m_stopRequested = false; - - Runnable m_runnable; - - ProcessResultData m_resultData; -}; - -} // Internal - -static QProcess::ProcessChannelMode defaultProcessChannelMode() -{ - return ProjectExplorerPlugin::appOutputSettings().mergeChannels - ? QProcess::MergedChannels : QProcess::SeparateChannels; -} - -ApplicationLauncherPrivate::ApplicationLauncherPrivate(ApplicationLauncher *parent) - : q(parent) -{ - m_process.setProcessChannelMode(defaultProcessChannelMode()); - connect(&m_process, &QtcProcess::started, q, &ApplicationLauncher::started); - connect(&m_process, &QtcProcess::done, this, &ApplicationLauncherPrivate::handleDone); - connect(&m_process, &QtcProcess::readyReadStandardError, - this, &ApplicationLauncherPrivate::handleStandardError); - connect(&m_process, &QtcProcess::readyReadStandardOutput, - this, &ApplicationLauncherPrivate::handleStandardOutput); - - if (WinDebugInterface::instance()) { - connect(WinDebugInterface::instance(), &WinDebugInterface::cannotRetrieveDebugOutput, - this, [this] { - disconnect(WinDebugInterface::instance(), nullptr, this, nullptr); - emit q->appendMessage(ApplicationLauncher::tr("Cannot retrieve debugging output.") - + QLatin1Char('\n'), ErrorMessageFormat); - }); - - connect(WinDebugInterface::instance(), &WinDebugInterface::debugOutput, - this, [this](qint64 pid, const QString &message) { - if (applicationPID() == pid) - emit q->appendMessage(message, DebugFormat); - }); - } -} - -ApplicationLauncher::ApplicationLauncher(QObject *parent) : QObject(parent), - d(std::make_unique<ApplicationLauncherPrivate>(this)) -{ -} - -ApplicationLauncher::~ApplicationLauncher() = default; - -void ApplicationLauncher::setUseTerminal(bool on) -{ - d->m_process.setTerminalMode(on ? Utils::TerminalMode::On : Utils::TerminalMode::Off); -} - -void ApplicationLauncher::setRunAsRoot(bool on) -{ - d->m_runAsRoot = on; -} - -void ApplicationLauncher::setRunnable(const Runnable &runnable) -{ - d->m_runnable = runnable; -} - -void ApplicationLauncher::stop() -{ - d->stop(); -} - -void ApplicationLauncherPrivate::stop() -{ - m_resultData.m_exitStatus = QProcess::CrashExit; - if (m_isLocal) { - if (!isRunning()) - return; - m_process.stopProcess(); - QTimer::singleShot(100, this, [this] { emit q->done(); }); - } else { - if (m_stopRequested) - return; - m_stopRequested = true; - emit q->appendMessage(ApplicationLauncher::tr("User requested stop. Shutting down..."), - NormalMessageFormat); - switch (m_state) { - case Run: - m_process.terminate(); - break; - case Inactive: - break; - } - } -} - -bool ApplicationLauncherPrivate::isRunning() const -{ - return m_process.state() != QProcess::NotRunning; -} - -ProcessHandle ApplicationLauncher::applicationPID() const -{ - return ProcessHandle(d->applicationPID()); -} - -qint64 ApplicationLauncherPrivate::applicationPID() const -{ - if (!isRunning()) - return 0; - - return m_process.processId(); -} - -ProcessResultData ApplicationLauncher::resultData() const -{ - return d->m_resultData; -} - -void ApplicationLauncherPrivate::handleDone() -{ - m_resultData = m_process.resultData(); - - if (m_isLocal) { - if (m_resultData.m_error == QProcess::UnknownError) { - emit q->done(); - return; - } - // TODO: why below handlings are different? - if (m_process.usesTerminal()) { - emit q->appendMessage(m_process.errorString(), ErrorMessageFormat); - if (m_processRunning && m_process.processId() == 0) { - m_processRunning = false; - m_resultData.m_exitCode = -1; // FIXME: Why? - } - } else { - QString errorString; - switch (m_resultData.m_error) { - case QProcess::FailedToStart: - errorString = ApplicationLauncher::tr("Failed to start program. Path or permissions wrong?"); - break; - case QProcess::Crashed: - m_resultData.m_exitStatus = QProcess::CrashExit; - break; - default: - errorString = ApplicationLauncher::tr("Some error has occurred while running the program."); - } - if (!errorString.isEmpty()) - emit q->appendMessage(errorString, ErrorMessageFormat); - if (m_processRunning && !isRunning()) { - m_processRunning = false; - m_resultData.m_exitCode = -1; - } - } - - } else { - QTC_ASSERT(m_state == Run, emit q->done(); return); - if (m_resultData.m_error == QProcess::FailedToStart) { - m_resultData.m_exitStatus = QProcess::CrashExit; - } else if (m_resultData.m_exitStatus == QProcess::CrashExit) { - m_resultData.m_error = QProcess::Crashed; - } - m_state = Inactive; - } - emit q->done(); -} - -void ApplicationLauncherPrivate::handleStandardOutput() -{ - const QByteArray data = m_process.readAllStandardOutput(); - const QString msg = m_outputCodec->toUnicode( - data.constData(), data.length(), &m_outputCodecState); - emit q->appendMessage(msg, StdOutFormat, false); -} - -void ApplicationLauncherPrivate::handleStandardError() -{ - const QByteArray data = m_process.readAllStandardError(); - const QString msg = m_outputCodec->toUnicode( - data.constData(), data.length(), &m_errorCodecState); - emit q->appendMessage(msg, StdErrFormat, false); -} - -void ApplicationLauncher::start() -{ - d->start(); -} - -void ApplicationLauncherPrivate::start() -{ - m_isLocal = m_runnable.device.isNull() || m_runnable.device.dynamicCast<const DesktopDevice>(); - - m_resultData = {}; - - if (m_isLocal) { - // Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...) - const FilePath fixedPath = m_runnable.workingDirectory.normalizedPathName(); - m_process.setWorkingDirectory(fixedPath); - - Environment env = m_runnable.environment; - if (m_runAsRoot) - RunControl::provideAskPassEntry(env); - - m_process.setEnvironment(env); - - m_processRunning = true; - - WinDebugInterface::startIfNeeded(); - - CommandLine cmdLine = m_runnable.command; - - if (HostOsInfo::isMacHost()) { - CommandLine disclaim(Core::ICore::libexecPath("disclaim")); - disclaim.addCommandLineAsArgs(cmdLine); - cmdLine = disclaim; - } - - m_process.setRunAsRoot(m_runAsRoot); - m_process.setCommand(cmdLine); - } else { - QTC_ASSERT(m_state == Inactive, return); - - if (!m_runnable.device) { - m_resultData.m_errorString = ApplicationLauncher::tr("Cannot run: No device."); - m_resultData.m_error = QProcess::FailedToStart; - m_resultData.m_exitStatus = QProcess::CrashExit; - emit q->done(); - return; - } - - if (!m_runnable.device->isEmptyCommandAllowed() && m_runnable.command.isEmpty()) { - m_resultData.m_errorString = ApplicationLauncher::tr("Cannot run: No command given."); - m_resultData.m_error = QProcess::FailedToStart; - m_resultData.m_exitStatus = QProcess::CrashExit; - emit q->done(); - return; - } - - m_state = Run; - m_stopRequested = false; - - m_process.setCommand(m_runnable.command); - m_process.setWorkingDirectory(m_runnable.workingDirectory); - m_process.setEnvironment(m_runnable.environment); - m_process.setExtraData(m_runnable.extraData); - } - - if (m_isLocal) - m_outputCodec = QTextCodec::codecForLocale(); - else - m_outputCodec = QTextCodec::codecForName("utf8"); - - m_process.start(); -} - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/applicationlauncher.h b/src/plugins/projectexplorer/applicationlauncher.h deleted file mode 100644 index e3ea98698b..0000000000 --- a/src/plugins/projectexplorer/applicationlauncher.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of Qt Creator. -** -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3 as published by the Free Software -** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-3.0.html. -** -****************************************************************************/ - -#pragma once - -#include "projectexplorer_export.h" - -#include <utils/outputformat.h> -#include <utils/processhandle.h> - -#include <QProcess> - -#include <memory> - -namespace Utils { -class ProcessHandle; -class ProcessResultData; -} // Utils - -namespace ProjectExplorer { - -class Runnable; -namespace Internal { class ApplicationLauncherPrivate; } - -// Documentation inside. -class PROJECTEXPLORER_EXPORT ApplicationLauncher : public QObject -{ - Q_OBJECT - -public: - explicit ApplicationLauncher(QObject *parent = nullptr); - ~ApplicationLauncher() override; - - void setUseTerminal(bool on); - void setRunAsRoot(bool on); - void setRunnable(const Runnable &runnable); - - void start(); - void stop(); - - Utils::ProcessHandle applicationPID() const; - - Utils::ProcessResultData resultData() const; - -signals: - void appendMessage(const QString &message, Utils::OutputFormat format, bool appendNewLine = true); - void started(); - void done(); - -private: - std::unique_ptr<Internal::ApplicationLauncherPrivate> d; -}; - -} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index a9a865a3ec..c6f403a891 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -27,7 +27,6 @@ Project { "addrunconfigdialog.cpp", "addrunconfigdialog.h", "allprojectsfilter.cpp", "allprojectsfilter.h", "allprojectsfind.cpp", "allprojectsfind.h", - "applicationlauncher.cpp", "applicationlauncher.h", "appoutputpane.cpp", "appoutputpane.h", "baseprojectwizarddialog.cpp", "baseprojectwizarddialog.h", "buildaspects.cpp", "buildaspects.h", diff --git a/src/plugins/projectexplorer/runcontrol.cpp b/src/plugins/projectexplorer/runcontrol.cpp index 053130d8f2..c37dc2bdbd 100644 --- a/src/plugins/projectexplorer/runcontrol.cpp +++ b/src/plugins/projectexplorer/runcontrol.cpp @@ -25,43 +25,47 @@ #include "runcontrol.h" -#include "applicationlauncher.h" -#include "devicesupport/desktopdevice.h" -#include "devicesupport/idevice.h" -#include "abi.h" #include "buildconfiguration.h" #include "customparser.h" -#include "environmentaspect.h" +#include "devicesupport/desktopdevice.h" +#include "devicesupport/idevice.h" #include "kitinformation.h" #include "project.h" #include "projectexplorer.h" +#include "projectexplorersettings.h" #include "runconfigurationaspects.h" +#include "runcontrol.h" #include "session.h" #include "target.h" -#include "toolchain.h" +#include "windebuginterface.h" + +#include <coreplugin/icontext.h> +#include <coreplugin/icore.h> #include <utils/algorithm.h> #include <utils/checkablemessagebox.h> #include <utils/detailswidget.h> #include <utils/fileinprojectfinder.h> +#include <utils/fileutils.h> #include <utils/outputformatter.h> #include <utils/processinterface.h> +#include <utils/processinterface.h> #include <utils/qtcassert.h> +#include <utils/qtcprocess.h> #include <utils/utilsicons.h> #include <utils/variablechooser.h> -#include <coreplugin/icontext.h> -#include <coreplugin/icore.h> - #include <ssh/sshsettings.h> #include <QDir> #include <QFormLayout> #include <QHash> -#include <QPushButton> -#include <QTimer> #include <QLoggingCategory> +#include <QPushButton> #include <QSettings> +#include <QTextCodec> +#include <QTimer> + #if defined (WITH_JOURNALD) #include "journaldwatcher.h" @@ -336,6 +340,8 @@ public: class RunControlPrivate : public QObject, public RunControlPrivateData { + Q_OBJECT + public: RunControlPrivate(RunControl *parent, Utils::Id mode) : q(parent), runMode(mode) @@ -1188,7 +1194,344 @@ void RunControlPrivate::debugMessage(const QString &msg) qCDebug(statesLog()) << msg; } + +// ApplicationLauncher + +class ApplicationLauncher; + +class ApplicationLauncherPrivate : public QObject +{ +public: + enum State { Inactive, Run }; + explicit ApplicationLauncherPrivate(ApplicationLauncher *parent); + + ~ApplicationLauncherPrivate() override; + + void start(); + void stop(); + + void handleStandardOutput(); + void handleStandardError(); + void handleDone(); + + // Local + qint64 applicationPID() const; + bool isRunning() const; + +public: + ApplicationLauncher *q; + + bool m_isLocal = true; + bool m_runAsRoot = false; + + QtcProcess m_process; + + QTextCodec *m_outputCodec = nullptr; + QTextCodec::ConverterState m_outputCodecState; + QTextCodec::ConverterState m_errorCodecState; + + // Keep track whether we need to emit a finished signal + bool m_processRunning = false; + + // Remote + State m_state = Inactive; + bool m_stopRequested = false; + + Runnable m_runnable; + + ProcessResultData m_resultData; +}; + +class ApplicationLauncher : public QObject +{ + Q_OBJECT + +public: + explicit ApplicationLauncher(QObject *parent = nullptr); + ~ApplicationLauncher() override; + + void setUseTerminal(bool on); + void setRunAsRoot(bool on); + void setRunnable(const Runnable &runnable); + + void start(); + void stop(); + + Utils::ProcessHandle applicationPID() const; + + Utils::ProcessResultData resultData() const; + +signals: + void appendMessage(const QString &message, Utils::OutputFormat format, bool appendNewLine = true); + void started(); + void done(); + +private: + std::unique_ptr<ApplicationLauncherPrivate> d; +}; + +static QProcess::ProcessChannelMode defaultProcessChannelMode() +{ + return ProjectExplorerPlugin::appOutputSettings().mergeChannels + ? QProcess::MergedChannels : QProcess::SeparateChannels; +} + +ApplicationLauncherPrivate::ApplicationLauncherPrivate(ApplicationLauncher *parent) + : q(parent) +{ + m_process.setProcessChannelMode(defaultProcessChannelMode()); + connect(&m_process, &QtcProcess::started, q, &ApplicationLauncher::started); + connect(&m_process, &QtcProcess::done, this, &ApplicationLauncherPrivate::handleDone); + connect(&m_process, &QtcProcess::readyReadStandardError, + this, &ApplicationLauncherPrivate::handleStandardError); + connect(&m_process, &QtcProcess::readyReadStandardOutput, + this, &ApplicationLauncherPrivate::handleStandardOutput); + + if (WinDebugInterface::instance()) { + connect(WinDebugInterface::instance(), &WinDebugInterface::cannotRetrieveDebugOutput, + this, [this] { + disconnect(WinDebugInterface::instance(), nullptr, this, nullptr); + emit q->appendMessage(ApplicationLauncher::tr("Cannot retrieve debugging output.") + + QLatin1Char('\n'), ErrorMessageFormat); + }); + + connect(WinDebugInterface::instance(), &WinDebugInterface::debugOutput, + this, [this](qint64 pid, const QString &message) { + if (applicationPID() == pid) + emit q->appendMessage(message, DebugFormat); + }); + } +} + +ApplicationLauncherPrivate::~ApplicationLauncherPrivate() +{ + if (m_state == Run) + emit q->done(); +} + +ApplicationLauncher::ApplicationLauncher(QObject *parent) : QObject(parent), + d(std::make_unique<ApplicationLauncherPrivate>(this)) +{ +} + +ApplicationLauncher::~ApplicationLauncher() = default; + +void ApplicationLauncher::setUseTerminal(bool on) +{ + d->m_process.setTerminalMode(on ? Utils::TerminalMode::On : Utils::TerminalMode::Off); +} + +void ApplicationLauncher::setRunAsRoot(bool on) +{ + d->m_runAsRoot = on; +} + +void ApplicationLauncher::setRunnable(const Runnable &runnable) +{ + d->m_runnable = runnable; +} + +void ApplicationLauncher::stop() +{ + d->stop(); +} + +void ApplicationLauncherPrivate::stop() +{ + m_resultData.m_exitStatus = QProcess::CrashExit; + if (m_isLocal) { + if (!isRunning()) + return; + m_process.stopProcess(); + QTimer::singleShot(100, this, [this] { emit q->done(); }); + } else { + if (m_stopRequested) + return; + m_stopRequested = true; + emit q->appendMessage(ApplicationLauncher::tr("User requested stop. Shutting down..."), + NormalMessageFormat); + switch (m_state) { + case Run: + m_process.terminate(); + break; + case Inactive: + break; + } + } +} + +bool ApplicationLauncherPrivate::isRunning() const +{ + return m_process.state() != QProcess::NotRunning; +} + +ProcessHandle ApplicationLauncher::applicationPID() const +{ + return ProcessHandle(d->applicationPID()); +} + +qint64 ApplicationLauncherPrivate::applicationPID() const +{ + if (!isRunning()) + return 0; + + return m_process.processId(); +} + +ProcessResultData ApplicationLauncher::resultData() const +{ + return d->m_resultData; +} + +void ApplicationLauncherPrivate::handleDone() +{ + m_resultData = m_process.resultData(); + + if (m_isLocal) { + if (m_resultData.m_error == QProcess::UnknownError) { + emit q->done(); + return; + } + // TODO: why below handlings are different? + if (m_process.usesTerminal()) { + emit q->appendMessage(m_process.errorString(), ErrorMessageFormat); + if (m_processRunning && m_process.processId() == 0) { + m_processRunning = false; + m_resultData.m_exitCode = -1; // FIXME: Why? + } + } else { + QString errorString; + switch (m_resultData.m_error) { + case QProcess::FailedToStart: + errorString = ApplicationLauncher::tr("Failed to start program. Path or permissions wrong?"); + break; + case QProcess::Crashed: + m_resultData.m_exitStatus = QProcess::CrashExit; + break; + default: + errorString = ApplicationLauncher::tr("Some error has occurred while running the program."); + } + if (!errorString.isEmpty()) + emit q->appendMessage(errorString, ErrorMessageFormat); + if (m_processRunning && !isRunning()) { + m_processRunning = false; + m_resultData.m_exitCode = -1; + } + } + + } else { + QTC_ASSERT(m_state == Run, emit q->done(); return); + if (m_resultData.m_error == QProcess::FailedToStart) { + m_resultData.m_exitStatus = QProcess::CrashExit; + } else if (m_resultData.m_exitStatus == QProcess::CrashExit) { + m_resultData.m_error = QProcess::Crashed; + } + m_state = Inactive; + } + emit q->done(); +} + +void ApplicationLauncherPrivate::handleStandardOutput() +{ + const QByteArray data = m_process.readAllStandardOutput(); + const QString msg = m_outputCodec->toUnicode( + data.constData(), data.length(), &m_outputCodecState); + emit q->appendMessage(msg, StdOutFormat, false); +} + +void ApplicationLauncherPrivate::handleStandardError() +{ + const QByteArray data = m_process.readAllStandardError(); + const QString msg = m_outputCodec->toUnicode( + data.constData(), data.length(), &m_errorCodecState); + emit q->appendMessage(msg, StdErrFormat, false); +} + +void ApplicationLauncher::start() +{ + d->start(); +} + +void ApplicationLauncherPrivate::start() +{ + m_isLocal = m_runnable.device.isNull() || m_runnable.device.dynamicCast<const DesktopDevice>(); + + m_resultData = {}; + + if (m_isLocal) { + // Work around QTBUG-17529 (QtDeclarative fails with 'File name case mismatch' ...) + const FilePath fixedPath = m_runnable.workingDirectory.normalizedPathName(); + m_process.setWorkingDirectory(fixedPath); + + Environment env = m_runnable.environment; + if (m_runAsRoot) + RunControl::provideAskPassEntry(env); + + m_process.setEnvironment(env); + + m_processRunning = true; + + WinDebugInterface::startIfNeeded(); + + CommandLine cmdLine = m_runnable.command; + + if (HostOsInfo::isMacHost()) { + CommandLine disclaim(Core::ICore::libexecPath("disclaim")); + disclaim.addCommandLineAsArgs(cmdLine); + cmdLine = disclaim; + } + + m_process.setRunAsRoot(m_runAsRoot); + m_process.setCommand(cmdLine); + } else { + QTC_ASSERT(m_state == Inactive, return); + + if (!m_runnable.device) { + m_resultData.m_errorString = ApplicationLauncher::tr("Cannot run: No device."); + m_resultData.m_error = QProcess::FailedToStart; + m_resultData.m_exitStatus = QProcess::CrashExit; + emit q->done(); + return; + } + + if (!m_runnable.device->isEmptyCommandAllowed() && m_runnable.command.isEmpty()) { + m_resultData.m_errorString = ApplicationLauncher::tr("Cannot run: No command given."); + m_resultData.m_error = QProcess::FailedToStart; + m_resultData.m_exitStatus = QProcess::CrashExit; + emit q->done(); + return; + } + + m_state = Run; + m_stopRequested = false; + + m_process.setCommand(m_runnable.command); + m_process.setWorkingDirectory(m_runnable.workingDirectory); + m_process.setEnvironment(m_runnable.environment); + m_process.setExtraData(m_runnable.extraData); + } + + if (m_isLocal) + m_outputCodec = QTextCodec::codecForLocale(); + else + m_outputCodec = QTextCodec::codecForName("utf8"); + + m_process.start(); +} + + // SimpleTargetRunner +/*! + \class ProjectExplorer::SimpleTargetRunner + + \brief The SimpleTargetRunner class is the application launcher of the + ProjectExplorer plugin. + + Encapsulates processes running in a console or as GUI processes, + captures debug output of GUI processes on Windows (outputDebugString()). + + \sa Utils::QtcProcess +*/ namespace Internal { @@ -1648,3 +1991,5 @@ void OutputFormatterFactory::setFormatterCreator(const FormatterCreator &creator } } // namespace ProjectExplorer + +#include "runcontrol.moc" |