From 1d85d8e706cd2f0af3731d71781caaa8d528dc68 Mon Sep 17 00:00:00 2001 From: Christian Kandeler <christian.kandeler@nokia.com> Date: Thu, 26 Jul 2012 09:02:34 +0200 Subject: [PATCH] ProjectExplorer: Introduce generic application runner. This class aims to be a flexible worker class for SSH-based run controls. It supersedes AbstractRemoteLinuxApplicationRunner as well as all of its derived classes, while having no RemoteLinux dependencies itself. Change-Id: If24f03a32126b36fc3d0b253a1615ad0af5f2b46 Reviewed-by: hjk <qthjk@ovi.com> --- src/plugins/madde/madde.pro | 12 +- src/plugins/madde/madde.qbs | 10 +- .../maemoapplicationrunnerhelperactions.cpp | 148 +++++ ... => maemoapplicationrunnerhelperactions.h} | 62 ++- src/plugins/madde/maemodebugsupport.cpp | 54 -- src/plugins/madde/maemodebugsupport.h | 56 -- src/plugins/madde/maemoremotemounter.h | 2 +- src/plugins/madde/maemorunconfiguration.cpp | 26 - src/plugins/madde/maemorunconfiguration.h | 2 - src/plugins/madde/maemoruncontrol.cpp | 66 --- src/plugins/madde/maemoruncontrol.h | 64 --- src/plugins/madde/maemorunfactories.cpp | 22 +- src/plugins/madde/maemosshrunner.cpp | 215 -------- .../devicesupport/deviceapplicationrunner.cpp | 339 ++++++++++++ .../devicesupport/deviceapplicationrunner.h | 104 ++++ .../projectexplorer/projectexplorer.pro | 6 +- .../projectexplorer/projectexplorer.qbs | 4 +- src/plugins/qmlprofiler/qmlprofilerengine.cpp | 2 + .../remotelinuxqmlprofilerrunner.cpp | 125 ++--- .../remotelinuxqmlprofilerrunner.h | 29 +- src/plugins/qnx/qnx.pro | 2 - src/plugins/qnx/qnxapplicationrunner.cpp | 85 --- src/plugins/qnx/qnxapplicationrunner.h | 69 --- src/plugins/qnx/qnxdebugsupport.cpp | 66 ++- src/plugins/qnx/qnxdebugsupport.h | 27 +- src/plugins/qnx/qnxruncontrol.cpp | 17 +- src/plugins/qnx/qnxruncontrol.h | 9 +- src/plugins/qnx/qnxutils.cpp | 8 + src/plugins/qnx/qnxutils.h | 1 + src/plugins/remotelinux/remotelinux.pro | 2 - src/plugins/remotelinux/remotelinux.qbs | 2 - .../remotelinuxapplicationrunner.cpp | 508 ------------------ .../remotelinuxapplicationrunner.h | 145 ----- .../remotelinux/remotelinuxdebugsupport.cpp | 207 ++++--- .../remotelinux/remotelinuxdebugsupport.h | 44 +- .../remotelinux/remotelinuxruncontrol.cpp | 121 ++--- .../remotelinux/remotelinuxruncontrol.h | 38 +- .../remotelinuxruncontrolfactory.cpp | 6 +- src/plugins/remotelinux/remotelinuxutils.cpp | 9 +- src/plugins/remotelinux/remotelinuxutils.h | 2 +- 40 files changed, 1013 insertions(+), 1703 deletions(-) create mode 100644 src/plugins/madde/maemoapplicationrunnerhelperactions.cpp rename src/plugins/madde/{maemosshrunner.h => maemoapplicationrunnerhelperactions.h} (55%) delete mode 100644 src/plugins/madde/maemodebugsupport.cpp delete mode 100644 src/plugins/madde/maemodebugsupport.h delete mode 100644 src/plugins/madde/maemoruncontrol.cpp delete mode 100644 src/plugins/madde/maemoruncontrol.h delete mode 100644 src/plugins/madde/maemosshrunner.cpp create mode 100644 src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp create mode 100644 src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h delete mode 100644 src/plugins/qnx/qnxapplicationrunner.cpp delete mode 100644 src/plugins/qnx/qnxapplicationrunner.h delete mode 100644 src/plugins/remotelinux/remotelinuxapplicationrunner.cpp delete mode 100644 src/plugins/remotelinux/remotelinuxapplicationrunner.h diff --git a/src/plugins/madde/madde.pro b/src/plugins/madde/madde.pro index f545b98ac9a..178e2f3e4bb 100644 --- a/src/plugins/madde/madde.pro +++ b/src/plugins/madde/madde.pro @@ -11,7 +11,6 @@ HEADERS += \ debianmanager.h \ maemoconstants.h \ maemorunconfigurationwidget.h \ - maemoruncontrol.h \ maemorunfactories.h \ maemosettingspages.h \ maemopackagecreationstep.h \ @@ -20,8 +19,6 @@ HEADERS += \ maemoqemumanager.h \ maemodeploystepfactory.h \ maemoglobal.h \ - maemosshrunner.h \ - maemodebugsupport.h \ maemoremotemountsmodel.h \ maemomountspecification.h \ maemoremotemounter.h \ @@ -52,13 +49,13 @@ HEADERS += \ maddedevicetester.h \ maddedeviceconfigurationfactory.h \ maddedevice.h \ - rpmmanager.h + rpmmanager.h \ + maemoapplicationrunnerhelperactions.h SOURCES += \ maddeplugin.cpp \ debianmanager.cpp \ maemorunconfigurationwidget.cpp \ - maemoruncontrol.cpp \ maemorunfactories.cpp \ maemosettingspages.cpp \ maemopackagecreationstep.cpp \ @@ -67,8 +64,6 @@ SOURCES += \ maemoqemumanager.cpp \ maemodeploystepfactory.cpp \ maemoglobal.cpp \ - maemosshrunner.cpp \ - maemodebugsupport.cpp \ maemoremotemountsmodel.cpp \ maemomountspecification.cpp \ maemoremotemounter.cpp \ @@ -98,7 +93,8 @@ SOURCES += \ maddedevicetester.cpp \ maemorunconfiguration.cpp \ maddedevice.cpp \ - rpmmanager.cpp + rpmmanager.cpp \ + maemoapplicationrunnerhelperactions.cpp FORMS += \ maemopackagecreationwidget.ui \ diff --git a/src/plugins/madde/madde.qbs b/src/plugins/madde/madde.qbs index 4bf5ad8c0d8..7cac61e3994 100644 --- a/src/plugins/madde/madde.qbs +++ b/src/plugins/madde/madde.qbs @@ -31,8 +31,6 @@ QtcPlugin { "maddeuploadandinstallpackagesteps.cpp", "maddeuploadandinstallpackagesteps.h", "maemoconstants.h", - "maemodebugsupport.cpp", - "maemodebugsupport.h", "maemodeploybymountsteps.cpp", "maemodeploybymountsteps.h", "maemodeployconfigurationwidget.cpp", @@ -108,14 +106,10 @@ QtcPlugin { "maemorunconfiguration.h", "maemorunconfigurationwidget.cpp", "maemorunconfigurationwidget.h", - "maemoruncontrol.cpp", - "maemoruncontrol.h", "maemorunfactories.cpp", "maemorunfactories.h", "maemosettingspages.cpp", "maemosettingspages.h", - "maemosshrunner.cpp", - "maemosshrunner.h", "qt-maemo.qrc", "qt4maemodeployconfiguration.cpp", "qt4maemodeployconfiguration.h", @@ -124,6 +118,8 @@ QtcPlugin { "debianmanager.h", "debianmanager.cpp", "rpmmanager.h", - "rpmmanager.cpp" + "rpmmanager.cpp", + "maemoapplicationrunnerhelperactions.h", + "maemoapplicationrunnerhelperactions.cpp" ] } diff --git a/src/plugins/madde/maemoapplicationrunnerhelperactions.cpp b/src/plugins/madde/maemoapplicationrunnerhelperactions.cpp new file mode 100644 index 00000000000..2f82e7a5453 --- /dev/null +++ b/src/plugins/madde/maemoapplicationrunnerhelperactions.cpp @@ -0,0 +1,148 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ +#include "maemoapplicationrunnerhelperactions.h" + +#include "maemomountspecification.h" +#include "maemoremotemounter.h" + +#include <utils/qtcassert.h> + +using namespace ProjectExplorer; +using namespace Utils; + +namespace Madde { +namespace Internal { + +MaemoPreRunAction::MaemoPreRunAction(const IDevice::ConstPtr &device, const FileName &maddeRoot, + const QList<MaemoMountSpecification> &mountSpecs, QObject *parent) + : DeviceApplicationHelperAction(parent), m_mounter(new MaemoRemoteMounter(this)) +{ + m_mounter->setParameters(device, maddeRoot); + foreach (const MaemoMountSpecification &m, mountSpecs) + m_mounter->addMountSpecification(m, false); +} + +void MaemoPreRunAction::handleMounted() +{ + QTC_ASSERT(m_isRunning, return); + + setFinished(true); +} + +void MaemoPreRunAction::handleError(const QString &message) +{ + if (!m_isRunning) + return; + + emit reportError(message); + setFinished(false); +} + +void MaemoPreRunAction::start() +{ + QTC_ASSERT(!m_isRunning, return); + + connect(m_mounter, SIGNAL(debugOutput(QString)), SIGNAL(reportProgress(QString))); + connect(m_mounter, SIGNAL(reportProgress(QString)), SIGNAL(reportProgress(QString))); + connect(m_mounter, SIGNAL(mounted()), SLOT(handleMounted())); + connect(m_mounter, SIGNAL(error(QString)), SLOT(handleError(QString))); + m_isRunning = true; + m_mounter->mount(); +} + +void MaemoPreRunAction::stop() +{ + QTC_ASSERT(m_isRunning, return); + + m_mounter->stop(); + setFinished(false); +} + +void MaemoPreRunAction::setFinished(bool success) +{ + QTC_ASSERT(m_isRunning, return); + + m_mounter->disconnect(this); + m_isRunning = false; + emit finished(success); +} + +MaemoPostRunAction::MaemoPostRunAction(MaemoRemoteMounter *mounter, QObject *parent) + : DeviceApplicationHelperAction(parent), m_mounter(mounter) +{ +} + +void MaemoPostRunAction::handleUnmounted() +{ + QTC_ASSERT(m_isRunning, return); + + setFinished(true); +} + +void MaemoPostRunAction::handleError(const QString &message) +{ + if (!m_isRunning) + return; + + emit reportError(message); + setFinished(false); +} + +void MaemoPostRunAction::start() +{ + QTC_ASSERT(!m_isRunning, return); + + connect(m_mounter, SIGNAL(debugOutput(QString)), SIGNAL(reportProgress(QString))); + connect(m_mounter, SIGNAL(reportProgress(QString)), SIGNAL(reportProgress(QString))); + connect(m_mounter, SIGNAL(unmounted()), SLOT(handleUnmounted())); + connect(m_mounter, SIGNAL(error(QString)), SLOT(handleError(QString))); + m_isRunning = true; + m_mounter->unmount(); +} + +void MaemoPostRunAction::stop() +{ + QTC_ASSERT(m_isRunning, return); + + m_mounter->stop(); + setFinished(false); +} + +void MaemoPostRunAction::setFinished(bool success) +{ + QTC_ASSERT(m_isRunning, return); + + m_mounter->disconnect(this); + m_isRunning = false; + emit finished(success); +} + +} // namespace Internal +} // namespace Madde diff --git a/src/plugins/madde/maemosshrunner.h b/src/plugins/madde/maemoapplicationrunnerhelperactions.h similarity index 55% rename from src/plugins/madde/maemosshrunner.h rename to src/plugins/madde/maemoapplicationrunnerhelperactions.h index 6e9bd37d225..532ad9ac4b6 100644 --- a/src/plugins/madde/maemosshrunner.h +++ b/src/plugins/madde/maemoapplicationrunnerhelperactions.h @@ -6,6 +6,7 @@ ** ** Contact: http://www.qt-project.org/ ** +** ** GNU Lesser General Public License Usage ** ** This file may be used under the terms of the GNU Lesser General Public @@ -26,54 +27,65 @@ ** ** **************************************************************************/ +#ifndef MAEMOAPPLICATIONRUNNERHELPERACTIONS_H +#define MAEMOAPPLICATIONRUNNERHELPERACTIONS_H -#ifndef MAEMOSSHRUNNER_H -#define MAEMOSSHRUNNER_H +#include <projectexplorer/devicesupport/deviceapplicationrunner.h> -#include "maemomountspecification.h" +#include <QList> -#include <remotelinux/remotelinuxapplicationrunner.h> +namespace Utils { class FileName; } namespace Madde { namespace Internal { +class MaemoMountSpecification; class MaemoRemoteMounter; -class MaemoRunConfiguration; -class MaemoSshRunner : public RemoteLinux::AbstractRemoteLinuxApplicationRunner +class MaemoPreRunAction : public ProjectExplorer::DeviceApplicationHelperAction { Q_OBJECT - public: - MaemoSshRunner(QObject *parent, MaemoRunConfiguration *runConfig); + MaemoPreRunAction(const ProjectExplorer::IDevice::ConstPtr &device, + const Utils::FileName &maddeRoot, const QList<MaemoMountSpecification> &mountSpecs, + QObject *parent = 0); -signals: - void mountDebugOutput(const QString &output); + MaemoRemoteMounter *mounter() const { return m_mounter; } private slots: void handleMounted(); - void handleUnmounted(); - void handleMounterError(const QString &errorMsg); + void handleError(const QString &message); private: - enum MountState { InactiveMountState, InitialUnmounting, Mounting, Mounted, PostRunUnmounting }; + void start(); + void stop(); + + void setFinished(bool success); - bool canRun(QString &whyNot) const; - void doDeviceSetup(); - void doAdditionalInitialCleanup(); - void doAdditionalInitializations(); - void doPostRunCleanup(); - void doAdditionalConnectionErrorHandling(); + MaemoRemoteMounter * const m_mounter; + bool m_isRunning; +}; + +class MaemoPostRunAction : public ProjectExplorer::DeviceApplicationHelperAction +{ + Q_OBJECT +public: + MaemoPostRunAction(MaemoRemoteMounter *mounter, QObject *parent = 0); + +private slots: + void handleUnmounted(); + void handleError(const QString &message); + +private: + void start(); + void stop(); - void mount(); - void unmount(); + void setFinished(bool success); MaemoRemoteMounter * const m_mounter; - QList<MaemoMountSpecification> m_mountSpecs; - MountState m_mountState; - int m_qtId; + bool m_isRunning; }; } // namespace Internal } // namespace Madde -#endif // MAEMOSSHRUNNER_H +#endif // MAEMOAPPLICATIONRUNNERHELPERACTIONS_H diff --git a/src/plugins/madde/maemodebugsupport.cpp b/src/plugins/madde/maemodebugsupport.cpp deleted file mode 100644 index 7ff522f0697..00000000000 --- a/src/plugins/madde/maemodebugsupport.cpp +++ /dev/null @@ -1,54 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ -#include "maemodebugsupport.h" - -#include "maemorunconfiguration.h" -#include "maemosshrunner.h" - -#include <remotelinux/linuxdeviceconfiguration.h> - -using namespace RemoteLinux; - -namespace Madde { -namespace Internal { - -MaemoDebugSupport::MaemoDebugSupport(MaemoRunConfiguration *runConfig, Debugger::DebuggerEngine *engine) - : AbstractRemoteLinuxDebugSupport(runConfig, engine), - m_runner(new MaemoSshRunner(this, runConfig)) -{ -} - -MaemoDebugSupport::~MaemoDebugSupport() -{ -} - -AbstractRemoteLinuxApplicationRunner *MaemoDebugSupport::runner() const { return m_runner; } - -} // namespace Internal -} // namespace Madde diff --git a/src/plugins/madde/maemodebugsupport.h b/src/plugins/madde/maemodebugsupport.h deleted file mode 100644 index 0aab12532a2..00000000000 --- a/src/plugins/madde/maemodebugsupport.h +++ /dev/null @@ -1,56 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef MAEMODEBUGSUPPORT_H -#define MAEMODEBUGSUPPORT_H - -#include <remotelinux/remotelinuxdebugsupport.h> - -namespace Madde { -namespace Internal { -class MaemoRunConfiguration; -class MaemoSshRunner; - -class MaemoDebugSupport : public RemoteLinux::AbstractRemoteLinuxDebugSupport -{ - Q_OBJECT -public: - MaemoDebugSupport(MaemoRunConfiguration *runConfig, Debugger::DebuggerEngine *engine); - ~MaemoDebugSupport(); - -private: - RemoteLinux::AbstractRemoteLinuxApplicationRunner *runner() const; - - MaemoSshRunner * const m_runner; -}; - -} // namespace Internal -} // namespace Madde - -#endif // MAEMODEBUGSUPPORT_H diff --git a/src/plugins/madde/maemoremotemounter.h b/src/plugins/madde/maemoremotemounter.h index dcd2e39eb33..0814e846702 100644 --- a/src/plugins/madde/maemoremotemounter.h +++ b/src/plugins/madde/maemoremotemounter.h @@ -59,7 +59,7 @@ public: ~MaemoRemoteMounter(); void setParameters(const ProjectExplorer::IDevice::ConstPtr &devConf, - const Utils::FileName &fileName); + const Utils::FileName &maddeRoot); void addMountSpecification(const MaemoMountSpecification &mountSpec, bool mountAsRoot); bool hasValidMountSpecifications() const; diff --git a/src/plugins/madde/maemorunconfiguration.cpp b/src/plugins/madde/maemorunconfiguration.cpp index 6bfbd257486..32ce32763b8 100644 --- a/src/plugins/madde/maemorunconfiguration.cpp +++ b/src/plugins/madde/maemorunconfiguration.cpp @@ -135,32 +135,6 @@ Utils::PortList MaemoRunConfiguration::freePorts() const return MaemoGlobal::freePorts(target()->profile()); } -QString MaemoRunConfiguration::localDirToMountForRemoteGdb() const -{ - const QString projectDir - = QDir::fromNativeSeparators(QDir::cleanPath(activeBuildConfiguration() - ->target()->project()->projectDirectory())); - const QString execDir - = QDir::fromNativeSeparators(QFileInfo(localExecutableFilePath()).path()); - const int length = qMin(projectDir.length(), execDir.length()); - int lastSeparatorPos = 0; - for (int i = 0; i < length; ++i) { - if (projectDir.at(i) != execDir.at(i)) - return projectDir.left(lastSeparatorPos); - if (projectDir.at(i) == QLatin1Char('/')) - lastSeparatorPos = i; - } - return projectDir.length() == execDir.length() - ? projectDir : projectDir.left(lastSeparatorPos); -} - -QString MaemoRunConfiguration::remoteProjectSourcesMountPoint() const -{ - return MaemoGlobal::homeDirOnDevice(DeviceProfileInformation::device(target()->profile())->sshParameters().userName) - + QLatin1String("/gdbSourcesDir_") - + QFileInfo(localExecutableFilePath()).fileName(); -} - bool MaemoRunConfiguration::hasEnoughFreePorts(RunMode mode) const { const int freePortCount = freePorts().count(); diff --git a/src/plugins/madde/maemorunconfiguration.h b/src/plugins/madde/maemorunconfiguration.h index dacc187cf12..b816f6682df 100644 --- a/src/plugins/madde/maemorunconfiguration.h +++ b/src/plugins/madde/maemorunconfiguration.h @@ -53,8 +53,6 @@ public: Internal::MaemoRemoteMountsModel *remoteMounts() const { return m_remoteMounts; } bool hasEnoughFreePorts(ProjectExplorer::RunMode mode) const; - QString localDirToMountForRemoteGdb() const; - QString remoteProjectSourcesMountPoint() const; signals: void remoteMountsChanged(); diff --git a/src/plugins/madde/maemoruncontrol.cpp b/src/plugins/madde/maemoruncontrol.cpp deleted file mode 100644 index 74d242bc295..00000000000 --- a/src/plugins/madde/maemoruncontrol.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include "maemoruncontrol.h" - -#include "maemoglobal.h" -#include "maemorunconfiguration.h" -#include "maemosshrunner.h" - -namespace Madde { -namespace Internal { - -using namespace RemoteLinux; -using ProjectExplorer::RunConfiguration; - -MaemoRunControl::MaemoRunControl(RunConfiguration *rc) - : AbstractRemoteLinuxRunControl(rc) - , m_runner(new MaemoSshRunner(this, qobject_cast<MaemoRunConfiguration *>(rc))) -{ -} - -MaemoRunControl::~MaemoRunControl() -{ -} - -void MaemoRunControl::start() -{ - AbstractRemoteLinuxRunControl::start(); - connect(m_runner, SIGNAL(mountDebugOutput(QString)), SLOT(handleMountDebugOutput(QString))); -} - -void MaemoRunControl::handleMountDebugOutput(const QString &output) -{ - appendMessage(output, Utils::StdErrFormatSameLine); -} - -AbstractRemoteLinuxApplicationRunner *MaemoRunControl::runner() const { return m_runner; } - -} // namespace Internal -} // namespace Madde diff --git a/src/plugins/madde/maemoruncontrol.h b/src/plugins/madde/maemoruncontrol.h deleted file mode 100644 index 92d94324295..00000000000 --- a/src/plugins/madde/maemoruncontrol.h +++ /dev/null @@ -1,64 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef MAEMORUNCONTROL_H -#define MAEMORUNCONTROL_H - -#include <remotelinux/remotelinuxruncontrol.h> - -namespace RemoteLinux { -class RemoteLinuxRunConfiguration; -} - -namespace Madde { -namespace Internal { -class MaemoSshRunner; - -class MaemoRunControl : public RemoteLinux::AbstractRemoteLinuxRunControl -{ - Q_OBJECT -public: - explicit MaemoRunControl(ProjectExplorer::RunConfiguration *runConfig); - virtual ~MaemoRunControl(); - - void start(); - -private slots: - void handleMountDebugOutput(const QString &output); - -private: - virtual RemoteLinux::AbstractRemoteLinuxApplicationRunner *runner() const; - - MaemoSshRunner * const m_runner; -}; - -} // namespace Internal -} // namespace Madde - -#endif // MAEMORUNCONTROL_H diff --git a/src/plugins/madde/maemorunfactories.cpp b/src/plugins/madde/maemorunfactories.cpp index 022b0d79d9f..02b084b96b2 100644 --- a/src/plugins/madde/maemorunfactories.cpp +++ b/src/plugins/madde/maemorunfactories.cpp @@ -28,11 +28,11 @@ **************************************************************************/ #include "maemorunfactories.h" +#include "maemoapplicationrunnerhelperactions.h" #include "maemoconstants.h" -#include "maemodebugsupport.h" +#include "maemoglobal.h" #include "maemoremotemountsmodel.h" #include "maemorunconfiguration.h" -#include "maemoruncontrol.h" #include <debugger/debuggerconstants.h> #include <debugger/debuggerstartparameters.h> @@ -44,6 +44,8 @@ #include <qt4projectmanager/qt4nodes.h> #include <qt4projectmanager/qt4project.h> #include <qtsupport/customexecutablerunconfiguration.h> +#include <remotelinux/remotelinuxdebugsupport.h> +#include <remotelinux/remotelinuxruncontrol.h> using namespace Debugger; using namespace ProjectExplorer; @@ -169,7 +171,6 @@ QList<RunConfiguration *> MaemoRunConfigurationFactory::runConfigurationsForNode return result; } -// #pragma mark -- MaemoRunControlFactory MaemoRunControlFactory::MaemoRunControlFactory(QObject *parent) : IRunControlFactory(parent) @@ -197,14 +198,21 @@ RunControl* MaemoRunControlFactory::create(RunConfiguration *runConfig, RunMode Q_ASSERT(rc); if (mode == NormalRunMode) - return new MaemoRunControl(rc); + return new RemoteLinuxRunControl(rc); - const DebuggerStartParameters params - = AbstractRemoteLinuxDebugSupport::startParameters(rc); + const DebuggerStartParameters params = LinuxDeviceDebugSupport::startParameters(rc); DebuggerRunControl * const runControl = DebuggerPlugin::createDebugger(params, rc); if (!runControl) return 0; - MaemoDebugSupport *debugSupport = new MaemoDebugSupport(rc, runControl->engine()); + LinuxDeviceDebugSupport * const debugSupport + = new LinuxDeviceDebugSupport(rc, runControl->engine()); + const Profile * const profile = runConfig->target()->profile(); + MaemoPreRunAction * const preRunAction = new MaemoPreRunAction( + DeviceProfileInformation::device(profile), MaemoGlobal::maddeRoot(profile), + rc->remoteMounts()->mountSpecs(), rc); + MaemoPostRunAction * const postRunAction = new MaemoPostRunAction(preRunAction->mounter(), rc); + debugSupport->setApplicationRunnerPreRunAction(preRunAction); + debugSupport->setApplicationRunnerPostRunAction(postRunAction); connect(runControl, SIGNAL(finished()), debugSupport, SLOT(handleDebuggingFinished())); return runControl; } diff --git a/src/plugins/madde/maemosshrunner.cpp b/src/plugins/madde/maemosshrunner.cpp deleted file mode 100644 index 260596b551f..00000000000 --- a/src/plugins/madde/maemosshrunner.cpp +++ /dev/null @@ -1,215 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ -#include "maemosshrunner.h" - -#include "maemoglobal.h" -#include "maemoqemumanager.h" -#include "maemoremotemounter.h" -#include "maemoremotemountsmodel.h" -#include "maemorunconfiguration.h" - -#include <projectexplorer/buildconfiguration.h> -#include <projectexplorer/target.h> -#include <qtsupport/qtprofileinformation.h> -#include <utils/qtcassert.h> -#include <ssh/sshconnection.h> - -using namespace ProjectExplorer; -using namespace QSsh; -using namespace RemoteLinux; - -namespace Madde { -namespace Internal { - -MaemoSshRunner::MaemoSshRunner(QObject *parent, MaemoRunConfiguration *runConfig) - : AbstractRemoteLinuxApplicationRunner(runConfig, parent), - m_mounter(new MaemoRemoteMounter(this)), - m_mountSpecs(runConfig->remoteMounts()->mountSpecs()), - m_mountState(InactiveMountState) -{ - const BuildConfiguration * const bc = runConfig->target()->activeBuildConfiguration(); - Profile *profile = bc ? bc->target()->profile() : 0; - m_qtId = QtSupport::QtProfileInformation::qtVersionId(profile); - m_mounter->setParameters(devConfig(), MaemoGlobal::maddeRoot(profile)); - connect(m_mounter, SIGNAL(mounted()), this, SLOT(handleMounted())); - connect(m_mounter, SIGNAL(unmounted()), this, SLOT(handleUnmounted())); - connect(m_mounter, SIGNAL(error(QString)), this, - SLOT(handleMounterError(QString))); - connect(m_mounter, SIGNAL(reportProgress(QString)), this, - SIGNAL(reportProgress(QString))); - connect(m_mounter, SIGNAL(debugOutput(QString)), this, - SIGNAL(mountDebugOutput(QString))); -} - -bool MaemoSshRunner::canRun(QString &whyNot) const -{ - if (!AbstractRemoteLinuxApplicationRunner::canRun(whyNot)) - return false; - - if (devConfig()->machineType() == IDevice::Emulator - && !MaemoQemuManager::instance().qemuIsRunning()) { - MaemoQemuRuntime rt; - if (MaemoQemuManager::instance().runtimeForQtVersion(m_qtId, &rt)) { - MaemoQemuManager::instance().startRuntime(); - whyNot = tr("Qemu was not running. It has now been started up for you, but it will " - "take a bit of time until it is ready. Please try again then."); - } else { - whyNot = tr("You want to run on Qemu, but it is not enabled for this Qt version."); - } - return false; - } - - return true; -} - -void MaemoSshRunner::doDeviceSetup() -{ - QTC_ASSERT(m_mountState == InactiveMountState, return); - - handleDeviceSetupDone(true); -} - -void MaemoSshRunner::doAdditionalInitialCleanup() -{ - QTC_ASSERT(m_mountState == InactiveMountState, return); - - m_mounter->resetMountSpecifications(); - for (int i = 0; i < m_mountSpecs.count(); ++i) - m_mounter->addMountSpecification(m_mountSpecs.at(i), false); - m_mountState = InitialUnmounting; - unmount(); -} - -void MaemoSshRunner::doAdditionalInitializations() -{ - mount(); -} - -void MaemoSshRunner::doPostRunCleanup() -{ - QTC_ASSERT(m_mountState == Mounted, return); - - m_mountState = PostRunUnmounting; - unmount(); -} - -void MaemoSshRunner::handleUnmounted() -{ - QTC_ASSERT(m_mountState == InitialUnmounting || m_mountState == PostRunUnmounting, return); - - switch (m_mountState) { - case InitialUnmounting: - m_mountState = InactiveMountState; - handleInitialCleanupDone(true); - break; - case PostRunUnmounting: - m_mountState = InactiveMountState; - handlePostRunCleanupDone(); - break; - default: - break; - } - m_mountState = InactiveMountState; -} - -void MaemoSshRunner::doAdditionalConnectionErrorHandling() -{ - m_mountState = InactiveMountState; -} - -void MaemoSshRunner::handleMounted() -{ - QTC_ASSERT(m_mountState == Mounting, return); - - if (m_mountState == Mounting) { - m_mountState = Mounted; - handleInitializationsDone(true); - } -} - -void MaemoSshRunner::handleMounterError(const QString &errorMsg) -{ - QTC_ASSERT(m_mountState == InitialUnmounting || m_mountState == Mounting - || m_mountState == PostRunUnmounting, return); - - const MountState oldMountState = m_mountState; - m_mountState = InactiveMountState; - emit error(errorMsg); - switch (oldMountState) { - case InitialUnmounting: - handleInitialCleanupDone(false); - break; - case Mounting: - handleInitializationsDone(false); - break; - case PostRunUnmounting: - handlePostRunCleanupDone(); - break; - default: - break; - } -} - -void MaemoSshRunner::mount() -{ - m_mountState = Mounting; - if (m_mounter->hasValidMountSpecifications()) { - emit reportProgress(tr("Mounting host directories...")); - m_mounter->mount(); - } else { - handleMounted(); - } -} - -void MaemoSshRunner::unmount() -{ - QTC_ASSERT(m_mountState == InitialUnmounting || m_mountState == PostRunUnmounting, return); - - if (m_mounter->hasValidMountSpecifications()) { - QString message; - switch (m_mountState) { - case InitialUnmounting: - message = tr("Potentially unmounting left-over host directory mounts..."); - break; - case PostRunUnmounting: - message = tr("Unmounting host directories..."); - break; - default: - break; - } - emit reportProgress(message); - m_mounter->unmount(); - } else { - handleUnmounted(); - } -} - -} // namespace Internal -} // namespace Madde - diff --git a/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp new file mode 100644 index 00000000000..0638b9a7ba5 --- /dev/null +++ b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp @@ -0,0 +1,339 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ +#include "deviceapplicationrunner.h" + +#include <ssh/sshconnection.h> +#include <ssh/sshconnectionmanager.h> +#include <ssh/sshremoteprocess.h> +#include <utils/qtcassert.h> + +#include <QTimer> + +using namespace QSsh; + +namespace ProjectExplorer { + +namespace { +enum State { Inactive, Connecting, PreRun, Run, PostRun }; +} // anonymous namespace + +class DeviceApplicationRunner::DeviceApplicationRunnerPrivate +{ +public: + SshConnection *connection; + DeviceApplicationHelperAction *preRunAction; + DeviceApplicationHelperAction *postRunAction; + IDevice::ConstPtr device; + SshRemoteProcess::Ptr remoteApp; + QTimer stopTimer; + QByteArray commandLine; + State state; + bool stopRequested; + bool success; +}; + + +DeviceApplicationHelperAction::DeviceApplicationHelperAction(QObject *parent) : QObject(parent) +{ +} + +DeviceApplicationHelperAction::~DeviceApplicationHelperAction() +{ +} + + +DeviceApplicationRunner::DeviceApplicationRunner(QObject *parent) : + QObject(parent), d(new DeviceApplicationRunnerPrivate) +{ + d->preRunAction = 0; + d->postRunAction = 0; + d->connection = 0; + d->state = Inactive; + + d->stopTimer.setSingleShot(true); + connect(&d->stopTimer, SIGNAL(timeout()), SLOT(handleStopTimeout())); +} + +DeviceApplicationRunner::~DeviceApplicationRunner() +{ + setFinished(); + delete d; +} + +void DeviceApplicationRunner::start(const IDevice::ConstPtr &device, + const QByteArray &commandLine) +{ + QTC_ASSERT(d->state == Inactive, return); + + d->device = device; + d->commandLine = commandLine; + d->stopRequested = false; + d->success = true; + + connectToServer(); +} + +void DeviceApplicationRunner::stop(const QByteArray &stopCommand) +{ + QTC_ASSERT(d->state != Inactive, return); + + if (d->stopRequested) + return; + d->stopRequested = true; + d->success = false; + emit reportProgress(tr("User requested stop. Shutting down...")); + switch (d->state) { + case Connecting: + setFinished(); + break; + case PreRun: + d->preRunAction->stop(); + break; + case Run: + d->stopTimer.start(10000); + d->connection->createRemoteProcess(stopCommand)->start(); + break; + case PostRun: + d->postRunAction->stop(); + break; + case Inactive: + break; + } +} + +void DeviceApplicationRunner::setPreRunAction(DeviceApplicationHelperAction *action) +{ + addAction(d->preRunAction, action); +} + +void DeviceApplicationRunner::setPostRunAction(DeviceApplicationHelperAction *action) +{ + addAction(d->postRunAction, action); +} + +void DeviceApplicationRunner::connectToServer() +{ + QTC_CHECK(!d->connection); + + d->state = Connecting; + + if (!d->device) { + emit reportError(tr("Cannot run: No device.")); + setFinished(); + return; + } + + d->connection = SshConnectionManager::instance().acquireConnection(d->device->sshParameters()); + connect(d->connection, SIGNAL(error(QSsh::SshError)), SLOT(handleConnectionFailure())); + if (d->connection->state() == SshConnection::Connected) { + handleConnected(); + } else { + emit reportProgress(tr("Connecting to device...")); + connect(d->connection, SIGNAL(connected()), SLOT(handleConnected())); + if (d->connection->state() == QSsh::SshConnection::Unconnected) + d->connection->connectToHost(); + } +} + +void DeviceApplicationRunner::executePreRunAction() +{ + QTC_ASSERT(d->state == Connecting, return); + + d->state = PreRun; + if (d->preRunAction) + d->preRunAction->start(); + else + runApplication(); +} + +void DeviceApplicationRunner::executePostRunAction() +{ + QTC_ASSERT(d->state == PreRun || d->state == Run, return); + + d->state = PostRun; + if (d->postRunAction) + d->postRunAction->start(); + else + setFinished(); +} + +void DeviceApplicationRunner::setFinished() +{ + if (d->state == Inactive) + return; + + if (d->remoteApp) { + d->remoteApp->disconnect(this); + d->remoteApp->close(); + d->remoteApp.clear(); + } + if (d->connection) { + d->connection->disconnect(this); + SshConnectionManager::instance().releaseConnection(d->connection); + d->connection = 0; + } + + d->state = Inactive; + emit finished(d->success); +} + +void DeviceApplicationRunner::handleConnected() +{ + QTC_ASSERT(d->state == Connecting, return); + + if (d->stopRequested) { + setFinished(); + return; + } + + executePreRunAction(); +} + +void DeviceApplicationRunner::handleConnectionFailure() +{ + QTC_ASSERT(d->state != Inactive, return); + + emit reportError(tr("SSH connection failed: %1").arg(d->connection->errorString())); + d->success = false; + switch (d->state) { + case Inactive: + break; // Can't happen. + case Connecting: + setFinished(); + break; + case PreRun: + d->preRunAction->stop(); + break; + case Run: + d->stopTimer.stop(); + d->remoteApp->disconnect(this); + executePostRunAction(); + break; + case PostRun: + d->postRunAction->stop(); + break; + } +} + +void DeviceApplicationRunner::handleHelperActionFinished(bool success) +{ + switch (d->state) { + case Inactive: + break; + case PreRun: + if (success && d->success) { + runApplication(); + } else if (success && !d->success) { + executePostRunAction(); + } else { + d->success = false; + setFinished(); + } + break; + case PostRun: + if (!success) + d->success = false; + setFinished(); + break; + default: + QTC_CHECK(false); + } +} + +void DeviceApplicationRunner::addAction(DeviceApplicationHelperAction *&target, + DeviceApplicationHelperAction *source) +{ + QTC_ASSERT(d->state == Inactive, return); + + if (target) + disconnect(target, 0, this, 0); + target = source; + if (target) { + connect(target, SIGNAL(finished(bool)), SLOT(handleHelperActionFinished(bool))); + connect(target, SIGNAL(reportProgress(QString)), SIGNAL(reportProgress(QString))); + connect(target, SIGNAL(reportError(QString)), SIGNAL(reportError(QString))); + } +} + +void DeviceApplicationRunner::handleStopTimeout() +{ + QTC_ASSERT(d->stopRequested && d->state == Run, return); + + emit reportError(tr("Application did not finish in time, aborting.")); + d->success = false; + setFinished(); +} + +void DeviceApplicationRunner::handleApplicationFinished(int exitStatus) +{ + QTC_ASSERT(d->state == Run, return); + + d->stopTimer.stop(); + if (exitStatus == SshRemoteProcess::CrashExit) { + emit reportError(tr("Remote application crashed: %1").arg(d->remoteApp->errorString())); + d->success = false; + } else { + const int exitCode = d->remoteApp->exitCode(); + if (exitCode != 0) { + emit reportError(tr("Remote application finished with exit code %1.").arg(exitCode)); + d->success = false; + } else { + emit reportProgress(tr("Remote application finished with exit code 0.")); + } + } + executePostRunAction(); +} + +void DeviceApplicationRunner::handleRemoteStdout() +{ + QTC_ASSERT(d->state == Run, return); + emit remoteStdout(d->remoteApp->readAllStandardOutput()); +} + +void DeviceApplicationRunner::handleRemoteStderr() +{ + QTC_ASSERT(d->state == Run, return); + emit remoteStderr(d->remoteApp->readAllStandardError()); +} + +void DeviceApplicationRunner::runApplication() +{ + QTC_ASSERT(d->state == PreRun, return); + + d->state = Run; + d->remoteApp = d->connection->createRemoteProcess(d->commandLine); + connect(d->remoteApp.data(), SIGNAL(started()), SIGNAL(remoteProcessStarted())); + connect(d->remoteApp.data(), SIGNAL(readyReadStandardOutput()), SLOT(handleRemoteStdout())); + connect(d->remoteApp.data(), SIGNAL(readyReadStandardError()), SLOT(handleRemoteStderr())); + connect(d->remoteApp.data(), SIGNAL(closed(int)), SLOT(handleApplicationFinished(int))); + d->remoteApp->start(); +} + +} // namespace ProjectExplorer diff --git a/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h new file mode 100644 index 00000000000..2b19f0783ca --- /dev/null +++ b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h @@ -0,0 +1,104 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: http://www.qt-project.org/ +** +** +** GNU Lesser General Public License Usage +** +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this file. +** Please review the following information to ensure the GNU Lesser General +** Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** Other Usage +** +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +**************************************************************************/ +#ifndef ONDEVICEAPPLICATIONRUNNER_H +#define ONDEVICEAPPLICATIONRUNNER_H + +#include "idevice.h" + +#include "../projectexplorer_export.h" + +#include <QObject> + +namespace ProjectExplorer { + +class PROJECTEXPLORER_EXPORT DeviceApplicationHelperAction : public QObject +{ + Q_OBJECT +public: + ~DeviceApplicationHelperAction(); + virtual void start() = 0; + virtual void stop() = 0; +signals: + void reportProgress(const QString &progressOutput); + void reportError(const QString &errorOutput); + void finished(bool success); + +protected: + DeviceApplicationHelperAction(QObject *parent = 0); +}; + +class PROJECTEXPLORER_EXPORT DeviceApplicationRunner : public QObject +{ + Q_OBJECT +public: + explicit DeviceApplicationRunner(QObject *parent = 0); + virtual ~DeviceApplicationRunner(); + + void start(const IDevice::ConstPtr &device, const QByteArray &commandLine); + void stop(const QByteArray &stopCommand); + + // Use these if you need to do something before and after the application is run, respectively. + // Typically, the post-run action reverts the effects of the pre-run action. + // If you only have a pre-run action, you probably want a deploy step instead. + void setPreRunAction(DeviceApplicationHelperAction *action); + void setPostRunAction(DeviceApplicationHelperAction *action); + +signals: + void remoteStdout(const QByteArray &output); + void remoteStderr(const QByteArray &output); + void reportProgress(const QString &progressOutput); + void reportError(const QString &errorOutput); + void remoteProcessStarted(); + void finished(bool success); + +private slots: + void handleConnected(); + void handleConnectionFailure(); + void handleHelperActionFinished(bool success); + void handleStopTimeout(); + void handleApplicationFinished(int exitStatus); + void handleRemoteStdout(); + void handleRemoteStderr(); + +private: + void addAction(DeviceApplicationHelperAction *&target, DeviceApplicationHelperAction *source); + void connectToServer(); + void executePreRunAction(); + void executePostRunAction(); + void runApplication(); + void setFinished(); + + class DeviceApplicationRunnerPrivate; + DeviceApplicationRunnerPrivate * const d; +}; + +} // namespace ProjectExplorer + +#endif // ONDEVICEAPPLICATIONRUNNER_H diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro index cd8a533557f..d27b13f22c4 100644 --- a/src/plugins/projectexplorer/projectexplorer.pro +++ b/src/plugins/projectexplorer/projectexplorer.pro @@ -125,7 +125,8 @@ HEADERS += projectexplorer.h \ devicesupport/deviceprocessesdialog.h \ devicesupport/devicesettingswidget.h \ devicesupport/devicesettingspage.h \ - devicesupport/deviceusedportsgatherer.h + devicesupport/deviceusedportsgatherer.h \ + devicesupport/deviceapplicationrunner.h SOURCES += projectexplorer.cpp \ abi.cpp \ @@ -227,7 +228,8 @@ SOURCES += projectexplorer.cpp \ devicesupport/deviceprocessesdialog.cpp \ devicesupport/devicesettingswidget.cpp \ devicesupport/devicesettingspage.cpp \ - devicesupport/deviceusedportsgatherer.cpp + devicesupport/deviceusedportsgatherer.cpp \ + devicesupport/deviceapplicationrunner.cpp FORMS += processstep.ui \ editorsettingspropertiespage.ui \ diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs index 0e5dbeeae56..10234f3ab56 100644 --- a/src/plugins/projectexplorer/projectexplorer.qbs +++ b/src/plugins/projectexplorer/projectexplorer.qbs @@ -308,7 +308,9 @@ QtcPlugin { "devicesupport/deviceusedportsgatherer.h", "devicesupport/idevicewidget.h", "devicesupport/idevicefactory.cpp", - "devicesupport/idevicefactory.h" + "devicesupport/idevicefactory.h", + "devicesupport/deviceapplicationrunner.cpp", + "devicesupport/deviceapplicationrunner.h" ] Group { diff --git a/src/plugins/qmlprofiler/qmlprofilerengine.cpp b/src/plugins/qmlprofiler/qmlprofilerengine.cpp index 7149c5a42b6..32a667242d8 100644 --- a/src/plugins/qmlprofiler/qmlprofilerengine.cpp +++ b/src/plugins/qmlprofiler/qmlprofilerengine.cpp @@ -45,6 +45,7 @@ #include <qt4projectmanager/qt-s60/s60devicedebugruncontrol.h> #include <qt4projectmanager/qt-s60/s60devicerunconfiguration.h> #include <qmldebug/qmloutputparser.h> +#include <remotelinux/remotelinuxrunconfiguration.h> #include <QMainWindow> #include <QMessageBox> @@ -370,6 +371,7 @@ void QmlProfilerEngine::profilerStateChanged() case QmlProfilerStateManager::Idle : { // When all the profiling is done, delete the profiler runner // (a new one will be created at start) + d->m_noDebugOutputTimer.stop(); if (d->m_runner) { delete d->m_runner; d->m_runner = 0; diff --git a/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.cpp b/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.cpp index 9c5a3483ff8..695e65eaab2 100644 --- a/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.cpp +++ b/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.cpp @@ -27,15 +27,18 @@ ** ** **************************************************************************/ - #include "remotelinuxqmlprofilerrunner.h" -#include <extensionsystem/pluginmanager.h> + +#include <projectexplorer/devicesupport/deviceapplicationrunner.h> +#include <projectexplorer/devicesupport/deviceusedportsgatherer.h> +#include <projectexplorer/profileinformation.h> #include <projectexplorer/projectexplorerconstants.h> -#include <remotelinux/remotelinuxapplicationrunner.h> +#include <projectexplorer/target.h> +#include <remotelinux/remotelinuxrunconfiguration.h> +#include <remotelinux/remotelinuxutils.h> #include <utils/portlist.h> #include <utils/qtcassert.h> -using namespace ExtensionSystem; using namespace ProjectExplorer; using namespace QmlProfiler::Internal; using namespace RemoteLinux; @@ -43,55 +46,43 @@ using namespace RemoteLinux; RemoteLinuxQmlProfilerRunner::RemoteLinuxQmlProfilerRunner( RemoteLinuxRunConfiguration *runConfiguration, QObject *parent) : AbstractQmlProfilerRunner(parent) + , m_portsGatherer(new DeviceUsedPortsGatherer(this)) + , m_runner(new DeviceApplicationRunner(this)) + , m_device(DeviceProfileInformation::device(runConfiguration->target()->profile())) + , m_remoteExecutable(runConfiguration->remoteExecutableFilePath()) + , m_arguments(runConfiguration->arguments()) + , m_commandPrefix(runConfiguration->commandPrefix()) , m_port(0) - , m_runControl(0) { - // find run control factory - IRunControlFactory *runControlFactory = 0; - QList<IRunControlFactory*> runControlFactories - = PluginManager::getObjects<IRunControlFactory>(); - - foreach (IRunControlFactory *factory, runControlFactories) { - if (factory->canRun(runConfiguration, NormalRunMode)) { - runControlFactory = factory; - break; - } - } - - QTC_ASSERT(runControlFactory, return); - - // create run control - RunControl *runControl = runControlFactory->create(runConfiguration, NormalRunMode); - - m_runControl = qobject_cast<AbstractRemoteLinuxRunControl*>(runControl); - QTC_ASSERT(m_runControl, return); - - connect(runner(), SIGNAL(readyForExecution()), this, SLOT(getPorts())); - connect(runner(), SIGNAL(error(QString)), this, SLOT(handleError(QString))); - connect(runner(), SIGNAL(remoteErrorOutput(QByteArray)), this, SLOT(handleStdErr(QByteArray))); - connect(runner(), SIGNAL(remoteOutput(QByteArray)), this, SLOT(handleStdOut(QByteArray))); - - connect(runner(), SIGNAL(remoteProcessStarted()), this, SLOT(handleRemoteProcessStarted())); - connect(runner(), SIGNAL(remoteProcessFinished(qint64)), - this, SLOT(handleRemoteProcessFinished(qint64))); - connect(runner(), SIGNAL(reportProgress(QString)), this, SLOT(handleProgressReport(QString))); + connect(m_runner, SIGNAL(reportError(QString)), this, SLOT(handleError(QString))); + connect(m_runner, SIGNAL(remoteStderr(QByteArray)), this, SLOT(handleStdErr(QByteArray))); + connect(m_runner, SIGNAL(remoteStdout(QByteArray)), this, SLOT(handleStdOut(QByteArray))); + connect(m_runner, SIGNAL(finished(bool)), SLOT(handleRemoteProcessFinished(bool))); + connect(m_runner, SIGNAL(reportProgress(QString)), this, SLOT(handleProgressReport(QString))); + connect(m_portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGathererError(QString))); + connect(m_portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady())); } RemoteLinuxQmlProfilerRunner::~RemoteLinuxQmlProfilerRunner() { - delete m_runControl; + stop(); } void RemoteLinuxQmlProfilerRunner::start() { - QTC_ASSERT(runner(), return); - runner()->start(); + QTC_ASSERT(m_port == 0, return); + + m_portsGatherer->start(m_device); + emit started(); } void RemoteLinuxQmlProfilerRunner::stop() { - QTC_ASSERT(runner(), return); - runner()->stop(); + if (m_port == 0) + m_portsGatherer->stop(); + else + m_runner->stop(RemoteLinuxUtils::killApplicationCommandLine(m_remoteExecutable).toUtf8()); + m_port = 0; } quint16 RemoteLinuxQmlProfilerRunner::debugPort() const @@ -99,26 +90,37 @@ quint16 RemoteLinuxQmlProfilerRunner::debugPort() const return m_port; } +void RemoteLinuxQmlProfilerRunner::handlePortsGathererError(const QString &message) +{ + emit appendMessage(tr("Gathering ports failed: %1").arg(message), Utils::ErrorMessageFormat); + m_port = 0; + emit stopped(); +} + +void RemoteLinuxQmlProfilerRunner::handlePortListReady() +{ + getPorts(); +} + void RemoteLinuxQmlProfilerRunner::getPorts() { - QTC_ASSERT(runner(), return); - m_port = runner()->freePorts()->getNext(); - if (m_port == 0) { + Utils::PortList portList = m_device->freePorts(); + m_port = m_portsGatherer->getNextFreePort(&portList); + + if (m_port == -1) { emit appendMessage(tr("Not enough free ports on device for analyzing.\n"), Utils::ErrorMessageFormat); - runner()->stop(); + m_port = 0; + emit stopped(); } else { emit appendMessage(tr("Starting remote process ...\n"), Utils::NormalMessageFormat); - - QString arguments = runner()->arguments(); + QString arguments = m_arguments; if (!arguments.isEmpty()) arguments.append(QLatin1Char(' ')); arguments.append(QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(m_port)); - - runner()->startExecution(QString::fromLatin1("%1 %2 %3") - .arg(runner()->commandPrefix()) - .arg(runner()->remoteExecutable()) - .arg(arguments).toUtf8()); + const QString commandLine = QString::fromLatin1("%1 %2 %3") + .arg(m_commandPrefix, m_remoteExecutable, arguments); + m_runner->start(m_device, commandLine.toUtf8()); } } @@ -137,18 +139,11 @@ void RemoteLinuxQmlProfilerRunner::handleStdOut(const QByteArray &msg) emit appendMessage(QString::fromUtf8(msg), Utils::StdOutFormat); } -void RemoteLinuxQmlProfilerRunner::handleRemoteProcessStarted() +void RemoteLinuxQmlProfilerRunner::handleRemoteProcessFinished(bool success) { - emit started(); -} - -void RemoteLinuxQmlProfilerRunner::handleRemoteProcessFinished(qint64 exitCode) -{ - if (exitCode != AbstractRemoteLinuxApplicationRunner::InvalidExitCode) { - appendMessage(tr("Finished running remote process. Exit code was %1.\n") - .arg(exitCode), Utils::NormalMessageFormat); - } - + if (!success) + appendMessage(tr("Failure running remote process."), Utils::NormalMessageFormat); + m_port = 0; emit stopped(); } @@ -156,11 +151,3 @@ void RemoteLinuxQmlProfilerRunner::handleProgressReport(const QString &progressS { appendMessage(progressString + QLatin1Char('\n'), Utils::NormalMessageFormat); } - -AbstractRemoteLinuxApplicationRunner *RemoteLinuxQmlProfilerRunner::runner() const -{ - if (!m_runControl) - return 0; - return m_runControl->runner(); -} - diff --git a/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.h b/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.h index 5f178edc422..6d0a766aff8 100644 --- a/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.h +++ b/src/plugins/qmlprofiler/remotelinuxqmlprofilerrunner.h @@ -32,8 +32,16 @@ #define REMOTELINUXQMLPROFILERRUNNER_H #include "abstractqmlprofilerrunner.h" -#include <remotelinux/remotelinuxrunconfiguration.h> -#include <remotelinux/remotelinuxruncontrol.h> + +#include <projectexplorer/devicesupport/idevice.h> + +#include <QString> + +namespace ProjectExplorer { +class DeviceApplicationRunner; +class DeviceUsedPortsGatherer; +} +namespace RemoteLinux { class RemoteLinuxRunConfiguration; } namespace QmlProfiler { namespace Internal { @@ -54,19 +62,24 @@ public: virtual quint16 debugPort() const; private slots: - void getPorts(); void handleError(const QString &msg); void handleStdErr(const QByteArray &msg); void handleStdOut(const QByteArray &msg); - void handleRemoteProcessStarted(); - void handleRemoteProcessFinished(qint64); + void handleRemoteProcessFinished(bool success); void handleProgressReport(const QString &progressString); + void handlePortsGathererError(const QString &message); + void handlePortListReady(); private: - RemoteLinux::AbstractRemoteLinuxApplicationRunner *runner() const; + void getPorts(); - quint16 m_port; - RemoteLinux::AbstractRemoteLinuxRunControl *m_runControl; + ProjectExplorer::DeviceUsedPortsGatherer * const m_portsGatherer; + ProjectExplorer::DeviceApplicationRunner * const m_runner; + const ProjectExplorer::IDevice::ConstPtr m_device; + const QString m_remoteExecutable; + const QString m_arguments; + const QString m_commandPrefix; + int m_port; }; } // namespace Internal diff --git a/src/plugins/qnx/qnx.pro b/src/plugins/qnx/qnx.pro index af0f672ff40..ed729e954f8 100644 --- a/src/plugins/qnx/qnx.pro +++ b/src/plugins/qnx/qnx.pro @@ -41,7 +41,6 @@ SOURCES += qnxplugin.cpp \ qnxrunconfiguration.cpp \ qnxruncontrolfactory.cpp \ qnxdebugsupport.cpp \ - qnxapplicationrunner.cpp \ qnxdeploystepfactory.cpp \ qnxdeployconfigurationfactory.cpp \ qnxrunconfigurationfactory.cpp \ @@ -91,7 +90,6 @@ HEADERS += qnxplugin.h\ qnxrunconfiguration.h \ qnxruncontrolfactory.h \ qnxdebugsupport.h \ - qnxapplicationrunner.h \ qnxdeploystepfactory.h \ qnxdeployconfigurationfactory.h \ qnxrunconfigurationfactory.h \ diff --git a/src/plugins/qnx/qnxapplicationrunner.cpp b/src/plugins/qnx/qnxapplicationrunner.cpp deleted file mode 100644 index 2156f059aac..00000000000 --- a/src/plugins/qnx/qnxapplicationrunner.cpp +++ /dev/null @@ -1,85 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (C) 2011 - 2012 Research In Motion -** -** Contact: Research In Motion (blackberry-qt@qnx.com) -** Contact: KDAB (info@kdab.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#include "qnxapplicationrunner.h" -#include "qnxrunconfiguration.h" -#include "qnxconstants.h" - -using namespace Qnx; -using namespace Qnx::Internal; - -QnxApplicationRunner::QnxApplicationRunner(QnxRunConfiguration *runConfig, QObject *parent) - : RemoteLinux::AbstractRemoteLinuxApplicationRunner(runConfig, parent) - , m_debugMode(false) -{ - usedPortsGatherer()->setCommand(QLatin1String(Constants::QNX_PORT_GATHERER_COMMAND)); -} - -void QnxApplicationRunner::setDebugMode(bool debugMode) -{ - m_debugMode = debugMode; -} - -void QnxApplicationRunner::doDeviceSetup() -{ - handleDeviceSetupDone(true); -} - -void QnxApplicationRunner::doAdditionalInitialCleanup() -{ - handleInitialCleanupDone(true); -} - -void QnxApplicationRunner::doAdditionalInitializations() -{ - handleInitializationsDone(true); -} - -void QnxApplicationRunner::doPostRunCleanup() -{ - handlePostRunCleanupDone(); -} - -void QnxApplicationRunner::doAdditionalConnectionErrorHandling() -{ -} - -QString QnxApplicationRunner::killApplicationCommandLine() const -{ - QString executable = m_debugMode ? QLatin1String(Constants::QNX_DEBUG_EXECUTABLE) : remoteExecutable(); - executable.replace(QLatin1String("/"), QLatin1String("\\/")); - return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); " - "do " - "kill $PID; sleep 1; kill -9 $PID; " - "done").arg(executable); -} diff --git a/src/plugins/qnx/qnxapplicationrunner.h b/src/plugins/qnx/qnxapplicationrunner.h deleted file mode 100644 index bcd861954ff..00000000000 --- a/src/plugins/qnx/qnxapplicationrunner.h +++ /dev/null @@ -1,69 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (C) 2011 - 2012 Research In Motion -** -** Contact: Research In Motion (blackberry-qt@qnx.com) -** Contact: KDAB (info@kdab.com) -** -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** If you have questions regarding the use of this file, please contact -** Nokia at info@qt.nokia.com. -** -**************************************************************************/ - -#ifndef QNX_INTERNAL_QNXAPPLICATIONRUNNER_H -#define QNX_INTERNAL_QNXAPPLICATIONRUNNER_H - -#include <remotelinux/remotelinuxapplicationrunner.h> - -namespace Qnx { -namespace Internal { - -class QnxRunConfiguration; - -class QnxApplicationRunner : public RemoteLinux::AbstractRemoteLinuxApplicationRunner -{ - Q_OBJECT -public: - explicit QnxApplicationRunner(QnxRunConfiguration *runConfig, - QObject *parent = 0); - - void setDebugMode(bool debugMode); - -protected: - void doDeviceSetup(); - void doAdditionalInitialCleanup(); - void doAdditionalInitializations(); - void doPostRunCleanup(); - void doAdditionalConnectionErrorHandling(); - -private: - QString killApplicationCommandLine() const; - - bool m_debugMode; -}; - -} // namespace Internal -} // namespace Qnx - -#endif // QNX_INTERNAL_QNXAPPLICATIONRUNNER_H diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp index afda2edac5b..766a06c9bf0 100644 --- a/src/plugins/qnx/qnxdebugsupport.cpp +++ b/src/plugins/qnx/qnxdebugsupport.cpp @@ -32,22 +32,46 @@ **************************************************************************/ #include "qnxdebugsupport.h" -#include "qnxapplicationrunner.h" #include "qnxconstants.h" +#include "qnxrunconfiguration.h" +#include "qnxutils.h" #include <debugger/debuggerengine.h> +#include <projectexplorer/devicesupport/deviceapplicationrunner.h> +#include <projectexplorer/devicesupport/deviceusedportsgatherer.h> +#include <projectexplorer/profileinformation.h> +#include <projectexplorer/target.h> +#include <utils/portlist.h> #include <utils/qtcassert.h> +using namespace ProjectExplorer; +using namespace RemoteLinux; + +using namespace Qnx; using namespace Qnx::Internal; QnxDebugSupport::QnxDebugSupport(QnxRunConfiguration *runConfig, Debugger::DebuggerEngine *engine) : QObject(engine) + , m_executable(QLatin1String(Constants::QNX_DEBUG_EXECUTABLE)) + , m_commandPrefix(runConfig->commandPrefix()) + , m_arguments(runConfig->arguments()) + , m_device(DeviceProfileInformation::device(runConfig->target()->profile())) , m_engine(engine) , m_port(-1) , m_state(Inactive) { - m_runner = new QnxApplicationRunner(runConfig, this); - m_runner->setDebugMode(true); + m_runner = new DeviceApplicationRunner(this); + m_portsGatherer = new DeviceUsedPortsGatherer(this); + m_portsGatherer->setCommand(QLatin1String(Constants::QNX_PORT_GATHERER_COMMAND)); + + connect(m_portsGatherer, SIGNAL(error(QString)), SLOT(handleError(QString))); + connect(m_portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady())); + + connect(m_runner, SIGNAL(reportError(QString)), SLOT(handleError(QString))); + connect(m_runner, SIGNAL(remoteProcessStarted()), this, SLOT(handleRemoteProcessStarted())); + connect(m_runner, SIGNAL(finished(bool)), SLOT(handleRemoteProcessFinished(qint64))); + connect(m_runner, SIGNAL(reportProgress(QString)), this, SLOT(handleProgressReport(QString))); + connect(m_runner, SIGNAL(remoteStdout(QByteArray)), this, SLOT(handleRemoteOutput(QByteArray))); connect(m_engine, SIGNAL(requestRemoteSetup()), this, SLOT(handleAdapterSetupRequested())); } @@ -56,18 +80,16 @@ void QnxDebugSupport::handleAdapterSetupRequested() { QTC_ASSERT(m_state == Inactive, return); - m_state = StartingRunner; + m_state = GatheringPorts; if (m_engine) m_engine->showMessage(tr("Preparing remote side...\n"), Debugger::AppStuff); + m_portsGatherer->start(m_device); +} - connect(m_runner, SIGNAL(error(QString)), this, SLOT(handleSshError(QString))); - connect(m_runner, SIGNAL(readyForExecution()), this, SLOT(startExecution())); - connect(m_runner, SIGNAL(remoteProcessStarted()), this, SLOT(handleRemoteProcessStarted())); - connect(m_runner, SIGNAL(remoteProcessFinished(qint64)), this, SLOT(handleRemoteProcessFinished(qint64))); - connect(m_runner, SIGNAL(reportProgress(QString)), this, SLOT(handleProgressReport(QString))); - connect(m_runner, SIGNAL(remoteOutput(QByteArray)), this, SLOT(handleRemoteOutput(QByteArray))); - - m_runner->start(); +void QnxDebugSupport::handlePortListReady() +{ + QTC_ASSERT(m_state == GatheringPorts, return); + startExecution(); } void QnxDebugSupport::startExecution() @@ -75,13 +97,13 @@ void QnxDebugSupport::startExecution() if (m_state == Inactive) return; - QTC_ASSERT(m_state == StartingRunner, return); - m_state = StartingRemoteProcess; - m_port = m_runner->usedPortsGatherer()->getNextFreePort(m_runner->freePorts()); + Utils::PortList portList = m_device->freePorts(); + m_port = m_portsGatherer->getNextFreePort(&portList); - const QString remoteCommandLine = QString::fromLatin1("%1 %2 %3").arg(m_runner->commandPrefix()).arg(QLatin1String(Constants::QNX_DEBUG_EXECUTABLE)).arg(m_port); - m_runner->startExecution(remoteCommandLine.toUtf8()); + const QString remoteCommandLine = QString::fromLatin1("%1 %2 %3") + .arg(m_commandPrefix, m_executable).arg(m_port); + m_runner->start(m_device, remoteCommandLine.toUtf8()); } void QnxDebugSupport::handleRemoteProcessStarted() @@ -90,17 +112,17 @@ void QnxDebugSupport::handleRemoteProcessStarted() m_engine->notifyEngineRemoteSetupDone(m_port, -1); } -void QnxDebugSupport::handleRemoteProcessFinished(qint64 exitCode) +void QnxDebugSupport::handleRemoteProcessFinished(bool success) { if (m_engine || m_state == Inactive) return; if (m_state == Debugging) { - if (exitCode != 0) + if (!success) m_engine->notifyInferiorIll(); } else { - const QString errorMsg = tr("The %1 process closed unexpectedly.").arg(QLatin1String(Constants::QNX_DEBUG_EXECUTABLE)); + const QString errorMsg = tr("The %1 process closed unexpectedly.").arg(m_executable); m_engine->notifyEngineRemoteSetupFailed(errorMsg); } } @@ -113,7 +135,7 @@ void QnxDebugSupport::handleDebuggingFinished() void QnxDebugSupport::setFinished() { m_state = Inactive; - m_runner->stop(); + m_runner->stop(QnxUtils::applicationKillCommand(m_executable).toUtf8()); } void QnxDebugSupport::handleProgressReport(const QString &progressOutput) @@ -130,7 +152,7 @@ void QnxDebugSupport::handleRemoteOutput(const QByteArray &output) m_engine->showMessage(QString::fromUtf8(output), Debugger::AppOutput); } -void QnxDebugSupport::handleSshError(const QString &error) +void QnxDebugSupport::handleError(const QString &error) { if (m_state == Debugging) { if (m_engine) { diff --git a/src/plugins/qnx/qnxdebugsupport.h b/src/plugins/qnx/qnxdebugsupport.h index f2a9dd2b06e..a97796546c7 100644 --- a/src/plugins/qnx/qnxdebugsupport.h +++ b/src/plugins/qnx/qnxdebugsupport.h @@ -34,16 +34,20 @@ #ifndef QNX_INTERNAL_QNXDEBUGSUPPORT_H #define QNX_INTERNAL_QNXDEBUGSUPPORT_H +#include <projectexplorer/devicesupport/idevice.h> + #include <QObject> +#include <QString> -namespace Debugger { -class DebuggerEngine; +namespace Debugger { class DebuggerEngine; } +namespace ProjectExplorer { +class DeviceApplicationRunner; +class DeviceUsedPortsGatherer; } namespace Qnx { namespace Internal { -class QnxApplicationRunner; class QnxRunConfiguration; class QnxDebugSupport : public QObject @@ -59,25 +63,30 @@ public slots: private slots: void handleAdapterSetupRequested(); - void startExecution(); void handleRemoteProcessStarted(); - void handleRemoteProcessFinished(qint64 exitCode); + void handleRemoteProcessFinished(bool success); void handleProgressReport(const QString &progressOutput); void handleRemoteOutput(const QByteArray &output); - void handleSshError(const QString &error); + void handleError(const QString &error); + void handlePortListReady(); private: + void startExecution(); void setFinished(); enum State { Inactive, - StartingRunner, + GatheringPorts, StartingRemoteProcess, Debugging }; - QnxApplicationRunner *m_runner; - + const QString m_executable; + const QString m_commandPrefix; + const QString m_arguments; + ProjectExplorer::IDevice::ConstPtr m_device; + ProjectExplorer::DeviceApplicationRunner *m_runner; + ProjectExplorer::DeviceUsedPortsGatherer * m_portsGatherer; Debugger::DebuggerEngine *m_engine; int m_port; diff --git a/src/plugins/qnx/qnxruncontrol.cpp b/src/plugins/qnx/qnxruncontrol.cpp index 187317fe118..f3cb262c56e 100644 --- a/src/plugins/qnx/qnxruncontrol.cpp +++ b/src/plugins/qnx/qnxruncontrol.cpp @@ -32,21 +32,22 @@ **************************************************************************/ #include "qnxruncontrol.h" -#include "qnxapplicationrunner.h" #include "qnxrunconfiguration.h" +#include "qnxutils.h" #include <projectexplorer/runconfiguration.h> +#include <remotelinux/remotelinuxrunconfiguration.h> using namespace Qnx; using namespace Qnx::Internal; +using namespace RemoteLinux; QnxRunControl::QnxRunControl(ProjectExplorer::RunConfiguration *runConfig) - : RemoteLinux::AbstractRemoteLinuxRunControl(runConfig) - , m_runner(new QnxApplicationRunner(qobject_cast<QnxRunConfiguration *>(runConfig), this)) + : RemoteLinuxRunControl(runConfig) { -} - -RemoteLinux::AbstractRemoteLinuxApplicationRunner *QnxRunControl::runner() const -{ - return m_runner; + const RemoteLinuxRunConfiguration * const rc + = qobject_cast<RemoteLinuxRunConfiguration *>(runConfig); + QString executable = rc->remoteExecutableFilePath(); + executable.replace(QLatin1String("/"), QLatin1String("\\/")); + overrideStopCommandLine(QnxUtils::applicationKillCommand(executable).toUtf8()); } diff --git a/src/plugins/qnx/qnxruncontrol.h b/src/plugins/qnx/qnxruncontrol.h index f96ac525d09..d90b27debfe 100644 --- a/src/plugins/qnx/qnxruncontrol.h +++ b/src/plugins/qnx/qnxruncontrol.h @@ -39,18 +39,11 @@ namespace Qnx { namespace Internal { -class QnxApplicationRunner; - -class QnxRunControl : public RemoteLinux::AbstractRemoteLinuxRunControl +class QnxRunControl : public RemoteLinux::RemoteLinuxRunControl { Q_OBJECT public: explicit QnxRunControl(ProjectExplorer::RunConfiguration *runConfig); - - RemoteLinux::AbstractRemoteLinuxApplicationRunner *runner() const; - -private: - QnxApplicationRunner * const m_runner; }; } // namespace Internal diff --git a/src/plugins/qnx/qnxutils.cpp b/src/plugins/qnx/qnxutils.cpp index 4ef95137c97..d96b50649a0 100644 --- a/src/plugins/qnx/qnxutils.cpp +++ b/src/plugins/qnx/qnxutils.cpp @@ -75,3 +75,11 @@ QStringList QnxUtils::searchPaths(QnxAbstractQtVersion *qtVersion) return searchPaths; } + +QString QnxUtils::applicationKillCommand(const QString &applicationFilePath) +{ + return QString::fromLatin1("for PID in $(ps -f -o pid,comm | grep %1 | awk '/%1/ {print $1}'); " + "do " + "kill $PID; sleep 1; kill -9 $PID; " + "done").arg(applicationFilePath); +} diff --git a/src/plugins/qnx/qnxutils.h b/src/plugins/qnx/qnxutils.h index 1195f87c579..82d63de8413 100644 --- a/src/plugins/qnx/qnxutils.h +++ b/src/plugins/qnx/qnxutils.h @@ -49,6 +49,7 @@ public: static QString addQuotes(const QString &string); static Qnx::QnxArchitecture cpudirToArch(const QString &cpuDir); static QStringList searchPaths(QnxAbstractQtVersion *qtVersion); + static QString applicationKillCommand(const QString &applicationFilePath); }; } // namespace Internal diff --git a/src/plugins/remotelinux/remotelinux.pro b/src/plugins/remotelinux/remotelinux.pro index 898f7cdf456..ed18ddd839f 100644 --- a/src/plugins/remotelinux/remotelinux.pro +++ b/src/plugins/remotelinux/remotelinux.pro @@ -17,7 +17,6 @@ HEADERS += \ genericlinuxdeviceconfigurationfactory.h \ remotelinuxrunconfigurationwidget.h \ remotelinuxrunconfigurationfactory.h \ - remotelinuxapplicationrunner.h \ remotelinuxruncontrol.h \ remotelinuxruncontrolfactory.h \ remotelinuxdebugsupport.h \ @@ -65,7 +64,6 @@ SOURCES += \ genericlinuxdeviceconfigurationfactory.cpp \ remotelinuxrunconfigurationwidget.cpp \ remotelinuxrunconfigurationfactory.cpp \ - remotelinuxapplicationrunner.cpp \ remotelinuxruncontrol.cpp \ remotelinuxruncontrolfactory.cpp \ remotelinuxdebugsupport.cpp \ diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs index 2236fe1511b..7c353ea2fcf 100644 --- a/src/plugins/remotelinux/remotelinux.qbs +++ b/src/plugins/remotelinux/remotelinux.qbs @@ -64,8 +64,6 @@ QtcPlugin { "remotelinux.qrc", "remotelinux_constants.h", "remotelinux_export.h", - "remotelinuxapplicationrunner.cpp", - "remotelinuxapplicationrunner.h", "remotelinuxcustomcommanddeploymentstep.h", "remotelinuxcustomcommanddeployservice.cpp", "remotelinuxcustomcommanddeployservice.h", diff --git a/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp b/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp deleted file mode 100644 index 1d73d77cf56..00000000000 --- a/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#include "remotelinuxapplicationrunner.h" - -#include "linuxdeviceconfiguration.h" -#include "remotelinuxrunconfiguration.h" - -#include <projectexplorer/target.h> -#include <projectexplorer/profileinformation.h> -#include <projectexplorer/devicesupport/deviceusedportsgatherer.h> - -#include <utils/portlist.h> -#include <utils/qtcassert.h> -#include <ssh/sshconnection.h> -#include <ssh/sshconnectionmanager.h> -#include <ssh/sshremoteprocess.h> - -#include <limits> - -using namespace ProjectExplorer; -using namespace QSsh; -using namespace Utils; - -namespace RemoteLinux { -namespace Internal { -namespace { - -enum State { - Inactive, SettingUpDevice, Connecting, PreRunCleaning, AdditionalPreRunCleaning, - GatheringPorts, AdditionalInitializing, ReadyForExecution, ProcessStarting, ProcessStarted, - PostRunCleaning -}; - -} // anonymous namespace - -class AbstractRemoteLinuxApplicationRunnerPrivate -{ -public: - AbstractRemoteLinuxApplicationRunnerPrivate(const RemoteLinuxRunConfiguration *runConfig) - : devConfig(DeviceProfileInformation::device(runConfig->target()->profile())), - remoteExecutable(runConfig->remoteExecutableFilePath()), - appArguments(runConfig->arguments()), - commandPrefix(runConfig->commandPrefix()), - initialFreePorts(devConfig->freePorts()), - connection(0), - stopRequested(false), - state(Inactive) - { } - - DeviceUsedPortsGatherer portsGatherer; - IDevice::ConstPtr devConfig; - const QString remoteExecutable; - const QString appArguments; - const QString commandPrefix; - const PortList initialFreePorts; - - QSsh::SshConnection *connection; - QSsh::SshRemoteProcess::Ptr runner; - QSsh::SshRemoteProcess::Ptr cleaner; - - PortList freePorts; - int exitStatus; - bool stopRequested; - State state; - -}; -} // namespace Internal - - -using namespace Internal; - -AbstractRemoteLinuxApplicationRunner::AbstractRemoteLinuxApplicationRunner(RemoteLinuxRunConfiguration *runConfig, - QObject *parent) - : QObject(parent), d(new AbstractRemoteLinuxApplicationRunnerPrivate(runConfig)) -{ - connect(&d->portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGathererError(QString))); - connect(&d->portsGatherer, SIGNAL(portListReady()), SLOT(handleUsedPortsAvailable())); -} - -AbstractRemoteLinuxApplicationRunner::~AbstractRemoteLinuxApplicationRunner() -{ - delete d; -} - -SshConnection *AbstractRemoteLinuxApplicationRunner::connection() const -{ - return d->connection; -} - -IDevice::ConstPtr AbstractRemoteLinuxApplicationRunner::devConfig() const -{ - return d->devConfig; -} - -DeviceUsedPortsGatherer *AbstractRemoteLinuxApplicationRunner::usedPortsGatherer() const -{ - return &d->portsGatherer; -} - -PortList *AbstractRemoteLinuxApplicationRunner::freePorts() -{ - return &d->freePorts; -} - -QString AbstractRemoteLinuxApplicationRunner::remoteExecutable() const -{ - return d->remoteExecutable; -} - -QString AbstractRemoteLinuxApplicationRunner::arguments() const -{ - return d->appArguments; -} - -QString AbstractRemoteLinuxApplicationRunner::commandPrefix() const -{ - return d->commandPrefix; -} - -void AbstractRemoteLinuxApplicationRunner::start() -{ - QTC_ASSERT(!d->stopRequested && d->state == Inactive, return); - - QString errorMsg; - if (!canRun(errorMsg)) { - emitError(tr("Cannot run: %1").arg(errorMsg), true); - return; - } - - d->state = SettingUpDevice; - doDeviceSetup(); -} - -void AbstractRemoteLinuxApplicationRunner::stop() -{ - if (d->stopRequested) - return; - - switch (d->state) { - case Connecting: - setInactive(); - emit remoteProcessFinished(InvalidExitCode); - break; - case GatheringPorts: - d->portsGatherer.stop(); - setInactive(); - emit remoteProcessFinished(InvalidExitCode); - break; - case SettingUpDevice: - case PreRunCleaning: - case AdditionalPreRunCleaning: - case AdditionalInitializing: - case ProcessStarting: - case PostRunCleaning: - d->stopRequested = true; // TODO: We might need stopPreRunCleaning() etc. for the subclasses - break; - case ReadyForExecution: - d->stopRequested = true; - d->state = PostRunCleaning; - doPostRunCleanup(); - break; - case ProcessStarted: - d->stopRequested = true; - cleanup(); - break; - case Inactive: - break; - } -} - -void AbstractRemoteLinuxApplicationRunner::handleConnected() -{ - QTC_ASSERT(d->state == Connecting, return); - - if (d->stopRequested) { - emit remoteProcessFinished(InvalidExitCode); - setInactive(); - } else { - d->state = PreRunCleaning; - cleanup(); - } -} - -void AbstractRemoteLinuxApplicationRunner::handleConnectionFailure() -{ - QTC_ASSERT(d->state != Inactive, return); - - if (d->state != Connecting || d->state != PreRunCleaning) - doAdditionalConnectionErrorHandling(); - - const QString errorMsg = d->state == Connecting - ? tr("Could not connect to host: %1") : tr("Connection error: %1"); - emitError(errorMsg.arg(d->connection->errorString())); -} - -void AbstractRemoteLinuxApplicationRunner::cleanup() -{ - QTC_ASSERT(d->state == PreRunCleaning - || (d->state == ProcessStarted && d->stopRequested), return); - - emit reportProgress(tr("Killing remote process(es)...")); - d->cleaner = d->connection->createRemoteProcess(killApplicationCommandLine().toUtf8()); - connect(d->cleaner.data(), SIGNAL(closed(int)), SLOT(handleCleanupFinished(int))); - d->cleaner->start(); -} - -void AbstractRemoteLinuxApplicationRunner::handleCleanupFinished(int exitStatus) -{ - Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart - || exitStatus == SshRemoteProcess::CrashExit - || exitStatus == SshRemoteProcess::NormalExit); - - QTC_ASSERT(d->state == PreRunCleaning - || (d->state == ProcessStarted && d->stopRequested) || d->state == Inactive, return); - - if (d->state == Inactive) - return; - if (d->stopRequested && d->state == PreRunCleaning) { - setInactive(); - emit remoteProcessFinished(InvalidExitCode); - return; - } - if (d->stopRequested) { - d->state = PostRunCleaning; - doPostRunCleanup(); - return; - } - - if (exitStatus != SshRemoteProcess::NormalExit) { - emitError(tr("Initial cleanup failed: %1").arg(d->cleaner->errorString())); - emit remoteProcessFinished(InvalidExitCode); - return; - } - - d->state = AdditionalPreRunCleaning; - doAdditionalInitialCleanup(); -} - -void AbstractRemoteLinuxApplicationRunner::startExecution(const QByteArray &remoteCall) -{ - QTC_ASSERT(d->state == ReadyForExecution, return); - - if (d->stopRequested) - return; - - d->runner = d->connection->createRemoteProcess(remoteCall); - connect(d->runner.data(), SIGNAL(started()), SLOT(handleRemoteProcessStarted())); - connect(d->runner.data(), SIGNAL(closed(int)), SLOT(handleRemoteProcessFinished(int))); - connect(d->runner.data(), SIGNAL(readyReadStandardOutput()), SLOT(handleRemoteStdout())); - connect(d->runner.data(), SIGNAL(readyReadStandardError()), SLOT(handleRemoteStderr())); - d->state = ProcessStarting; - d->runner->start(); -} - -void AbstractRemoteLinuxApplicationRunner::handleRemoteProcessStarted() -{ - QTC_ASSERT(d->state == ProcessStarting, return); - - d->state = ProcessStarted; - if (d->stopRequested) { - cleanup(); - return; - } - - emit reportProgress(tr("Remote process started.")); - emit remoteProcessStarted(); -} - -void AbstractRemoteLinuxApplicationRunner::handleRemoteProcessFinished(int exitStatus) -{ - Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart - || exitStatus == SshRemoteProcess::CrashExit - || exitStatus == SshRemoteProcess::NormalExit); - QTC_ASSERT(d->state == ProcessStarted || d->state == Inactive, return); - - d->exitStatus = exitStatus; - if (!d->stopRequested && d->state != Inactive) { - d->state = PostRunCleaning; - doPostRunCleanup(); - } -} - -void AbstractRemoteLinuxApplicationRunner::setInactive() -{ - d->portsGatherer.stop(); - if (d->connection) { - disconnect(d->connection, 0, this, 0); - SshConnectionManager::instance().releaseConnection(d->connection); - d->connection = 0; - } - if (d->cleaner) - disconnect(d->cleaner.data(), 0, this, 0); - d->stopRequested = false; - d->state = Inactive; -} - -void AbstractRemoteLinuxApplicationRunner::emitError(const QString &errorMsg, bool force) -{ - if (d->state != Inactive) { - setInactive(); - emit error(errorMsg); - } else if (force) { - emit error(errorMsg); - } -} - -void AbstractRemoteLinuxApplicationRunner::handlePortsGathererError(const QString &errorMsg) -{ - if (d->state != Inactive) { - if (connection()->errorState() != SshNoError) { - emitError(errorMsg); - } else { - emit reportProgress(tr("Gathering ports failed: %1\nContinuing anyway.").arg(errorMsg)); - handleUsedPortsAvailable(); - } - } -} - -void AbstractRemoteLinuxApplicationRunner::handleUsedPortsAvailable() -{ - QTC_ASSERT(d->state == GatheringPorts, return); - - if (d->stopRequested) { - setInactive(); - emit remoteProcessFinished(InvalidExitCode); - return; - } - - d->state = AdditionalInitializing; - doAdditionalInitializations(); -} - -void AbstractRemoteLinuxApplicationRunner::handleRemoteStdout() -{ - emit remoteOutput(d->runner->readAllStandardOutput()); -} - -void AbstractRemoteLinuxApplicationRunner::handleRemoteStderr() -{ - emit remoteErrorOutput(d->runner->readAllStandardError()); -} - -bool AbstractRemoteLinuxApplicationRunner::canRun(QString &whyNot) const -{ - if (d->remoteExecutable.isEmpty()) { - whyNot = tr("No remote executable set."); - return false; - } - - if (!d->devConfig) { - whyNot = tr("No device configuration set."); - return false; - } - - return true; -} - -void AbstractRemoteLinuxApplicationRunner::handleDeviceSetupDone(bool success) -{ - QTC_ASSERT(d->state == SettingUpDevice, return); - - if (!success || d->stopRequested) { - setInactive(); - emit remoteProcessFinished(InvalidExitCode); - return; - } - - d->connection = SshConnectionManager::instance().acquireConnection(d->devConfig->sshParameters()); - d->state = Connecting; - d->exitStatus = -1; - d->freePorts = d->initialFreePorts; - connect(d->connection, SIGNAL(connected()), SLOT(handleConnected())); - connect(d->connection, SIGNAL(error(QSsh::SshError)), - SLOT(handleConnectionFailure())); - if (d->connection->state() == SshConnection::Connected) { - handleConnected(); - } else { - emit reportProgress(tr("Connecting to device...")); - if (d->connection->state() == QSsh::SshConnection::Unconnected) - d->connection->connectToHost(); - } -} - -void AbstractRemoteLinuxApplicationRunner::handleInitialCleanupDone(bool success) -{ - QTC_ASSERT(d->state == AdditionalPreRunCleaning, return); - - if (!success || d->stopRequested) { - setInactive(); - emit remoteProcessFinished(InvalidExitCode); - return; - } - - d->state = GatheringPorts; - d->portsGatherer.start(d->devConfig); -} - -void AbstractRemoteLinuxApplicationRunner::handleInitializationsDone(bool success) -{ - QTC_ASSERT(d->state == AdditionalInitializing, return); - - if (!success) { - setInactive(); - emit remoteProcessFinished(InvalidExitCode); - return; - } - if (d->stopRequested) { - d->state = PostRunCleaning; - doPostRunCleanup(); - return; - } - - d->state = ReadyForExecution; - emit readyForExecution(); -} - -void AbstractRemoteLinuxApplicationRunner::handlePostRunCleanupDone() -{ - QTC_ASSERT(d->state == PostRunCleaning, return); - - const bool wasStopRequested = d->stopRequested; - setInactive(); - if (wasStopRequested) - emit remoteProcessFinished(InvalidExitCode); - else if (d->exitStatus == SshRemoteProcess::NormalExit) - emit remoteProcessFinished(d->runner->exitCode()); - else - emit error(tr("Error running remote process: %1").arg(d->runner->errorString())); -} - -QString AbstractRemoteLinuxApplicationRunner::killApplicationCommandLine() const -{ - return QString::fromLatin1("cd /proc; for pid in `ls -d [0123456789]*`; " - "do " - "if [ \"`readlink /proc/$pid/exe`\" = \"%1\" ]; then " - " kill $pid; sleep 1; kill -9 $pid; " - "fi; " - "done").arg(remoteExecutable()); -} - - -const qint64 AbstractRemoteLinuxApplicationRunner::InvalidExitCode = std::numeric_limits<qint64>::min(); - - -GenericRemoteLinuxApplicationRunner::GenericRemoteLinuxApplicationRunner(RemoteLinuxRunConfiguration *runConfig, - QObject *parent) - : AbstractRemoteLinuxApplicationRunner(runConfig, parent) -{ -} - -GenericRemoteLinuxApplicationRunner::~GenericRemoteLinuxApplicationRunner() -{ -} - - -void GenericRemoteLinuxApplicationRunner::doDeviceSetup() -{ - handleDeviceSetupDone(true); -} - -void GenericRemoteLinuxApplicationRunner::doAdditionalInitialCleanup() -{ - handleInitialCleanupDone(true); -} - -void GenericRemoteLinuxApplicationRunner::doAdditionalInitializations() -{ - handleInitializationsDone(true); -} - -void GenericRemoteLinuxApplicationRunner::doPostRunCleanup() -{ - handlePostRunCleanupDone(); -} - -void GenericRemoteLinuxApplicationRunner::doAdditionalConnectionErrorHandling() -{ -} - -} // namespace RemoteLinux - diff --git a/src/plugins/remotelinux/remotelinuxapplicationrunner.h b/src/plugins/remotelinux/remotelinuxapplicationrunner.h deleted file mode 100644 index 1b0d850bca5..00000000000 --- a/src/plugins/remotelinux/remotelinuxapplicationrunner.h +++ /dev/null @@ -1,145 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: http://www.qt-project.org/ -** -** GNU Lesser General Public License Usage -** -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this file. -** Please review the following information to ensure the GNU Lesser General -** Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** Other Usage -** -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -**************************************************************************/ - -#ifndef REMOTELINUXAPPLICATIONRUNNER_H -#define REMOTELINUXAPPLICATIONRUNNER_H - -#include "remotelinux_export.h" - -#include <projectexplorer/devicesupport/idevice.h> -#include <projectexplorer/devicesupport/deviceusedportsgatherer.h> - -namespace QSsh { class SshConnection; } -namespace Utils { class PortList; } - -namespace RemoteLinux { -class RemoteLinuxRunConfiguration; - -namespace Internal { class AbstractRemoteLinuxApplicationRunnerPrivate; } - -class REMOTELINUX_EXPORT AbstractRemoteLinuxApplicationRunner : public QObject -{ - Q_OBJECT - Q_DISABLE_COPY(AbstractRemoteLinuxApplicationRunner) -public: - AbstractRemoteLinuxApplicationRunner(RemoteLinuxRunConfiguration *runConfig, - QObject *parent = 0); - ~AbstractRemoteLinuxApplicationRunner(); - - void start(); - void stop(); - - void startExecution(const QByteArray &remoteCall); - - ProjectExplorer::IDevice::ConstPtr devConfig() const; - QSsh::SshConnection *connection() const; - ProjectExplorer::DeviceUsedPortsGatherer *usedPortsGatherer() const; - Utils::PortList *freePorts(); - QString remoteExecutable() const; - QString arguments() const; - QString commandPrefix() const; - - static const qint64 InvalidExitCode; - -signals: - void error(const QString &error); - void readyForExecution(); - void remoteOutput(const QByteArray &output); - void remoteErrorOutput(const QByteArray &output); - void reportProgress(const QString &progressOutput); - void remoteProcessStarted(); - void remoteProcessFinished(qint64 exitCode); - -protected: - // Override to to additional checks. - virtual bool canRun(QString &whyNot) const; - - void handleDeviceSetupDone(bool success); - void handleInitialCleanupDone(bool success); - void handleInitializationsDone(bool success); - void handlePostRunCleanupDone(); - -private slots: - void handleConnected(); - void handleConnectionFailure(); - void handleCleanupFinished(int exitStatus); - void handleRemoteProcessStarted(); - void handleRemoteProcessFinished(int exitStatus); - void handlePortsGathererError(const QString &errorMsg); - void handleUsedPortsAvailable(); - void handleRemoteStdout(); - void handleRemoteStderr(); - -private: - - virtual QString killApplicationCommandLine() const; - - // Implement to do custom setup of the device *before* connecting. - // Call handleDeviceSetupDone() afterwards. - virtual void doDeviceSetup() = 0; - - // Implement to do additional pre-run cleanup and call handleInitialCleanupDone(). - virtual void doAdditionalInitialCleanup() = 0; - - // Implement to do additional initializations right before the application is ready. - // Call handleInitializationsDone() afterwards. - virtual void doAdditionalInitializations() = 0; - - // Implement to do cleanups after application exit and call handlePostRunCleanupDone(); - virtual void doPostRunCleanup() = 0; - - virtual void doAdditionalConnectionErrorHandling() = 0; - - void setInactive(); - void emitError(const QString &errorMsg, bool force = false); - void cleanup(); - - Internal::AbstractRemoteLinuxApplicationRunnerPrivate * const d; -}; - - -class REMOTELINUX_EXPORT GenericRemoteLinuxApplicationRunner : public AbstractRemoteLinuxApplicationRunner -{ - Q_OBJECT -public: - GenericRemoteLinuxApplicationRunner(RemoteLinuxRunConfiguration *runConfig, - QObject *parent = 0); - ~GenericRemoteLinuxApplicationRunner(); - -protected: - void doDeviceSetup(); - void doAdditionalInitialCleanup(); - void doAdditionalInitializations(); - void doPostRunCleanup(); - void doAdditionalConnectionErrorHandling(); -}; - -} // namespace RemoteLinux - -#endif // REMOTELINUXAPPLICATIONRUNNER_H diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp index 30dd23fe660..e9d299db943 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp @@ -29,8 +29,8 @@ #include "remotelinuxdebugsupport.h" -#include "remotelinuxapplicationrunner.h" #include "remotelinuxrunconfiguration.h" +#include "remotelinuxutils.h" #include <debugger/debuggerengine.h> #include <debugger/debuggerstartparameters.h> @@ -42,6 +42,8 @@ #include <projectexplorer/project.h> #include <projectexplorer/target.h> #include <projectexplorer/toolchain.h> +#include <projectexplorer/devicesupport/deviceapplicationrunner.h> +#include <utils/portlist.h> #include <utils/qtcassert.h> #include <QPointer> @@ -54,19 +56,23 @@ using namespace ProjectExplorer; namespace RemoteLinux { namespace Internal { namespace { -enum State { Inactive, StartingRunner, StartingRemoteProcess, Debugging }; +enum State { Inactive, GatheringPorts, StartingRunner, Debugging }; } // anonymous namespace -class AbstractRemoteLinuxDebugSupportPrivate +class LinuxDeviceDebugSupportPrivate { public: - AbstractRemoteLinuxDebugSupportPrivate(RunConfiguration *runConfig, + LinuxDeviceDebugSupportPrivate(const RemoteLinuxRunConfiguration *runConfig, DebuggerEngine *engine) : engine(engine), qmlDebugging(runConfig->debuggerAspect()->useQmlDebugger()), cppDebugging(runConfig->debuggerAspect()->useCppDebugger()), state(Inactive), - gdbServerPort(-1), qmlPort(-1) + gdbServerPort(-1), qmlPort(-1), + device(DeviceProfileInformation::device(runConfig->target()->profile())), + remoteFilePath(runConfig->remoteExecutableFilePath()), + arguments(runConfig->arguments()), + commandPrefix(runConfig->commandPrefix()) { } @@ -77,21 +83,20 @@ public: State state; int gdbServerPort; int qmlPort; -}; - -class RemoteLinuxDebugSupportPrivate -{ -public: - RemoteLinuxDebugSupportPrivate(RemoteLinuxRunConfiguration *runConfig) : runner(runConfig) {} - - GenericRemoteLinuxApplicationRunner runner; + DeviceApplicationRunner appRunner; + DeviceUsedPortsGatherer portsGatherer; + const ProjectExplorer::IDevice::ConstPtr device; + Utils::PortList portList; + const QString remoteFilePath; + const QString arguments; + const QString commandPrefix; }; } // namespace Internal using namespace Internal; -DebuggerStartParameters AbstractRemoteLinuxDebugSupport::startParameters(const RemoteLinuxRunConfiguration *runConfig) +DebuggerStartParameters LinuxDeviceDebugSupport::startParameters(const RemoteLinuxRunConfiguration *runConfig) { DebuggerStartParameters params; Target *target = runConfig->target(); @@ -130,92 +135,101 @@ DebuggerStartParameters AbstractRemoteLinuxDebugSupport::startParameters(const R return params; } -AbstractRemoteLinuxDebugSupport::AbstractRemoteLinuxDebugSupport(RunConfiguration *runConfig, +LinuxDeviceDebugSupport::LinuxDeviceDebugSupport(RunConfiguration *runConfig, DebuggerEngine *engine) - : QObject(engine), d(new AbstractRemoteLinuxDebugSupportPrivate(runConfig, engine)) + : QObject(engine), + d(new LinuxDeviceDebugSupportPrivate(static_cast<RemoteLinuxRunConfiguration *>(runConfig), engine)) { connect(d->engine, SIGNAL(requestRemoteSetup()), this, SLOT(handleRemoteSetupRequested())); } -AbstractRemoteLinuxDebugSupport::~AbstractRemoteLinuxDebugSupport() +LinuxDeviceDebugSupport::~LinuxDeviceDebugSupport() { setFinished(); delete d; } -void AbstractRemoteLinuxDebugSupport::showMessage(const QString &msg, int channel) +void LinuxDeviceDebugSupport::setApplicationRunnerPreRunAction(DeviceApplicationHelperAction *action) { - if (d->engine) + d->appRunner.setPreRunAction(action); +} + +void LinuxDeviceDebugSupport::setApplicationRunnerPostRunAction(DeviceApplicationHelperAction *action) +{ + d->appRunner.setPostRunAction(action); +} + +void LinuxDeviceDebugSupport::showMessage(const QString &msg, int channel) +{ + if (d->state != Inactive && d->engine) d->engine->showMessage(msg, channel); } -void AbstractRemoteLinuxDebugSupport::handleRemoteSetupRequested() +void LinuxDeviceDebugSupport::handleRemoteSetupRequested() { QTC_ASSERT(d->state == Inactive, return); - d->state = StartingRunner; - showMessage(tr("Preparing remote side...\n"), AppStuff); - disconnect(runner(), 0, this, 0); - connect(runner(), SIGNAL(error(QString)), this, SLOT(handleSshError(QString))); - connect(runner(), SIGNAL(readyForExecution()), this, SLOT(startExecution())); - connect(runner(), SIGNAL(reportProgress(QString)), this, SLOT(handleProgressReport(QString))); - runner()->start(); + d->state = GatheringPorts; + showMessage(tr("Checking available ports...\n"), LogStatus); + connect(&d->portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGathererError(QString))); + connect(&d->portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady())); + d->portsGatherer.start(d->device); } -void AbstractRemoteLinuxDebugSupport::handleSshError(const QString &error) +void LinuxDeviceDebugSupport::handlePortsGathererError(const QString &message) { - if (d->state == Debugging) { - showMessage(error, AppError); - if (d->engine) - d->engine->notifyInferiorIll(); - } else if (d->state != Inactive) { - handleAdapterSetupFailed(error); - } + QTC_ASSERT(d->state == GatheringPorts, return); + handleAdapterSetupFailed(message); } -void AbstractRemoteLinuxDebugSupport::startExecution() +void LinuxDeviceDebugSupport::handlePortListReady() { - if (d->state == Inactive) - return; + QTC_ASSERT(d->state == GatheringPorts, return); - QTC_ASSERT(d->state == StartingRunner, return); + d->portList = d->device->freePorts(); + startExecution(); +} + +void LinuxDeviceDebugSupport::startExecution() +{ + QTC_ASSERT(d->state == GatheringPorts, return); if (d->cppDebugging && !setPort(d->gdbServerPort)) return; if (d->qmlDebugging && !setPort(d->qmlPort)) return; - d->state = StartingRemoteProcess; + d->state = StartingRunner; d->gdbserverOutput.clear(); - connect(runner(), SIGNAL(remoteErrorOutput(QByteArray)), this, - SLOT(handleRemoteErrorOutput(QByteArray))); - connect(runner(), SIGNAL(remoteOutput(QByteArray)), this, - SLOT(handleRemoteOutput(QByteArray))); - if (d->qmlDebugging && !d->cppDebugging) { - connect(runner(), SIGNAL(remoteProcessStarted()), - SLOT(handleRemoteProcessStarted())); - } - const QString &remoteExe = runner()->remoteExecutable(); - QString args = runner()->arguments(); - if (d->qmlDebugging) { - args += QString::fromLatin1(" -qmljsdebugger=port:%1,block") - .arg(d->qmlPort); - } - const QHostAddress peerAddress = runner()->connection()->connectionInfo().peerAddress; - QString peerAddressString = peerAddress.toString(); - if (peerAddress.protocol() == QAbstractSocket::IPv6Protocol) - peerAddressString.prepend(QLatin1Char('[')).append(QLatin1Char(']')); + connect(&d->appRunner, SIGNAL(remoteStderr(QByteArray)), + SLOT(handleRemoteErrorOutput(QByteArray))); + connect(&d->appRunner, SIGNAL(remoteStdout(QByteArray)), SLOT(handleRemoteOutput(QByteArray))); + if (d->qmlDebugging && !d->cppDebugging) + connect(&d->appRunner, SIGNAL(remoteProcessStarted()), SLOT(handleRemoteProcessStarted())); + QString args = d->arguments; + if (d->qmlDebugging) + args += QString::fromLocal8Bit(" -qmljsdebugger=port:%1,block").arg(d->qmlPort); const QString remoteCommandLine = (d->qmlDebugging && !d->cppDebugging) - ? QString::fromLatin1("%1 %2 %3").arg(runner()->commandPrefix()).arg(remoteExe).arg(args) - : QString::fromLatin1("%1 gdbserver %5:%2 %3 %4").arg(runner()->commandPrefix()) - .arg(d->gdbServerPort).arg(remoteExe).arg(args).arg(peerAddressString); - connect(runner(), SIGNAL(remoteProcessFinished(qint64)), - SLOT(handleRemoteProcessFinished(qint64))); - runner()->startExecution(remoteCommandLine.toUtf8()); + ? QString::fromLatin1("%1 %2 %3").arg(d->commandPrefix).arg(d->remoteFilePath).arg(args) + : QString::fromLatin1("%1 gdbserver :%2 %3 %4").arg(d->commandPrefix) + .arg(d->gdbServerPort).arg(d->remoteFilePath).arg(args); + connect(&d->appRunner, SIGNAL(finished(bool)), SLOT(handleAppRunnerFinished(bool))); + d->appRunner.start(d->device, remoteCommandLine.toUtf8()); } -void AbstractRemoteLinuxDebugSupport::handleRemoteProcessFinished(qint64 exitCode) +void LinuxDeviceDebugSupport::handleAppRunnerError(const QString &error) +{ + if (d->state == Debugging) { + showMessage(error, AppError); + if (d->engine) + d->engine->notifyInferiorIll(); + } else if (d->state != Inactive) { + handleAdapterSetupFailed(error); + } +} + +void LinuxDeviceDebugSupport::handleAppRunnerFinished(bool success) { if (!d->engine || d->state == Inactive) return; @@ -224,39 +238,35 @@ void AbstractRemoteLinuxDebugSupport::handleRemoteProcessFinished(qint64 exitCod // The QML engine does not realize on its own that the application has finished. if (d->qmlDebugging && !d->cppDebugging) d->engine->quitDebugger(); - else if (exitCode != 0) + else if (!success) d->engine->notifyInferiorIll(); } else { - const QString errorMsg = (d->qmlDebugging && !d->cppDebugging) - ? tr("Remote application failed with exit code %1.").arg(exitCode) - : tr("The gdbserver process closed unexpectedly."); - d->engine->notifyEngineRemoteSetupFailed(errorMsg); + d->engine->notifyEngineRemoteSetupFailed(tr("Debugging failed.")); } } -void AbstractRemoteLinuxDebugSupport::handleDebuggingFinished() +void LinuxDeviceDebugSupport::handleDebuggingFinished() { setFinished(); } -void AbstractRemoteLinuxDebugSupport::handleRemoteOutput(const QByteArray &output) +void LinuxDeviceDebugSupport::handleRemoteOutput(const QByteArray &output) { QTC_ASSERT(d->state == Inactive || d->state == Debugging, return); showMessage(QString::fromUtf8(output), AppOutput); } -void AbstractRemoteLinuxDebugSupport::handleRemoteErrorOutput(const QByteArray &output) +void LinuxDeviceDebugSupport::handleRemoteErrorOutput(const QByteArray &output) { - QTC_ASSERT(d->state == Inactive || d->state == StartingRemoteProcess || d->state == Debugging, - return); + QTC_ASSERT(d->state != GatheringPorts, return); if (!d->engine) return; - showMessage(QString::fromUtf8(output), AppOutput); - if (d->state == StartingRemoteProcess && d->cppDebugging) { + showMessage(QString::fromUtf8(output), AppError); + if (d->state == StartingRunner && d->cppDebugging) { d->gdbserverOutput += output; if (d->gdbserverOutput.contains("Listening on port")) { handleAdapterSetupDone(); @@ -265,42 +275,45 @@ void AbstractRemoteLinuxDebugSupport::handleRemoteErrorOutput(const QByteArray & } } -void AbstractRemoteLinuxDebugSupport::handleProgressReport(const QString &progressOutput) +void LinuxDeviceDebugSupport::handleProgressReport(const QString &progressOutput) { - showMessage(progressOutput + QLatin1Char('\n'), AppStuff); + showMessage(progressOutput + QLatin1Char('\n'), LogStatus); } -void AbstractRemoteLinuxDebugSupport::handleAdapterSetupFailed(const QString &error) +void LinuxDeviceDebugSupport::handleAdapterSetupFailed(const QString &error) { setFinished(); d->engine->notifyEngineRemoteSetupFailed(tr("Initial setup failed: %1").arg(error)); } -void AbstractRemoteLinuxDebugSupport::handleAdapterSetupDone() +void LinuxDeviceDebugSupport::handleAdapterSetupDone() { d->state = Debugging; d->engine->notifyEngineRemoteSetupDone(d->gdbServerPort, d->qmlPort); } -void AbstractRemoteLinuxDebugSupport::handleRemoteProcessStarted() +void LinuxDeviceDebugSupport::handleRemoteProcessStarted() { - Q_ASSERT(d->qmlDebugging && !d->cppDebugging); - QTC_ASSERT(d->state == StartingRemoteProcess, return); + QTC_ASSERT(d->qmlDebugging && !d->cppDebugging, return); + QTC_ASSERT(d->state == StartingRunner, return); handleAdapterSetupDone(); } -void AbstractRemoteLinuxDebugSupport::setFinished() +void LinuxDeviceDebugSupport::setFinished() { if (d->state == Inactive) return; + d->portsGatherer.disconnect(this); + d->appRunner.disconnect(this); + if (d->state == StartingRunner) + d->appRunner.stop(RemoteLinuxUtils::killApplicationCommandLine(d->remoteFilePath).toUtf8()); d->state = Inactive; - runner()->stop(); } -bool AbstractRemoteLinuxDebugSupport::setPort(int &port) +bool LinuxDeviceDebugSupport::setPort(int &port) { - port = runner()->usedPortsGatherer()->getNextFreePort(runner()->freePorts()); + port = d->portsGatherer.getNextFreePort(&d->portList); if (port == -1) { handleAdapterSetupFailed(tr("Not enough free ports on device for debugging.")); return false; @@ -308,22 +321,4 @@ bool AbstractRemoteLinuxDebugSupport::setPort(int &port) return true; } - -RemoteLinuxDebugSupport::RemoteLinuxDebugSupport(RemoteLinuxRunConfiguration *runConfig, - DebuggerEngine *engine) - : AbstractRemoteLinuxDebugSupport(runConfig, engine), - d(new RemoteLinuxDebugSupportPrivate(runConfig)) -{ -} - -RemoteLinuxDebugSupport::~RemoteLinuxDebugSupport() -{ - delete d; -} - -AbstractRemoteLinuxApplicationRunner *RemoteLinuxDebugSupport::runner() const -{ - return &d->runner; -} - } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.h b/src/plugins/remotelinux/remotelinuxdebugsupport.h index cee77a14209..6643835c503 100644 --- a/src/plugins/remotelinux/remotelinuxdebugsupport.h +++ b/src/plugins/remotelinux/remotelinuxdebugsupport.h @@ -40,65 +40,49 @@ class DebuggerStartParameters; } namespace ProjectExplorer { -class RunControl; +class DeviceApplicationHelperAction; class RunConfiguration; } namespace RemoteLinux { class RemoteLinuxRunConfiguration; -class AbstractRemoteLinuxApplicationRunner; -namespace Internal { -class AbstractRemoteLinuxDebugSupportPrivate; -class RemoteLinuxDebugSupportPrivate; -} // namespace Internal +namespace Internal { class LinuxDeviceDebugSupportPrivate; } -class REMOTELINUX_EXPORT AbstractRemoteLinuxDebugSupport : public QObject +class REMOTELINUX_EXPORT LinuxDeviceDebugSupport : public QObject { Q_OBJECT - Q_DISABLE_COPY(AbstractRemoteLinuxDebugSupport) public: static Debugger::DebuggerStartParameters startParameters(const RemoteLinuxRunConfiguration *runConfig); - AbstractRemoteLinuxDebugSupport(ProjectExplorer::RunConfiguration *runConfig, - Debugger::DebuggerEngine *engine); - ~AbstractRemoteLinuxDebugSupport(); + LinuxDeviceDebugSupport(ProjectExplorer::RunConfiguration *runConfig, + Debugger::DebuggerEngine *engine); + ~LinuxDeviceDebugSupport(); + + void setApplicationRunnerPreRunAction(ProjectExplorer::DeviceApplicationHelperAction *action); + void setApplicationRunnerPostRunAction(ProjectExplorer::DeviceApplicationHelperAction *action); private slots: void handleRemoteSetupRequested(); - void handleSshError(const QString &error); + void handleAppRunnerError(const QString &error); void startExecution(); void handleDebuggingFinished(); void handleRemoteOutput(const QByteArray &output); void handleRemoteErrorOutput(const QByteArray &output); void handleProgressReport(const QString &progressOutput); void handleRemoteProcessStarted(); - void handleRemoteProcessFinished(qint64 exitCode); + void handleAppRunnerFinished(bool success); + void handlePortsGathererError(const QString &message); + void handlePortListReady(); private: - virtual AbstractRemoteLinuxApplicationRunner *runner() const = 0; - void handleAdapterSetupFailed(const QString &error); void handleAdapterSetupDone(); void setFinished(); bool setPort(int &port); void showMessage(const QString &msg, int channel); - Internal::AbstractRemoteLinuxDebugSupportPrivate * const d; -}; - - -class REMOTELINUX_EXPORT RemoteLinuxDebugSupport : public AbstractRemoteLinuxDebugSupport -{ - Q_OBJECT -public: - RemoteLinuxDebugSupport(RemoteLinuxRunConfiguration *runConfig, Debugger::DebuggerEngine *engine); - ~RemoteLinuxDebugSupport(); - -private: - AbstractRemoteLinuxApplicationRunner *runner() const; - - Internal::RemoteLinuxDebugSupportPrivate * const d; + Internal::LinuxDeviceDebugSupportPrivate * const d; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxruncontrol.cpp b/src/plugins/remotelinux/remotelinuxruncontrol.cpp index b550c21331e..3492cf3a731 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrol.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrol.cpp @@ -29,10 +29,13 @@ #include "remotelinuxruncontrol.h" -#include "remotelinuxapplicationrunner.h" #include "remotelinuxrunconfiguration.h" +#include "remotelinuxutils.h" +#include <projectexplorer/devicesupport/deviceapplicationrunner.h> +#include <projectexplorer/profileinformation.h> #include <projectexplorer/projectexplorerconstants.h> +#include <projectexplorer/target.h> #include <utils/qtcassert.h> #include <QString> @@ -42,120 +45,112 @@ using namespace ProjectExplorer; namespace RemoteLinux { -using ProjectExplorer::RunConfiguration; +class RemoteLinuxRunControl::RemoteLinuxRunControlPrivate +{ +public: + bool running; + ProjectExplorer::DeviceApplicationRunner runner; + IDevice::ConstPtr device; + QString remoteExecutable; + QString arguments; + QString prefix; + QByteArray stopCommand; +}; -AbstractRemoteLinuxRunControl::AbstractRemoteLinuxRunControl(RunConfiguration *rc) - : RunControl(rc, ProjectExplorer::NormalRunMode) - , m_running(false) +RemoteLinuxRunControl::RemoteLinuxRunControl(RunConfiguration *rc) + : RunControl(rc, ProjectExplorer::NormalRunMode), d(new RemoteLinuxRunControlPrivate) { + d->running = false; + d->device = DeviceProfileInformation::device(rc->target()->profile()); + const RemoteLinuxRunConfiguration * const lrc = qobject_cast<RemoteLinuxRunConfiguration *>(rc); + d->remoteExecutable = lrc->remoteExecutableFilePath(); + d->arguments = lrc->arguments(); + d->prefix = lrc->commandPrefix(); + d->stopCommand = RemoteLinuxUtils::killApplicationCommandLine(d->remoteExecutable).toUtf8(); } -AbstractRemoteLinuxRunControl::~AbstractRemoteLinuxRunControl() +RemoteLinuxRunControl::~RemoteLinuxRunControl() { + delete d; } -void AbstractRemoteLinuxRunControl::start() +void RemoteLinuxRunControl::start() { - m_running = true; + d->running = true; emit started(); - disconnect(runner(), 0, this, 0); - connect(runner(), SIGNAL(error(QString)), SLOT(handleSshError(QString))); - connect(runner(), SIGNAL(readyForExecution()), SLOT(startExecution())); - connect(runner(), SIGNAL(remoteErrorOutput(QByteArray)), + d->runner.disconnect(this); + connect(&d->runner, SIGNAL(reportError(QString)), SLOT(handleErrorMessage(QString))); + connect(&d->runner, SIGNAL(remoteStderr(QByteArray)), SLOT(handleRemoteErrorOutput(QByteArray))); - connect(runner(), SIGNAL(remoteOutput(QByteArray)), - SLOT(handleRemoteOutput(QByteArray))); - connect(runner(), SIGNAL(remoteProcessStarted()), - SLOT(handleRemoteProcessStarted())); - connect(runner(), SIGNAL(remoteProcessFinished(qint64)), - SLOT(handleRemoteProcessFinished(qint64))); - connect(runner(), SIGNAL(reportProgress(QString)), - SLOT(handleProgressReport(QString))); - runner()->start(); + connect(&d->runner, SIGNAL(remoteStdout(QByteArray)), SLOT(handleRemoteOutput(QByteArray))); + connect(&d->runner, SIGNAL(finished(bool)), SLOT(handleRunnerFinished())); + connect(&d->runner, SIGNAL(reportProgress(QString)), SLOT(handleProgressReport(QString))); + const QString commandLine = QString::fromLatin1("%1 %2 %3") + .arg(d->prefix, d->remoteExecutable, d->arguments); + d->runner.start(d->device, commandLine.toUtf8()); } -RunControl::StopResult AbstractRemoteLinuxRunControl::stop() +RunControl::StopResult RemoteLinuxRunControl::stop() { - runner()->stop(); + d->runner.stop(d->stopCommand); return AsynchronousStop; } -void AbstractRemoteLinuxRunControl::handleSshError(const QString &error) +void RemoteLinuxRunControl::handleErrorMessage(const QString &error) { - handleError(error); - setFinished(); + appendMessage(error, Utils::ErrorMessageFormat); } -void AbstractRemoteLinuxRunControl::startExecution() +void RemoteLinuxRunControl::handleRunnerFinished() { - appendMessage(tr("Starting remote process...\n"), Utils::NormalMessageFormat); - runner()->startExecution(QString::fromLatin1("%1 %2 %3") - .arg(runner()->commandPrefix()) - .arg(runner()->remoteExecutable()) - .arg(runner()->arguments()).toUtf8()); -} - -void AbstractRemoteLinuxRunControl::handleRemoteProcessFinished(qint64 exitCode) -{ - if (exitCode != AbstractRemoteLinuxApplicationRunner::InvalidExitCode) { - appendMessage(tr("Finished running remote process. Exit code was %1.\n") - .arg(exitCode), Utils::NormalMessageFormat); - } setFinished(); } -void AbstractRemoteLinuxRunControl::handleRemoteOutput(const QByteArray &output) +void RemoteLinuxRunControl::handleRemoteOutput(const QByteArray &output) { appendMessage(QString::fromUtf8(output), Utils::StdOutFormatSameLine); } -void AbstractRemoteLinuxRunControl::handleRemoteErrorOutput(const QByteArray &output) +void RemoteLinuxRunControl::handleRemoteErrorOutput(const QByteArray &output) { appendMessage(QString::fromUtf8(output), Utils::StdErrFormatSameLine); } -void AbstractRemoteLinuxRunControl::handleProgressReport(const QString &progressString) +void RemoteLinuxRunControl::handleProgressReport(const QString &progressString) { appendMessage(progressString + QLatin1Char('\n'), Utils::NormalMessageFormat); } -bool AbstractRemoteLinuxRunControl::isRunning() const +bool RemoteLinuxRunControl::isRunning() const { - return m_running; + return d->running; } -QIcon AbstractRemoteLinuxRunControl::icon() const +QIcon RemoteLinuxRunControl::icon() const { return QIcon(ProjectExplorer::Constants::ICON_RUN_SMALL); } -void AbstractRemoteLinuxRunControl::handleError(const QString &errString) +void RemoteLinuxRunControl::setApplicationRunnerPreRunAction(DeviceApplicationHelperAction *action) { - stop(); - appendMessage(errString, Utils::ErrorMessageFormat); + d->runner.setPreRunAction(action); } -void AbstractRemoteLinuxRunControl::setFinished() +void RemoteLinuxRunControl::setApplicationRunnerPostRunAction(DeviceApplicationHelperAction *action) { - disconnect(runner(), 0, this, 0); - m_running = false; - emit finished(); + d->runner.setPostRunAction(action); } - -RemoteLinuxRunControl::RemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig) - : AbstractRemoteLinuxRunControl(runConfig), - m_runner(new GenericRemoteLinuxApplicationRunner(qobject_cast<RemoteLinuxRunConfiguration *>(runConfig), this)) -{ -} - -RemoteLinuxRunControl::~RemoteLinuxRunControl() +void RemoteLinuxRunControl::overrideStopCommandLine(const QByteArray &commandLine) { + d->stopCommand = commandLine; } -AbstractRemoteLinuxApplicationRunner *RemoteLinuxRunControl::runner() const +void RemoteLinuxRunControl::setFinished() { - return m_runner; + d->runner.disconnect(this); + d->running = false; + emit finished(); } } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxruncontrol.h b/src/plugins/remotelinux/remotelinuxruncontrol.h index adde0a01e45..86f690d66a5 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrol.h +++ b/src/plugins/remotelinux/remotelinuxruncontrol.h @@ -34,54 +34,38 @@ #include <projectexplorer/runconfiguration.h> -QT_FORWARD_DECLARE_CLASS(QString) +namespace ProjectExplorer { class DeviceApplicationHelperAction; } namespace RemoteLinux { -class AbstractRemoteLinuxApplicationRunner; -class REMOTELINUX_EXPORT AbstractRemoteLinuxRunControl : public ProjectExplorer::RunControl +class REMOTELINUX_EXPORT RemoteLinuxRunControl : public ProjectExplorer::RunControl { Q_OBJECT - Q_DISABLE_COPY(AbstractRemoteLinuxRunControl) public: - explicit AbstractRemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig); - virtual ~AbstractRemoteLinuxRunControl(); + explicit RemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig); + virtual ~RemoteLinuxRunControl(); virtual void start(); virtual StopResult stop(); virtual bool isRunning() const; virtual QIcon icon() const; - virtual AbstractRemoteLinuxApplicationRunner *runner() const = 0; + void setApplicationRunnerPreRunAction(ProjectExplorer::DeviceApplicationHelperAction *action); + void setApplicationRunnerPostRunAction(ProjectExplorer::DeviceApplicationHelperAction *action); + void overrideStopCommandLine(const QByteArray &commandLine); private slots: - void startExecution(); - void handleSshError(const QString &error); - void handleRemoteProcessStarted() {} - void handleRemoteProcessFinished(qint64 exitCode); + void handleErrorMessage(const QString &error); + void handleRunnerFinished(); void handleRemoteOutput(const QByteArray &output); void handleRemoteErrorOutput(const QByteArray &output); void handleProgressReport(const QString &progressString); private: void setFinished(); - void handleError(const QString &errString); - - bool m_running; -}; - - -class REMOTELINUX_EXPORT RemoteLinuxRunControl : public AbstractRemoteLinuxRunControl -{ - Q_OBJECT - -public: - explicit RemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig); - virtual ~RemoteLinuxRunControl(); -private: - virtual AbstractRemoteLinuxApplicationRunner *runner() const; - AbstractRemoteLinuxApplicationRunner * const m_runner; + class RemoteLinuxRunControlPrivate; + RemoteLinuxRunControlPrivate * const d; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp index 36e2820b36d..449ef7832f9 100644 --- a/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp +++ b/src/plugins/remotelinux/remotelinuxruncontrolfactory.cpp @@ -89,14 +89,14 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Ru if (mode == ProjectExplorer::NormalRunMode) return new RemoteLinuxRunControl(rc); - DebuggerStartParameters params = AbstractRemoteLinuxDebugSupport::startParameters(rc); + DebuggerStartParameters params = LinuxDeviceDebugSupport::startParameters(rc); if (mode == ProjectExplorer::DebugRunModeWithBreakOnMain) params.breakOnMain = true; DebuggerRunControl * const runControl = DebuggerPlugin::createDebugger(params, rc); if (!runControl) return 0; - RemoteLinuxDebugSupport *debugSupport = - new RemoteLinuxDebugSupport(rc, runControl->engine()); + LinuxDeviceDebugSupport * const debugSupport = + new LinuxDeviceDebugSupport(rc, runControl->engine()); connect(runControl, SIGNAL(finished()), debugSupport, SLOT(handleDebuggingFinished())); return runControl; } diff --git a/src/plugins/remotelinux/remotelinuxutils.cpp b/src/plugins/remotelinux/remotelinuxutils.cpp index 481fcb2afed..80d2e428634 100644 --- a/src/plugins/remotelinux/remotelinuxutils.cpp +++ b/src/plugins/remotelinux/remotelinuxutils.cpp @@ -41,9 +41,14 @@ using namespace ExtensionSystem; namespace RemoteLinux { -QString RemoteLinuxUtils::deviceConfigurationName(const LinuxDeviceConfiguration::ConstPtr &devConf) +QString RemoteLinuxUtils::killApplicationCommandLine(const QString &applicationFilePath) { - return devConf ? devConf->displayName() : QCoreApplication::translate("RemoteLinux", "(No device)"); + return QString::fromLatin1("cd /proc; for pid in `ls -d [0123456789]*`; " + "do " + "if [ \"`readlink /proc/$pid/exe`\" = \"%1\" ]; then " + " kill $pid; sleep 1; kill -9 $pid; " + "fi; " + "done").arg(applicationFilePath); } } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxutils.h b/src/plugins/remotelinux/remotelinuxutils.h index 69ae6deeab4..403a60d8d55 100644 --- a/src/plugins/remotelinux/remotelinuxutils.h +++ b/src/plugins/remotelinux/remotelinuxutils.h @@ -40,7 +40,7 @@ class LinuxDeviceConfiguration; class REMOTELINUX_EXPORT RemoteLinuxUtils { public: - static QString deviceConfigurationName(const QSharedPointer<const LinuxDeviceConfiguration> &devConf); + static QString killApplicationCommandLine(const QString &applicationFilePath); }; } // namespace RemoteLinux -- GitLab