Commit 439b4561 authored by Christian Kandeler's avatar Christian Kandeler
Browse files

Start making the Maemo support more generic.

This includes:
    - decoupling deploy configurations from targets (Reviewed-by: dt)
    - adding a "Generic Linux" device type
    - splitting up the Maemo deployment step into small pieces that
      can be combined in different ways (and much more easily maintained)
    - adding a new version handler for pro.user files
      (Reviewed-by: Tobias Hunger)

Also:
  - Add and use an SSH manager class for easier connection sharing.
  - Make the SSH connection parameters a fixed attribute of the connection.
parent 9be947bd
......@@ -110,13 +110,14 @@ QTCREATOR_UTILS_EXPORT bool operator!=(const SshConnectionParameters &p1, const
// TODO: Mechanism for checking the host key. First connection to host: save, later: compare
SshConnection::Ptr SshConnection::create()
SshConnection::Ptr SshConnection::create(const SshConnectionParameters &serverInfo)
{
doStaticInitializationsIfNecessary();
return Ptr(new SshConnection);
return Ptr(new SshConnection(serverInfo));
}
SshConnection::SshConnection() : d(new Internal::SshConnectionPrivate(this))
SshConnection::SshConnection(const SshConnectionParameters &serverInfo)
: d(new Internal::SshConnectionPrivate(this, serverInfo))
{
connect(d, SIGNAL(connected()), this, SIGNAL(connected()),
Qt::QueuedConnection);
......@@ -128,9 +129,9 @@ SshConnection::SshConnection() : d(new Internal::SshConnectionPrivate(this))
SIGNAL(error(Utils::SshError)), Qt::QueuedConnection);
}
void SshConnection::connectToHost(const SshConnectionParameters &serverInfo)
void SshConnection::connectToHost()
{
d->connectToHost(serverInfo);
d->connectToHost();
}
void SshConnection::disconnectFromHost()
......@@ -188,14 +189,17 @@ QSharedPointer<SftpChannel> SshConnection::createSftpChannel()
namespace Internal {
SshConnectionPrivate::SshConnectionPrivate(SshConnection *conn)
SshConnectionPrivate::SshConnectionPrivate(SshConnection *conn,
const SshConnectionParameters &serverInfo)
: m_socket(new QTcpSocket(this)), m_state(SocketUnconnected),
m_sendFacility(m_socket),
m_channelManager(new SshChannelManager(m_sendFacility, this)),
m_connParams(SshConnectionParameters::DefaultProxy),
m_error(SshNoError), m_ignoreNextPacket(false), m_conn(conn)
m_connParams(serverInfo), m_error(SshNoError), m_ignoreNextPacket(false),
m_conn(conn)
{
setupPacketHandlers();
m_socket->setProxy(m_connParams.proxyType == SshConnectionParameters::DefaultProxy
? QNetworkProxy::DefaultProxy : QNetworkProxy::NoProxy);
m_timeoutTimer.setSingleShot(true);
m_keepAliveTimer.setSingleShot(true);
m_keepAliveTimer.setInterval(10000);
......@@ -581,7 +585,7 @@ void SshConnectionPrivate::sendKeepAlivePacket()
m_timeoutTimer.start(5000);
}
void SshConnectionPrivate::connectToHost(const SshConnectionParameters &serverInfo)
void SshConnectionPrivate::connectToHost()
{
m_incomingData.clear();
m_incomingPacket.reset();
......@@ -596,12 +600,9 @@ void SshConnectionPrivate::connectToHost(const SshConnectionParameters &serverIn
connect(m_socket, SIGNAL(disconnected()), this,
SLOT(handleSocketDisconnected()));
connect(&m_timeoutTimer, SIGNAL(timeout()), this, SLOT(handleTimeout()));
this->m_connParams = serverInfo;
m_state = SocketConnecting;
m_timeoutTimer.start(m_connParams.timeout * 1000);
m_socket->setProxy(m_connParams.proxyType == SshConnectionParameters::DefaultProxy
? QNetworkProxy::DefaultProxy : QNetworkProxy::NoProxy);
m_socket->connectToHost(serverInfo.host, serverInfo.port);
m_socket->connectToHost(m_connParams.host, m_connParams.port);
}
void SshConnectionPrivate::closeConnection(SshErrorCode sshError,
......
......@@ -78,9 +78,9 @@ public:
enum State { Unconnected, Connecting, Connected };
typedef QSharedPointer<SshConnection> Ptr;
static Ptr create();
static Ptr create(const SshConnectionParameters &serverInfo);
void connectToHost(const SshConnectionParameters &serverInfo);
void connectToHost();
void disconnectFromHost();
State state() const;
SshError errorState() const;
......@@ -98,11 +98,11 @@ signals:
void error(Utils::SshError);
private:
SshConnection();
SshConnection(const SshConnectionParameters &serverInfo);
Internal::SshConnectionPrivate *d;
};
} // namespace Internal
} // namespace Utils
#endif // SSHCONNECTION_H
......@@ -78,10 +78,11 @@ class SshConnectionPrivate : public QObject
Q_OBJECT
friend class Utils::SshConnection;
public:
SshConnectionPrivate(SshConnection *conn);
SshConnectionPrivate(SshConnection *conn,
const SshConnectionParameters &serverInfo);
~SshConnectionPrivate();
void connectToHost(const SshConnectionParameters &serverInfo);
void connectToHost();
void closeConnection(SshErrorCode sshError, SshError userError,
const QByteArray &serverErrorString, const QString &userErrorString);
QSharedPointer<SshRemoteProcess> createRemoteProcess(const QByteArray &command);
......@@ -150,7 +151,7 @@ private:
SshIncomingPacket m_incomingPacket;
SshSendFacility m_sendFacility;
SshChannelManager * const m_channelManager;
SshConnectionParameters m_connParams;
const SshConnectionParameters m_connParams;
QByteArray m_incomingData;
SshError m_error;
QString m_errorString;
......
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#include "sshconnectionmanager.h"
#include "sshconnection.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QList>
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>
#include <QtCore/QObject>
#include <QtCore/QThread>
#include <QtCore/QTimer>
namespace Utils {
namespace Internal {
struct ConnectionInfo
{
typedef QSharedPointer<ConnectionInfo> Ptr;
static ConnectionInfo::Ptr create(const SshConnection::Ptr &conn)
{
return Ptr(new ConnectionInfo(conn));
}
SshConnection::Ptr connection;
int refCount;
bool isConnecting;
private:
ConnectionInfo(const SshConnection::Ptr &conn)
: connection(conn), refCount(1), isConnecting(false) {}
};
class SshConnectionManagerPrivate : public QObject
{
Q_OBJECT
public:
static QMutex instanceMutex;
static SshConnectionManager &instance()
{
static SshConnectionManager manager;
return manager;
}
SshConnectionManagerPrivate()
{
moveToThread(QCoreApplication::instance()->thread());
connect(&m_cleanupTimer, SIGNAL(timeout()), SLOT(cleanup()));
m_cleanupTimer.start(5*60*1000);
}
ConnectionInfo::Ptr findConnection(const SshConnection::Ptr &connection)
{
foreach (const ConnectionInfo::Ptr &connInfo, m_connections) {
if (connInfo->connection == connection)
return connInfo;
}
return ConnectionInfo::Ptr();
}
QSharedPointer<SshConnection> acquireConnection(const SshConnectionParameters &sshParams)
{
QMutexLocker locker(&m_listMutex);
foreach (const ConnectionInfo::Ptr &connInfo, m_connections) {
const SshConnection::Ptr connection = connInfo->connection;
bool connectionUsable = false;
if (connection->state() == SshConnection::Connected
&& connection->connectionParameters() == sshParams) {
if (connInfo->refCount == 0) {
if (connection->thread() != QThread::currentThread()) {
QMetaObject::invokeMethod(this, "switchToCallerThread",
Qt::BlockingQueuedConnection,
Q_ARG(SshConnection *, connection.data()),
Q_ARG(QObject *, QThread::currentThread()));
}
connectionUsable = true;
} else if (connection->thread() == QThread::currentThread()) {
connectionUsable = true;
}
if (connectionUsable) {
++connInfo->refCount;
return connection;
}
}
}
ConnectionInfo::Ptr connInfo
= ConnectionInfo::create(SshConnection::create(sshParams));
m_connections << connInfo;
return connInfo->connection;
}
void releaseConnection(const SshConnection::Ptr &connection)
{
QMutexLocker locker(&m_listMutex);
ConnectionInfo::Ptr connInfo = findConnection(connection);
Q_ASSERT_X(connInfo, Q_FUNC_INFO, "Fatal: Unowned SSH Connection released.");
if (--connInfo->refCount == 0) {
connection->moveToThread(QCoreApplication::instance()->thread());
if (connection->state() != SshConnection::Connected)
m_connections.removeOne(connInfo);
}
}
private:
Q_INVOKABLE void switchToCallerThread(SshConnection *connection, QObject *threadObj)
{
connection->moveToThread(qobject_cast<QThread *>(threadObj));
}
Q_SLOT void cleanup()
{
QMutexLocker locker(&m_listMutex);
foreach (const ConnectionInfo::Ptr &connInfo, m_connections) {
if (connInfo->refCount == 0 &&
connInfo->connection->state() != SshConnection::Connected) {
m_connections.removeOne(connInfo);
}
}
}
// We expect the number of concurrently open connections to be small.
// If that turns out to not be the case, we can still use a data
// structure with faster access.
QList<ConnectionInfo::Ptr> m_connections;
QMutex m_listMutex;
QTimer m_cleanupTimer;
};
QMutex SshConnectionManagerPrivate::instanceMutex;
} // namespace Internal
SshConnectionManager &SshConnectionManager::instance()
{
QMutexLocker locker(&Internal::SshConnectionManagerPrivate::instanceMutex);
return Internal::SshConnectionManagerPrivate::instance();
}
SshConnectionManager::SshConnectionManager()
: d(new Internal::SshConnectionManagerPrivate)
{
}
SshConnectionManager::~SshConnectionManager()
{
}
SshConnection::Ptr SshConnectionManager::acquireConnection(const SshConnectionParameters &sshParams)
{
return d->acquireConnection(sshParams);
}
void SshConnectionManager::releaseConnection(const SshConnection::Ptr &connection)
{
d->releaseConnection(connection);
}
} // namespace Utils
#include "sshconnectionmanager.moc"
/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** No Commercial Usage
**
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
**************************************************************************/
#ifndef SSHCONNECTIONMANAGER_H
#define SSHCONNECTIONMANAGER_H
#include <utils/utils_global.h>
#include <QtCore/QScopedPointer>
#include <QtCore/QSharedPointer>
namespace Utils {
class SshConnection;
class SshConnectionParameters;
namespace Internal { class SshConnectionManagerPrivate; }
class QTCREATOR_UTILS_EXPORT SshConnectionManager
{
friend class Internal::SshConnectionManagerPrivate;
public:
static SshConnectionManager &instance();
QSharedPointer<SshConnection> acquireConnection(const SshConnectionParameters &sshParams);
void releaseConnection(const QSharedPointer<SshConnection> &connection);
private:
explicit SshConnectionManager();
virtual ~SshConnectionManager();
SshConnectionManager(const SshConnectionManager &);
SshConnectionManager &operator=(const SshConnectionManager &);
const QScopedPointer<Internal::SshConnectionManagerPrivate> d;
};
} // namespace Utils
#endif // SSHCONNECTIONMANAGER_H
......@@ -33,6 +33,8 @@
#include "sshremoteprocessrunner.h"
#include "sshconnectionmanager.h"
#define ASSERT_STATE(states) assertState(states, Q_FUNC_INFO)
/*!
......@@ -51,6 +53,7 @@ public:
QObject *parent);
SshRemoteProcessRunnerPrivate(const SshConnection::Ptr &connection,
QObject *parent);
~SshRemoteProcessRunnerPrivate();
void run(const QByteArray &command);
QByteArray command() const { return m_command; }
......@@ -79,29 +82,34 @@ private:
void assertState(State allowedState, const char *func);
State m_state;
bool m_needsRelease;
QByteArray m_command;
const SshConnectionParameters m_params;
};
SshRemoteProcessRunnerPrivate::SshRemoteProcessRunnerPrivate(const SshConnectionParameters &params,
QObject *parent)
: QObject(parent),
m_connection(SshConnection::create()),
m_connection(SshConnectionManager::instance().acquireConnection(params)),
m_state(Inactive),
m_params(params)
m_needsRelease(true)
{
}
SshRemoteProcessRunnerPrivate::SshRemoteProcessRunnerPrivate(const SshConnection::Ptr &connection,
QObject *parent)
: QObject(parent),
m_connection(connection),
m_state(Inactive),
m_params(connection->connectionParameters())
: QObject(parent),
m_connection(connection),
m_state(Inactive),
m_needsRelease(false)
{
}
SshRemoteProcessRunnerPrivate::~SshRemoteProcessRunnerPrivate()
{
setState(Inactive);
}
void SshRemoteProcessRunnerPrivate::run(const QByteArray &command)
{
ASSERT_STATE(Inactive);
......@@ -117,7 +125,7 @@ void SshRemoteProcessRunnerPrivate::run(const QByteArray &command)
} else {
connect(m_connection.data(), SIGNAL(connected()),
SLOT(handleConnected()));
m_connection->connectToHost(m_params);
m_connection->connectToHost();
}
}
......@@ -182,6 +190,8 @@ void SshRemoteProcessRunnerPrivate::setState(State state)
if (m_process)
disconnect(m_process.data(), 0, this, 0);
disconnect(m_connection.data(), 0, this, 0);
if (m_needsRelease)
SshConnectionManager::instance().releaseConnection(m_connection);
}
}
}
......
......@@ -76,7 +76,8 @@ SOURCES += $$PWD/environment.cpp \
$$PWD/ssh/sftpincomingpacket.cpp \
$$PWD/ssh/sftpdefs.cpp \
$$PWD/ssh/sftpchannel.cpp \
$$PWD/ssh/sshremoteprocessrunner.cpp
$$PWD/ssh/sshremoteprocessrunner.cpp \
$$PWD/ssh/sshconnectionmanager.cpp
win32 {
SOURCES += $$PWD/abstractprocess_win.cpp \
......@@ -169,6 +170,7 @@ HEADERS += $$PWD/environment.h \
$$PWD/ssh/sftpchannel.h \
$$PWD/ssh/sftpchannel_p.h \
$$PWD/ssh/sshremoteprocessrunner.h \
$$PWD/ssh/sshconnectionmanager.h \
$$PWD/settingsutils.h
FORMS += $$PWD/filewizardpage.ui \
......
......@@ -65,8 +65,7 @@ QString displayNameForId(const QString &id) {
CMakeTarget::CMakeTarget(CMakeProject *parent) :
ProjectExplorer::Target(parent, QLatin1String(DEFAULT_CMAKE_TARGET_ID)),
m_buildConfigurationFactory(new CMakeBuildConfigurationFactory(this)),
m_deployConfigurationFactory(new ProjectExplorer::DeployConfigurationFactory(this))
m_buildConfigurationFactory(new CMakeBuildConfigurationFactory(this))
{
setDefaultDisplayName(displayNameForId(id()));
setIcon(qApp->style()->standardIcon(QStyle::SP_ComputerIcon));
......@@ -102,11 +101,6 @@ CMakeBuildConfigurationFactory *CMakeTarget::buildConfigurationFactory() const
return m_buildConfigurationFactory;
}
ProjectExplorer::DeployConfigurationFactory *CMakeTarget::deployConfigurationFactory() const
{
return m_deployConfigurationFactory;
}
QString CMakeTarget::defaultBuildDirectory() const
{
return cmakeProject()->defaultBuildDirectory();
......@@ -228,7 +222,7 @@ CMakeTarget *CMakeTargetFactory::create(ProjectExplorer::Project *parent, const
t->addBuildConfiguration(bc);
t->addDeployConfiguration(t->deployConfigurationFactory()->create(t, ProjectExplorer::Constants::DEFAULT_DEPLOYCONFIGURATION_ID));
t->addDeployConfiguration(t->createDeployConfiguration(ProjectExplorer::Constants::DEFAULT_DEPLOYCONFIGURATION_ID));
t->updateRunConfigurations();
......
......@@ -64,7 +64,6 @@ public:
CMakeBuildConfiguration *activeBuildConfiguration() const;
CMakeBuildConfigurationFactory *buildConfigurationFactory() const;
ProjectExplorer::DeployConfigurationFactory *deployConfigurationFactory() const;
QString defaultBuildDirectory() const;
......@@ -76,7 +75,6 @@ private slots:
private:
CMakeBuildConfigurationFactory *m_buildConfigurationFactory;
ProjectExplorer::DeployConfigurationFactory *m_deployConfigurationFactory;
};
class CMakeTargetFactory : public ProjectExplorer::ITargetFactory
......
......@@ -37,12 +37,13 @@
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/ssh/sshconnectionmanager.h>
#include <QtCore/QFileInfo>
#include <ctype.h>
using namespace Core;
using namespace Utils;
namespace Debugger {
namespace Internal {
......@@ -91,11 +92,15 @@ void RemoteGdbProcess::realStart(const QString &cmd, const QStringList &args,
m_gdbOutput.clear();
m_errorOutput.clear();
m_inputToSend.clear();
m_conn = Utils::SshConnection::create();
connect(m_conn.data(), SIGNAL(connected()), this, SLOT(handleConnected()));
m_conn = SshConnectionManager::instance().acquireConnection(m_connParams);
connect(m_conn.data(), SIGNAL(error(Utils::SshError)), this,
SLOT(handleConnectionError()));
m_conn->connectToHost(m_connParams);
if (m_conn->state() == SshConnection::Connected) {
handleConnected();
} else {
connect(m_conn.data(), SIGNAL(connected()), this, SLOT(handleConnected()));
m_conn->connectToHost();
}
}
void RemoteGdbProcess::handleConnected()
......@@ -386,7 +391,8 @@ void RemoteGdbProcess::setState(State newState)
m_fifoCreator = Utils::SshRemoteProcess::Ptr();
}
disconnect(m_conn.data(), 0, this, 0);
m_conn->disconnectFromHost();
SshConnectionManager::instance().releaseConnection(m_conn);
m_conn.clear();
}
}
......
......@@ -58,8 +58,7 @@ using namespace GenericProjectManager::Internal;
GenericTarget::GenericTarget(GenericProject *parent) :
ProjectExplorer::Target(parent, QLatin1String(GENERIC_DESKTOP_TARGET_ID)),
m_buildConfigurationFactory(new GenericBuildConfigurationFactory(this)),
m_deployConfigurationFactory(new ProjectExplorer::DeployConfigurationFactory(this))