From 032e7dc4c67fffe366bebdf4ace4d648efb3125c Mon Sep 17 00:00:00 2001 From: ck <qt-info@nokia.com> Date: Wed, 14 Jul 2010 17:26:51 +0200 Subject: [PATCH] Maemo: Factor SSH operations out of run control classes. Preparation for removing MaemoDebugRunControl. Reviewed-by: kh1 --- src/plugins/coreplugin/ssh/sshconnection.h | 9 + .../debugger/gdb/remoteplaingdbadapter.cpp | 3 +- .../qt-maemo/maemorunconfiguration.cpp | 10 +- .../qt-maemo/maemorunconfiguration.h | 3 +- .../qt-maemo/maemorunconfigurationwidget.cpp | 4 +- .../qt-maemo/maemoruncontrol.cpp | 249 +++++------------- .../qt-maemo/maemoruncontrol.h | 40 +-- .../qt-maemo/maemosshrunner.cpp | 193 ++++++++++++++ .../qt-maemo/maemosshrunner.h | 104 ++++++++ .../qt4projectmanager/qt-maemo/qt-maemo.pri | 6 +- 10 files changed, 392 insertions(+), 229 deletions(-) create mode 100644 src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp create mode 100644 src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h diff --git a/src/plugins/coreplugin/ssh/sshconnection.h b/src/plugins/coreplugin/ssh/sshconnection.h index e7f73995a4a..d863fd50b47 100644 --- a/src/plugins/coreplugin/ssh/sshconnection.h +++ b/src/plugins/coreplugin/ssh/sshconnection.h @@ -57,6 +57,15 @@ struct CORE_EXPORT SshConnectionParameters enum AuthType { AuthByPwd, AuthByKey } authType; quint16 port; }; +CORE_EXPORT inline bool operator==(const SshConnectionParameters &p1, + const SshConnectionParameters &p2) +{ + return p1.host == p2.host && p1.uname == p2.uname + && p1.authType == p2.authType + && (p1.authType == SshConnectionParameters::AuthByPwd ? + p1.pwd == p2.pwd : p1.privateKeyFile == p2.privateKeyFile) + && p1.timeout == p2.timeout && p1.port == p2.port; +} /* diff --git a/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp b/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp index 88946c11360..96c1d11ebb4 100644 --- a/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp +++ b/src/plugins/debugger/gdb/remoteplaingdbadapter.cpp @@ -85,8 +85,7 @@ QString RemotePlainGdbAdapter::fromLocalEncoding(const QByteArray &b) const void RemotePlainGdbAdapter::handleApplicationOutput(const QByteArray &output) { - // FIXME: Remote encoding? - showMessage(QString::fromLatin1(output), AppOutput); + showMessage(QString::fromUtf8(output), AppOutput); } } // namespace Internal diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp index 6b09682b13d..eb32c1d2c98 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.cpp @@ -29,9 +29,9 @@ #include "maemorunconfiguration.h" +#include "maemodeployables.h" #include "maemodeploystep.h" #include "maemoglobal.h" -#include "maemopackagecreationstep.h" #include "maemorunconfigurationwidget.h" #include "maemotoolchain.h" #include "qemuruntimemanager.h" @@ -217,7 +217,7 @@ const QString MaemoRunConfiguration::dumperLib() const return qt4bc->qtVersion()->debuggingHelperLibrary(); } -QString MaemoRunConfiguration::executable() const +QString MaemoRunConfiguration::localExecutableFilePath() const { TargetInformation ti = qt4Target()->qt4Project()->rootProjectNode() ->targetInformation(m_proFilePath); @@ -227,6 +227,12 @@ QString MaemoRunConfiguration::executable() const return QDir::cleanPath(ti.workingDir + QLatin1Char('/') + ti.target); } +QString MaemoRunConfiguration::remoteExecutableFilePath() const +{ + return deployStep()->deployables() + ->remoteExecutableFilePath(localExecutableFilePath()); +} + QString MaemoRunConfiguration::runtimeGdbServerPort() const { if (Qt4BuildConfiguration *qt4bc = activeQt4BuildConfiguration()) { diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h index 81a2897d53f..1aa8814bf8c 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfiguration.h @@ -75,7 +75,8 @@ public: MaemoDeployStep *deployStep() const; QString maddeRoot() const; - QString executable() const; + QString localExecutableFilePath() const; + QString remoteExecutableFilePath() const; const QString sysRoot() const; const QString targetRoot() const; const QStringList arguments() const; diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfigurationwidget.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfigurationwidget.cpp index e5b7fdf5d2c..5d53ce6f057 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemorunconfigurationwidget.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemorunconfigurationwidget.cpp @@ -83,7 +83,7 @@ MaemoRunConfigurationWidget::MaemoRunConfigurationWidget( devConfLayout->addWidget(debuggerConfLabel); mainLayout->addRow(new QLabel(tr("Device configuration:")), devConfWidget); - m_executableLabel = new QLabel(m_runConfiguration->executable()); + m_executableLabel = new QLabel(m_runConfiguration->localExecutableFilePath()); mainLayout->addRow(tr("Executable:"), m_executableLabel); m_argsLineEdit = new QLineEdit(m_runConfiguration->arguments().join(" ")); mainLayout->addRow(tr("Arguments:"), m_argsLineEdit); @@ -118,7 +118,7 @@ void MaemoRunConfigurationWidget::argumentsEdited(const QString &text) void MaemoRunConfigurationWidget::updateTargetInformation() { - m_executableLabel->setText(m_runConfiguration->executable()); + m_executableLabel->setText(m_runConfiguration->localExecutableFilePath()); } void MaemoRunConfigurationWidget::deviceConfigurationChanged(const QString &name) diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp index 007018c5131..1dc98468182 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.cpp @@ -34,15 +34,14 @@ #include "maemoruncontrol.h" -#include "maemodeployables.h" #include "maemodeploystep.h" #include "maemoglobal.h" #include "maemorunconfiguration.h" +#include "maemosshrunner.h" #include <coreplugin/icore.h> #include <coreplugin/ssh/sftpchannel.h> #include <coreplugin/ssh/sshconnection.h> -#include <coreplugin/ssh/sshremoteprocess.h> #include <debugger/debuggerengine.h> #include <debugger/debuggerplugin.h> #include <debugger/debuggerrunner.h> @@ -73,6 +72,8 @@ AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc, QString m : RunControl(rc, mode) , m_runConfig(qobject_cast<MaemoRunConfiguration *>(rc)) , m_devConfig(m_runConfig ? m_runConfig->deviceConfig() : MaemoDeviceConfig()) + , m_runner(new MaemoSshRunner(this, m_runConfig)) + , m_running(false) { } @@ -80,115 +81,62 @@ AbstractMaemoRunControl::~AbstractMaemoRunControl() { } - // TODO: We can cache the connection. We'd have to check if the connection - // is active and its parameters are the same as m_devConfig. If yes, - // skip the connection step and jump right to handleConnected() void AbstractMaemoRunControl::start() { if (!m_devConfig.isValid()) { handleError(tr("No device configuration set for run configuration.")); } else { + emit appendMessage(this, tr("Preparing remote side ..."), false); + m_running = true; m_stopped = false; emit started(); - m_connection = SshConnection::create(); - connect(m_connection.data(), SIGNAL(connected()), this, - SLOT(handleConnected())); - connect(m_connection.data(), SIGNAL(error(SshError)), this, - SLOT(handleConnectionFailure())); - m_connection->connectToHost(m_devConfig.server); + connect(m_runner, SIGNAL(error(QString)), this, + SLOT(handleSshError(QString))); + connect(m_runner, SIGNAL(readyForExecution()), this, + SLOT(startExecution())); + connect(m_runner, SIGNAL(remoteErrorOutput(QByteArray)), this, + SLOT(handleRemoteErrorOutput(QByteArray))); + connect(m_runner, SIGNAL(remoteOutput(QByteArray)), this, + SLOT(handleRemoteOutput(QByteArray))); + connect(m_runner, SIGNAL(remoteProcessStarted()), this, + SLOT(handleRemoteProcessStarted())); + connect(m_runner, SIGNAL(remoteProcessFinished(int)), this, + SLOT(handleRemoteProcessFinished(int))); + m_runner->start(); } } -void AbstractMaemoRunControl::handleConnected() -{ - if (m_stopped) - return; - - emit appendMessage(this, tr("Cleaning up remote leftovers first ..."), false); - const QStringList appsToKill = QStringList() << executableFileName() -#ifdef USE_GDBSERVER - << QLatin1String("gdbserver"); -#else - << QLatin1String("gdb"); -#endif - killRemoteProcesses(appsToKill, true); -} - -void AbstractMaemoRunControl::handleConnectionFailure() -{ - if (m_stopped) - return; - - handleError(tr("Could not connect to host: %1") - .arg(m_connection->errorString())); - emit finished(); -} - void AbstractMaemoRunControl::stop() { m_stopped = true; - if (m_connection && m_connection->state() == SshConnection::Connecting) { - disconnect(m_connection.data(), 0, this, 0); - m_connection->disconnectFromHost(); - emit finished(); - } else if (m_initialCleaner && m_initialCleaner->isRunning()) { - disconnect(m_initialCleaner.data(), 0, this, 0); - emit finished(); - } else { - stopInternal(); - } -} - -QString AbstractMaemoRunControl::executableFilePathOnTarget() const -{ - const MaemoDeployables * const deployables - = m_runConfig->deployStep()->deployables(); - return deployables->remoteExecutableFilePath(m_runConfig->executable()); + if (m_runner) + m_runner->stop(); + stopInternal(); } -void AbstractMaemoRunControl::startExecutionIfPossible() +void AbstractMaemoRunControl::handleSshError(const QString &error) { - if (executableFilePathOnTarget().isEmpty()) { - handleError(tr("Cannot run: No remote executable set.")); - emit finished(); - } else { - startExecution(); - } + handleError(error); + setFinished(); } void AbstractMaemoRunControl::startExecution() { - m_runner = m_connection->createRemoteProcess(remoteCall().toUtf8()); - connect(m_runner.data(), SIGNAL(started()), this, - SLOT(handleRemoteProcessStarted())); - connect(m_runner.data(), SIGNAL(closed(int)), this, - SLOT(handleRemoteProcessFinished(int))); - connect(m_runner.data(), SIGNAL(outputAvailable(QByteArray)), this, - SLOT(handleRemoteOutput(QByteArray))); - connect(m_runner.data(), SIGNAL(errorOutputAvailable(QByteArray)), this, - SLOT(handleRemoteErrorOutput(QByteArray))); - emit appendMessage(this, tr("Starting remote application."), false); - m_runner->start(); + emit appendMessage(this, tr("Starting remote process ..."), false); + m_runner->startExecution(QString::fromLocal8Bit("%1 %2 %3") + .arg(targetCmdLinePrefix()).arg(m_runConfig->remoteExecutableFilePath()) + .arg(arguments()).toUtf8()); } -void AbstractMaemoRunControl::handleRemoteProcessFinished(int exitStatus) +void AbstractMaemoRunControl::handleRemoteProcessFinished(int exitCode) { - Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart - || exitStatus == SshRemoteProcess::KilledBySignal - || exitStatus == SshRemoteProcess::ExitedNormally); - if (m_stopped) return; - if (exitStatus == SshRemoteProcess::ExitedNormally) { - emit appendMessage(this, - tr("Finished running remote process. Exit code was %1.") - .arg(m_runner->exitCode()), false); - emit finished(); - } else { - handleError(tr("Error running remote process: %1") - .arg(m_runner->errorString())); - } + emit appendMessage(this, + tr("Finished running remote process. Exit code was %1.").arg(exitCode), + false); + setFinished(); } void AbstractMaemoRunControl::handleRemoteOutput(const QByteArray &output) @@ -203,84 +151,17 @@ void AbstractMaemoRunControl::handleRemoteErrorOutput(const QByteArray &output) bool AbstractMaemoRunControl::isRunning() const { - return m_runner && m_runner->isRunning(); -} - -void AbstractMaemoRunControl::stopRunning(bool forDebugging) -{ - if (m_runner && m_runner->isRunning()) { - disconnect(m_runner.data(), 0, this, 0); - QStringList apps(executableFileName()); - if (forDebugging) - apps << QLatin1String("gdbserver"); - killRemoteProcesses(apps, false); - emit finished(); - } -} - -void AbstractMaemoRunControl::killRemoteProcesses(const QStringList &apps, - bool initialCleanup) -{ - QString niceKill; - QString brutalKill; - foreach (const QString &app, apps) { - niceKill += QString::fromLocal8Bit("pkill -x %1;").arg(app); - brutalKill += QString::fromLocal8Bit("pkill -x -9 %1;").arg(app); - } - QString remoteCall = niceKill + QLatin1String("sleep 1; ") + brutalKill; - remoteCall.remove(remoteCall.count() - 1, 1); // Get rid of trailing semicolon. - SshRemoteProcess::Ptr proc - = m_connection->createRemoteProcess(remoteCall.toUtf8()); - if (initialCleanup) { - m_initialCleaner = proc; - connect(m_initialCleaner.data(), SIGNAL(closed(int)), this, - SLOT(handleInitialCleanupFinished(int))); - } else { - m_stopper = proc; - } - proc->start(); -} - -void AbstractMaemoRunControl::handleInitialCleanupFinished(int exitStatus) -{ - Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart - || exitStatus == SshRemoteProcess::KilledBySignal - || exitStatus == SshRemoteProcess::ExitedNormally); - - if (m_stopped) - return; - - if (exitStatus != SshRemoteProcess::ExitedNormally) { - handleError(tr("Initial cleanup failed: %1") - .arg(m_initialCleaner->errorString())); - } else { - emit appendMessage(this, tr("Initial cleanup done."), false); - startExecutionIfPossible(); - } -} - -const QString AbstractMaemoRunControl::executableOnHost() const -{ - return m_runConfig->executable(); -} - -const QString AbstractMaemoRunControl::executableFileName() const -{ - return QFileInfo(executableOnHost()).fileName(); -} - -const QString AbstractMaemoRunControl::uploadDir() const -{ - return MaemoGlobal::homeDirOnDevice(m_devConfig.server.uname); + return m_running; } const QString AbstractMaemoRunControl::targetCmdLinePrefix() const { return QString::fromLocal8Bit("%1 chmod a+x %2 && source /etc/profile && DISPLAY=:0.0 ") - .arg(MaemoGlobal::remoteSudo()).arg(executableFilePathOnTarget()); + .arg(MaemoGlobal::remoteSudo()) + .arg(m_runConfig->remoteExecutableFilePath()); } -QString AbstractMaemoRunControl::targetCmdLineSuffix() const +QString AbstractMaemoRunControl::arguments() const { return m_runConfig->arguments().join(" "); } @@ -292,12 +173,10 @@ void AbstractMaemoRunControl::handleError(const QString &errString) stop(); } -template<typename SshChannel> void AbstractMaemoRunControl::closeSshChannel(SshChannel &channel) +void AbstractMaemoRunControl::setFinished() { - if (channel) { - disconnect(channel.data(), 0, this, 0); - // channel->closeChannel(); - } + m_running = false; + emit finished(); } @@ -311,15 +190,9 @@ MaemoRunControl::~MaemoRunControl() stop(); } -QString MaemoRunControl::remoteCall() const -{ - return QString::fromLocal8Bit("%1 %2 %3").arg(targetCmdLinePrefix()) - .arg(executableFilePathOnTarget()).arg(targetCmdLineSuffix()); -} - void MaemoRunControl::stopInternal() { - AbstractMaemoRunControl::stopRunning(false); + setFinished(); } @@ -331,17 +204,19 @@ MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration) { #ifdef USE_GDBSERVER m_startParams->startMode = AttachToRemote; - m_startParams->executable = executableOnHost(); + m_startParams->executable = m_runConfig->localExecutableFilePath(); m_startParams->debuggerCommand = m_runConfig->gdbCmd(); m_startParams->remoteChannel = m_devConfig.server.host % QLatin1Char(':') % gdbServerPort(); m_startParams->remoteArchitecture = QLatin1String("arm"); + m_runner->addProcsToKill(QStringList() << QLatin1String("gdbserver")); #else m_startParams->startMode = StartRemoteGdb; - m_startParams->executable = executableFilePathOnTarget(); + m_startParams->executable = m_runConfig->remoteExecutableFilePath(); m_startParams->debuggerCommand = targetCmdLinePrefix() + QLatin1String(" /usr/bin/gdb"); m_startParams->connParams = m_devConfig.server; + m_runner->addProcsToKill(QStringList() << QLatin1String("gdb")); #endif m_startParams->processArgs = m_runConfig->arguments(); m_startParams->sysRoot = m_runConfig->sysRoot(); @@ -362,20 +237,13 @@ MaemoDebugRunControl::~MaemoDebugRunControl() stop(); } -QString MaemoDebugRunControl::remoteCall() const -{ - return QString::fromLocal8Bit("%1 gdbserver :%2 %3 %4") - .arg(targetCmdLinePrefix()).arg(gdbServerPort()) - .arg(executableFilePathOnTarget()).arg(targetCmdLineSuffix()); -} - void MaemoDebugRunControl::startExecution() { const QString &dumperLib = m_runConfig->dumperLib(); if (!dumperLib.isEmpty() && m_runConfig->deployStep()->currentlyNeedsDeployment(m_devConfig.server.host, MaemoDeployable(dumperLib, uploadDir()))) { - m_uploader = m_connection->createSftpChannel(); + m_uploader = m_runner->connection()->createSftpChannel(); connect(m_uploader.data(), SIGNAL(initialized()), this, SLOT(handleSftpChannelInitialized())); connect(m_uploader.data(), SIGNAL(initializationFailed(QString)), this, @@ -438,7 +306,10 @@ void MaemoDebugRunControl::handleSftpJobFinished(Core::SftpJobId job, void MaemoDebugRunControl::startDebugging() { #ifdef USE_GDBSERVER - AbstractMaemoRunControl::startExecution(); + m_runner->startExecution(QString::fromLocal8Bit("%1 gdbserver :%2 %3 %4") + .arg(targetCmdLinePrefix()).arg(gdbServerPort()) + .arg(m_runConfig->remoteExecutableFilePath()) + .arg(arguments()).toUtf8()); #else DebuggerPlugin::startDebugger(m_debuggerRunControl); #endif @@ -455,27 +326,20 @@ void MaemoDebugRunControl::stopInternal() disconnect(m_uploader.data(), 0, this, 0); m_uploader->closeChannel(); m_uploadJob = SftpInvalidJob; - emit finished(); + setFinished(); } else if (m_debuggerRunControl && m_debuggerRunControl->engine()) { m_debuggerRunControl->engine()->quitDebugger(); } else { - emit finished(); + setFinished(); } } -bool MaemoDebugRunControl::isRunning() const -{ - return isDeploying() || AbstractMaemoRunControl::isRunning() - || m_debuggerRunControl->state() != DebuggerNotReady; -} - void MaemoDebugRunControl::debuggingFinished() { #ifdef USE_GDBSERVER - AbstractMaemoRunControl::stopRunning(true); -#else - emit finished(); + m_runner->stop(); #endif + setFinished(); } void MaemoDebugRunControl::handleRemoteProcessStarted() @@ -497,5 +361,10 @@ QString MaemoDebugRunControl::gdbServerPort() const // but we will make sure we use the right port from the information file. } +QString MaemoDebugRunControl::uploadDir() const +{ + return MaemoGlobal::homeDirOnDevice(m_devConfig.server.uname); +} + } // namespace Internal } // namespace Qt4ProjectManager diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h index a9af1e60719..4604898a5b0 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h +++ b/src/plugins/qt4projectmanager/qt-maemo/maemoruncontrol.h @@ -42,10 +42,6 @@ #include <QtCore/QString> -QT_BEGIN_NAMESPACE -class QProcess; -QT_END_NAMESPACE - namespace Core { class SftpChannel; class SshConnection; @@ -60,57 +56,43 @@ namespace Debugger { namespace Qt4ProjectManager { namespace Internal { class MaemoRunConfiguration; +class MaemoSshRunner; class AbstractMaemoRunControl : public ProjectExplorer::RunControl { Q_OBJECT - public: explicit AbstractMaemoRunControl(ProjectExplorer::RunConfiguration *runConfig, QString mode); virtual ~AbstractMaemoRunControl(); protected: - virtual bool isRunning() const; virtual void start(); virtual void stop(); - void stopRunning(bool forDebugging); - virtual void startExecution(); + void setFinished(); void handleError(const QString &errString); - const QString executableOnHost() const; - const QString executableFileName() const; const QString targetCmdLinePrefix() const; - QString targetCmdLineSuffix() const; - const QString uploadDir() const; - QString executableFilePathOnTarget() const; + QString arguments() const; private slots: - void handleConnected(); - void handleConnectionFailure(); - void handleInitialCleanupFinished(int exitStatus); + virtual void startExecution(); + void handleSshError(const QString &error); virtual void handleRemoteProcessStarted() {} - void handleRemoteProcessFinished(int exitStatus); + void handleRemoteProcessFinished(int exitCode); void handleRemoteOutput(const QByteArray &output); void handleRemoteErrorOutput(const QByteArray &output); protected: MaemoRunConfiguration *m_runConfig; // TODO this pointer can be invalid const MaemoDeviceConfig m_devConfig; - QSharedPointer<Core::SshConnection> m_connection; + MaemoSshRunner * const m_runner; bool m_stopped; private: + virtual bool isRunning() const; virtual void stopInternal()=0; - virtual QString remoteCall() const=0; - - void killRemoteProcesses(const QStringList &apps, bool initialCleanup); - void cancelActions(); - template<class SshChannel> void closeSshChannel(SshChannel &channel); - void startExecutionIfPossible(); - QSharedPointer<Core::SshRemoteProcess> m_runner; - QSharedPointer<Core::SshRemoteProcess> m_stopper; - QSharedPointer<Core::SshRemoteProcess> m_initialCleaner; + bool m_running; }; class MaemoRunControl : public AbstractMaemoRunControl @@ -122,7 +104,6 @@ public: private: virtual void stopInternal(); - virtual QString remoteCall() const; }; class MaemoDebugRunControl : public AbstractMaemoRunControl @@ -131,7 +112,6 @@ class MaemoDebugRunControl : public AbstractMaemoRunControl public: explicit MaemoDebugRunControl(ProjectExplorer::RunConfiguration *runConfiguration); ~MaemoDebugRunControl(); - bool isRunning() const; private slots: virtual void handleRemoteProcessStarted(); @@ -144,7 +124,7 @@ private slots: private: virtual void stopInternal(); virtual void startExecution(); - virtual QString remoteCall() const; + QString uploadDir() const; QString gdbServerPort() const; void startDebugging(); diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp new file mode 100644 index 00000000000..81b7ded2466 --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.cpp @@ -0,0 +1,193 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Creator. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "maemosshrunner.h" + +#include "maemodeviceconfigurations.h" +#include "maemorunconfiguration.h" + +#include <coreplugin/ssh/sshconnection.h> +#include <coreplugin/ssh/sshremoteprocess.h> + +#include <QtCore/QFileInfo> + +using namespace Core; + +namespace Qt4ProjectManager { +namespace Internal { + +MaemoSshRunner::MaemoSshRunner(QObject *parent, + MaemoRunConfiguration *runConfig) + : QObject(parent), m_runConfig(runConfig), + m_devConfig(runConfig->deviceConfig()) +{ + m_procsToKill << QFileInfo(m_runConfig->localExecutableFilePath()).fileName(); +} + +MaemoSshRunner::~MaemoSshRunner() {} + +void MaemoSshRunner::setConnection(const QSharedPointer<Core::SshConnection> &connection) +{ + m_connection = connection; +} + +void MaemoSshRunner::addProcsToKill(const QStringList &appNames) +{ + m_procsToKill << appNames; +} + +void MaemoSshRunner::start() +{ + m_stop = false; + if (m_connection) + disconnect(m_connection.data(), 0, this, 0); + const bool reUse = m_connection + && m_connection->state() == SshConnection::Connected + && m_connection->connectionParameters() == m_devConfig.server; + if (!reUse) + m_connection = SshConnection::create(); + connect(m_connection.data(), SIGNAL(connected()), this, + SLOT(handleConnected())); + connect(m_connection.data(), SIGNAL(error(SshError)), this, + SLOT(handleConnectionFailure())); + if (reUse) + handleConnected(); + else + m_connection->connectToHost(m_devConfig.server); +} + +void MaemoSshRunner::stop() +{ + m_stop = true; + disconnect(m_connection.data(), 0, this, 0); + if (m_initialCleaner) + disconnect(m_initialCleaner.data(), 0, this, 0); + if (m_runner) { + disconnect(m_runner.data(), 0, this, 0); + m_runner->closeChannel(); + killRemoteProcs(false); + } +} + +void MaemoSshRunner::handleConnected() +{ + if (m_stop) + return; + + killRemoteProcs(true); +} + +void MaemoSshRunner::handleConnectionFailure() +{ + emit error(tr("Could not connect to host: %1") + .arg(m_connection->errorString())); +} + +void MaemoSshRunner::killRemoteProcs(bool initialCleanup) +{ + QString niceKill; + QString brutalKill; + foreach (const QString &proc, m_procsToKill) { + niceKill += QString::fromLocal8Bit("pkill -x %1;").arg(proc); + brutalKill += QString::fromLocal8Bit("pkill -x -9 %1;").arg(proc); + } + QString remoteCall = niceKill + QLatin1String("sleep 1; ") + brutalKill; + remoteCall.remove(remoteCall.count() - 1, 1); // Get rid of trailing semicolon. + SshRemoteProcess::Ptr proc + = m_connection->createRemoteProcess(remoteCall.toUtf8()); + if (initialCleanup) { + m_initialCleaner = proc; + connect(m_initialCleaner.data(), SIGNAL(closed(int)), this, + SLOT(handleInitialCleanupFinished(int))); + } + proc->start(); +} + +void MaemoSshRunner::handleInitialCleanupFinished(int exitStatus) +{ + Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart + || exitStatus == SshRemoteProcess::KilledBySignal + || exitStatus == SshRemoteProcess::ExitedNormally); + + if (m_stop) + return; + + if (exitStatus != SshRemoteProcess::ExitedNormally) { + emit error(tr("Initial cleanup failed: %1") + .arg(m_initialCleaner->errorString())); + } else { + emit readyForExecution(); + } +} + +void MaemoSshRunner::startExecution(const QByteArray &remoteCall) +{ + if (m_runConfig->remoteExecutableFilePath().isEmpty()) { + emit error(tr("Cannot run: No remote executable set.")); + return; + } + + m_runner = m_connection->createRemoteProcess(remoteCall); + connect(m_runner.data(), SIGNAL(started()), this, + SIGNAL(remoteProcessStarted())); + connect(m_runner.data(), SIGNAL(closed(int)), this, + SLOT(handleRemoteProcessFinished(int))); + connect(m_runner.data(), SIGNAL(outputAvailable(QByteArray)), this, + SIGNAL(remoteOutput(QByteArray))); + connect(m_runner.data(), SIGNAL(errorOutputAvailable(QByteArray)), this, + SIGNAL(remoteErrorOutput(QByteArray))); + m_runner->start(); +} + +void MaemoSshRunner::handleRemoteProcessFinished(int exitStatus) +{ + Q_ASSERT(exitStatus == SshRemoteProcess::FailedToStart + || exitStatus == SshRemoteProcess::KilledBySignal + || exitStatus == SshRemoteProcess::ExitedNormally); + + if (m_stop) + return; + + if (exitStatus == SshRemoteProcess::ExitedNormally) { + emit remoteProcessFinished(m_runner->exitCode()); + } else { + emit error(tr("Error running remote process: %1") + .arg(m_runner->errorString())); + } +} + + +} // namespace Internal +} // namespace Qt4ProjectManager + diff --git a/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h new file mode 100644 index 00000000000..02f80f36ec2 --- /dev/null +++ b/src/plugins/qt4projectmanager/qt-maemo/maemosshrunner.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the Qt Creator. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, 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. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef MAEMOSSHRUNNER_H +#define MAEMOSSHRUNNER_H + +#include <QtCore/QObject> +#include <QtCore/QSharedPointer> + +#include "maemodeviceconfigurations.h" + +#include <coreplugin/ssh/sftpdefs.h> + +#include <QtCore/QStringList> + +namespace Core { + class SftpChannel; + class SshConnection; + class SshRemoteProcess; +} + +namespace Qt4ProjectManager { +namespace Internal { +class MaemoRunConfiguration; + +class MaemoSshRunner : public QObject +{ + Q_OBJECT +public: + MaemoSshRunner(QObject *parent, MaemoRunConfiguration *runConfig); + ~MaemoSshRunner(); + + void setConnection(const QSharedPointer<Core::SshConnection> &connection); + void addProcsToKill(const QStringList &appNames); + + void start(); + void stop(); + + void startExecution(const QByteArray &remoteCall); + + QSharedPointer<Core::SshConnection> connection() const { return m_connection; } + +signals: + void error(const QString &error); + void readyForExecution(); + void remoteOutput(const QByteArray &output); + void remoteErrorOutput(const QByteArray &output); + void remoteProcessStarted(); + void remoteProcessFinished(int exitCode); + +private slots: + void handleConnected(); + void handleConnectionFailure(); + void handleInitialCleanupFinished(int exitStatus); + void handleRemoteProcessFinished(int exitStatus); + +private: + void killRemoteProcs(bool initialCleanup); + + MaemoRunConfiguration * const m_runConfig; // TODO this pointer can be invalid + const MaemoDeviceConfig m_devConfig; + + QSharedPointer<Core::SshConnection> m_connection; + QSharedPointer<Core::SshRemoteProcess> m_runner; + QSharedPointer<Core::SshRemoteProcess> m_initialCleaner; + QStringList m_procsToKill; + bool m_stop; +}; + +} // namespace Internal +} // namespace Qt4ProjectManager + +#endif // MAEMOSSHRUNNER_H diff --git a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri index 2ea996a8c0f..8fb70f89598 100644 --- a/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri +++ b/src/plugins/qt4projectmanager/qt-maemo/qt-maemo.pri @@ -23,7 +23,8 @@ HEADERS += \ $$PWD/maemodeploystep.h \ $$PWD/maemodeploystepwidget.h \ $$PWD/maemodeploystepfactory.h \ - $$PWD/maemoglobal.h + $$PWD/maemoglobal.h \ + $$PWD/maemosshrunner.h SOURCES += \ $$PWD/maemoconfigtestdialog.cpp \ @@ -48,7 +49,8 @@ SOURCES += \ $$PWD/maemodeploystep.cpp \ $$PWD/maemodeploystepwidget.cpp \ $$PWD/maemodeploystepfactory.cpp \ - $$PWD/maemoglobal.cpp + $$PWD/maemoglobal.cpp \ + $$PWD/maemosshrunner.cpp FORMS += \ $$PWD/maemoconfigtestdialog.ui \ -- GitLab