summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@digia.com>2013-08-08 14:05:11 +0200
committerChristian Kandeler <christian.kandeler@digia.com>2013-08-19 16:13:21 +0200
commit22599094b0d72e271ba4d8bad2c1587f9ce75c69 (patch)
tree5ec3ab520f062145bd7005d1357022269f9274c6
parentdc07796c236d137d4fce2b2ea1117496839ccf08 (diff)
downloadqt-creator-22599094b0d72e271ba4d8bad2c1587f9ce75c69.tar.gz
Introduce the concept of a "device process".
Provide a QProcess-like abstraction that can be used to implement processes running locally or on a remote device. Objects of a concrete class implementing the functionality are created by IDevice objects. Current implementations are: - Local execution (QProcess-based), provided via the DesktopDevice. - Remote execution via SSH. - A specialized case of the former for remote Linux systems (provided by LinuxDevice). The latter is already being used in a number of places. As a result, lots of code dealing with details such as setting the remote environment could be moved to a central location. These things are no longer the concern of whoever is wishing to run a remote process. Change-Id: I919260ee6e77a020ca47226a4a534e7b8398106f Reviewed-by: hjk <hjk121@nokiamail.com>
-rw-r--r--src/libs/ssh/sshremoteprocess.cpp5
-rw-r--r--src/libs/ssh/sshremoteprocess.h1
-rw-r--r--src/plugins/madde/maddedevice.cpp12
-rw-r--r--src/plugins/madde/maddedevice.h1
-rw-r--r--src/plugins/madde/maemorunconfiguration.cpp18
-rw-r--r--src/plugins/madde/maemorunconfiguration.h2
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdevice.cpp6
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdevice.h2
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp125
-rw-r--r--src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h70
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp71
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h16
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceprocess.cpp52
-rw-r--r--src/plugins/projectexplorer/devicesupport/deviceprocess.h87
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.cpp6
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.h5
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp329
-rw-r--r--src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h86
-rw-r--r--src/plugins/projectexplorer/projectexplorer.pro6
-rw-r--r--src/plugins/projectexplorer/projectexplorer.qbs6
-rw-r--r--src/plugins/qnx/blackberrydeviceprocesssupport.cpp17
-rw-r--r--src/plugins/qnx/blackberrydeviceprocesssupport.h1
-rw-r--r--src/plugins/qnx/qnxabstractrunsupport.cpp10
-rw-r--r--src/plugins/qnx/qnxabstractrunsupport.h7
-rw-r--r--src/plugins/qnx/qnxanalyzesupport.cpp11
-rw-r--r--src/plugins/qnx/qnxdebugsupport.cpp14
-rw-r--r--src/plugins/qnx/qnxdeviceconfiguration.cpp17
-rw-r--r--src/plugins/qnx/qnxrunconfiguration.cpp23
-rw-r--r--src/plugins/qnx/qnxrunconfiguration.h4
-rw-r--r--src/plugins/qnx/qnxruncontrolfactory.cpp5
-rw-r--r--src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp32
-rw-r--r--src/plugins/remotelinux/abstractremotelinuxrunsupport.h7
-rw-r--r--src/plugins/remotelinux/linuxdevice.cpp24
-rw-r--r--src/plugins/remotelinux/linuxdevice.h3
-rw-r--r--src/plugins/remotelinux/linuxdeviceprocess.cpp84
-rw-r--r--src/plugins/remotelinux/linuxdeviceprocess.h64
-rw-r--r--src/plugins/remotelinux/remotelinux.pro6
-rw-r--r--src/plugins/remotelinux/remotelinux.qbs2
-rw-r--r--src/plugins/remotelinux/remotelinuxanalyzesupport.cpp11
-rw-r--r--src/plugins/remotelinux/remotelinuxdebugsupport.cpp22
-rw-r--r--src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp2
-rw-r--r--src/plugins/remotelinux/remotelinuxenvironmentreader.cpp59
-rw-r--r--src/plugins/remotelinux/remotelinuxenvironmentreader.h15
-rw-r--r--src/plugins/remotelinux/remotelinuxrunconfiguration.cpp36
-rw-r--r--src/plugins/remotelinux/remotelinuxrunconfiguration.h12
-rw-r--r--src/plugins/remotelinux/remotelinuxrunconfigurationwidget.cpp2
-rw-r--r--src/plugins/remotelinux/remotelinuxruncontrol.cpp19
-rw-r--r--src/plugins/valgrind/valgrindruncontrolfactory.cpp3
48 files changed, 1212 insertions, 206 deletions
diff --git a/src/libs/ssh/sshremoteprocess.cpp b/src/libs/ssh/sshremoteprocess.cpp
index ec40f9c6f3..6602b3c1df 100644
--- a/src/libs/ssh/sshremoteprocess.cpp
+++ b/src/libs/ssh/sshremoteprocess.cpp
@@ -176,6 +176,11 @@ void SshRemoteProcess::addToEnvironment(const QByteArray &var, const QByteArray
d->m_env << qMakePair(var, value); // Cached locally and sent on start()
}
+void SshRemoteProcess::clearEnvironment()
+{
+ d->m_env.clear();
+}
+
void SshRemoteProcess::requestTerminal(const SshPseudoTerminal &terminal)
{
QSSH_ASSERT_AND_RETURN(d->channelState() == Internal::SshRemoteProcessPrivate::Inactive);
diff --git a/src/libs/ssh/sshremoteprocess.h b/src/libs/ssh/sshremoteprocess.h
index a50a3f0f2f..40c7db7790 100644
--- a/src/libs/ssh/sshremoteprocess.h
+++ b/src/libs/ssh/sshremoteprocess.h
@@ -80,6 +80,7 @@ public:
* usually configured to ignore such requests for security reasons.
*/
void addToEnvironment(const QByteArray &var, const QByteArray &value);
+ void clearEnvironment();
void requestTerminal(const SshPseudoTerminal &terminal);
void start();
diff --git a/src/plugins/madde/maddedevice.cpp b/src/plugins/madde/maddedevice.cpp
index 821fb059f6..b055872adb 100644
--- a/src/plugins/madde/maddedevice.cpp
+++ b/src/plugins/madde/maddedevice.cpp
@@ -31,10 +31,13 @@
#include "maddedevicetester.h"
#include "maemoconstants.h"
+#include <remotelinux/linuxdeviceprocess.h>
#include <remotelinux/publickeydeploymentdialog.h>
#include <remotelinux/remotelinux_constants.h>
#include <utils/qtcassert.h>
+#include <QStringList>
+
using namespace ProjectExplorer;
using namespace RemoteLinux;
@@ -115,5 +118,14 @@ DeviceTester *MaddeDevice::createDeviceTester() const
return new MaddeDeviceTester;
}
+DeviceProcess *MaddeDevice::createProcess(QObject *parent) const
+{
+ LinuxDeviceProcess * const proc
+ = static_cast<LinuxDeviceProcess *>(LinuxDevice::createProcess(parent));
+ proc->setRcFilesToSource(QStringList() << QLatin1String("/etc/profile")
+ << QLatin1String("/home/user/.profile") << QLatin1String("~/.profile"));
+ return proc;
+}
+
} // namespace Internal
} // namespace Madde
diff --git a/src/plugins/madde/maddedevice.h b/src/plugins/madde/maddedevice.h
index bd2ec00253..a0bb80ca6d 100644
--- a/src/plugins/madde/maddedevice.h
+++ b/src/plugins/madde/maddedevice.h
@@ -59,6 +59,7 @@ public:
static QSize packageManagerIconSize(Core::Id type);
ProjectExplorer::DeviceTester *createDeviceTester() const;
+ ProjectExplorer::DeviceProcess *createProcess(QObject *parent) const;
private:
MaddeDevice();
diff --git a/src/plugins/madde/maemorunconfiguration.cpp b/src/plugins/madde/maemorunconfiguration.cpp
index b046428523..55c17c8393 100644
--- a/src/plugins/madde/maemorunconfiguration.cpp
+++ b/src/plugins/madde/maemorunconfiguration.cpp
@@ -112,24 +112,6 @@ bool MaemoRunConfiguration::fromMap(const QVariantMap &map)
return true;
}
-QString MaemoRunConfiguration::environmentPreparationCommand() const
-{
- return MaemoGlobal::remoteSourceProfilesCommand();
-}
-
-QString MaemoRunConfiguration::commandPrefix() const
-{
- IDevice::ConstPtr dev = DeviceKitInformation::device(target()->kit());
- if (!dev)
- return QString();
-
- const QString prefix = environmentPreparationCommand() + QLatin1Char(';');
-
- RemoteLinuxEnvironmentAspect *aspect = extraAspect<RemoteLinuxEnvironmentAspect>();
- QTC_ASSERT(aspect, return QString());
- return QString::fromLatin1("%1 %2").arg(prefix, aspect->userEnvironmentChangesAsString());
-}
-
Utils::PortList MaemoRunConfiguration::freePorts() const
{
return MaemoGlobal::freePorts(target()->kit());
diff --git a/src/plugins/madde/maemorunconfiguration.h b/src/plugins/madde/maemorunconfiguration.h
index d7083322d9..edfebb8fe7 100644
--- a/src/plugins/madde/maemorunconfiguration.h
+++ b/src/plugins/madde/maemorunconfiguration.h
@@ -48,8 +48,6 @@ public:
bool fromMap(const QVariantMap &map);
bool isEnabled() const;
QWidget *createConfigurationWidget();
- QString environmentPreparationCommand() const;
- QString commandPrefix() const;
Utils::PortList freePorts() const;
Internal::MaemoRemoteMountsModel *remoteMounts() const { return m_remoteMounts; }
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
index 68478164d7..d0e7643e6d 100644
--- a/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
+++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.cpp
@@ -29,6 +29,7 @@
#include "desktopdevice.h"
#include "projectexplorerconstants.h"
+#include "desktopdeviceprocess.h"
#include "deviceprocesslist.h"
#include "localprocesslist.h"
#include "desktopdeviceconfigurationwidget.h"
@@ -108,6 +109,11 @@ DeviceProcessList *DesktopDevice::createProcessListModel(QObject *parent) const
return new Internal::LocalProcessList(sharedFromThis(), parent);
}
+DeviceProcess *DesktopDevice::createProcess(QObject *parent) const
+{
+ return new Internal::DesktopDeviceProcess(sharedFromThis(), parent);
+}
+
IDevice::Ptr DesktopDevice::clone() const
{
return Ptr(new DesktopDevice(*this));
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdevice.h b/src/plugins/projectexplorer/devicesupport/desktopdevice.h
index 58f86d191a..d737ceeea7 100644
--- a/src/plugins/projectexplorer/devicesupport/desktopdevice.h
+++ b/src/plugins/projectexplorer/devicesupport/desktopdevice.h
@@ -53,6 +53,8 @@ public:
bool canAutoDetectPorts() const;
bool canCreateProcessModel() const;
DeviceProcessList *createProcessListModel(QObject *parent) const;
+ bool canCreateProcess() const { return true; }
+ DeviceProcess *createProcess(QObject *parent) const;
IDevice::Ptr clone() const;
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp
new file mode 100644
index 0000000000..a151a983dd
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.cpp
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "desktopdeviceprocess.h"
+
+#include <utils/environment.h>
+#include <utils/qtcassert.h>
+
+#ifdef Q_OS_UNIX
+#include <signal.h>
+#endif
+
+namespace ProjectExplorer {
+namespace Internal {
+
+DesktopDeviceProcess::DesktopDeviceProcess(const QSharedPointer<const IDevice> &device,
+ QObject *parent)
+ : DeviceProcess(device, parent), m_process(new QProcess(this))
+{
+ connect(m_process, SIGNAL(error(QProcess::ProcessError)),
+ SIGNAL(error(QProcess::ProcessError)));
+ connect(m_process, SIGNAL(finished(int)), SIGNAL(finished()));
+ connect(m_process, SIGNAL(readyReadStandardOutput()), SIGNAL(readyReadStandardOutput()));
+ connect(m_process, SIGNAL(readyReadStandardError()), SIGNAL(readyReadStandardError()));
+ connect(m_process, SIGNAL(started()), SIGNAL(started()));
+}
+
+void DesktopDeviceProcess::start(const QString &executable, const QStringList &arguments)
+{
+ QTC_ASSERT(m_process->state() == QProcess::NotRunning, return);
+ m_process->start(executable, arguments);
+}
+
+void DesktopDeviceProcess::interrupt()
+{
+#ifdef Q_OS_UNIX
+ ::kill(m_process->pid(), SIGINT);
+#elif Q_OS_WIN
+ // tbd
+#endif
+}
+
+void DesktopDeviceProcess::terminate()
+{
+ m_process->terminate();
+}
+
+void DesktopDeviceProcess::kill()
+{
+ m_process->kill();
+}
+
+QProcess::ProcessState DesktopDeviceProcess::state() const
+{
+ return m_process->state();
+}
+
+QProcess::ExitStatus DesktopDeviceProcess::exitStatus() const
+{
+ return m_process->exitStatus();
+}
+
+int DesktopDeviceProcess::exitCode() const
+{
+ return m_process->exitCode();
+}
+
+QString DesktopDeviceProcess::errorString() const
+{
+ return m_process->errorString();
+}
+
+Utils::Environment DesktopDeviceProcess::environment() const
+{
+ return Utils::Environment(m_process->processEnvironment().toStringList());
+}
+
+void DesktopDeviceProcess::setEnvironment(const Utils::Environment &env)
+{
+ m_process->setProcessEnvironment(env.toProcessEnvironment());
+}
+
+void DesktopDeviceProcess::setWorkingDirectory(const QString &directory)
+{
+ m_process->setWorkingDirectory(directory);
+}
+
+QByteArray DesktopDeviceProcess::readAllStandardOutput()
+{
+ return m_process->readAllStandardOutput();
+}
+
+QByteArray DesktopDeviceProcess::readAllStandardError()
+{
+ return m_process->readAllStandardError();
+}
+
+} // namespace Internal
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h
new file mode 100644
index 0000000000..1a245a8195
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/desktopdeviceprocess.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QTC_DESKTOPDEVICEPROCESS_H
+#define QTC_DESKTOPDEVICEPROCESS_H
+
+#include "deviceprocess.h"
+
+namespace ProjectExplorer {
+namespace Internal {
+class ProcessHelper;
+
+class DesktopDeviceProcess : public DeviceProcess
+{
+ Q_OBJECT
+public:
+ DesktopDeviceProcess(const QSharedPointer<const IDevice> &device, QObject *parent = 0);
+
+ void start(const QString &executable, const QStringList &arguments);
+ void interrupt();
+ void terminate();
+ void kill();
+
+ QProcess::ProcessState state() const;
+ QProcess::ExitStatus exitStatus() const;
+ int exitCode() const;
+ QString errorString() const;
+
+ Utils::Environment environment() const;
+ void setEnvironment(const Utils::Environment &env);
+
+ void setWorkingDirectory(const QString &directory);
+
+ QByteArray readAllStandardOutput();
+ QByteArray readAllStandardError();
+
+private:
+ QProcess * const m_process;
+};
+
+} // namespace Internal
+} // namespace ProjectExplorer
+
+#endif // Include guard
diff --git a/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp
index b7fe7248c3..deda2ebb2e 100644
--- a/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp
+++ b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.cpp
@@ -28,11 +28,14 @@
****************************************************************************/
#include "deviceapplicationrunner.h"
+#include "sshdeviceprocess.h"
+
#include <ssh/sshconnection.h>
#include <ssh/sshconnectionmanager.h>
-#include <ssh/sshremoteprocess.h>
+#include <utils/environment.h>
#include <utils/qtcassert.h>
+#include <QStringList>
#include <QTimer>
using namespace QSsh;
@@ -49,10 +52,13 @@ public:
SshConnection *connection;
DeviceApplicationHelperAction *preRunAction;
DeviceApplicationHelperAction *postRunAction;
+ DeviceProcess *deviceProcess;
IDevice::ConstPtr device;
- SshRemoteProcess::Ptr remoteApp;
QTimer stopTimer;
- QByteArray commandLine;
+ QString command;
+ QStringList arguments;
+ Utils::Environment environment;
+ QString workingDir;
State state;
bool stopRequested;
bool success;
@@ -74,6 +80,7 @@ DeviceApplicationRunner::DeviceApplicationRunner(QObject *parent) :
d->preRunAction = 0;
d->postRunAction = 0;
d->connection = 0;
+ d->deviceProcess = 0;
d->state = Inactive;
d->stopTimer.setSingleShot(true);
@@ -86,23 +93,33 @@ DeviceApplicationRunner::~DeviceApplicationRunner()
delete d;
}
+void DeviceApplicationRunner::setEnvironment(const Utils::Environment &env)
+{
+ d->environment = env;
+}
+
+void DeviceApplicationRunner::setWorkingDirectory(const QString &workingDirectory)
+{
+ d->workingDir = workingDirectory;
+}
+
void DeviceApplicationRunner::start(const IDevice::ConstPtr &device,
- const QByteArray &commandLine)
+ const QString &command, const QStringList &arguments)
{
+ QTC_ASSERT(device->canCreateProcess(), return);
QTC_ASSERT(d->state == Inactive, return);
d->device = device;
- d->commandLine = commandLine;
+ d->command = command;
+ d->arguments = arguments;
d->stopRequested = false;
d->success = true;
connectToServer();
}
-void DeviceApplicationRunner::stop(const QByteArray &stopCommand)
+void DeviceApplicationRunner::stop()
{
- QTC_ASSERT(d->state != Inactive, return);
-
if (d->stopRequested)
return;
d->stopRequested = true;
@@ -117,7 +134,7 @@ void DeviceApplicationRunner::stop(const QByteArray &stopCommand)
break;
case Run:
d->stopTimer.start(10000);
- d->connection->createRemoteProcess(stopCommand)->start();
+ d->deviceProcess->terminate();
break;
case PostRun:
d->postRunAction->stop();
@@ -188,10 +205,10 @@ void DeviceApplicationRunner::setFinished()
if (d->state == Inactive)
return;
- if (d->remoteApp) {
- d->remoteApp->disconnect(this);
- d->remoteApp->close();
- d->remoteApp.clear();
+ if (d->deviceProcess) {
+ d->deviceProcess->disconnect(this);
+ d->deviceProcess->deleteLater();
+ d->deviceProcess = 0;
}
if (d->connection) {
d->connection->disconnect(this);
@@ -232,7 +249,7 @@ void DeviceApplicationRunner::handleConnectionFailure()
break;
case Run:
d->stopTimer.stop();
- d->remoteApp->disconnect(this);
+ d->deviceProcess->disconnect(this);
executePostRunAction();
break;
case PostRun:
@@ -290,16 +307,16 @@ void DeviceApplicationRunner::handleStopTimeout()
setFinished();
}
-void DeviceApplicationRunner::handleApplicationFinished(int exitStatus)
+void DeviceApplicationRunner::handleApplicationFinished()
{
QTC_ASSERT(d->state == Run, return);
d->stopTimer.stop();
- if (exitStatus == SshRemoteProcess::CrashExit) {
- emit reportError(tr("Remote application crashed: %1").arg(d->remoteApp->errorString()));
+ if (d->deviceProcess->exitStatus() == QProcess::CrashExit) {
+ emit reportError(tr("Remote application crashed: %1").arg(d->deviceProcess->errorString()));
d->success = false;
} else {
- const int exitCode = d->remoteApp->exitCode();
+ const int exitCode = d->deviceProcess->exitCode();
if (exitCode != 0) {
emit reportError(tr("Remote application finished with exit code %1.").arg(exitCode));
d->success = false;
@@ -313,13 +330,13 @@ void DeviceApplicationRunner::handleApplicationFinished(int exitStatus)
void DeviceApplicationRunner::handleRemoteStdout()
{
QTC_ASSERT(d->state == Run, return);
- emit remoteStdout(d->remoteApp->readAllStandardOutput());
+ emit remoteStdout(d->deviceProcess->readAllStandardOutput());
}
void DeviceApplicationRunner::handleRemoteStderr()
{
QTC_ASSERT(d->state == Run, return);
- emit remoteStderr(d->remoteApp->readAllStandardError());
+ emit remoteStderr(d->deviceProcess->readAllStandardError());
}
void DeviceApplicationRunner::runApplication()
@@ -327,12 +344,14 @@ 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();
+ d->deviceProcess = d->device->createProcess(this);
+ connect(d->deviceProcess, SIGNAL(started()), SIGNAL(remoteProcessStarted()));
+ connect(d->deviceProcess, SIGNAL(readyReadStandardOutput()), SLOT(handleRemoteStdout()));
+ connect(d->deviceProcess, SIGNAL(readyReadStandardError()), SLOT(handleRemoteStderr()));
+ connect(d->deviceProcess, SIGNAL(finished()), SLOT(handleApplicationFinished()));
+ d->deviceProcess->setEnvironment(d->environment);
+ d->deviceProcess->setWorkingDirectory(d->workingDir);
+ d->deviceProcess->start(d->command, d->arguments);
}
} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h
index 483f125692..188d05be22 100644
--- a/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h
+++ b/src/plugins/projectexplorer/devicesupport/deviceapplicationrunner.h
@@ -35,6 +35,12 @@
#include <QObject>
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace Utils { class Environment; }
+
namespace ProjectExplorer {
class PROJECTEXPLORER_EXPORT DeviceApplicationHelperAction : public QObject
@@ -60,8 +66,12 @@ public:
explicit DeviceApplicationRunner(QObject *parent = 0);
virtual ~DeviceApplicationRunner();
- void start(const IDevice::ConstPtr &device, const QByteArray &commandLine);
- void stop(const QByteArray &stopCommand);
+ void setEnvironment(const Utils::Environment &env);
+ void setWorkingDirectory(const QString &workingDirectory);
+
+ void start(const IDevice::ConstPtr &device, const QString &command,
+ const QStringList &arguments);
+ void stop();
// 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.
@@ -82,7 +92,7 @@ private slots:
void handleConnectionFailure();
void handleHelperActionFinished(bool success);
void handleStopTimeout();
- void handleApplicationFinished(int exitStatus);
+ void handleApplicationFinished();
void handleRemoteStdout();
void handleRemoteStderr();
diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp
new file mode 100644
index 0000000000..aa2f8c748c
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/deviceprocess.cpp
@@ -0,0 +1,52 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "deviceprocess.h"
+
+#include "idevice.h"
+
+#include <utils/qtcassert.h>
+
+namespace ProjectExplorer {
+
+DeviceProcess::DeviceProcess(const IDevice::ConstPtr &device, QObject *parent)
+ : QObject(parent), m_device(device)
+{
+}
+
+DeviceProcess::~DeviceProcess()
+{
+}
+
+IDevice::ConstPtr DeviceProcess::device() const
+{
+ return m_device;
+}
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/devicesupport/deviceprocess.h b/src/plugins/projectexplorer/devicesupport/deviceprocess.h
new file mode 100644
index 0000000000..92ef02dda0
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/deviceprocess.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QTC_DEVICEPROCESS_H
+#define QTC_DEVICEPROCESS_H
+
+#include "../projectexplorer_export.h"
+
+#include <QObject>
+#include <QProcess>
+#include <QSharedPointer>
+#include <QStringList>
+
+namespace Utils { class Environment; }
+
+namespace ProjectExplorer {
+class IDevice;
+
+class PROJECTEXPLORER_EXPORT DeviceProcess : public QObject
+{
+ Q_OBJECT
+public:
+ virtual ~DeviceProcess();
+
+ virtual void start(const QString &executable, const QStringList &arguments = QStringList()) = 0;
+ virtual void interrupt() = 0;
+ virtual void terminate() = 0;
+ virtual void kill() = 0;
+
+ virtual QProcess::ProcessState state() const = 0;
+ virtual QProcess::ExitStatus exitStatus() const = 0;
+ virtual int exitCode() const = 0;
+ virtual QString errorString() const = 0;
+
+ virtual Utils::Environment environment() const = 0;
+ virtual void setEnvironment(const Utils::Environment &env) = 0;
+
+ virtual void setWorkingDirectory(const QString &workingDirectory) = 0;
+
+ virtual QByteArray readAllStandardOutput() = 0;
+ virtual QByteArray readAllStandardError() = 0;
+
+signals:
+ void started();
+ void finished();
+ void error(QProcess::ProcessError error);
+
+ void readyReadStandardOutput();
+ void readyReadStandardError();
+
+protected:
+ DeviceProcess(const QSharedPointer<const IDevice> &device, QObject *parent = 0);
+ QSharedPointer<const IDevice> device() const;
+
+private:
+ const QSharedPointer<const IDevice> m_device;
+};
+
+} // namespace ProjectExplorer
+
+#endif // Include guard.
diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp
index 7f24712c73..f39615def8 100644
--- a/src/plugins/projectexplorer/devicesupport/idevice.cpp
+++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp
@@ -275,6 +275,12 @@ DeviceTester *IDevice::createDeviceTester() const
return 0;
}
+DeviceProcess *IDevice::createProcess(QObject * /* parent */) const
+{
+ QTC_CHECK(false);
+ return 0;
+}
+
IDevice::DeviceState IDevice::deviceState() const
{
return d->deviceState;
diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h
index b066688132..8b416c0409 100644
--- a/src/plugins/projectexplorer/devicesupport/idevice.h
+++ b/src/plugins/projectexplorer/devicesupport/idevice.h
@@ -47,6 +47,7 @@ namespace QSsh { class SshConnectionParameters; }
namespace Utils { class PortList; }
namespace ProjectExplorer {
+class DeviceProcess;
class DeviceProcessList;
namespace Internal { class IDevicePrivate; }
@@ -62,6 +63,7 @@ public:
virtual ~DeviceProcessSupport();
virtual QString killProcessByPidCommandLine(int pid) const = 0;
virtual QString killProcessByNameCommandLine(const QString &filePath) const = 0;
+ virtual QString interruptProcessByNameCommandLine(const QString &filePath) const = 0;
};
class PROJECTEXPLORER_EXPORT PortsGatheringMethod
@@ -121,6 +123,9 @@ public:
virtual bool hasDeviceTester() const { return false; }
virtual DeviceTester *createDeviceTester() const;
+ virtual bool canCreateProcess() const { return false; }
+ virtual DeviceProcess *createProcess(QObject *parent) const;
+
enum DeviceState { DeviceReadyToUse, DeviceConnected, DeviceDisconnected, DeviceStateUnknown };
DeviceState deviceState() const;
void setDeviceState(const DeviceState state);
diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp
new file mode 100644
index 0000000000..1fad5540b2
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.cpp
@@ -0,0 +1,329 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#include "sshdeviceprocess.h"
+
+#include "idevice.h"
+
+#include <ssh/sshconnection.h>
+#include <ssh/sshconnectionmanager.h>
+#include <ssh/sshremoteprocess.h>
+#include <utils/environment.h>
+#include <utils/qtcassert.h>
+
+#include <QString>
+
+namespace ProjectExplorer {
+
+class SshDeviceProcess::SshDeviceProcessPrivate
+{
+public:
+ SshDeviceProcessPrivate(SshDeviceProcess *q) : q(q) {}
+
+ SshDeviceProcess * const q;
+ bool serverSupportsSignals;
+ QSsh::SshConnection *connection;
+ QSsh::SshRemoteProcess::Ptr process;
+ QString executable;
+ QStringList arguments;
+ QString errorMessage;
+ QSsh::SshRemoteProcess::ExitStatus exitStatus;
+ QByteArray stdOut;
+ QByteArray stdErr;
+ int exitCode;
+ enum State { Inactive, Connecting, Connected, ProcessRunning } state;
+ Utils::Environment environment;
+
+ void setState(State newState);
+ void doSignal(QSsh::SshRemoteProcess::Signal signal);
+};
+
+SshDeviceProcess::SshDeviceProcess(const IDevice::ConstPtr &device, QObject *parent)
+ : DeviceProcess(device, parent), d(new SshDeviceProcessPrivate(this))
+{
+ d->connection = 0;
+ d->state = SshDeviceProcessPrivate::Inactive;
+ setSshServerSupportsSignals(false);
+}
+
+SshDeviceProcess::~SshDeviceProcess()
+{
+ d->setState(SshDeviceProcessPrivate::Inactive);
+ delete d;
+}
+
+void SshDeviceProcess::start(const QString &executable, const QStringList &arguments)
+{
+ QTC_ASSERT(d->state == SshDeviceProcessPrivate::Inactive, return);
+ d->setState(SshDeviceProcessPrivate::Connecting);
+
+ d->errorMessage.clear();
+ d->exitCode = -1;
+ d->executable = executable;
+ d->arguments = arguments;
+ d->connection
+ = QSsh::SshConnectionManager::instance().acquireConnection(device()->sshParameters());
+ connect(d->connection, SIGNAL(error(QSsh::SshError)), SLOT(handleConnectionError()));
+ connect(d->connection, SIGNAL(disconnected()), SLOT(handleDisconnected()));
+ if (d->connection->state() == QSsh::SshConnection::Connected) {
+ handleConnected();
+ } else {
+ connect(d->connection, SIGNAL(connected()), SLOT(handleConnected()));
+ if (d->connection->state() == QSsh::SshConnection::Unconnected)
+ d->connection->connectToHost();
+ }
+}
+
+void SshDeviceProcess::interrupt()
+{
+ QTC_ASSERT(d->state == SshDeviceProcessPrivate::ProcessRunning, return);
+ d->doSignal(QSsh::SshRemoteProcess::IntSignal);
+}
+
+void SshDeviceProcess::terminate()
+{
+ d->doSignal(QSsh::SshRemoteProcess::TermSignal);
+}
+
+void SshDeviceProcess::kill()
+{
+ d->doSignal(QSsh::SshRemoteProcess::KillSignal);
+}
+
+QString SshDeviceProcess::executable() const
+{
+ return d->executable;
+}
+
+QStringList SshDeviceProcess::arguments() const
+{
+ return d->arguments;
+}
+
+QProcess::ProcessState SshDeviceProcess::state() const
+{
+ switch (d->state) {
+ case SshDeviceProcessPrivate::Inactive:
+ return QProcess::NotRunning;
+ case SshDeviceProcessPrivate::Connecting:
+ case SshDeviceProcessPrivate::Connected:
+ return QProcess::Starting;
+ case SshDeviceProcessPrivate::ProcessRunning:
+ return QProcess::Running;
+ default:
+ QTC_CHECK(false);
+ return QProcess::NotRunning;
+ }
+}
+
+QProcess::ExitStatus SshDeviceProcess::exitStatus() const
+{
+ return d->exitStatus == QSsh::SshRemoteProcess::NormalExit
+ ? QProcess::NormalExit : QProcess::CrashExit;
+}
+
+int SshDeviceProcess::exitCode() const
+{
+ return d->exitCode;
+}
+
+QString SshDeviceProcess::errorString() const
+{
+ return d->errorMessage;
+}
+
+Utils::Environment SshDeviceProcess::environment() const
+{
+ return d->environment;
+}
+
+void SshDeviceProcess::setEnvironment(const Utils::Environment &env)
+{
+ d->environment = env;
+}
+
+QByteArray SshDeviceProcess::readAllStandardOutput()
+{
+ const QByteArray data = d->stdOut;
+ d->stdOut.clear();
+ return data;
+}
+
+QByteArray SshDeviceProcess::readAllStandardError()
+{
+ const QByteArray data = d->stdErr;
+ d->stdErr.clear();
+ return data;
+}
+
+void SshDeviceProcess::setSshServerSupportsSignals(bool signalsSupported)
+{
+ d->serverSupportsSignals = signalsSupported;
+}
+
+void SshDeviceProcess::handleConnected()
+{
+ QTC_ASSERT(d->state == SshDeviceProcessPrivate::Connecting, return);
+ d->setState(SshDeviceProcessPrivate::Connected);
+
+ d->process = d->connection->createRemoteProcess(fullCommandLine().toUtf8());
+ connect(d->process.data(), SIGNAL(started()), SLOT(handleProcessStarted()));
+ connect(d->process.data(), SIGNAL(closed(int)), SLOT(handleProcessFinished(int)));
+ connect(d->process.data(), SIGNAL(readyReadStandardOutput()), SLOT(handleStdout()));
+ connect(d->process.data(), SIGNAL(readyReadStandardError()), SLOT(handleStderr()));
+
+ d->process->clearEnvironment();
+ const Utils::Environment env = environment();
+ for (Utils::Environment::const_iterator it = env.constBegin(); it != env.constEnd(); ++it)
+ d->process->addToEnvironment(env.key(it).toUtf8(), env.value(it).toUtf8());
+ d->process->start();
+}
+
+void SshDeviceProcess::handleConnectionError()
+{
+ QTC_ASSERT(d->state != SshDeviceProcessPrivate::Inactive, return);
+
+ d->errorMessage = d->connection->errorString();
+ handleDisconnected();
+}
+
+void SshDeviceProcess::handleDisconnected()
+{
+ QTC_ASSERT(d->state != SshDeviceProcessPrivate::Inactive, return);
+ const SshDeviceProcessPrivate::State oldState = d->state;
+ d->setState(SshDeviceProcessPrivate::Inactive);
+ switch (oldState) {
+ case SshDeviceProcessPrivate::Connecting:
+ case SshDeviceProcessPrivate::Connected:
+ emit error(QProcess::FailedToStart);
+ break;
+ case SshDeviceProcessPrivate::ProcessRunning:
+ emit finished();
+ default:
+ break;
+ }
+}
+
+void SshDeviceProcess::handleProcessStarted()
+{
+ QTC_ASSERT(d->state == SshDeviceProcessPrivate::Connected, return);
+
+ d->setState(SshDeviceProcessPrivate::ProcessRunning);
+ emit started();
+}
+
+void SshDeviceProcess::handleProcessFinished(int exitStatus)
+{
+ d->exitStatus = static_cast<QSsh::SshRemoteProcess::ExitStatus>(exitStatus);
+ switch (d->exitStatus) {
+ case QSsh::SshRemoteProcess::FailedToStart:
+ QTC_ASSERT(d->state == SshDeviceProcessPrivate::Connected, return);
+ break;
+ case QSsh::SshRemoteProcess::CrashExit:
+ QTC_ASSERT(d->state == SshDeviceProcessPrivate::ProcessRunning, return);
+ break;
+ case QSsh::SshRemoteProcess::NormalExit:
+ QTC_ASSERT(d->state == SshDeviceProcessPrivate::ProcessRunning, return);
+ d->exitCode = d->process->exitCode();
+ break;
+ default:
+ QTC_ASSERT(false, return);
+ }
+ d->errorMessage = d->process->errorString();
+ d->setState(SshDeviceProcessPrivate::Inactive);
+ emit finished();
+}
+
+void SshDeviceProcess::handleStdout()
+{
+ d->stdOut += d->process->readAllStandardOutput();
+ emit readyReadStandardOutput();
+}
+
+void SshDeviceProcess::handleStderr()
+{
+ d->stdErr += d->process->readAllStandardError();
+ emit readyReadStandardError();
+}
+
+QString SshDeviceProcess::fullCommandLine() const
+{
+ QString cmdLine = executable();
+ if (!arguments().isEmpty())
+ cmdLine.append(QLatin1Char(' ')).append(arguments().join(QLatin1String(" ")));
+ return cmdLine;
+}
+
+void SshDeviceProcess::SshDeviceProcessPrivate::doSignal(QSsh::SshRemoteProcess::Signal signal)
+{
+ switch (state) {
+ case SshDeviceProcessPrivate::Inactive:
+ QTC_ASSERT(false, return);
+ break;
+ case SshDeviceProcessPrivate::Connecting:
+ errorMessage = tr("Terminated by request.");
+ setState(SshDeviceProcessPrivate::Inactive);
+ emit q->error(QProcess::FailedToStart);
+ break;
+ case SshDeviceProcessPrivate::Connected:
+ case SshDeviceProcessPrivate::ProcessRunning:
+ if (serverSupportsSignals) {
+ process->sendSignal(signal);
+ } else {
+ const DeviceProcessSupport::Ptr processSupport = q->device()->processSupport();
+ QString signalCommandLine = signal == QSsh::SshRemoteProcess::IntSignal
+ ? processSupport->interruptProcessByNameCommandLine(executable)
+ : processSupport->killProcessByNameCommandLine(executable);
+ const QSsh::SshRemoteProcess::Ptr signalProcess
+ = connection->createRemoteProcess(signalCommandLine.toUtf8());
+ signalProcess->start();
+ }
+ break;
+ }
+}
+
+void SshDeviceProcess::SshDeviceProcessPrivate::setState(SshDeviceProcess::SshDeviceProcessPrivate::State newState)
+{
+ if (state == newState)
+ return;
+
+ state = newState;
+ if (state != Inactive)
+ return;
+
+ if (process)
+ process->disconnect(q);
+ if (connection) {
+ connection->disconnect(q);
+ QSsh::SshConnectionManager::instance().releaseConnection(connection);
+ connection = 0;
+ }
+}
+
+} // namespace ProjectExplorer
diff --git a/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h
new file mode 100644
index 0000000000..6981921a72
--- /dev/null
+++ b/src/plugins/projectexplorer/devicesupport/sshdeviceprocess.h
@@ -0,0 +1,86 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QTC_SSHDEVICEPROCESS_H
+#define QTC_SSHDEVICEPROCESS_H
+
+#include "deviceprocess.h"
+
+namespace ProjectExplorer {
+
+class PROJECTEXPLORER_EXPORT SshDeviceProcess : public DeviceProcess
+{
+ Q_OBJECT
+public:
+ SshDeviceProcess(const QSharedPointer<const IDevice> &device, QObject *parent = 0);
+ ~SshDeviceProcess();
+
+ void start(const QString &executable, const QStringList &arguments);
+ void interrupt();
+ void terminate();
+ void kill();
+
+ QString executable() const;
+ QStringList arguments() const;
+ QProcess::ProcessState state() const;
+ QProcess::ExitStatus exitStatus() const;
+ int exitCode() const;
+ QString errorString() const;
+
+ Utils::Environment environment() const;
+ void setEnvironment(const Utils::Environment &env);
+
+ void setWorkingDirectory(const QString & /* directory */) { } // No such thing in the RFC.
+
+ QByteArray readAllStandardOutput();
+ QByteArray readAllStandardError();
+
+ // Default is "false" due to OpenSSH not implementing this feature for some reason.
+ void setSshServerSupportsSignals(bool signalsSupported);
+
+private slots:
+ void handleConnected();
+ void handleConnectionError();
+ void handleDisconnected();
+ void handleProcessStarted();
+ void handleProcessFinished(int exitStatus);
+ void handleStdout();
+ void handleStderr();
+
+private:
+ virtual QString fullCommandLine() const;
+
+ class SshDeviceProcessPrivate;
+ friend class SshDeviceProcessPrivate;
+ SshDeviceProcessPrivate * const d;
+};
+
+} // namespace ProjectExplorer
+
+#endif // Include guard.
diff --git a/src/plugins/projectexplorer/projectexplorer.pro b/src/plugins/projectexplorer/projectexplorer.pro
index d1a17621b2..484db7658f 100644
--- a/src/plugins/projectexplorer/projectexplorer.pro
+++ b/src/plugins/projectexplorer/projectexplorer.pro
@@ -113,10 +113,12 @@ HEADERS += projectexplorer.h \
devicesupport/desktopdevicefactory.h \
devicesupport/idevicewidget.h \
devicesupport/idevicefactory.h \
+ devicesupport/desktopdeviceprocess.h \
devicesupport/devicecheckbuildstep.h \
devicesupport/devicemanager.h \
devicesupport/devicemanagermodel.h \
devicesupport/devicefactoryselectiondialog.h \
+ devicesupport/deviceprocess.h \
devicesupport/deviceprocesslist.h \
devicesupport/deviceprocessesdialog.h \
devicesupport/devicesettingswidget.h \
@@ -125,6 +127,7 @@ HEADERS += projectexplorer.h \
devicesupport/deviceusedportsgatherer.h \
devicesupport/deviceapplicationrunner.h \
devicesupport/localprocesslist.h \
+ devicesupport/sshdeviceprocess.h \
devicesupport/sshdeviceprocesslist.h \
devicesupport/desktopdeviceconfigurationwidget.h \
deploymentdata.h \
@@ -232,10 +235,12 @@ SOURCES += projectexplorer.cpp \
devicesupport/desktopdevice.cpp \
devicesupport/desktopdevicefactory.cpp \
devicesupport/idevicefactory.cpp \
+ devicesupport/desktopdeviceprocess.cpp \
devicesupport/devicecheckbuildstep.cpp \
devicesupport/devicemanager.cpp \
devicesupport/devicemanagermodel.cpp \
devicesupport/devicefactoryselectiondialog.cpp \
+ devicesupport/deviceprocess.cpp \
devicesupport/deviceprocesslist.cpp \
devicesupport/deviceprocessesdialog.cpp \
devicesupport/devicesettingswidget.cpp \
@@ -244,6 +249,7 @@ SOURCES += projectexplorer.cpp \
devicesupport/deviceusedportsgatherer.cpp \
devicesupport/deviceapplicationrunner.cpp \
devicesupport/localprocesslist.cpp \
+ devicesupport/sshdeviceprocess.cpp \
devicesupport/sshdeviceprocesslist.cpp \
devicesupport/desktopdeviceconfigurationwidget.cpp \
deployablefile.cpp \
diff --git a/src/plugins/projectexplorer/projectexplorer.qbs b/src/plugins/projectexplorer/projectexplorer.qbs
index eeea81b108..0d6985344b 100644
--- a/src/plugins/projectexplorer/projectexplorer.qbs
+++ b/src/plugins/projectexplorer/projectexplorer.qbs
@@ -265,6 +265,8 @@ QtcPlugin {
"devicesupport/devicemanager.h",
"devicesupport/devicemanagermodel.cpp",
"devicesupport/devicemanagermodel.h",
+ "devicesupport/deviceprocess.cpp",
+ "devicesupport/deviceprocess.h",
"devicesupport/deviceprocessesdialog.cpp",
"devicesupport/deviceprocessesdialog.h",
"devicesupport/deviceprocesslist.cpp",
@@ -284,8 +286,12 @@ QtcPlugin {
"devicesupport/idevicefactory.cpp",
"devicesupport/idevicefactory.h",
"devicesupport/idevicewidget.h",
+ "devicesupport/desktopdeviceprocess.cpp",
+ "devicesupport/desktopdeviceprocess.h",
"devicesupport/localprocesslist.cpp",
"devicesupport/localprocesslist.h",
+ "devicesupport/sshdeviceprocess.cpp",
+ "devicesupport/sshdeviceprocess.h",
"devicesupport/sshdeviceprocesslist.cpp",
"devicesupport/sshdeviceprocesslist.h",
"devicesupport/desktopdeviceconfigurationwidget.cpp",
diff --git a/src/plugins/qnx/blackberrydeviceprocesssupport.cpp b/src/plugins/qnx/blackberrydeviceprocesssupport.cpp
index bedf0cc618..2acce3e5fe 100644
--- a/src/plugins/qnx/blackberrydeviceprocesssupport.cpp
+++ b/src/plugins/qnx/blackberrydeviceprocesssupport.cpp
@@ -34,12 +34,23 @@
using namespace Qnx;
using namespace Qnx::Internal;
-QString BlackBerryDeviceProcessSupport::killProcessByNameCommandLine(const QString &filePath) const
+static QString signalProcessByNameCommandLine(const QString &filePath, int signal)
{
QString executable = filePath;
return QString::fromLatin1("for PID in $(pidin -F \"%a %A\" | grep \"%1\" | awk '/%1/ {print $1}'); "
"do "
- "kill $PID; sleep 1; kill -9 $PID; "
- "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/")));
+ "kill -%2 $PID; "
+ "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(signal);
+}
+
+QString BlackBerryDeviceProcessSupport::killProcessByNameCommandLine(const QString &filePath) const
+{
+ return QString::fromLatin1("%1; %2").arg(signalProcessByNameCommandLine(filePath, 15),
+ signalProcessByNameCommandLine(filePath, 9));
+}
+
+QString BlackBerryDeviceProcessSupport::interruptProcessByNameCommandLine(const QString &filePath) const
+{
+ return signalProcessByNameCommandLine(filePath, 2);
}
diff --git a/src/plugins/qnx/blackberrydeviceprocesssupport.h b/src/plugins/qnx/blackberrydeviceprocesssupport.h
index e79f647305..656df0c1f1 100644
--- a/src/plugins/qnx/blackberrydeviceprocesssupport.h
+++ b/src/plugins/qnx/blackberrydeviceprocesssupport.h
@@ -41,6 +41,7 @@ class BlackBerryDeviceProcessSupport : public RemoteLinux::LinuxDeviceProcessSup
{
public:
QString killProcessByNameCommandLine(const QString &filePath) const;
+ QString interruptProcessByNameCommandLine(const QString &filePath) const;
};
} // namespace Internal
diff --git a/src/plugins/qnx/qnxabstractrunsupport.cpp b/src/plugins/qnx/qnxabstractrunsupport.cpp
index cb97aa36f9..151dc8f0fd 100644
--- a/src/plugins/qnx/qnxabstractrunsupport.cpp
+++ b/src/plugins/qnx/qnxabstractrunsupport.cpp
@@ -46,9 +46,10 @@ using namespace Qnx::Internal;
QnxAbstractRunSupport::QnxAbstractRunSupport(QnxRunConfiguration *runConfig, QObject *parent)
: QObject(parent)
, m_remoteExecutable(runConfig->remoteExecutableFilePath())
- , m_commandPrefix(runConfig->commandPrefix())
, m_device(DeviceKitInformation::device(runConfig->target()->kit()))
, m_state(Inactive)
+ , m_environment(runConfig->environment())
+ , m_workingDir(runConfig->workingDirectory())
{
m_runner = new DeviceApplicationRunner(this);
m_portsGatherer = new DeviceUsedPortsGatherer(this);
@@ -84,7 +85,7 @@ void QnxAbstractRunSupport::handleRemoteProcessFinished(bool)
void QnxAbstractRunSupport::setFinished()
{
if (m_state != GatheringPorts && m_state != Inactive)
- m_runner->stop(m_device->processSupport()->killProcessByNameCommandLine(executable()).toUtf8());
+ m_runner->stop();
m_state = Inactive;
}
@@ -104,11 +105,6 @@ DeviceApplicationRunner *QnxAbstractRunSupport::appRunner() const
return m_runner;
}
-QString QnxAbstractRunSupport::commandPrefix() const
-{
- return m_commandPrefix;
-}
-
const IDevice::ConstPtr QnxAbstractRunSupport::device() const
{
return m_device;
diff --git a/src/plugins/qnx/qnxabstractrunsupport.h b/src/plugins/qnx/qnxabstractrunsupport.h
index 1e37059774..73650283de 100644
--- a/src/plugins/qnx/qnxabstractrunsupport.h
+++ b/src/plugins/qnx/qnxabstractrunsupport.h
@@ -31,6 +31,7 @@
#define QNXABSTRACTRUNSUPPORT_H
#include <projectexplorer/devicesupport/idevice.h>
+#include <utils/environment.h>
#include <utils/portlist.h>
#include <QObject>
@@ -64,6 +65,8 @@ protected:
virtual void startExecution() = 0;
virtual QString executable() const;
+ Utils::Environment environment() const { return m_environment; }
+ QString workingDirectory() const { return m_workingDir; }
void setFinished();
@@ -71,7 +74,6 @@ protected:
void setState(State state);
ProjectExplorer::DeviceApplicationRunner *appRunner() const;
- QString commandPrefix() const;
const ProjectExplorer::IDevice::ConstPtr device() const;
protected slots:
@@ -90,10 +92,11 @@ private:
ProjectExplorer::DeviceUsedPortsGatherer * m_portsGatherer;
Utils::PortList m_portList;
const QString m_remoteExecutable;
- const QString m_commandPrefix;
ProjectExplorer::IDevice::ConstPtr m_device;
ProjectExplorer::DeviceApplicationRunner *m_runner;
State m_state;
+ Utils::Environment m_environment;
+ QString m_workingDir;
};
} // namespace Internal
diff --git a/src/plugins/qnx/qnxanalyzesupport.cpp b/src/plugins/qnx/qnxanalyzesupport.cpp
index b67d0e6083..fe9caf70bf 100644
--- a/src/plugins/qnx/qnxanalyzesupport.cpp
+++ b/src/plugins/qnx/qnxanalyzesupport.cpp
@@ -34,6 +34,7 @@
#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
using namespace ProjectExplorer;
@@ -78,10 +79,12 @@ void QnxAnalyzeSupport::startExecution()
setState(StartingRemoteProcess);
- const QString args = m_runControl->startParameters().debuggeeArgs +
- QString::fromLatin1(" -qmljsdebugger=port:%1,block").arg(m_qmlPort);
- const QString command = QString::fromLatin1("%1 %2 %3").arg(commandPrefix(), executable(), args);
- appRunner()->start(device(), command.toUtf8());
+ const QStringList args = QStringList()
+ << Utils::QtcProcess::splitArgs(m_runControl->startParameters().debuggeeArgs)
+ << QString::fromLatin1("-qmljsdebugger=port:%1,block").arg(m_qmlPort);
+ appRunner()->setEnvironment(environment());
+ appRunner()->setWorkingDirectory(workingDirectory());
+ appRunner()->start(device(), executable(), args);
}
void QnxAnalyzeSupport::handleRemoteProcessFinished(bool success)
diff --git a/src/plugins/qnx/qnxdebugsupport.cpp b/src/plugins/qnx/qnxdebugsupport.cpp
index 7b76080fc7..02049fbf62 100644
--- a/src/plugins/qnx/qnxdebugsupport.cpp
+++ b/src/plugins/qnx/qnxdebugsupport.cpp
@@ -41,6 +41,7 @@
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
#include <utils/qtcassert.h>
+#include <utils/qtcprocess.h>
using namespace ProjectExplorer;
using namespace RemoteLinux;
@@ -91,15 +92,14 @@ void QnxDebugSupport::startExecution()
if (m_useQmlDebugger)
m_engine->startParameters().processArgs += QString::fromLocal8Bit(" -qmljsdebugger=port:%1,block").arg(m_qmlPort);
- QString remoteCommandLine;
+ QStringList arguments;
if (m_useCppDebugger)
- remoteCommandLine = QString::fromLatin1("%1 %2 %3")
- .arg(commandPrefix(), executable()).arg(m_pdebugPort);
+ arguments << QString::number(m_pdebugPort);
else if (m_useQmlDebugger && !m_useCppDebugger)
- remoteCommandLine = QString::fromLatin1("%1 %2 %3")
- .arg(commandPrefix(), executable(), m_engine->startParameters().processArgs);
-
- appRunner()->start(device(), remoteCommandLine.toUtf8());
+ arguments = Utils::QtcProcess::splitArgs(m_engine->startParameters().processArgs);
+ appRunner()->setEnvironment(environment());
+ appRunner()->setWorkingDirectory(workingDirectory());
+ appRunner()->start(device(), executable(), arguments);
}
void QnxDebugSupport::handleRemoteProcessStarted()
diff --git a/src/plugins/qnx/qnxdeviceconfiguration.cpp b/src/plugins/qnx/qnxdeviceconfiguration.cpp
index 5810617fc6..2f9a5a2571 100644
--- a/src/plugins/qnx/qnxdeviceconfiguration.cpp
+++ b/src/plugins/qnx/qnxdeviceconfiguration.cpp
@@ -42,13 +42,24 @@ using namespace Qnx::Internal;
class QnxDeviceProcessSupport : public RemoteLinux::LinuxDeviceProcessSupport
{
- QString killProcessByNameCommandLine(const QString &filePath) const
+ static QString signalProcessByNameCommandLine(const QString &filePath, int sig)
{
QString executable = filePath;
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.replace(QLatin1String("/"), QLatin1String("\\/")));
+ "kill -%2 $PID; "
+ "done").arg(executable.replace(QLatin1String("/"), QLatin1String("\\/"))).arg(sig);
+ }
+
+ QString killProcessByNameCommandLine(const QString &filePath) const
+ {
+ return QString::fromLatin1("%1; %2").arg(signalProcessByNameCommandLine(filePath, 15),
+ signalProcessByNameCommandLine(filePath, 9));
+ }
+
+ QString interruptProcessByNameCommandLine(const QString &filePath) const
+ {
+ return signalProcessByNameCommandLine(filePath, 2);
}
};
diff --git a/src/plugins/qnx/qnxrunconfiguration.cpp b/src/plugins/qnx/qnxrunconfiguration.cpp
index 277bcfe6e1..2f5f2c3074 100644
--- a/src/plugins/qnx/qnxrunconfiguration.cpp
+++ b/src/plugins/qnx/qnxrunconfiguration.cpp
@@ -33,6 +33,7 @@
#include "qnxconstants.h"
#include <remotelinux/remotelinuxrunconfigurationwidget.h>
+#include <utils/environment.h>
#include <QLabel>
#include <QLineEdit>
@@ -60,22 +61,14 @@ void QnxRunConfiguration::setQtLibPath(const QString &path)
m_qtLibPath = path;
}
-QString QnxRunConfiguration::environmentPreparationCommand() const
+Utils::Environment QnxRunConfiguration::environment() const
{
- QString command;
- const QStringList filesToSource = QStringList() << QLatin1String("/etc/profile")
- << QLatin1String("$HOME/.profile");
- foreach (const QString &filePath, filesToSource)
- command += QString::fromLatin1("test -f %1 && . %1;").arg(filePath);
- if (!workingDirectory().isEmpty())
- command += QLatin1String("cd ") + workingDirectory() + QLatin1Char(';');
-
- if (!m_qtLibPath.isEmpty())
- command += QLatin1String("LD_LIBRARY_PATH=") + m_qtLibPath + QLatin1String(":$LD_LIBRARY_PATH");
- else
- command.chop(1); // Trailing semicolon.
-
- return command;
+ Utils::Environment env = RemoteLinuxRunConfiguration::environment();
+ if (!m_qtLibPath.isEmpty()) {
+ env.appendOrSet(QLatin1String("LD_LIBRARY_PATH"),
+ m_qtLibPath + QLatin1String(":$LD_LIBRARY_PATH"));
+ }
+ return env;
}
QWidget *QnxRunConfiguration::createConfigurationWidget()
diff --git a/src/plugins/qnx/qnxrunconfiguration.h b/src/plugins/qnx/qnxrunconfiguration.h
index 7d0f173985..18e67d62de 100644
--- a/src/plugins/qnx/qnxrunconfiguration.h
+++ b/src/plugins/qnx/qnxrunconfiguration.h
@@ -34,6 +34,8 @@
#include <remotelinux/remotelinuxrunconfiguration.h>
+namespace Utils { class Environment; }
+
namespace Qnx {
namespace Internal {
@@ -44,7 +46,7 @@ public:
QnxRunConfiguration(ProjectExplorer::Target *parent, const Core::Id id,
const QString &projectFilePath);
- QString environmentPreparationCommand() const;
+ Utils::Environment environment() const;
QWidget *createConfigurationWidget();
diff --git a/src/plugins/qnx/qnxruncontrolfactory.cpp b/src/plugins/qnx/qnxruncontrolfactory.cpp
index 389870502a..f979280ffa 100644
--- a/src/plugins/qnx/qnxruncontrolfactory.cpp
+++ b/src/plugins/qnx/qnxruncontrolfactory.cpp
@@ -86,7 +86,7 @@ static DebuggerStartParameters createDebuggerStartParameters(const QnxRunConfigu
params.displayName = runConfig->displayName();
params.remoteSetupNeeded = true;
params.closeMode = KillAtClose;
- params.processArgs = runConfig->arguments();
+ params.processArgs = runConfig->arguments().join(QLatin1String(" "));
Debugger::DebuggerRunConfigurationAspect *aspect
= runConfig->extraAspect<Debugger::DebuggerRunConfigurationAspect>();
@@ -127,9 +127,8 @@ static AnalyzerStartParameters createAnalyzerStartParameters(const QnxRunConfigu
if (mode == QmlProfilerRunMode)
params.startMode = StartLocal;
params.debuggee = runConfig->remoteExecutableFilePath();
- params.debuggeeArgs = runConfig->arguments();
+ params.debuggeeArgs = runConfig->arguments().join(QLatin1String(" "));
params.connParams = DeviceKitInformation::device(runConfig->target()->kit())->sshParameters();
- params.analyzerCmdPrefix = runConfig->commandPrefix();
params.displayName = runConfig->displayName();
params.sysroot = SysRootKitInformation::sysRoot(runConfig->target()->kit()).toString();
params.analyzerHost = params.connParams.host;
diff --git a/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp b/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp
index 6424cb80c8..b36c8390ed 100644
--- a/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp
+++ b/src/plugins/remotelinux/abstractremotelinuxrunsupport.cpp
@@ -34,7 +34,7 @@
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
#include <projectexplorer/devicesupport/deviceusedportsgatherer.h>
-
+#include <utils/environment.h>
#include <utils/portlist.h>
using namespace ProjectExplorer;
@@ -50,7 +50,8 @@ public:
device(DeviceKitInformation::device(runConfig->target()->kit())),
remoteFilePath(runConfig->remoteExecutableFilePath()),
arguments(runConfig->arguments()),
- commandPrefix(runConfig->commandPrefix())
+ environment(runConfig->environment()),
+ workingDir(runConfig->workingDirectory())
{
}
@@ -60,8 +61,9 @@ public:
const ProjectExplorer::IDevice::ConstPtr device;
Utils::PortList portList;
const QString remoteFilePath;
- const QString arguments;
- const QString commandPrefix;
+ const QStringList arguments;
+ const Utils::Environment environment;
+ const QString workingDir;
};
} // namespace Internal
@@ -138,11 +140,8 @@ void AbstractRemoteLinuxRunSupport::setFinished()
{
if (d->state == Inactive)
return;
- if (d->state == Running) {
- const QString stopCommand
- = d->device->processSupport()->killProcessByNameCommandLine(d->remoteFilePath);
- d->appRunner.stop(stopCommand.toUtf8());
- }
+ if (d->state == Running)
+ d->appRunner.stop();
d->state = Inactive;
}
@@ -156,19 +155,24 @@ bool AbstractRemoteLinuxRunSupport::setPort(int &port)
return true;
}
-QString AbstractRemoteLinuxRunSupport::arguments() const
+QStringList AbstractRemoteLinuxRunSupport::arguments() const
{
return d->arguments;
}
-QString AbstractRemoteLinuxRunSupport::commandPrefix() const
+QString AbstractRemoteLinuxRunSupport::remoteFilePath() const
{
- return d->commandPrefix;
+ return d->remoteFilePath;
}
-QString AbstractRemoteLinuxRunSupport::remoteFilePath() const
+Utils::Environment AbstractRemoteLinuxRunSupport::environment() const
{
- return d->remoteFilePath;
+ return d->environment;
+}
+
+QString AbstractRemoteLinuxRunSupport::workingDirectory() const
+{
+ return d->workingDir;
}
const IDevice::ConstPtr AbstractRemoteLinuxRunSupport::device() const
diff --git a/src/plugins/remotelinux/abstractremotelinuxrunsupport.h b/src/plugins/remotelinux/abstractremotelinuxrunsupport.h
index a7a954681b..c052a7a3c3 100644
--- a/src/plugins/remotelinux/abstractremotelinuxrunsupport.h
+++ b/src/plugins/remotelinux/abstractremotelinuxrunsupport.h
@@ -41,6 +41,8 @@ class DeviceApplicationHelperAction;
class DeviceApplicationRunner;
}
+namespace Utils { class Environment; }
+
namespace RemoteLinux {
class RemoteLinuxRunConfiguration;
@@ -79,9 +81,10 @@ protected:
void setFinished();
bool setPort(int &port);
- QString arguments() const;
- QString commandPrefix() const;
+ QStringList arguments() const;
QString remoteFilePath() const;
+ Utils::Environment environment() const;
+ QString workingDirectory() const;
const ProjectExplorer::IDevice::ConstPtr device() const;
void reset();
diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp
index efb014e5eb..64570c225f 100644
--- a/src/plugins/remotelinux/linuxdevice.cpp
+++ b/src/plugins/remotelinux/linuxdevice.cpp
@@ -30,6 +30,7 @@
#include "linuxdevice.h"
#include "genericlinuxdeviceconfigurationwidget.h"
+#include "linuxdeviceprocess.h"
#include "linuxdevicetester.h"
#include "publickeydeploymentdialog.h"
#include "remotelinux_constants.h"
@@ -122,14 +123,26 @@ QString LinuxDeviceProcessSupport::killProcessByPidCommandLine(int pid) const
return QLatin1String("kill -9 ") + QString::number(pid);
}
-QString LinuxDeviceProcessSupport::killProcessByNameCommandLine(const QString &filePath) const
+
+static QString signalProcessByNameCommandLine(const QString &filePath, int signal)
{
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; "
+ " kill %2 $pid;"
"fi; "
- "done").arg(filePath);
+ "done").arg(filePath).arg(signal);
+}
+
+QString LinuxDeviceProcessSupport::killProcessByNameCommandLine(const QString &filePath) const
+{
+ return QString::fromLatin1("%1; %2").arg(signalProcessByNameCommandLine(filePath, 15),
+ signalProcessByNameCommandLine(filePath, 9));
+}
+
+QString LinuxDeviceProcessSupport::interruptProcessByNameCommandLine(const QString &filePath) const
+{
+ return signalProcessByNameCommandLine(filePath, 2);
}
@@ -244,6 +257,11 @@ DeviceProcessSupport::Ptr LinuxDevice::processSupport() const
return DeviceProcessSupport::Ptr(new LinuxDeviceProcessSupport);
}
+DeviceProcess *LinuxDevice::createProcess(QObject *parent) const
+{
+ return new LinuxDeviceProcess(sharedFromThis(), parent);
+}
+
bool LinuxDevice::canAutoDetectPorts() const
{
return true;
diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h
index 7e8224a475..85946e735e 100644
--- a/src/plugins/remotelinux/linuxdevice.h
+++ b/src/plugins/remotelinux/linuxdevice.h
@@ -47,6 +47,7 @@ class REMOTELINUX_EXPORT LinuxDeviceProcessSupport : public ProjectExplorer::Dev
public:
QString killProcessByPidCommandLine(int pid) const;
QString killProcessByNameCommandLine(const QString &filePath) const;
+ QString interruptProcessByNameCommandLine(const QString &filePath) const;
};
class REMOTELINUX_EXPORT LinuxDevice : public ProjectExplorer::IDevice
@@ -69,6 +70,8 @@ public:
ProjectExplorer::IDevice::Ptr clone() const;
ProjectExplorer::DeviceProcessSupport::Ptr processSupport() const;
+ bool canCreateProcess() const { return true; }
+ ProjectExplorer::DeviceProcess *createProcess(QObject *parent) const;
bool canAutoDetectPorts() const;
ProjectExplorer::PortsGatheringMethod::Ptr portsGatheringMethod() const;
bool canCreateProcessModel() const { return true; }
diff --git a/src/plugins/remotelinux/linuxdeviceprocess.cpp b/src/plugins/remotelinux/linuxdeviceprocess.cpp
new file mode 100644
index 0000000000..2dd8e792a7
--- /dev/null
+++ b/src/plugins/remotelinux/linuxdeviceprocess.cpp
@@ -0,0 +1,84 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+#include "linuxdeviceprocess.h"
+
+#include <utils/environment.h>
+#include <utils/qtcprocess.h>
+
+namespace RemoteLinux {
+
+static QString quote(const QString &s) { return Utils::QtcProcess::quoteArgUnix(s); }
+
+LinuxDeviceProcess::LinuxDeviceProcess(const QSharedPointer<const ProjectExplorer::IDevice> &device,
+ QObject *parent)
+ : ProjectExplorer::SshDeviceProcess(device, parent)
+{
+ setEnvironment(Utils::Environment(Utils::OsTypeLinux));
+}
+
+void LinuxDeviceProcess::setRcFilesToSource(const QStringList &filePaths)
+{
+ m_rcFilesToSource = filePaths;
+}
+
+void LinuxDeviceProcess::setWorkingDirectory(const QString &directory)
+{
+ m_workingDir = directory;
+}
+
+QString LinuxDeviceProcess::fullCommandLine() const
+{
+ QString fullCommandLine;
+ foreach (const QString &filePath, rcFilesToSource())
+ fullCommandLine += QString::fromLatin1("test -f %1 && source %1;").arg(filePath);
+ if (!m_workingDir.isEmpty()) {
+ fullCommandLine.append(QLatin1String("cd ")).append(quote(m_workingDir))
+ .append(QLatin1String(" && "));
+ }
+ const QString envString = environment().toStringList().join(QLatin1String(" "));
+ if (!envString.isEmpty())
+ fullCommandLine.append(QLatin1Char(' ')).append(envString);
+ if (!fullCommandLine.isEmpty())
+ fullCommandLine += QLatin1Char(' ');
+ fullCommandLine.append(quote(executable()));
+ if (!arguments().isEmpty()) {
+ fullCommandLine.append(QLatin1Char(' '));
+ fullCommandLine.append(Utils::QtcProcess::joinArgsUnix(arguments()));
+ }
+ return fullCommandLine;
+}
+
+QStringList LinuxDeviceProcess::rcFilesToSource() const
+{
+ if (!m_rcFilesToSource.isEmpty())
+ return m_rcFilesToSource;
+ return QStringList() << QLatin1String("/etc/profile") << QLatin1String("$HOME/.profile");
+}
+
+} // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/linuxdeviceprocess.h b/src/plugins/remotelinux/linuxdeviceprocess.h
new file mode 100644
index 0000000000..c42e1e7c97
--- /dev/null
+++ b/src/plugins/remotelinux/linuxdeviceprocess.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia. For licensing terms and
+** conditions see http://qt.digia.com/licensing. For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** 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, Digia gives you certain additional
+** rights. These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+****************************************************************************/
+
+#ifndef QTC_LINUXDEVICEPROCESS_H
+#define QTC_LINUXDEVICEPROCESS_H
+
+#include "remotelinux_export.h"
+
+#include <projectexplorer/devicesupport/sshdeviceprocess.h>
+
+#include <QStringList>
+
+namespace RemoteLinux {
+
+class REMOTELINUX_EXPORT LinuxDeviceProcess : public ProjectExplorer::SshDeviceProcess
+{
+ Q_OBJECT
+public:
+ explicit LinuxDeviceProcess(const QSharedPointer<const ProjectExplorer::IDevice> &device,
+ QObject *parent = 0);
+
+ // Files to source before executing the command (if they exist). Overrides the default.
+ void setRcFilesToSource(const QStringList &filePaths);
+
+ void setWorkingDirectory(const QString &directory);
+
+private:
+ QString fullCommandLine() const;
+
+ QStringList rcFilesToSource() const;
+
+ QStringList m_rcFilesToSource;
+ QString m_workingDir;
+};
+
+} // namespace RemoteLinux
+
+#endif // Include guard.
diff --git a/src/plugins/remotelinux/remotelinux.pro b/src/plugins/remotelinux/remotelinux.pro
index 62b3061f40..8c4453cabb 100644
--- a/src/plugins/remotelinux/remotelinux.pro
+++ b/src/plugins/remotelinux/remotelinux.pro
@@ -47,7 +47,8 @@ HEADERS += \
remotelinuxcheckforfreediskspacestep.h \
remotelinuxdeploymentdatamodel.h \
remotelinuxanalyzesupport.h \
- abstractremotelinuxrunsupport.h
+ abstractremotelinuxrunsupport.h \
+ linuxdeviceprocess.h
SOURCES += \
embeddedlinuxqtversion.cpp \
@@ -92,7 +93,8 @@ SOURCES += \
remotelinuxcheckforfreediskspacestep.cpp \
remotelinuxdeploymentdatamodel.cpp \
remotelinuxanalyzesupport.cpp \
- abstractremotelinuxrunsupport.cpp
+ abstractremotelinuxrunsupport.cpp \
+ linuxdeviceprocess.cpp
FORMS += \
genericlinuxdeviceconfigurationwizardsetuppage.ui \
diff --git a/src/plugins/remotelinux/remotelinux.qbs b/src/plugins/remotelinux/remotelinux.qbs
index 15cf5ce44a..cb610ef7a6 100644
--- a/src/plugins/remotelinux/remotelinux.qbs
+++ b/src/plugins/remotelinux/remotelinux.qbs
@@ -47,6 +47,8 @@ QtcPlugin {
"genericremotelinuxdeploystepfactory.h",
"linuxdevice.cpp",
"linuxdevice.h",
+ "linuxdeviceprocess.cpp",
+ "linuxdeviceprocess.h",
"linuxdevicetester.cpp",
"linuxdevicetester.h",
"packageuploader.cpp",
diff --git a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp
index e51b544f87..48680b861f 100644
--- a/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp
+++ b/src/plugins/remotelinux/remotelinuxanalyzesupport.cpp
@@ -81,7 +81,6 @@ AnalyzerStartParameters RemoteLinuxAnalyzeSupport::startParameters(const RemoteL
params.startMode = StartLocal;
params.runMode = runMode;
params.connParams = DeviceKitInformation::device(runConfig->target()->kit())->sshParameters();
- params.analyzerCmdPrefix = runConfig->commandPrefix();
params.displayName = runConfig->displayName();
params.sysroot = SysRootKitInformation::sysRoot(runConfig->target()->kit()).toString();
params.analyzerHost = params.connParams.host;
@@ -140,11 +139,11 @@ void RemoteLinuxAnalyzeSupport::startExecution()
connect(runner, SIGNAL(reportProgress(QString)), SLOT(handleProgressReport(QString)));
connect(runner, SIGNAL(reportError(QString)), SLOT(handleAppRunnerError(QString)));
- const QString args = arguments()
- + QString::fromLocal8Bit(" -qmljsdebugger=port:%1,block").arg(d->qmlPort);
- const QString remoteCommandLine =
- QString::fromLatin1("%1 %2 %3").arg(commandPrefix()).arg(remoteFilePath()).arg(args);
- runner->start(device(), remoteCommandLine.toUtf8());
+ const QStringList args = arguments()
+ << QString::fromLocal8Bit("-qmljsdebugger=port:%1,block").arg(d->qmlPort);
+ runner->setWorkingDirectory(workingDirectory());
+ runner->setEnvironment(environment());
+ runner->start(device(), remoteFilePath(), args);
}
void RemoteLinuxAnalyzeSupport::handleAppRunnerError(const QString &error)
diff --git a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp
index 2ccecb0e5f..8448103e58 100644
--- a/src/plugins/remotelinux/remotelinuxdebugsupport.cpp
+++ b/src/plugins/remotelinux/remotelinuxdebugsupport.cpp
@@ -98,7 +98,7 @@ DebuggerStartParameters LinuxDeviceDebugSupport::startParameters(const RemoteLin
}
if (aspect->useCppDebugger()) {
params.languages |= CppLanguage;
- params.processArgs = runConfig->arguments();
+ params.processArgs = runConfig->arguments().join(QLatin1String(" "));
params.startMode = AttachToRemoteServer;
params.executable = runConfig->localExecutableFilePath();
params.remoteChannel = device->sshParameters().host + QLatin1String(":-1");
@@ -162,17 +162,23 @@ void LinuxDeviceDebugSupport::startExecution()
connect(runner, SIGNAL(remoteStdout(QByteArray)), SLOT(handleRemoteOutput(QByteArray)));
if (d->qmlDebugging && !d->cppDebugging)
connect(runner, SIGNAL(remoteProcessStarted()), SLOT(handleRemoteProcessStarted()));
- QString args = arguments();
+ QString command;
+ QStringList args = 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(commandPrefix()).arg(remoteFilePath()).arg(args)
- : QString::fromLatin1("%1 gdbserver :%2 %3 %4").arg(commandPrefix())
- .arg(d->gdbServerPort).arg(remoteFilePath()).arg(args);
+ args += QString::fromLocal8Bit("-qmljsdebugger=port:%1,block").arg(d->qmlPort);
+ if (d->qmlDebugging && !d->cppDebugging) {
+ command = remoteFilePath();
+ } else {
+ command = QLatin1String("gdbserver");
+ args.prepend(remoteFilePath());
+ args.prepend(QString::fromLatin1(":%1").arg(d->gdbServerPort));
+ }
connect(runner, SIGNAL(finished(bool)), SLOT(handleAppRunnerFinished(bool)));
connect(runner, SIGNAL(reportProgress(QString)), SLOT(handleProgressReport(QString)));
connect(runner, SIGNAL(reportError(QString)), SLOT(handleAppRunnerError(QString)));
- runner->start(device(), remoteCommandLine.toUtf8());
+ runner->setEnvironment(environment());
+ runner->setWorkingDirectory(workingDirectory());
+ runner->start(device(), command, args);
}
void LinuxDeviceDebugSupport::handleAppRunnerError(const QString &error)
diff --git a/src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp b/src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp
index 69c0b57cc9..222c06f9ac 100644
--- a/src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp
+++ b/src/plugins/remotelinux/remotelinuxenvironmentaspectwidget.cpp
@@ -70,7 +70,7 @@ void RemoteLinuxEnvironmentAspectWidget::fetchEnvironment()
disconnect(button, SIGNAL(clicked()), this, SLOT(fetchEnvironment()));
connect(button, SIGNAL(clicked()), this, SLOT(stopFetchEnvironment()));
button->setText(tr("Cancel Fetch Operation"));
- deviceEnvReader->start(aspect()->runConfiguration()->environmentPreparationCommand());
+ deviceEnvReader->start();
}
void RemoteLinuxEnvironmentAspectWidget::fetchEnvironmentFinished()
diff --git a/src/plugins/remotelinux/remotelinuxenvironmentreader.cpp b/src/plugins/remotelinux/remotelinuxenvironmentreader.cpp
index 2f3d8161cd..2ffa21bdac 100644
--- a/src/plugins/remotelinux/remotelinuxenvironmentreader.cpp
+++ b/src/plugins/remotelinux/remotelinuxenvironmentreader.cpp
@@ -28,7 +28,7 @@
****************************************************************************/
#include "remotelinuxenvironmentreader.h"
-#include <ssh/sshremoteprocessrunner.h>
+#include <projectexplorer/devicesupport/deviceprocess.h>
#include <projectexplorer/devicesupport/idevice.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/runconfiguration.h>
@@ -44,79 +44,67 @@ RemoteLinuxEnvironmentReader::RemoteLinuxEnvironmentReader(RunConfiguration *con
, m_stop(false)
, m_env(Utils::OsTypeLinux)
, m_kit(config->target()->kit())
- , m_remoteProcessRunner(0)
+ , m_deviceProcess(0)
{
connect(config->target(), SIGNAL(kitChanged()),
this, SLOT(handleCurrentDeviceConfigChanged()));
}
-void RemoteLinuxEnvironmentReader::start(const QString &environmentSetupCommand)
+void RemoteLinuxEnvironmentReader::start()
{
IDevice::ConstPtr device = DeviceKitInformation::device(m_kit);
if (!device)
return;
m_stop = false;
- if (!m_remoteProcessRunner)
- m_remoteProcessRunner = new QSsh::SshRemoteProcessRunner(this);
- connect(m_remoteProcessRunner, SIGNAL(connectionError()), SLOT(handleConnectionFailure()));
- connect(m_remoteProcessRunner, SIGNAL(processClosed(int)), SLOT(remoteProcessFinished(int)));
- const QByteArray remoteCall
- = QString(environmentSetupCommand + QLatin1String("; env")).toUtf8();
- m_remoteProcessRunner->run(remoteCall, device->sshParameters());
+ m_deviceProcess = device->createProcess(this);
+ connect(m_deviceProcess, SIGNAL(error(QProcess::ProcessError)), SLOT(handleError()));
+ connect(m_deviceProcess, SIGNAL(finished()), SLOT(remoteProcessFinished()));
+ m_deviceProcess->start(QLatin1String("env"));
}
void RemoteLinuxEnvironmentReader::stop()
{
m_stop = true;
- if (m_remoteProcessRunner)
- disconnect(m_remoteProcessRunner, 0, this, 0);
+ destroyProcess();
}
-void RemoteLinuxEnvironmentReader::handleConnectionFailure()
+void RemoteLinuxEnvironmentReader::handleError()
{
if (m_stop)
return;
- disconnect(m_remoteProcessRunner, 0, this, 0);
- emit error(tr("Connection error: %1").arg(m_remoteProcessRunner->lastConnectionErrorString()));
- emit finished();
+ emit error(tr("Error: %1").arg(m_deviceProcess->errorString()));
+ setFinished();
}
void RemoteLinuxEnvironmentReader::handleCurrentDeviceConfigChanged()
{
- if (m_remoteProcessRunner)
- disconnect(m_remoteProcessRunner, 0, this, 0);
m_env.clear();
setFinished();
}
-void RemoteLinuxEnvironmentReader::remoteProcessFinished(int exitStatus)
+void RemoteLinuxEnvironmentReader::remoteProcessFinished()
{
- Q_ASSERT(exitStatus == QSsh::SshRemoteProcess::FailedToStart
- || exitStatus == QSsh::SshRemoteProcess::CrashExit
- || exitStatus == QSsh::SshRemoteProcess::NormalExit);
-
if (m_stop)
return;
- disconnect(m_remoteProcessRunner, 0, this, 0);
m_env.clear();
QString errorMessage;
- if (exitStatus != QSsh::SshRemoteProcess::NormalExit) {
- errorMessage = m_remoteProcessRunner->processErrorString();
- } else if (m_remoteProcessRunner->processExitCode() != 0) {
+ if (m_deviceProcess->exitStatus() != QProcess::NormalExit) {
+ errorMessage = m_deviceProcess->errorString();
+ } else if (m_deviceProcess->exitCode() != 0) {
errorMessage = tr("Process exited with code %1.")
- .arg(m_remoteProcessRunner->processExitCode());
+ .arg(m_deviceProcess->exitCode());
}
if (!errorMessage.isEmpty()) {
errorMessage = tr("Error running 'env': %1").arg(errorMessage);
const QString remoteStderr
- = QString::fromUtf8(m_remoteProcessRunner->readAllStandardError()).trimmed();
+ = QString::fromUtf8(m_deviceProcess->readAllStandardError()).trimmed();
if (!remoteStderr.isEmpty())
errorMessage += tr("\nRemote stderr was: '%1'").arg(remoteStderr);
emit error(errorMessage);
} else {
- QString remoteOutput = QString::fromUtf8(m_remoteProcessRunner->readAllStandardOutput());
+ QString remoteOutput = QString::fromUtf8(m_deviceProcess->readAllStandardOutput());
if (!remoteOutput.isEmpty()) {
m_env = Utils::Environment(remoteOutput.split(QLatin1Char('\n'),
QString::SkipEmptyParts), Utils::OsTypeLinux);
@@ -131,5 +119,16 @@ void RemoteLinuxEnvironmentReader::setFinished()
emit finished();
}
+void RemoteLinuxEnvironmentReader::destroyProcess()
+{
+ if (!m_deviceProcess)
+ return;
+ m_deviceProcess->disconnect(this);
+ if (m_deviceProcess->state() != QProcess::NotRunning)
+ m_deviceProcess->terminate();
+ m_deviceProcess->deleteLater();
+ m_deviceProcess = 0;
+}
+
} // namespace Internal
} // namespace RemoteLinux
diff --git a/src/plugins/remotelinux/remotelinuxenvironmentreader.h b/src/plugins/remotelinux/remotelinuxenvironmentreader.h
index e495440af5..f8cb02f73f 100644
--- a/src/plugins/remotelinux/remotelinuxenvironmentreader.h
+++ b/src/plugins/remotelinux/remotelinuxenvironmentreader.h
@@ -35,12 +35,11 @@
#include <QObject>
namespace ProjectExplorer {
-class RunConfiguration;
+class DeviceProcess;
class Kit;
+class RunConfiguration;
}
-namespace QSsh { class SshRemoteProcessRunner; }
-
namespace RemoteLinux {
namespace Internal {
@@ -51,7 +50,7 @@ class RemoteLinuxEnvironmentReader : public QObject
public:
RemoteLinuxEnvironmentReader(ProjectExplorer::RunConfiguration *config, QObject *parent = 0);
- void start(const QString &environmentSetupCommand);
+ void start();
void stop();
Utils::Environment remoteEnvironment() const { return m_env; }
@@ -61,18 +60,18 @@ signals:
void error(const QString &error);
private slots:
- void handleConnectionFailure();
+ void handleError();
void handleCurrentDeviceConfigChanged();
-
- void remoteProcessFinished(int exitStatus);
+ void remoteProcessFinished();
private:
void setFinished();
+ void destroyProcess();
bool m_stop;
Utils::Environment m_env;
ProjectExplorer::Kit *m_kit;
- QSsh::SshRemoteProcessRunner *m_remoteProcessRunner;
+ ProjectExplorer::DeviceProcess *m_deviceProcess;
};
} // namespace Internal
diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp
index d248e22e79..5b872ecde7 100644
--- a/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp
+++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.cpp
@@ -38,6 +38,7 @@
#include <projectexplorer/project.h>
#include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
+#include <utils/qtcprocess.h>
using namespace ProjectExplorer;
using namespace Utils;
@@ -73,7 +74,7 @@ public:
QString projectFilePath;
QString gdbPath;
- QString arguments;
+ QStringList arguments;
QString disabledReason;
bool useAlternateRemoteExecutable;
QString alternateRemoteExecutable;
@@ -142,6 +143,7 @@ OutputFormatter *RemoteLinuxRunConfiguration::createOutputFormatter() const
return new QtSupport::QtOutputFormatter(target()->project());
}
+
QVariantMap RemoteLinuxRunConfiguration::toMap() const
{
QVariantMap map(RunConfiguration::toMap());
@@ -159,7 +161,7 @@ bool RemoteLinuxRunConfiguration::fromMap(const QVariantMap &map)
if (!RunConfiguration::fromMap(map))
return false;
- d->arguments = map.value(QLatin1String(ArgumentsKey)).toString();
+ d->arguments = map.value(QLatin1String(ArgumentsKey)).toStringList();
const QDir dir = QDir(target()->project()->projectDirectory());
d->projectFilePath
= QDir::cleanPath(dir.filePath(map.value(QLatin1String(ProFileKey)).toString()));
@@ -181,31 +183,21 @@ QString RemoteLinuxRunConfiguration::defaultDisplayName()
return tr("Run on Remote Device");
}
-QString RemoteLinuxRunConfiguration::arguments() const
+QStringList RemoteLinuxRunConfiguration::arguments() const
{
return d->arguments;
}
-QString RemoteLinuxRunConfiguration::environmentPreparationCommand() const
-{
- QString command;
- const QStringList filesToSource = QStringList() << QLatin1String("/etc/profile")
- << QLatin1String("$HOME/.profile");
- foreach (const QString &filePath, filesToSource)
- command += QString::fromLatin1("test -f %1 && source %1;").arg(filePath);
- if (!workingDirectory().isEmpty())
- command += QLatin1String("cd ") + workingDirectory();
- else
- command.chop(1); // Trailing semicolon.
- return command;
-}
-
-QString RemoteLinuxRunConfiguration::commandPrefix() const
+Environment RemoteLinuxRunConfiguration::environment() const
{
RemoteLinuxEnvironmentAspect *aspect = extraAspect<RemoteLinuxEnvironmentAspect>();
- QTC_ASSERT(aspect, return QString());
- return QString::fromLatin1("%1; DISPLAY=:0.0 %2")
- .arg(environmentPreparationCommand(), aspect->userEnvironmentChangesAsString());
+ QTC_ASSERT(aspect, return Environment());
+ Environment env(OsTypeLinux);
+ env.modify(aspect->userEnvironmentChanges());
+ const QString displayKey = QLatin1String("DISPLAY");
+ if (!env.hasKey(displayKey))
+ env.appendOrSet(displayKey, QLatin1String(":0.0"));
+ return env;
}
QString RemoteLinuxRunConfiguration::localExecutableFilePath() const
@@ -228,7 +220,7 @@ QString RemoteLinuxRunConfiguration::remoteExecutableFilePath() const
void RemoteLinuxRunConfiguration::setArguments(const QString &args)
{
- d->arguments = args;
+ d->arguments = QtcProcess::splitArgs(args); // TODO: Widget should be list-based.
}
QString RemoteLinuxRunConfiguration::workingDirectory() const
diff --git a/src/plugins/remotelinux/remotelinuxrunconfiguration.h b/src/plugins/remotelinux/remotelinuxrunconfiguration.h
index 1419164b62..af2fdca6df 100644
--- a/src/plugins/remotelinux/remotelinuxrunconfiguration.h
+++ b/src/plugins/remotelinux/remotelinuxrunconfiguration.h
@@ -34,7 +34,12 @@
#include <projectexplorer/runconfiguration.h>
-namespace Utils { class PortList; }
+#include <QStringList>
+
+namespace Utils {
+class Environment;
+class PortList;
+}
namespace RemoteLinux {
class RemoteLinuxRunConfigurationWidget;
@@ -62,13 +67,12 @@ public:
QWidget *createConfigurationWidget();
Utils::OutputFormatter *createOutputFormatter() const;
- virtual QString environmentPreparationCommand() const;
- virtual QString commandPrefix() const;
+ virtual Utils::Environment environment() const;
QString localExecutableFilePath() const;
QString defaultRemoteExecutableFilePath() const;
QString remoteExecutableFilePath() const;
- QString arguments() const;
+ QStringList arguments() const;
void setArguments(const QString &args);
QString workingDirectory() const;
void setWorkingDirectory(const QString &wd);
diff --git a/src/plugins/remotelinux/remotelinuxrunconfigurationwidget.cpp b/src/plugins/remotelinux/remotelinuxrunconfigurationwidget.cpp
index 2b744daa2e..964715838e 100644
--- a/src/plugins/remotelinux/remotelinuxrunconfigurationwidget.cpp
+++ b/src/plugins/remotelinux/remotelinuxrunconfigurationwidget.cpp
@@ -148,7 +148,7 @@ void RemoteLinuxRunConfigurationWidget::addGenericWidgets(QVBoxLayout *mainLayou
altRemoteExeLayout->addWidget(&d->useAlternateCommandBox);
d->genericWidgetsLayout.addRow(tr("Alternate executable on device:"), altRemoteExeWidget);
- d->argsLineEdit.setText(d->runConfiguration->arguments());
+ d->argsLineEdit.setText(d->runConfiguration->arguments().join(QLatin1String(" ")));
d->genericWidgetsLayout.addRow(tr("Arguments:"), &d->argsLineEdit);
d->workingDirLineEdit.setPlaceholderText(tr("<default>"));
diff --git a/src/plugins/remotelinux/remotelinuxruncontrol.cpp b/src/plugins/remotelinux/remotelinuxruncontrol.cpp
index 93b3f69ec5..1d9e281315 100644
--- a/src/plugins/remotelinux/remotelinuxruncontrol.cpp
+++ b/src/plugins/remotelinux/remotelinuxruncontrol.cpp
@@ -34,6 +34,7 @@
#include <projectexplorer/devicesupport/deviceapplicationrunner.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/target.h>
+#include <utils/environment.h>
#include <QString>
#include <QIcon>
@@ -49,8 +50,9 @@ public:
ProjectExplorer::DeviceApplicationRunner runner;
IDevice::ConstPtr device;
QString remoteExecutable;
- QString arguments;
- QString prefix;
+ QStringList arguments;
+ Utils::Environment environment;
+ QString workingDir;
};
RemoteLinuxRunControl::RemoteLinuxRunControl(RunConfiguration *rc)
@@ -61,7 +63,8 @@ RemoteLinuxRunControl::RemoteLinuxRunControl(RunConfiguration *rc)
const RemoteLinuxRunConfiguration * const lrc = qobject_cast<RemoteLinuxRunConfiguration *>(rc);
d->remoteExecutable = lrc->remoteExecutableFilePath();
d->arguments = lrc->arguments();
- d->prefix = lrc->commandPrefix();
+ d->environment = lrc->environment();
+ d->workingDir = lrc->workingDirectory();
}
RemoteLinuxRunControl::~RemoteLinuxRunControl()
@@ -80,16 +83,14 @@ void RemoteLinuxRunControl::start()
connect(&d->runner, SIGNAL(remoteStdout(QByteArray)), SLOT(handleRemoteOutput(QByteArray)));
connect(&d->runner, SIGNAL(finished(bool)), SLOT(handleRunnerFinished()));
connect(&d->runner, SIGNAL(reportProgress(QString)), SLOT(handleProgressReport(QString)));
- const QString commandLine = QString::fromLatin1("%1 %2 %3")
- .arg(d->prefix, d->remoteExecutable, d->arguments);
- d->runner.start(d->device, commandLine.toUtf8());
+ d->runner.setEnvironment(d->environment);
+ d->runner.setWorkingDirectory(d->workingDir);
+ d->runner.start(d->device, d->remoteExecutable, d->arguments);
}
RunControl::StopResult RemoteLinuxRunControl::stop()
{
- const QString stopCommandLine
- = d->device->processSupport()->killProcessByNameCommandLine(d->remoteExecutable);
- d->runner.stop(stopCommandLine.toUtf8());
+ d->runner.stop();
return AsynchronousStop;
}
diff --git a/src/plugins/valgrind/valgrindruncontrolfactory.cpp b/src/plugins/valgrind/valgrindruncontrolfactory.cpp
index 0e087c5204..67b31438eb 100644
--- a/src/plugins/valgrind/valgrindruncontrolfactory.cpp
+++ b/src/plugins/valgrind/valgrindruncontrolfactory.cpp
@@ -99,8 +99,7 @@ RunControl *ValgrindRunControlFactory::create(RunConfiguration *runConfiguration
sp.startMode = StartRemote;
sp.debuggee = rc2->remoteExecutableFilePath();
sp.connParams = DeviceKitInformation::device(rc2->target()->kit())->sshParameters();
- sp.analyzerCmdPrefix = rc2->commandPrefix();
- sp.debuggeeArgs = rc2->arguments();
+ sp.debuggeeArgs = rc2->arguments().join(QLatin1String(" "));
} else {
QTC_ASSERT(false, return 0);
}