Commit 07d4c290 authored by Christian Kandeler's avatar Christian Kandeler
Browse files

RemoteLinux: Provide a custom run configuration.



Like the existing "Custom Executable" run config,
but for a remote Linux target.

Task-number: QTCREATORBUG-12168
Change-Id: I0527c2f8080f0e3467fe7210968435fc401fbf76
Reviewed-by: default avatarDaniel Teske <daniel.teske@digia.com>
parent b9f79cbd
......@@ -28,6 +28,8 @@
****************************************************************************/
#include "abstractremotelinuxrunconfiguration.h"
#include <debugger/debuggerrunconfigurationaspect.h>
namespace RemoteLinux {
AbstractRemoteLinuxRunConfiguration::AbstractRemoteLinuxRunConfiguration(ProjectExplorer::Target *parent,
......@@ -47,4 +49,17 @@ AbstractRemoteLinuxRunConfiguration::AbstractRemoteLinuxRunConfiguration(Project
}
int AbstractRemoteLinuxRunConfiguration::portsUsedByDebuggers() const
{
int ports = 0;
Debugger::DebuggerRunConfigurationAspect *aspect
= extraAspect<Debugger::DebuggerRunConfigurationAspect>();
if (aspect->useQmlDebugger())
++ports;
if (aspect->useCppDebugger())
++ports;
return ports;
}
} // namespace RemoteLinux
......@@ -55,6 +55,8 @@ public:
virtual QString workingDirectory() const = 0;
virtual Utils::Environment environment() const = 0;
int portsUsedByDebuggers() const;
protected:
AbstractRemoteLinuxRunConfiguration(ProjectExplorer::Target *parent,
AbstractRemoteLinuxRunConfiguration *source);
......
......@@ -48,6 +48,7 @@ HEADERS += \
remotelinuxanalyzesupport.h \
abstractremotelinuxrunsupport.h \
linuxdeviceprocess.h \
remotelinuxcustomrunconfiguration.h \
remotelinuxsignaloperation.h
SOURCES += \
......@@ -94,12 +95,14 @@ SOURCES += \
remotelinuxanalyzesupport.cpp \
abstractremotelinuxrunsupport.cpp \
linuxdeviceprocess.cpp \
remotelinuxcustomrunconfiguration.cpp \
remotelinuxsignaloperation.cpp
FORMS += \
genericlinuxdeviceconfigurationwizardsetuppage.ui \
genericlinuxdeviceconfigurationwidget.ui \
remotelinuxcheckforfreediskspacestepwidget.ui
remotelinuxcheckforfreediskspacestepwidget.ui \
remotelinuxcustomrunconfigurationwidget.ui
RESOURCES += remotelinux.qrc
......
......@@ -73,6 +73,9 @@ QtcPlugin {
"remotelinuxcustomcommanddeploymentstep.h",
"remotelinuxcustomcommanddeployservice.cpp",
"remotelinuxcustomcommanddeployservice.h",
"remotelinuxcustomrunconfiguration.cpp",
"remotelinuxcustomrunconfiguration.h",
"remotelinuxcustomrunconfigurationwidget.ui",
"remotelinuxdebugsupport.cpp",
"remotelinuxdebugsupport.h",
"remotelinuxdeployconfiguration.cpp",
......
/****************************************************************************
**
** Copyright (C) 2014 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 "remotelinuxcustomrunconfiguration.h"
#include "remotelinuxenvironmentaspect.h"
#include "ui_remotelinuxcustomrunconfigurationwidget.h"
#include <projectexplorer/target.h>
#include <qtsupport/qtoutputformatter.h>
#include <utils/detailswidget.h>
#include <utils/qtcprocess.h>
namespace RemoteLinux {
namespace Internal {
class RemoteLinuxCustomRunConfigWidget : public ProjectExplorer::RunConfigWidget
{
Q_OBJECT
public:
RemoteLinuxCustomRunConfigWidget(RemoteLinuxCustomRunConfiguration *runConfig)
: m_runConfig(runConfig)
{
QVBoxLayout * const mainLayout = new QVBoxLayout(this);
mainLayout->setMargin(0);
auto * const detailsContainer = new Utils::DetailsWidget(this);
mainLayout->addWidget(detailsContainer);
detailsContainer->setState(Utils::DetailsWidget::NoSummary);
QWidget * const detailsWidget = new QWidget(this);
detailsContainer->setWidget(detailsWidget);
m_ui.setupUi(detailsWidget);
m_ui.localExecutablePathChooser->setExpectedKind(Utils::PathChooser::File);
m_ui.localExecutablePathChooser->setPath(m_runConfig->localExecutableFilePath());
m_ui.remoteExeLineEdit->setText(m_runConfig->remoteExecutableFilePath());
m_ui.argsLineEdit->setText(Utils::QtcProcess::joinArgs(m_runConfig->arguments(),
Utils::OsTypeLinux));
m_ui.workingDirLineEdit->setText(m_runConfig->workingDirectory());
connect(m_ui.localExecutablePathChooser, SIGNAL(pathChanged(QString)),
SLOT(handleLocalExecutableChanged(QString)));
connect(m_ui.remoteExeLineEdit, SIGNAL(textEdited(QString)),
SLOT(handleRemoteExecutableChanged(QString)));
connect(m_ui.argsLineEdit, SIGNAL(textEdited(QString)),
SLOT(handleArgumentsChanged(QString)));
connect(m_ui.workingDirLineEdit, SIGNAL(textEdited(QString)),
SLOT(handleWorkingDirChanged(QString)));
}
private slots:
void handleLocalExecutableChanged(const QString &path) {
m_runConfig->setLocalExecutableFilePath(path.trimmed());
}
void handleRemoteExecutableChanged(const QString &path) {
m_runConfig->setRemoteExecutableFilePath(path.trimmed());
emit displayNameChanged(displayName());
}
void handleArgumentsChanged(const QString &arguments) {
m_runConfig->setArguments(Utils::QtcProcess::splitArgs(arguments.trimmed(),
Utils::OsTypeLinux));
}
void handleWorkingDirChanged(const QString &wd) {
m_runConfig->setWorkingDirectory(wd.trimmed());
}
private:
QString displayName() const { return m_runConfig->displayName(); }
RemoteLinuxCustomRunConfiguration * const m_runConfig;
Ui::RemoteLinuxCustomRunConfigurationWidget m_ui;
};
RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *parent)
: AbstractRemoteLinuxRunConfiguration(parent, runConfigId())
{
init();
}
RemoteLinuxCustomRunConfiguration::RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *parent,
RemoteLinuxCustomRunConfiguration *source)
: AbstractRemoteLinuxRunConfiguration(parent, source)
, m_localExecutable(source->m_localExecutable)
, m_remoteExecutable(source->m_remoteExecutable)
, m_arguments(source->m_arguments)
, m_workingDirectory(source->m_workingDirectory)
{
init();
}
bool RemoteLinuxCustomRunConfiguration::isConfigured() const
{
return !m_remoteExecutable.isEmpty();
}
bool RemoteLinuxCustomRunConfiguration::ensureConfigured(QString *errorMessage)
{
if (!isConfigured()) {
if (errorMessage) {
*errorMessage = tr("The remote executable must be set "
"in order to run a custom remote run configuration.");
}
return false;
}
return true;
}
QWidget *RemoteLinuxCustomRunConfiguration::createConfigurationWidget()
{
return new RemoteLinuxCustomRunConfigWidget(this);
}
Utils::OutputFormatter *RemoteLinuxCustomRunConfiguration::createOutputFormatter() const
{
return new QtSupport::QtOutputFormatter(target()->project());
}
Utils::Environment RemoteLinuxCustomRunConfiguration::environment() const
{
RemoteLinuxEnvironmentAspect *aspect = extraAspect<RemoteLinuxEnvironmentAspect>();
QTC_ASSERT(aspect, return Utils::Environment());
return aspect->environment();
}
void RemoteLinuxCustomRunConfiguration::setRemoteExecutableFilePath(const QString &executable)
{
m_remoteExecutable = executable;
setDisplayName(tr("Run \"%1\" on Linux Device").arg(executable));
}
Core::Id RemoteLinuxCustomRunConfiguration::runConfigId()
{
return "RemoteLinux.CustomRunConfig";
}
QString RemoteLinuxCustomRunConfiguration::runConfigDefaultDisplayName()
{
return tr("Custom Executable (on Remote Generic Linux Host)");
}
void RemoteLinuxCustomRunConfiguration::init()
{
setDefaultDisplayName(runConfigDefaultDisplayName());
addExtraAspect(new RemoteLinuxEnvironmentAspect(this));
}
static QString localExeKey()
{
return QLatin1String("RemoteLinux.CustomRunConfig.LocalExecutable");
}
static QString remoteExeKey()
{
return QLatin1String("RemoteLinux.CustomRunConfig.RemoteExecutable");
}
static QString argsKey()
{
return QLatin1String("RemoteLinux.CustomRunConfig.Arguments");
}
static QString workingDirKey()
{
return QLatin1String("RemoteLinux.CustomRunConfig.WorkingDirectory");
}
bool RemoteLinuxCustomRunConfiguration::fromMap(const QVariantMap &map)
{
if (!AbstractRemoteLinuxRunConfiguration::fromMap(map))
return false;
setLocalExecutableFilePath(map.value(localExeKey()).toString());
setRemoteExecutableFilePath(map.value(remoteExeKey()).toString());
setArguments(map.value(argsKey()).toStringList());
setWorkingDirectory(map.value(workingDirKey()).toString());
return true;
}
QVariantMap RemoteLinuxCustomRunConfiguration::toMap() const
{
QVariantMap map = AbstractRemoteLinuxRunConfiguration::toMap();
map.insert(localExeKey(), m_localExecutable);
map.insert(remoteExeKey(), m_remoteExecutable);
map.insert(argsKey(), m_arguments);
map.insert(workingDirKey(), m_workingDirectory);
return map;
}
} // namespace Internal
} // namespace RemoteLinux
#include "remotelinuxcustomrunconfiguration.moc"
/****************************************************************************
**
** Copyright (C) 2014 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 REMOTELINUXCUSTOMRUNCONFIGURATION_H
#define REMOTELINUXCUSTOMRUNCONFIGURATION_H
#include "abstractremotelinuxrunconfiguration.h"
namespace RemoteLinux {
namespace Internal {
class RemoteLinuxCustomRunConfiguration : public AbstractRemoteLinuxRunConfiguration
{
Q_OBJECT
public:
RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *parent);
RemoteLinuxCustomRunConfiguration(ProjectExplorer::Target *parent,
RemoteLinuxCustomRunConfiguration *source);
bool fromMap(const QVariantMap &map);
QVariantMap toMap() const;
bool isEnabled() const { return true; }
bool isConfigured() const;
bool ensureConfigured(QString *errorMessage);
QWidget *createConfigurationWidget();
Utils::OutputFormatter *createOutputFormatter() const;
QString localExecutableFilePath() const { return m_localExecutable; }
QString remoteExecutableFilePath() const { return m_remoteExecutable; }
QStringList arguments() const { return m_arguments; }
QString workingDirectory() const { return m_workingDirectory; }
Utils::Environment environment() const;
void setLocalExecutableFilePath(const QString &executable) { m_localExecutable = executable; }
void setRemoteExecutableFilePath(const QString &executable);
void setArguments(const QStringList &args) { m_arguments = args; }
void setWorkingDirectory(const QString &wd) { m_workingDirectory = wd; }
static Core::Id runConfigId();
static QString runConfigDefaultDisplayName();
private:
void init();
QString m_localExecutable;
QString m_remoteExecutable;
QStringList m_arguments;
QString m_workingDirectory;
};
} // namespace Internal
} // namespace RemoteLinux
#endif // Include guard.
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>RemoteLinux::Internal::RemoteLinuxCustomRunConfigurationWidget</class>
<widget class="QWidget" name="RemoteLinux::Internal::RemoteLinuxCustomRunConfigurationWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>445</width>
<height>120</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QFormLayout" name="formLayout">
<item row="0" column="0">
<widget class="QLabel" name="localExeLabel">
<property name="text">
<string>Local Executable:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="Utils::PathChooser" name="localExecutablePathChooser" native="true"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="remoteExeLabel">
<property name="text">
<string>Remote Executable:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QLineEdit" name="remoteExeLineEdit"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="argsLabel">
<property name="text">
<string>Arguments:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QLineEdit" name="argsLineEdit"/>
</item>
<item row="3" column="0">
<widget class="QLabel" name="workingDirLabel">
<property name="text">
<string>Working Directory:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QLineEdit" name="workingDirLineEdit"/>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>Utils::PathChooser</class>
<extends>QWidget</extends>
<header location="global">utils/pathchooser.h</header>
<container>1</container>
<slots>
<signal>editingFinished()</signal>
<signal>browsingFinished()</signal>
</slots>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
......@@ -32,7 +32,6 @@
#include "remotelinuxenvironmentaspect.h"
#include "remotelinuxrunconfigurationwidget.h"
#include <debugger/debuggerrunconfigurationaspect.h>
#include <projectexplorer/buildtargetinfo.h>
#include <projectexplorer/deploymentdata.h>
#include <projectexplorer/project.h>
......@@ -240,19 +239,6 @@ QString RemoteLinuxRunConfiguration::alternateRemoteExecutable() const
return d->alternateRemoteExecutable;
}
int RemoteLinuxRunConfiguration::portsUsedByDebuggers() const
{
int ports = 0;
Debugger::DebuggerRunConfigurationAspect *aspect
= extraAspect<Debugger::DebuggerRunConfigurationAspect>();
if (aspect->useQmlDebugger())
++ports;
if (aspect->useCppDebugger())
++ports;
return ports;
}
void RemoteLinuxRunConfiguration::handleBuildSystemDataUpdated()
{
emit deploySpecsChanged();
......
......@@ -83,8 +83,6 @@ public:
QVariantMap toMap() const;
int portsUsedByDebuggers() const;
QString projectFilePath() const;
static const char *IdPrefix;
......
......@@ -29,6 +29,7 @@
#include "remotelinuxrunconfigurationfactory.h"
#include "remotelinux_constants.h"
#include "remotelinuxcustomrunconfiguration.h"
#include "remotelinuxrunconfiguration.h"
#include <projectexplorer/buildtargetinfo.h>
......@@ -70,14 +71,17 @@ bool RemoteLinuxRunConfigurationFactory::canCreate(Target *parent, const Core::I
{
if (!canHandle(parent))
return false;
return !parent->applicationTargets().targetForProject(pathFromId(id)).isEmpty();
return id == RemoteLinuxCustomRunConfiguration::runConfigId()
|| !parent->applicationTargets().targetForProject(pathFromId(id)).isEmpty();
}
bool RemoteLinuxRunConfigurationFactory::canRestore(Target *parent, const QVariantMap &map) const
{
if (!canHandle(parent))
return false;
return idFromMap(map).name().startsWith(RemoteLinuxRunConfiguration::IdPrefix);
const Core::Id id = idFromMap(map);
return id == RemoteLinuxCustomRunConfiguration::runConfigId()
|| id.name().startsWith(RemoteLinuxRunConfiguration::IdPrefix);
}
bool RemoteLinuxRunConfigurationFactory::canClone(Target *parent, RunConfiguration *source) const
......@@ -96,24 +100,30 @@ QList<Core::Id> RemoteLinuxRunConfigurationFactory::availableCreationIds(Target
const Core::Id base = Core::Id(RemoteLinuxRunConfiguration::IdPrefix);
foreach (const BuildTargetInfo &bti, parent->applicationTargets().list)
result << base.withSuffix(bti.projectFilePath.toString());
result << RemoteLinuxCustomRunConfiguration::runConfigId();
return result;
}
QString RemoteLinuxRunConfigurationFactory::displayNameForId(const Core::Id id) const
{
if (id == RemoteLinuxCustomRunConfiguration::runConfigId())
return RemoteLinuxCustomRunConfiguration::runConfigDefaultDisplayName();
return QFileInfo(pathFromId(id)).completeBaseName()
+ QLatin1Char(' ') + tr("(on Remote Generic Linux Host)");
}
RunConfiguration *RemoteLinuxRunConfigurationFactory::doCreate(Target *parent, const Core::Id id)
{
if (id == RemoteLinuxCustomRunConfiguration::runConfigId())
return new RemoteLinuxCustomRunConfiguration(parent);
return new RemoteLinuxRunConfiguration(parent, id, pathFromId(id));
}
RunConfiguration *RemoteLinuxRunConfigurationFactory::doRestore(Target *parent,
const QVariantMap &map)
{
Q_UNUSED(map);
if (idFromMap(map) == RemoteLinuxCustomRunConfiguration::runConfigId())
return new RemoteLinuxCustomRunConfiguration(parent);
return new RemoteLinuxRunConfiguration(parent,
Core::Id(RemoteLinuxRunConfiguration::IdPrefix), QString());
}
......@@ -122,6 +132,8 @@ RunConfiguration *RemoteLinuxRunConfigurationFactory::clone(Target *parent,
RunConfiguration *source)
{
QTC_ASSERT(canClone(parent, source), return 0);
if (RemoteLinuxCustomRunConfiguration *old = qobject_cast<RemoteLinuxCustomRunConfiguration *>(source))
return new RemoteLinuxCustomRunConfiguration(parent, old);
RemoteLinuxRunConfiguration *old = static_cast<RemoteLinuxRunConfiguration *>(source);
return new RemoteLinuxRunConfiguration(parent, old);
}
......
......@@ -31,6 +31,7 @@
#include "remotelinuxanalyzesupport.h"
#include "remotelinuxdebugsupport.h"
#include "remotelinuxcustomrunconfiguration.h"
#include "remotelinuxrunconfiguration.h"
#include "remotelinuxruncontrol.h"
......@@ -69,8 +70,10 @@ bool RemoteLinuxRunControlFactory::canRun(RunConfiguration *runConfiguration, Ru
return false;
}
const QByteArray idStr = runConfiguration->id().name();
return runConfiguration->isEnabled() && idStr.startsWith(RemoteLinuxRunConfiguration::IdPrefix);
const Core::Id id = runConfiguration->id();
return runConfiguration->isEnabled()
&& (id == RemoteLinuxCustomRunConfiguration::runConfigId()
|| id.name().startsWith(RemoteLinuxRunConfiguration::IdPrefix));
}
RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, RunMode mode,
......@@ -78,7 +81,7 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Ru
{
QTC_ASSERT(canRun(runConfig, mode), return 0);
RemoteLinuxRunConfiguration *rc = qobject_cast<RemoteLinuxRunConfiguration *>(runConfig);
auto * const rc = qobject_cast<AbstractRemoteLinuxRunConfiguration *>(runConfig);
QTC_ASSERT(rc, return 0);
switch (mode) {
case NormalRunMode:
......@@ -94,6 +97,12 @@ RunControl *RemoteLinuxRunControlFactory::create(RunConfiguration *runConfig, Ru
*errorMessage = tr("Cannot debug: Not enough free ports available.");
return 0;
}
auto *crc = qobject_cast<RemoteLinuxCustomRunConfiguration *>(rc);
if (crc && crc->localExecutableFilePath().isEmpty()) {
*errorMessage = tr("Cannot debug: Local executable is not set.");
return 0;
}