Commit 9357b054 authored by Christian Kandeler's avatar Christian Kandeler
Browse files

RemoteLinux: Add "custom command" deployment step.

It might be useful for developers to run a command before or after
uploading or even have a remote command *be* the "deployment" step.
Also: Stop trying to display the "deployment possible" state in the
widget. It's generally hard to do that correctly and it also interferes
with thread safety.

Change-Id: I28aaf368a645ee14156a165c606dbc17c3063e82
Reviewed-on: http://codereview.qt-project.org/5469

Reviewed-by: default avatarChristian Kandeler <christian.kandeler@nokia.com>
parent ad9dd78a
......@@ -61,13 +61,14 @@ public:
RemoteLinuxDeployConfiguration *deployConfiguration() const;
virtual AbstractRemoteLinuxDeployService *deployService() const = 0;
virtual bool isDeploymentPossible(QString *whyNot = 0) const;
protected:
AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl, const QString &id);
AbstractRemoteLinuxDeployStep(ProjectExplorer::BuildStepList *bsl,
AbstractRemoteLinuxDeployStep *other);
virtual bool isDeploymentPossible(QString *whyNot = 0) const;
private slots:
void handleProgressMessage(const QString &message);
void handleErrorMessage(const QString &message);
......
......@@ -33,6 +33,7 @@
#include "genericdirectuploadstep.h"
#include "remotelinuxdeployconfigurationfactory.h"
#include "remotelinuxcustomcommanddeploymentstep.h"
#include "tarpackagecreationstep.h"
#include "uploadandinstalltarpackagestep.h"
......@@ -56,7 +57,7 @@ QStringList GenericRemoteLinuxDeployStepFactory::availableCreationIds(BuildStepL
if (!dc || dc->id() != RemoteLinuxDeployConfigurationFactory::genericDeployConfigurationId())
return ids;
ids << TarPackageCreationStep::stepId() << UploadAndInstallTarPackageStep::stepId()
<< GenericDirectUploadStep::stepId();
<< GenericDirectUploadStep::stepId() << RemoteLinuxCustomCommandDeploymentStep::stepId();
return ids;
}
......@@ -68,6 +69,8 @@ QString GenericRemoteLinuxDeployStepFactory::displayNameForId(const QString &id)
return UploadAndInstallTarPackageStep::displayName();
if (id == GenericDirectUploadStep::stepId())
return GenericDirectUploadStep::displayName();
if (id == RemoteLinuxCustomCommandDeploymentStep::stepId())
return RemoteLinuxCustomCommandDeploymentStep::stepDisplayName();
return QString();
}
......@@ -86,6 +89,8 @@ BuildStep *GenericRemoteLinuxDeployStepFactory::create(BuildStepList *parent, co
return new UploadAndInstallTarPackageStep(parent);
if (id == GenericDirectUploadStep::stepId())
return new GenericDirectUploadStep(parent, GenericDirectUploadStep::stepId());
if (id == RemoteLinuxCustomCommandDeploymentStep::stepId())
return new RemoteLinuxCustomCommandDeploymentStep(parent);
return 0;
}
......@@ -121,6 +126,8 @@ BuildStep *GenericRemoteLinuxDeployStepFactory::clone(BuildStepList *parent, Bui
return new UploadAndInstallTarPackageStep(parent, other);
if (GenericDirectUploadStep * const other = qobject_cast<GenericDirectUploadStep *>(product))
return new GenericDirectUploadStep(parent, other);
if (RemoteLinuxCustomCommandDeploymentStep * const other = qobject_cast<RemoteLinuxCustomCommandDeploymentStep *>(product))
return new RemoteLinuxCustomCommandDeploymentStep(parent, other);
return 0;
}
......
......@@ -55,7 +55,9 @@ HEADERS += \
deploymentsettingsassistant.h \
remotelinuxdeployconfigurationwidget.h \
profilesupdatedialog.h \
startgdbserverdialog.h
startgdbserverdialog.h \
remotelinuxcustomcommanddeployservice.h \
remotelinuxcustomcommanddeploymentstep.h
SOURCES += \
remotelinuxplugin.cpp \
......@@ -105,7 +107,9 @@ SOURCES += \
deploymentsettingsassistant.cpp \
remotelinuxdeployconfigurationwidget.cpp \
profilesupdatedialog.cpp \
startgdbserverdialog.cpp
startgdbserverdialog.cpp \
remotelinuxcustomcommanddeployservice.cpp \
remotelinuxcustomcommanddeploymentstep.cpp
FORMS += \
linuxdevicefactoryselectiondialog.ui \
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#include "remotelinuxcustomcommanddeploymentstep.h"
#include "remotelinuxcustomcommanddeployservice.h"
#include "remotelinuxdeploystepwidget.h"
#include <QtCore/QString>
#include <QtGui/QHBoxLayout>
#include <QtGui/QLabel>
#include <QtGui/QLineEdit>
#include <QtGui/QVBoxLayout>
using namespace ProjectExplorer;
namespace RemoteLinux {
namespace Internal {
namespace {
const char CommandLineKey[] = "RemoteLinuxCustomCommandDeploymentStep.CommandLine";
class ConfigWidget : public BuildStepConfigWidget
{
Q_OBJECT
public:
ConfigWidget(RemoteLinuxCustomCommandDeploymentStep *step) : m_step(step), m_widget(step)
{
QVBoxLayout * const mainLayout = new QVBoxLayout(this);
mainLayout->setMargin(0);
mainLayout->addWidget(&m_widget);
QHBoxLayout * const commandLineLayout = new QHBoxLayout;
mainLayout->addLayout(commandLineLayout);
QLabel * const commandLineLabel = new QLabel(tr("Command line:"));
commandLineLayout->addWidget(commandLineLabel);
m_commandLineEdit.setText(m_step->commandLine());
commandLineLayout->addWidget(&m_commandLineEdit);
connect(&m_widget, SIGNAL(updateSummary()), SIGNAL(updateSummary()));
connect(&m_widget, SIGNAL(updateAdditionalSummary()), SIGNAL(updateAdditionalSummary()));
connect(&m_commandLineEdit, SIGNAL(textEdited(QString)), SLOT(handleCommandLineEdited()));
}
private:
QString summaryText() const { return m_widget.summaryText(); }
QString additionalSummaryText() const { return m_widget.additionalSummaryText(); }
QString displayName() const { return m_widget.displayName(); }
Q_SLOT void handleCommandLineEdited() {
m_step->setCommandLine(m_commandLineEdit.text().trimmed());
}
RemoteLinuxCustomCommandDeploymentStep * const m_step;
QLineEdit m_commandLineEdit;
RemoteLinuxDeployStepWidget m_widget;
};
} // anonymous namespace
class RemoteLinuxCustomCommandDeploymentStepPrivate
{
public:
RemoteLinuxCustomCommandDeployservice service;
QString commandLine;
};
} // namespace Internal
using namespace Internal;
RemoteLinuxCustomCommandDeploymentStep::RemoteLinuxCustomCommandDeploymentStep(BuildStepList *bsl)
: AbstractRemoteLinuxDeployStep(bsl, stepId())
{
ctor();
}
RemoteLinuxCustomCommandDeploymentStep::RemoteLinuxCustomCommandDeploymentStep(BuildStepList *bsl,
RemoteLinuxCustomCommandDeploymentStep *other)
: AbstractRemoteLinuxDeployStep(bsl, other)
{
ctor();
}
RemoteLinuxCustomCommandDeploymentStep::~RemoteLinuxCustomCommandDeploymentStep()
{
delete d;
}
void RemoteLinuxCustomCommandDeploymentStep::ctor()
{
d = new RemoteLinuxCustomCommandDeploymentStepPrivate;
setDisplayName(stepDisplayName());
}
bool RemoteLinuxCustomCommandDeploymentStep::fromMap(const QVariantMap &map)
{
if (!AbstractRemoteLinuxDeployStep::fromMap(map))
return false;
d->commandLine = map.value(QLatin1String(CommandLineKey)).toString();
return true;
}
QVariantMap RemoteLinuxCustomCommandDeploymentStep::toMap() const
{
QVariantMap map = AbstractRemoteLinuxDeployStep::toMap();
map.insert(QLatin1String(CommandLineKey), d->commandLine);
return map;
}
void RemoteLinuxCustomCommandDeploymentStep::setCommandLine(const QString &commandLine)
{
d->commandLine = commandLine;
}
QString RemoteLinuxCustomCommandDeploymentStep::commandLine() const
{
return d->commandLine;
}
bool RemoteLinuxCustomCommandDeploymentStep::isDeploymentPossible(QString *whyNot) const
{
d->service.setCommandLine(d->commandLine);
return AbstractRemoteLinuxDeployStep::isDeploymentPossible(whyNot);
}
AbstractRemoteLinuxDeployService *RemoteLinuxCustomCommandDeploymentStep::deployService() const
{
return &d->service;
}
BuildStepConfigWidget *RemoteLinuxCustomCommandDeploymentStep::createConfigWidget()
{
return new ConfigWidget(this);
}
QString RemoteLinuxCustomCommandDeploymentStep::stepId()
{
return QLatin1String("RemoteLinuxCustomCommandDeploymentStep");
}
QString RemoteLinuxCustomCommandDeploymentStep::stepDisplayName()
{
return tr("Run custom remote command");
}
} // namespace RemoteLinux
#include "remotelinuxcustomcommanddeploymentstep.moc"
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#ifndef REMOTELINUXCUSTOMCOMMANDDEPLOYMENTSTEP_H
#define REMOTELINUXCUSTOMCOMMANDDEPLOYMENTSTEP_H
#include "abstractremotelinuxdeploystep.h"
namespace RemoteLinux {
namespace Internal {
class RemoteLinuxCustomCommandDeploymentStepPrivate;
} // namespace Internal
class REMOTELINUX_EXPORT RemoteLinuxCustomCommandDeploymentStep
: public AbstractRemoteLinuxDeployStep
{
Q_OBJECT
public:
RemoteLinuxCustomCommandDeploymentStep(ProjectExplorer::BuildStepList *bsl);
RemoteLinuxCustomCommandDeploymentStep(ProjectExplorer::BuildStepList *bsl,
RemoteLinuxCustomCommandDeploymentStep *other);
~RemoteLinuxCustomCommandDeploymentStep();
bool fromMap(const QVariantMap &map);
QVariantMap toMap() const;
void setCommandLine(const QString &commandLine);
QString commandLine() const;
static QString stepId();
static QString stepDisplayName();
protected:
bool isDeploymentPossible(QString *whyNot = 0) const;
private:
void ctor();
AbstractRemoteLinuxDeployService *deployService() const;
ProjectExplorer::BuildStepConfigWidget *createConfigWidget();
Internal::RemoteLinuxCustomCommandDeploymentStepPrivate *d;
};
} // namespace RemoteLinux
#endif // REMOTELINUXCUSTOMCOMMANDDEPLOYMENTSTEP_H
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#include "remotelinuxcustomcommanddeployservice.h"
#include <utils/qtcassert.h>
#include <utils/ssh/sshremoteprocessrunner.h>
#include <QtCore/QString>
using namespace Utils;
namespace RemoteLinux {
namespace Internal {
namespace {
enum State { Inactive, Running };
}
class RemoteLinuxCustomCommandDeployservicePrivate
{
public:
RemoteLinuxCustomCommandDeployservicePrivate() : state(Inactive) { }
QString commandLine;
State state;
SshRemoteProcessRunner::Ptr runner;
};
} // namespace Internal
using namespace Internal;
RemoteLinuxCustomCommandDeployservice::RemoteLinuxCustomCommandDeployservice(QObject *parent)
: AbstractRemoteLinuxDeployService(parent), d(new RemoteLinuxCustomCommandDeployservicePrivate)
{
}
RemoteLinuxCustomCommandDeployservice::~RemoteLinuxCustomCommandDeployservice()
{
delete d;
}
void RemoteLinuxCustomCommandDeployservice::setCommandLine(const QString &commandLine)
{
QTC_ASSERT(d->state == Inactive, return);
d->commandLine = commandLine;
}
bool RemoteLinuxCustomCommandDeployservice::isDeploymentPossible(QString *whyNot) const
{
QTC_ASSERT(d->state == Inactive, return false);
if (!AbstractRemoteLinuxDeployService::isDeploymentPossible(whyNot))
return false;
if (d->commandLine.isEmpty()) {
if (whyNot)
*whyNot = tr("No command line given.");
return false;
}
return true;
}
void RemoteLinuxCustomCommandDeployservice::doDeploy()
{
QTC_ASSERT(d->state == Inactive, handleDeploymentDone());
d->runner = SshRemoteProcessRunner::create(connection());
connect(d->runner.data(), SIGNAL(processOutputAvailable(QByteArray)),
SLOT(handleStdout(QByteArray)));
connect(d->runner.data(), SIGNAL(processErrorOutputAvailable(QByteArray)),
SLOT(handleStderr(QByteArray)));
connect(d->runner.data(), SIGNAL(processClosed(int)), SLOT(handleProcessClosed(int)));
emit progressMessage(tr("Starting remote command '%1'...").arg(d->commandLine));
d->state = Running;
d->runner->run(d->commandLine.toUtf8());
}
void RemoteLinuxCustomCommandDeployservice::stopDeployment()
{
QTC_ASSERT(d->state == Running, return);
disconnect(d->runner.data(), 0, this, 0);
d->runner->process()->closeChannel();
d->runner = SshRemoteProcessRunner::Ptr();
d->state = Inactive;
handleDeploymentDone();
}
void RemoteLinuxCustomCommandDeployservice::handleStdout(const QByteArray &output)
{
emit stdOutData(QString::fromUtf8(output));
}
void RemoteLinuxCustomCommandDeployservice::handleStderr(const QByteArray &output)
{
emit stdErrData(QString::fromUtf8(output));
}
void RemoteLinuxCustomCommandDeployservice::handleProcessClosed(int exitStatus)
{
QTC_ASSERT(d->state == Running, return);
if (exitStatus == SshRemoteProcess::FailedToStart) {
emit errorMessage(tr("Remote process failed to start."));
} else if (exitStatus == SshRemoteProcess::KilledBySignal) {
emit errorMessage(tr("Remote process was killed by a signal."));
} else if (d->runner->process()->exitCode() != 0) {
emit errorMessage(tr("Remote process finished with exit code %1.")
.arg(d->runner->process()->exitCode()));
} else {
emit progressMessage(tr("Remote command finished successfully."));
}
stopDeployment();
}
} // namespace RemoteLinux
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/
#ifndef REMOTELINUXCUSTOMCOMMANDDEPLOYSERVICE_H
#define REMOTELINUXCUSTOMCOMMANDDEPLOYSERVICE_H
#include "abstractremotelinuxdeployservice.h"
namespace RemoteLinux {
namespace Internal {
class RemoteLinuxCustomCommandDeployservicePrivate;
} // namespace Internal
class REMOTELINUX_EXPORT RemoteLinuxCustomCommandDeployservice
: public AbstractRemoteLinuxDeployService
{
Q_OBJECT
public:
explicit RemoteLinuxCustomCommandDeployservice(QObject *parent = 0);
~RemoteLinuxCustomCommandDeployservice();
void setCommandLine(const QString &commandLine);
protected:
bool isDeploymentNecessary() const { return true; }
bool isDeploymentPossible(QString *whyNot = 0) const;
void doDeviceSetup() { handleDeviceSetupDone(true); }
void stopDeviceSetup() { handleDeviceSetupDone(false); }
void doDeploy();
void stopDeployment();
private slots:
void handleStdout(const QByteArray &output);
void handleStderr(const QByteArray &output);
void handleProcessClosed(int exitStatus);
private:
Internal::RemoteLinuxCustomCommandDeployservicePrivate *d;
};
} // namespace RemoteLinux
#endif // REMOTELINUXCUSTOMCOMMANDDEPLOYSERVICE_H
......@@ -55,13 +55,8 @@ RemoteLinuxDeployStepWidget::RemoteLinuxDeployStepWidget(AbstractRemoteLinuxDepl
connect(list, SIGNAL(aboutToRemoveStep(int)),
SLOT(handleStepToBeRemoved(int)));
// TODO: Move this knowledge into the deploy step itself.
connect(qobject_cast<Qt4Project *>(m_step->target()->project()), SIGNAL(proParsingDone()),
SIGNAL(updateSummary()));
connect(m_step->deployConfiguration(), SIGNAL(currentDeviceConfigurationChanged()),
SIGNAL(updateSummary()));
connect(m_step->deployConfiguration()->deploymentInfo().data(), SIGNAL(modelReset()),
SIGNAL(updateSummary()));
}
RemoteLinuxDeployStepWidget::~RemoteLinuxDeployStepWidget()
......@@ -79,12 +74,6 @@ void RemoteLinuxDeployStepWidget::handleStepToBeRemoved(int step)
QString RemoteLinuxDeployStepWidget::summaryText() const
{
QString error;
if (!m_step->isDeploymentPossible(&error)) {
return QLatin1String("<font color=\"red\">")
+ tr("Cannot deploy: %1").arg(error)
+ QLatin1String("</font>");
}
return tr("<b>%1 using device</b>: %2").arg(m_step->displayName(),
RemoteLinuxUtils::deviceConfigurationName(m_step->deployConfiguration()->deviceConfiguration()));
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment