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>
This commit is contained in:
Christian Kandeler
2012-07-26 09:02:34 +02:00
committed by hjk
parent 93756975e1
commit 1d85d8e706
40 changed files with 1063 additions and 1753 deletions

View File

@@ -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 \

View File

@@ -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"
]
}

View File

@@ -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

View File

@@ -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();
bool canRun(QString &whyNot) const;
void doDeviceSetup();
void doAdditionalInitialCleanup();
void doAdditionalInitializations();
void doPostRunCleanup();
void doAdditionalConnectionErrorHandling();
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;
};
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 setFinished(bool success);
MaemoRemoteMounter * const m_mounter;
bool m_isRunning;
};
} // namespace Internal
} // namespace Madde
#endif // MAEMOSSHRUNNER_H
#endif // MAEMOAPPLICATIONRUNNERHELPERACTIONS_H

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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();

View File

@@ -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();

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 \

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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();
}

View File

@@ -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

View File

@@ -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 \

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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) {

View File

@@ -34,16 +34,20 @@
#ifndef QNX_INTERNAL_QNXDEBUGSUPPORT_H
#define QNX_INTERNAL_QNXDEBUGSUPPORT_H
#include <QObject>
#include <projectexplorer/devicesupport/idevice.h>
namespace Debugger {
class DebuggerEngine;
#include <QObject>
#include <QString>
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;

View File

@@ -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());
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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 \

View File

@@ -64,8 +64,6 @@ QtcPlugin {
"remotelinux.qrc",
"remotelinux_constants.h",
"remotelinux_export.h",
"remotelinuxapplicationrunner.cpp",
"remotelinuxapplicationrunner.h",
"remotelinuxcustomcommanddeploymentstep.h",
"remotelinuxcustomcommanddeployservice.cpp",
"remotelinuxcustomcommanddeployservice.h",

View File

@@ -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

View File

@@ -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

View File

@@ -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,39 +135,90 @@ 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)
{
QTC_ASSERT(d->state == GatheringPorts, return);
handleAdapterSetupFailed(message);
}
void LinuxDeviceDebugSupport::handlePortListReady()
{
QTC_ASSERT(d->state == GatheringPorts, 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 = StartingRunner;
d->gdbserverOutput.clear();
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(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 LinuxDeviceDebugSupport::handleAppRunnerError(const QString &error)
{
if (d->state == Debugging) {
showMessage(error, AppError);
@@ -173,49 +229,7 @@ void AbstractRemoteLinuxDebugSupport::handleSshError(const QString &error)
}
}
void AbstractRemoteLinuxDebugSupport::startExecution()
{
if (d->state == Inactive)
return;
QTC_ASSERT(d->state == StartingRunner, return);
if (d->cppDebugging && !setPort(d->gdbServerPort))
return;
if (d->qmlDebugging && !setPort(d->qmlPort))
return;
d->state = StartingRemoteProcess;
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(']'));
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());
}
void AbstractRemoteLinuxDebugSupport::handleRemoteProcessFinished(qint64 exitCode)
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

View File

@@ -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

View File

@@ -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;
AbstractRemoteLinuxRunControl::AbstractRemoteLinuxRunControl(RunConfiguration *rc)
: RunControl(rc, ProjectExplorer::NormalRunMode)
, m_running(false)
class RemoteLinuxRunControl::RemoteLinuxRunControlPrivate
{
}
public:
bool running;
ProjectExplorer::DeviceApplicationRunner runner;
IDevice::ConstPtr device;
QString remoteExecutable;
QString arguments;
QString prefix;
QByteArray stopCommand;
};
AbstractRemoteLinuxRunControl::~AbstractRemoteLinuxRunControl()
{
}
void AbstractRemoteLinuxRunControl::start()
{
m_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)),
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();
}
RunControl::StopResult AbstractRemoteLinuxRunControl::stop()
{
runner()->stop();
return AsynchronousStop;
}
void AbstractRemoteLinuxRunControl::handleSshError(const QString &error)
{
handleError(error);
setFinished();
}
void AbstractRemoteLinuxRunControl::startExecution()
{
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)
{
appendMessage(QString::fromUtf8(output), Utils::StdOutFormatSameLine);
}
void AbstractRemoteLinuxRunControl::handleRemoteErrorOutput(const QByteArray &output)
{
appendMessage(QString::fromUtf8(output), Utils::StdErrFormatSameLine);
}
void AbstractRemoteLinuxRunControl::handleProgressReport(const QString &progressString)
{
appendMessage(progressString + QLatin1Char('\n'), Utils::NormalMessageFormat);
}
bool AbstractRemoteLinuxRunControl::isRunning() const
{
return m_running;
}
QIcon AbstractRemoteLinuxRunControl::icon() const
{
return QIcon(ProjectExplorer::Constants::ICON_RUN_SMALL);
}
void AbstractRemoteLinuxRunControl::handleError(const QString &errString)
{
stop();
appendMessage(errString, Utils::ErrorMessageFormat);
}
void AbstractRemoteLinuxRunControl::setFinished()
{
disconnect(runner(), 0, this, 0);
m_running = false;
emit finished();
}
RemoteLinuxRunControl::RemoteLinuxRunControl(ProjectExplorer::RunConfiguration *runConfig)
: AbstractRemoteLinuxRunControl(runConfig),
m_runner(new GenericRemoteLinuxApplicationRunner(qobject_cast<RemoteLinuxRunConfiguration *>(runConfig), this))
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();
}
RemoteLinuxRunControl::~RemoteLinuxRunControl()
{
delete d;
}
AbstractRemoteLinuxApplicationRunner *RemoteLinuxRunControl::runner() const
void RemoteLinuxRunControl::start()
{
return m_runner;
d->running = true;
emit started();
d->runner.disconnect(this);
connect(&d->runner, SIGNAL(reportError(QString)), SLOT(handleErrorMessage(QString)));
connect(&d->runner, SIGNAL(remoteStderr(QByteArray)),
SLOT(handleRemoteErrorOutput(QByteArray)));
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 RemoteLinuxRunControl::stop()
{
d->runner.stop(d->stopCommand);
return AsynchronousStop;
}
void RemoteLinuxRunControl::handleErrorMessage(const QString &error)
{
appendMessage(error, Utils::ErrorMessageFormat);
}
void RemoteLinuxRunControl::handleRunnerFinished()
{
setFinished();
}
void RemoteLinuxRunControl::handleRemoteOutput(const QByteArray &output)
{
appendMessage(QString::fromUtf8(output), Utils::StdOutFormatSameLine);
}
void RemoteLinuxRunControl::handleRemoteErrorOutput(const QByteArray &output)
{
appendMessage(QString::fromUtf8(output), Utils::StdErrFormatSameLine);
}
void RemoteLinuxRunControl::handleProgressReport(const QString &progressString)
{
appendMessage(progressString + QLatin1Char('\n'), Utils::NormalMessageFormat);
}
bool RemoteLinuxRunControl::isRunning() const
{
return d->running;
}
QIcon RemoteLinuxRunControl::icon() const
{
return QIcon(ProjectExplorer::Constants::ICON_RUN_SMALL);
}
void RemoteLinuxRunControl::setApplicationRunnerPreRunAction(DeviceApplicationHelperAction *action)
{
d->runner.setPreRunAction(action);
}
void RemoteLinuxRunControl::setApplicationRunnerPostRunAction(DeviceApplicationHelperAction *action)
{
d->runner.setPostRunAction(action);
}
void RemoteLinuxRunControl::overrideStopCommandLine(const QByteArray &commandLine)
{
d->stopCommand = commandLine;
}
void RemoteLinuxRunControl::setFinished()
{
d->runner.disconnect(this);
d->running = false;
emit finished();
}
} // namespace RemoteLinux

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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