diff options
author | Tobias Hunger <tobias.hunger@nokia.com> | 2011-12-12 15:13:22 +0100 |
---|---|---|
committer | Tobias Hunger <tobias.hunger@nokia.com> | 2011-12-21 15:44:39 +0100 |
commit | 34ed3f295be2a2c7dae156f86517236f5b07804d (patch) | |
tree | 41a2a01384cc7a251ac244446009828b07f0d4a8 | |
parent | a92e38f47f7c54a0844e98e47d3a0f830b1c4c93 (diff) | |
download | qt-creator-34ed3f295be2a2c7dae156f86517236f5b07804d.tar.gz |
Remote Linux: Rework device testing
Allow for a set of tests to be defined. This simplifies the code for
the individual test to run and allows for a more flexible approach
to device testing.
MaddeDeviceTester is no longer needed due to that.
Change-Id: I77fd2d53246dec2d8c6b584d0c73cc1134d7f47d
Reviewed-by: Christian Kandeler <christian.kandeler@nokia.com>
Reviewed-by: Tobias Hunger <tobias.hunger@nokia.com>
22 files changed, 613 insertions, 703 deletions
diff --git a/src/plugins/madde/madde.pro b/src/plugins/madde/madde.pro index 2ff8bf148e..debbe8c880 100644 --- a/src/plugins/madde/madde.pro +++ b/src/plugins/madde/madde.pro @@ -50,7 +50,6 @@ HEADERS += \ maemorunconfiguration.h \ maddeuploadandinstallpackagesteps.h \ maemodeploybymountsteps.h \ - maddedevicetester.h \ maddedeviceconfigurationfactory.h \ SOURCES += \ @@ -96,7 +95,6 @@ SOURCES += \ maddedeviceconfigurationfactory.cpp \ maddeuploadandinstallpackagesteps.cpp \ maemodeploybymountsteps.cpp \ - maddedevicetester.cpp \ maemorunconfiguration.cpp FORMS += \ diff --git a/src/plugins/madde/maddedeviceconfigurationfactory.cpp b/src/plugins/madde/maddedeviceconfigurationfactory.cpp index 7dfff2837a..d1d43506c9 100644 --- a/src/plugins/madde/maddedeviceconfigurationfactory.cpp +++ b/src/plugins/madde/maddedeviceconfigurationfactory.cpp @@ -31,9 +31,9 @@ **************************************************************************/ #include "maddedeviceconfigurationfactory.h" -#include "maddedevicetester.h" #include "maemoconstants.h" #include "maemodeviceconfigwizard.h" +#include "maemoglobal.h" #include <remotelinux/linuxdevicetestdialog.h> #include <remotelinux/publickeydeploymentdialog.h> @@ -46,10 +46,8 @@ using namespace RemoteLinux; namespace Madde { namespace Internal { -namespace { -const char MaddeDeviceTestActionId[] = "Madde.DeviceTestAction"; + const char MaddeRemoteProcessesActionId[] = "Madde.RemoteProcessesAction"; -} // anonymous namespace MaddeDeviceConfigurationFactory::MaddeDeviceConfigurationFactory(QObject *parent) : ILinuxDeviceConfigurationFactory(parent) @@ -107,8 +105,27 @@ QDialog *MaddeDeviceConfigurationFactory::createDeviceAction(const QString &acti { Q_ASSERT(supportedDeviceActionIds().contains(actionId)); - if (actionId == QLatin1String(MaddeDeviceTestActionId)) - return new LinuxDeviceTestDialog(deviceConfig, new MaddeDeviceTester, parent); + if (actionId == QLatin1String(MaddeDeviceTestActionId)) { + QList<LinuxDeviceTester *> tests; + tests.append(new AuthenticationTester(deviceConfig)); + tests.append(new LinuxDeviceTester(deviceConfig, + tr("Checking kernel version..."), + QLatin1String("uname -rsm"))); + QString infoCmd = QLatin1String("dpkg-query -W -f " + "'${Package} ${Version} ${Status}\\n' 'libqt*' | " + "grep ' installed$' | cut -d' ' -f-2"); + if (deviceConfig->osType() == MeeGoOsType) + infoCmd = QLatin1String("rpm -qa 'libqt*' --queryformat '%{NAME} %{VERSION}\\n'"); + tests.append(new LinuxDeviceTester(deviceConfig, tr("Checking for Qt libraries..."), infoCmd)); + tests.append(new LinuxDeviceTester(deviceConfig, + tr("Checking for connectivity support..."), + QLatin1String("test -x ") + MaemoGlobal::devrootshPath())); + tests.append(new LinuxDeviceTester(deviceConfig, + tr("Checking for QML tooling support..."), + QLatin1String("test -d /usr/lib/qt4/plugins/qmltooling"))); + tests.append(new UsedPortsTester(deviceConfig)); + return new LinuxDeviceTestDialog(tests, parent); + } if (actionId == QLatin1String(MaddeRemoteProcessesActionId)) return new RemoteLinuxProcessesDialog(new GenericRemoteLinuxProcessList(deviceConfig), parent); if (actionId == QLatin1String(Constants::GenericDeployKeyToDeviceActionId)) diff --git a/src/plugins/madde/maddedeviceconfigurationfactory.h b/src/plugins/madde/maddedeviceconfigurationfactory.h index 38da1b9894..133b9b1970 100644 --- a/src/plugins/madde/maddedeviceconfigurationfactory.h +++ b/src/plugins/madde/maddedeviceconfigurationfactory.h @@ -37,6 +37,8 @@ namespace Madde { namespace Internal { +const char MaddeDeviceTestActionId[] = "Madde.DeviceTestAction"; + class MaddeDeviceConfigurationFactory : public RemoteLinux::ILinuxDeviceConfigurationFactory { Q_OBJECT diff --git a/src/plugins/madde/maddedevicetester.cpp b/src/plugins/madde/maddedevicetester.cpp deleted file mode 100644 index 0968f20695..0000000000 --- a/src/plugins/madde/maddedevicetester.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@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 qt-info@nokia.com. -** -**************************************************************************/ -#include "maddedevicetester.h" - -#include "maemoconstants.h" -#include "maemoglobal.h" - -#include <remotelinux/linuxdeviceconfiguration.h> -#include <utils/qtcassert.h> -#include <utils/ssh/sshremoteprocessrunner.h> - -#include <QtCore/QRegExp> - -using namespace RemoteLinux; -using namespace Utils; - -namespace Madde { -namespace Internal { -namespace { -const char QmlToolingDirectory[] = "/usr/lib/qt4/plugins/qmltooling"; -} // anonymous namespace - -MaddeDeviceTester::MaddeDeviceTester(QObject *parent) - : AbstractLinuxDeviceTester(parent), - m_genericTester(new GenericLinuxDeviceTester(this)), - m_state(Inactive), - m_processRunner(0) -{ -} - -MaddeDeviceTester::~MaddeDeviceTester() -{ -} - -void MaddeDeviceTester::testDevice(const LinuxDeviceConfiguration::ConstPtr &deviceConfiguration) -{ - QTC_ASSERT(m_state == Inactive, return); - - m_deviceConfiguration = deviceConfiguration; - m_result = TestSuccess; - - m_state = GenericTest; - connect(m_genericTester, SIGNAL(progressMessage(QString)), SIGNAL(progressMessage(QString))); - connect(m_genericTester, SIGNAL(errorMessage(QString)), SIGNAL(errorMessage(QString))); - connect(m_genericTester, SIGNAL(finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)), - SLOT(handleGenericTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult))); - m_genericTester->testDevice(deviceConfiguration); -} - -void MaddeDeviceTester::stopTest() -{ - QTC_ASSERT(m_state != Inactive, return); - - switch (m_state) { - case Inactive: - break; - case GenericTest: - m_genericTester->stopTest(); - break; - case QtTest: - case MadDeveloperTest: - case QmlToolingTest: - m_processRunner->cancel(); - break; - } - - m_result = TestFailure; - setFinished(); -} - -void MaddeDeviceTester::handleGenericTestFinished(TestResult result) -{ - QTC_ASSERT(m_state == GenericTest, return); - - if (result == TestFailure) { - m_result = TestFailure; - setFinished(); - return; - } - - if (!m_processRunner) - m_processRunner = new SshRemoteProcessRunner(this); - connect(m_processRunner, SIGNAL(connectionError()), SLOT(handleConnectionError())); - connect(m_processRunner, SIGNAL(processOutputAvailable(QByteArray)), - SLOT(handleStdout(QByteArray))); - connect(m_processRunner, SIGNAL(processErrorOutputAvailable(QByteArray)), - SLOT(handleStderr(QByteArray))); - connect(m_processRunner, SIGNAL(processClosed(int)), SLOT(handleProcessFinished(int))); - - QString qtInfoCmd; - if (m_deviceConfiguration->osType() == QLatin1String(MeeGoOsType)) { - qtInfoCmd = QLatin1String("rpm -qa 'libqt*' --queryformat '%{NAME} %{VERSION}\\n'"); - } else { - qtInfoCmd = QLatin1String("dpkg-query -W -f " - "'${Package} ${Version} ${Status}\n' 'libqt*' |grep ' installed$'"); - } - - emit progressMessage(tr("Checking for Qt libraries...")); - m_stdout.clear(); - m_stderr.clear(); - m_state = QtTest; - m_processRunner->run(qtInfoCmd.toUtf8(), m_genericTester->connection()->connectionParameters()); -} - -void MaddeDeviceTester::handleConnectionError() -{ - QTC_ASSERT(m_state != Inactive, return); - - emit errorMessage(tr("SSH connection error: %1\n") - .arg(m_processRunner->lastConnectionErrorString())); - m_result = TestFailure; - setFinished(); -} - -void MaddeDeviceTester::handleStdout(const QByteArray &data) -{ - QTC_ASSERT(m_state == QtTest || m_state == MadDeveloperTest || m_state == QmlToolingTest, - return); - - m_stdout += data; -} - -void MaddeDeviceTester::handleStderr(const QByteArray &data) -{ - QTC_ASSERT(m_state == QtTest || m_state == MadDeveloperTest || m_state == QmlToolingTest, - return); - - m_stderr += data; -} - -void MaddeDeviceTester::handleProcessFinished(int exitStatus) -{ - switch (m_state) { - case QtTest: - handleQtTestFinished(exitStatus); - break; - case MadDeveloperTest: - handleMadDeveloperTestFinished(exitStatus); - break; - case QmlToolingTest: - handleQmlToolingTestFinished(exitStatus); - break; - default: - qWarning("%s: Unexpected state %d.", Q_FUNC_INFO, m_state); - } -} - -void MaddeDeviceTester::handleQtTestFinished(int exitStatus) -{ - if (exitStatus != SshRemoteProcess::ExitedNormally - || m_processRunner->processExitCode() != 0) { - if (!m_stderr.isEmpty()) { - emit errorMessage(tr("Error checking for Qt libraries: %1\n") - .arg(QString::fromUtf8(m_stderr))); - } else { - emit errorMessage(tr("Error checking for Qt libraries.\n")); - } - - m_result = TestFailure; - } else { - emit progressMessage(processedQtLibsList()); - } - - m_stdout.clear(); - m_stderr.clear(); - - emit progressMessage(tr("Checking for connectivity support...")); - m_state = MadDeveloperTest; - m_processRunner->run(QString(QLatin1String("test -x") + MaemoGlobal::devrootshPath()).toUtf8(), - m_genericTester->connection()->connectionParameters()); -} - -void MaddeDeviceTester::handleMadDeveloperTestFinished(int exitStatus) -{ - if (exitStatus != SshRemoteProcess::ExitedNormally) { - if (!m_stderr.isEmpty()) { - emit errorMessage(tr("Error checking for connectivity tool: %1\n") - .arg(QString::fromUtf8(m_stderr))); - } else { - emit errorMessage(tr("Error checking for connectivity tool.\n")); - } - m_result = TestFailure; - } else if (m_processRunner->processExitCode() != 0) { - QString message = tr("Connectivity tool not installed on device. " - "Deployment currently not possible."); - if (m_deviceConfiguration->osType() == QLatin1String(HarmattanOsType)) { - message += tr("Please switch the device to developer mode " - "via Settings -> Security."); - } - emit errorMessage(message + QLatin1Char('\n')); - m_result = TestFailure; - } else { - emit progressMessage(tr("Connectivity tool present.\n")); - } - - if (m_deviceConfiguration->osType() != QLatin1String(HarmattanOsType)) { - setFinished(); - return; - } - - m_stdout.clear(); - m_stderr.clear(); - - emit progressMessage(tr("Checking for QML tooling support...")); - m_state = QmlToolingTest; - m_processRunner->run(QString(QLatin1String("test -d ") - + QLatin1String(QmlToolingDirectory)).toUtf8(), - m_genericTester->connection()->connectionParameters()); -} - -void MaddeDeviceTester::handleQmlToolingTestFinished(int exitStatus) -{ - if (exitStatus != SshRemoteProcess::ExitedNormally) { - if (!m_stderr.isEmpty()) { - emit errorMessage(tr("Error checking for QML tooling support: %1\n") - .arg(QString::fromUtf8(m_stderr))); - } else { - emit errorMessage(tr("Error checking for QML tooling support.\n")); - } - m_result = TestFailure; - } else if (m_processRunner->processExitCode() != 0) { - emit errorMessage(tr("Missing directory '%1'. You will not be able to do " - "QML debugging on this device.\n").arg(QmlToolingDirectory)); - m_result = TestFailure; - } else { - emit progressMessage(tr("QML tooling support present.\n")); - } - - setFinished(); -} - -QString MaddeDeviceTester::processedQtLibsList() -{ - QString unfilteredLibs = QString::fromUtf8(m_stdout); - QString filteredLibs; - QString patternString; - if (m_deviceConfiguration->osType() == QLatin1String(MeeGoOsType)) - patternString = QLatin1String("(libqt\\S+) ((\\d+)\\.(\\d+)\\.(\\d+))"); - else - patternString = QLatin1String("(\\S+) (\\S*(\\d+)\\.(\\d+)\\.(\\d+)\\S*) \\S+ \\S+ \\S+"); - const QRegExp packagePattern(patternString); - int index = packagePattern.indexIn(unfilteredLibs); - if (index == -1) - return tr("No Qt packages installed."); - - do { - filteredLibs += QLatin1String(" ") + packagePattern.cap(1) + QLatin1String(": ") - + packagePattern.cap(2) + QLatin1Char('\n'); - index = packagePattern.indexIn(unfilteredLibs, index + packagePattern.cap(0).length()); - } while (index != -1); - return filteredLibs; -} - - void MaddeDeviceTester::setFinished() -{ - m_state = Inactive; - disconnect(m_genericTester, 0, this, 0); - if (m_processRunner) - disconnect(m_processRunner, 0, this, 0); - emit finished(m_result); -} - -} // namespace Internal -} // namespace Madde diff --git a/src/plugins/madde/maddedevicetester.h b/src/plugins/madde/maddedevicetester.h deleted file mode 100644 index cb13fe9109..0000000000 --- a/src/plugins/madde/maddedevicetester.h +++ /dev/null @@ -1,85 +0,0 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@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 qt-info@nokia.com. -** -**************************************************************************/ -#ifndef MADDEDEVICETESTER_H -#define MADDEDEVICETESTER_H - -#include <remotelinux/linuxdevicetester.h> - -#include <QtCore/QByteArray> - -namespace Utils { -class SshRemoteProcessRunner; -} - -namespace Madde { -namespace Internal { - -class MaddeDeviceTester : public RemoteLinux::AbstractLinuxDeviceTester -{ - Q_OBJECT -public: - explicit MaddeDeviceTester(QObject *parent = 0); - ~MaddeDeviceTester(); - - void testDevice(const QSharedPointer<const RemoteLinux::LinuxDeviceConfiguration> &deviceConfiguration); - void stopTest(); - -private slots: - void handleGenericTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result); - void handleConnectionError(); - void handleStdout(const QByteArray &data); - void handleStderr(const QByteArray &data); - void handleProcessFinished(int exitStatus); - -private: - enum State { Inactive, GenericTest, QtTest, MadDeveloperTest, QmlToolingTest }; - - void handleQtTestFinished(int exitStatus); - void handleMadDeveloperTestFinished(int exitStatus); - void handleQmlToolingTestFinished(int exitStatus); - - QString processedQtLibsList(); - void setFinished(); - - RemoteLinux::GenericLinuxDeviceTester * const m_genericTester; - State m_state; - TestResult m_result; - Utils::SshRemoteProcessRunner *m_processRunner; - QSharedPointer<const RemoteLinux::LinuxDeviceConfiguration> m_deviceConfiguration; - QByteArray m_stdout; - QByteArray m_stderr; -}; - -} // namespace Internal -} // namespace Madde - -#endif // MADDEDEVICETESTER_H diff --git a/src/plugins/madde/maemodeploymentmounter.cpp b/src/plugins/madde/maemodeploymentmounter.cpp index 81cca42c61..648ed0cbf7 100644 --- a/src/plugins/madde/maemodeploymentmounter.cpp +++ b/src/plugins/madde/maemodeploymentmounter.cpp @@ -52,7 +52,7 @@ MaemoDeploymentMounter::MaemoDeploymentMounter(QObject *parent) : QObject(parent), m_state(Inactive), m_mounter(new MaemoRemoteMounter(this)), - m_portsGatherer(new RemoteLinuxUsedPortsGatherer(this)) + m_portsGatherer(0) { connect(m_mounter, SIGNAL(error(QString)), SLOT(handleMountError(QString))); connect(m_mounter, SIGNAL(mounted()), SLOT(handleMounted())); @@ -61,11 +61,6 @@ MaemoDeploymentMounter::MaemoDeploymentMounter(QObject *parent) SIGNAL(reportProgress(QString))); connect(m_mounter, SIGNAL(debugOutput(QString)), SIGNAL(debugOutput(QString))); - - connect(m_portsGatherer, SIGNAL(error(QString)), - SLOT(handlePortsGathererError(QString))); - connect(m_portsGatherer, SIGNAL(portListReady()), - SLOT(handlePortListReady())); } MaemoDeploymentMounter::~MaemoDeploymentMounter() {} @@ -142,7 +137,12 @@ void MaemoDeploymentMounter::handleUnmounted() break; case UnmountingCurrentDirs: setState(GatheringPorts); - m_portsGatherer->start(m_connection, m_devConf); + if (m_portsGatherer) + delete m_portsGatherer; + m_portsGatherer = new RemoteLinuxUsedPortsGatherer(m_devConf); + connect(m_portsGatherer, SIGNAL(finished(RemoteLinux::LinuxDeviceTester::TestResult)), + this, SLOT(handlePortListReady(RemoteLinux::LinuxDeviceTester::TestResult))); + m_portsGatherer->run(); break; case UnmountingCurrentMounts: setState(Inactive); @@ -166,16 +166,20 @@ void MaemoDeploymentMounter::handlePortsGathererError(const QString &errorMsg) emit error(errorMsg); } -void MaemoDeploymentMounter::handlePortListReady() +void MaemoDeploymentMounter::handlePortListReady(LinuxDeviceTester::TestResult result) { QTC_ASSERT(m_state == GatheringPorts || m_state == Inactive, return); if (m_state == Inactive) return; - setState(Mounting); - m_freePorts = MaemoGlobal::freePorts(m_devConf, m_buildConfig->qtVersion()); - m_mounter->mount(&m_freePorts, m_portsGatherer); + if (result == LinuxDeviceTester::TestFailure) { + handlePortsGathererError(tr("Failed to gather port information.")); + } else { + setState(Mounting); + m_freePorts = MaemoGlobal::freePorts(m_devConf, m_buildConfig->qtVersion()); + m_mounter->mount(&m_freePorts, m_portsGatherer); + } } void MaemoDeploymentMounter::handleMountError(const QString &errorMsg) diff --git a/src/plugins/madde/maemodeploymentmounter.h b/src/plugins/madde/maemodeploymentmounter.h index 0a6ac4a698..50a1690958 100644 --- a/src/plugins/madde/maemodeploymentmounter.h +++ b/src/plugins/madde/maemodeploymentmounter.h @@ -35,6 +35,7 @@ #include "maemomountspecification.h" +#include <remotelinux/linuxdevicetester.h> #include <remotelinux/portlist.h> #include <QtCore/QList> @@ -79,7 +80,7 @@ private slots: void handleUnmounted(); void handleMountError(const QString &errorMsg); void handlePortsGathererError(const QString &errorMsg); - void handlePortListReady(); + void handlePortListReady(RemoteLinux::LinuxDeviceTester::TestResult result); void handleConnectionError(); private: @@ -96,7 +97,7 @@ private: QSharedPointer<Utils::SshConnection> m_connection; QSharedPointer<const RemoteLinux::LinuxDeviceConfiguration> m_devConf; MaemoRemoteMounter * const m_mounter; - RemoteLinux::RemoteLinuxUsedPortsGatherer * const m_portsGatherer; + RemoteLinux::RemoteLinuxUsedPortsGatherer *m_portsGatherer; RemoteLinux::PortList m_freePorts; QList<MaemoMountSpecification> m_mountSpecs; const Qt4ProjectManager::Qt4BuildConfiguration *m_buildConfig; diff --git a/src/plugins/madde/maemodeviceconfigwizard.cpp b/src/plugins/madde/maemodeviceconfigwizard.cpp index a627912870..a4f6f65616 100644 --- a/src/plugins/madde/maemodeviceconfigwizard.cpp +++ b/src/plugins/madde/maemodeviceconfigwizard.cpp @@ -30,21 +30,23 @@ **************************************************************************/ #include "maemodeviceconfigwizard.h" +#include "maddedeviceconfigurationfactory.h" #include "ui_maemodeviceconfigwizardkeycreationpage.h" #include "ui_maemodeviceconfigwizardkeydeploymentpage.h" #include "ui_maemodeviceconfigwizardpreviouskeysetupcheckpage.h" #include "ui_maemodeviceconfigwizardreusekeyscheckpage.h" #include "ui_maemodeviceconfigwizardstartpage.h" -#include "maddedevicetester.h" #include "maemoconstants.h" #include "maemoglobal.h" +#include <extensionsystem/pluginmanager.h> #include <remotelinux/genericlinuxdeviceconfigurationwizardpages.h> #include <remotelinux/linuxdevicetestdialog.h> #include <remotelinux/remotelinuxutils.h> #include <remotelinux/sshkeydeployer.h> #include <utils/fileutils.h> +#include <utils/qtcassert.h> #include <utils/ssh/sshkeygenerator.h> #include <QtCore/QDir> @@ -582,8 +584,13 @@ LinuxDeviceConfiguration::Ptr MaemoDeviceConfigWizard::deviceConfiguration() d->wizardData.osType, d->wizardData.deviceType, PortList::fromString(freePortsSpec), sshParams); if (doTest) { - LinuxDeviceTestDialog dlg(devConf, new MaddeDeviceTester(this), this); - dlg.exec(); + MaddeDeviceConfigurationFactory *factory + = ExtensionSystem::PluginManager::instance()->getObject<MaddeDeviceConfigurationFactory>(); + QTC_ASSERT(factory, return LinuxDeviceConfiguration::Ptr(0)); + QDialog *dlg = factory->createDeviceAction(QLatin1String(MaddeDeviceTestActionId), devConf, 0); + QTC_ASSERT(dlg, return LinuxDeviceConfiguration::Ptr(0)); + dlg->exec(); + delete dlg; } return devConf; } diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp index 65f3653308..364b5a2792 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.cpp @@ -93,8 +93,15 @@ QDialog *GenericLinuxDeviceConfigurationFactory::createDeviceAction(const QStrin { Q_ASSERT(supportedDeviceActionIds().contains(actionId)); - if (actionId == QLatin1String(Constants::GenericTestDeviceActionId)) - return new LinuxDeviceTestDialog(deviceConfig, new GenericLinuxDeviceTester, parent); + if (actionId == QLatin1String(Constants::GenericTestDeviceActionId)) { + QList<LinuxDeviceTester *> tests; + tests.append(new AuthenticationTester(deviceConfig)); + tests.append(new LinuxDeviceTester(deviceConfig, + tr("Checking kernel version..."), + QLatin1String("uname -rsm"))); + tests.append(new UsedPortsTester(deviceConfig)); + return new LinuxDeviceTestDialog(tests, parent); + } if (actionId == QLatin1String(Constants::GenericRemoteProcessesActionId)) { return new RemoteLinuxProcessesDialog(new GenericRemoteLinuxProcessList(deviceConfig), parent); diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.h b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.h index c29f52435f..931ae931b9 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.h +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationfactory.h @@ -29,6 +29,7 @@ ** Nokia at qt-info@nokia.com. ** **************************************************************************/ + #ifndef GENERICLINUXDEVICECONFIGURATIONFACTORY_H #define GENERICLINUXDEVICECONFIGURATIONFACTORY_H diff --git a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp index bbb838d98d..8bba285cf4 100644 --- a/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp +++ b/src/plugins/remotelinux/genericlinuxdeviceconfigurationwizard.cpp @@ -30,12 +30,17 @@ **************************************************************************/ #include "genericlinuxdeviceconfigurationwizard.h" +#include "genericlinuxdeviceconfigurationfactory.h" #include "genericlinuxdeviceconfigurationwizardpages.h" #include "linuxdevicetestdialog.h" #include "linuxdevicetester.h" #include "portlist.h" #include "remotelinux_constants.h" +#include <extensionsystem/pluginmanager.h> + +#include <utils/qtcassert.h> + using namespace Utils; namespace RemoteLinux { @@ -87,8 +92,16 @@ LinuxDeviceConfiguration::Ptr GenericLinuxDeviceConfigurationWizard::deviceConfi LinuxDeviceConfiguration::Ptr devConf = LinuxDeviceConfiguration::create(d->setupPage.configurationName(), QLatin1String(Constants::GenericLinuxOsType), LinuxDeviceConfiguration::Hardware, PortList::fromString(QLatin1String("10000-10100")), sshParams); - LinuxDeviceTestDialog dlg(devConf, new GenericLinuxDeviceTester(this), this); - dlg.exec(); + + GenericLinuxDeviceConfigurationFactory *factory = + ExtensionSystem::PluginManager::instance()->getObject<GenericLinuxDeviceConfigurationFactory>(); + QTC_ASSERT(factory, return LinuxDeviceConfiguration::Ptr(0)); + + QDialog *dlg = factory->createDeviceAction(QLatin1String(Constants::GenericTestDeviceActionId), devConf, 0); + QTC_ASSERT(dlg, return LinuxDeviceConfiguration::Ptr(0)); + dlg->exec(); + delete dlg; + return devConf; } diff --git a/src/plugins/remotelinux/linuxdevicetestdialog.cpp b/src/plugins/remotelinux/linuxdevicetestdialog.cpp index dcb9cfbb4a..e19f2c0a9a 100644 --- a/src/plugins/remotelinux/linuxdevicetestdialog.cpp +++ b/src/plugins/remotelinux/linuxdevicetestdialog.cpp @@ -32,6 +32,9 @@ #include "linuxdevicetestdialog.h" #include "ui_linuxdevicetestdialog.h" +#include <utils/qtcassert.h> +#include <utils/ssh/sshconnectionmanager.h> + #include <QtGui/QBrush> #include <QtGui/QColor> #include <QtGui/QFont> @@ -40,34 +43,77 @@ namespace RemoteLinux { namespace Internal { -class LinuxDeviceTestDialogPrivate { + +class LinuxDeviceTestDialogPrivate +{ public: - LinuxDeviceTestDialogPrivate(AbstractLinuxDeviceTester *tester) - : deviceTester(tester), finished(false) + LinuxDeviceTestDialogPrivate(LinuxDeviceTestDialog *qptr, QList<LinuxDeviceTester *> &tester) + : deviceTests(tester), lastTest(0), currentTestPosition(-1), failCount(0), q(qptr) + { } + + ~LinuxDeviceTestDialogPrivate() + { + qDeleteAll(deviceTests); + } + + LinuxDeviceTester *currentTest() + { + return deviceTests.at(currentTestPosition); + } + + void runTest() + { + if (lastTest) + QObject::disconnect(lastTest, 0, q, 0); + + LinuxDeviceTester *curTest = currentTest(); + + QObject::connect(curTest, SIGNAL(progressMessage(QString)), + q, SLOT(handleProgressMessage(QString))); + QObject::connect(curTest, SIGNAL(errorMessage(QString)), + q, SLOT(handleErrorMessage(QString))); + QObject::connect(curTest, SIGNAL(finished(int)), + q, SLOT(handleTestFinished(int))); + + lastTest = curTest; + + q->addText(curTest->headLine(), QLatin1String("black"), true); + q->addText(curTest->commandLine(), QLatin1String("darkGray"), false); + curTest->run(); + } + + bool runNextTest() { + ++currentTestPosition; + if (currentTestPosition < deviceTests.count()) { + runTest(); + } else { + currentTestPosition = -1; + lastTest = 0; + } + + return currentTestPosition != -1; } Ui::LinuxDeviceTestDialog ui; - AbstractLinuxDeviceTester * const deviceTester; - bool finished; + QList<LinuxDeviceTester *> deviceTests; + LinuxDeviceTester *lastTest; + int currentTestPosition; + int failCount; + LinuxDeviceTestDialog *const q; }; } // namespace Internal -using namespace Internal; - -LinuxDeviceTestDialog::LinuxDeviceTestDialog(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration, - AbstractLinuxDeviceTester *deviceTester, QWidget *parent) - : QDialog(parent), d(new LinuxDeviceTestDialogPrivate(deviceTester)) +LinuxDeviceTestDialog::LinuxDeviceTestDialog(QList<LinuxDeviceTester *> tests, QWidget *parent) : + QDialog(parent), + d(new Internal::LinuxDeviceTestDialogPrivate(this, tests)) { + QTC_ASSERT(!tests.isEmpty(), return); + d->ui.setupUi(this); - d->deviceTester->setParent(this); - connect(d->deviceTester, SIGNAL(progressMessage(QString)), SLOT(handleProgressMessage(QString))); - connect(d->deviceTester, SIGNAL(errorMessage(QString)), SLOT(handleErrorMessage(QString))); - connect(d->deviceTester, SIGNAL(finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult)), - SLOT(handleTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult))); - d->deviceTester->testDevice(deviceConfiguration); + d->runNextTest(); } LinuxDeviceTestDialog::~LinuxDeviceTestDialog() @@ -77,14 +123,22 @@ LinuxDeviceTestDialog::~LinuxDeviceTestDialog() void LinuxDeviceTestDialog::reject() { - if (!d->finished) - d->deviceTester->stopTest(); + if (d->currentTestPosition >= 0) { + d->deviceTests.at(d->currentTestPosition)->cancel(); + disconnect(d->deviceTests.at(d->currentTestPosition), 0, this, 0); + } + QDialog::reject(); } void LinuxDeviceTestDialog::handleProgressMessage(const QString &message) { - addText(message, QLatin1String("black"), false); + QString tmp = QLatin1String(" ") + message; + if (tmp.endsWith('\n')) + tmp = tmp.left(tmp.count() - 1); + tmp.replace(QLatin1Char('\n'), QLatin1String("\n ")); + + addText(tmp, QLatin1String("black"), false); } void LinuxDeviceTestDialog::handleErrorMessage(const QString &message) @@ -92,15 +146,33 @@ void LinuxDeviceTestDialog::handleErrorMessage(const QString &message) addText(message, QLatin1String("red"), false); } -void LinuxDeviceTestDialog::handleTestFinished(AbstractLinuxDeviceTester::TestResult result) +void LinuxDeviceTestDialog::handleTestFinished(int result) { - d->finished = true; - d->ui.buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Close")); + bool abortRun = false; + if (result == LinuxDeviceTester::TestSuccess) { + addText(tr("Ok.\n"), QLatin1String("black"), true); + } else if (result == LinuxDeviceTester::TestCriticalFailure) { + addText(tr("Critical device test failure, aborting.\n"), QLatin1String("red"), true); + ++d->failCount; + abortRun = true; + } else { + addText(tr("Device test failed.\n"), QLatin1String("red"), true); + ++d->failCount; + } + + if (abortRun || !d->runNextTest()) { + if (d->failCount == 0 && !abortRun) { + addText(tr("All device tests finished successfully.\n"), QLatin1String("blue"), true); + } else { + if (!abortRun) { + //: %1: number of failed tests, %2 total tests + addText(tr("%1 device tests of %2 failed.\n").arg(d->failCount).arg(d->deviceTests.count()), + QLatin1String("red"), true); + } + } - if (result == AbstractLinuxDeviceTester::TestSuccess) - addText(tr("Device test finished successfully."), QLatin1String("blue"), true); - else - addText(tr("Device test failed."), QLatin1String("red"), true); + d->ui.buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Close")); + } } void LinuxDeviceTestDialog::addText(const QString &text, const QString &color, bool bold) diff --git a/src/plugins/remotelinux/linuxdevicetestdialog.h b/src/plugins/remotelinux/linuxdevicetestdialog.h index ec8becdce9..6aa150bcc3 100644 --- a/src/plugins/remotelinux/linuxdevicetestdialog.h +++ b/src/plugins/remotelinux/linuxdevicetestdialog.h @@ -47,9 +47,8 @@ class REMOTELINUX_EXPORT LinuxDeviceTestDialog : public QDialog Q_OBJECT public: - // Note: The dialog takes ownership of deviceTester - explicit LinuxDeviceTestDialog(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration, - AbstractLinuxDeviceTester * deviceTester, QWidget *parent = 0); + // Note: The dialog takes ownership of deviceTests + LinuxDeviceTestDialog(QList<LinuxDeviceTester *> tests, QWidget *parent = 0); ~LinuxDeviceTestDialog(); void reject(); @@ -57,12 +56,14 @@ public: private slots: void handleProgressMessage(const QString &message); void handleErrorMessage(const QString &message); - void handleTestFinished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result); + void handleTestFinished(int result); private: void addText(const QString &text, const QString &color, bool bold); - Internal::LinuxDeviceTestDialogPrivate * const d; + Internal::LinuxDeviceTestDialogPrivate *const d; + + friend class Internal::LinuxDeviceTestDialogPrivate; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index cd9c465174..5d2f4b2c9a 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -35,164 +35,99 @@ #include "remotelinuxusedportsgatherer.h" #include <utils/qtcassert.h> -#include <utils/ssh/sshremoteprocess.h> +#include <utils/ssh/sshremoteprocessrunner.h> #include <utils/ssh/sshconnection.h> +#include <utils/ssh/sshconnectionmanager.h> using namespace Utils; namespace RemoteLinux { namespace Internal { -namespace { -enum State { Inactive, Connecting, RunningUname, TestingPorts }; - -} // anonymous namespace - -class GenericLinuxDeviceTesterPrivate +class LinuxDeviceTesterPrivate { public: - GenericLinuxDeviceTesterPrivate() : state(Inactive) {} + LinuxDeviceTesterPrivate() + { } - LinuxDeviceConfiguration::ConstPtr deviceConfiguration; - SshConnection::Ptr connection; - SshRemoteProcess::Ptr process; - RemoteLinuxUsedPortsGatherer portsGatherer; - State state; + QString headLine; }; } // namespace Internal using namespace Internal; -AbstractLinuxDeviceTester::AbstractLinuxDeviceTester(QObject *parent) : QObject(parent) +LinuxDeviceTester::LinuxDeviceTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration, + const QString &headline, const QString &commandline) : + SimpleRunner(deviceConfiguration, commandline), + d(new LinuxDeviceTesterPrivate) { + d->headLine = headline; } - -GenericLinuxDeviceTester::GenericLinuxDeviceTester(QObject *parent) - : AbstractLinuxDeviceTester(parent), d(new GenericLinuxDeviceTesterPrivate) +LinuxDeviceTester::~LinuxDeviceTester() { + delete d; } -GenericLinuxDeviceTester::~GenericLinuxDeviceTester() +QString LinuxDeviceTester::headLine() const { - delete d; + return d->headLine; } -void GenericLinuxDeviceTester::testDevice(const LinuxDeviceConfiguration::ConstPtr &deviceConfiguration) +int LinuxDeviceTester::processFinished(int exitStatus) { - QTC_ASSERT(d->state == Inactive, return); - - d->deviceConfiguration = deviceConfiguration; - d->connection = SshConnection::create(deviceConfiguration->sshParameters()); - connect(d->connection.data(), SIGNAL(connected()), SLOT(handleConnected())); - connect(d->connection.data(), SIGNAL(error(Utils::SshError)), - SLOT(handleConnectionFailure())); - - emit progressMessage(tr("Connecting to host...")); - d->state = Connecting; - d->connection->connectToHost(); + return SimpleRunner::processFinished(exitStatus) == 0 ? TestSuccess : TestFailure; } -void GenericLinuxDeviceTester::stopTest() +AuthenticationTester::AuthenticationTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration) : + LinuxDeviceTester(deviceConfiguration, tr("Checking authentication data..."), + QLatin1String("echo \"Success!\"")) { - QTC_ASSERT(d->state != Inactive, return); - - switch (d->state) { - case Connecting: - d->connection->disconnectFromHost(); - break; - case TestingPorts: - d->portsGatherer.stop(); - break; - case RunningUname: - d->process->close(); - break; - case Inactive: - break; - } - - setFinished(TestFailure); + SshConnectionManager::instance().forceNewConnection(sshParameters()); } -SshConnection::Ptr GenericLinuxDeviceTester::connection() const +void AuthenticationTester::handleStdOutput(const QByteArray &data) { - return d->connection; + m_authenticationSucceded = data.contains("Success!"); + LinuxDeviceTester::handleStdOutput(data); } -void GenericLinuxDeviceTester::handleConnected() +int AuthenticationTester::processFinished(int exitStatus) { - QTC_ASSERT(d->state == Connecting, return); - - d->process = d->connection->createRemoteProcess("uname -rsm"); - connect(d->process.data(), SIGNAL(closed(int)), SLOT(handleProcessFinished(int))); - - emit progressMessage("Checking kernel version..."); - d->state = RunningUname; - d->process->start(); + return LinuxDeviceTester::processFinished(exitStatus) == TestSuccess + && m_authenticationSucceded ? TestSuccess : TestCriticalFailure; } -void GenericLinuxDeviceTester::handleConnectionFailure() +UsedPortsTester::UsedPortsTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration) : + LinuxDeviceTester(deviceConfiguration, tr("Checking for available ports..."), QString()), + gatherer(new RemoteLinuxUsedPortsGatherer(deviceConfiguration)) { - QTC_ASSERT(d->state != Inactive, return); - - emit errorMessage(tr("SSH connection failure: %1\n").arg(d->connection->errorString())); - setFinished(TestFailure); + connect(gatherer, SIGNAL(aboutToStart()), this, SIGNAL(aboutToStart())); + connect(gatherer, SIGNAL(errorMessage(QString)), this, SIGNAL(errorMessage(QString))); + connect(gatherer, SIGNAL(finished(int)), this, SIGNAL(finished(int))); + connect(gatherer, SIGNAL(progressMessage(QString)), this, SIGNAL(progressMessage(QString))); + connect(gatherer, SIGNAL(started()), this, SIGNAL(started())); } -void GenericLinuxDeviceTester::handleProcessFinished(int exitStatus) +UsedPortsTester::~UsedPortsTester() { - QTC_ASSERT(d->state == RunningUname, return); - - if (exitStatus != SshRemoteProcess::ExitedNormally || d->process->exitCode() != 0) { - const QByteArray stderrOutput = d->process->readAllStandardError(); - if (!stderrOutput.isEmpty()) - emit errorMessage(tr("uname failed: %1\n").arg(QString::fromUtf8(stderrOutput))); - else - emit errorMessage(tr("uname failed.\n")); - } else { - emit progressMessage(QString::fromUtf8(d->process->readAllStandardOutput())); - } - - connect(&d->portsGatherer, SIGNAL(error(QString)), SLOT(handlePortsGatheringError(QString))); - connect(&d->portsGatherer, SIGNAL(portListReady()), SLOT(handlePortListReady())); - - emit progressMessage(tr("Checking if specified ports are available...")); - d->state = TestingPorts; - d->portsGatherer.start(d->connection, d->deviceConfiguration); + delete gatherer; } -void GenericLinuxDeviceTester::handlePortsGatheringError(const QString &message) +QString UsedPortsTester::commandLine() const { - QTC_ASSERT(d->state == TestingPorts, return); - - emit errorMessage(tr("Error gathering ports: %1\n").arg(message)); - setFinished(TestFailure); + return gatherer->commandLine(); } -void GenericLinuxDeviceTester::handlePortListReady() +void UsedPortsTester::run() { - QTC_ASSERT(d->state == TestingPorts, return); - - if (d->portsGatherer.usedPorts().isEmpty()) { - emit progressMessage("All specified ports are available.\n"); - } else { - QString portList; - foreach (const int port, d->portsGatherer.usedPorts()) - portList += QString::number(port) + QLatin1String(", "); - portList.remove(portList.count() - 2, 2); - emit errorMessage(tr("The following specified ports are currently in use: %1\n") - .arg(portList)); - } - setFinished(TestSuccess); + gatherer->run(); } -void GenericLinuxDeviceTester::setFinished(TestResult result) +void UsedPortsTester::cancel() { - d->state = Inactive; - disconnect(d->connection.data(), 0, this, 0); - disconnect(&d->portsGatherer, 0, this, 0); - emit finished(result); + gatherer->cancel(); } } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/linuxdevicetester.h b/src/plugins/remotelinux/linuxdevicetester.h index 1a469af806..7c1df21eae 100644 --- a/src/plugins/remotelinux/linuxdevicetester.h +++ b/src/plugins/remotelinux/linuxdevicetester.h @@ -34,65 +34,79 @@ #include "remotelinux_export.h" +#include "simplerunner.h" + +#include <utils/ssh/sshconnection.h> + #include <QtCore/QObject> #include <QtCore/QSharedPointer> QT_FORWARD_DECLARE_CLASS(QString) -namespace Utils { -class SshConnection; -} - namespace RemoteLinux { class LinuxDeviceConfiguration; +class RemoteLinuxUsedPortsGatherer; namespace Internal { -class GenericLinuxDeviceTesterPrivate; +class LinuxDeviceTesterPrivate; } // namespace Internal -class REMOTELINUX_EXPORT AbstractLinuxDeviceTester : public QObject +// ----------------------------------------------------------------------- +// LinuxDeviceTester: +// ----------------------------------------------------------------------- + +class REMOTELINUX_EXPORT LinuxDeviceTester : public SimpleRunner { Q_OBJECT - Q_DISABLE_COPY(AbstractLinuxDeviceTester) + public: - enum TestResult { TestSuccess, TestFailure }; + enum TestResult { TestSuccess = 0, TestFailure, TestCriticalFailure }; - virtual void testDevice(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration) = 0; - virtual void stopTest() = 0; + LinuxDeviceTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration, + const QString &headline, const QString &commandline); + ~LinuxDeviceTester(); -signals: - void progressMessage(const QString &message); - void errorMessage(const QString &message); - void finished(RemoteLinux::AbstractLinuxDeviceTester::TestResult result); + virtual QString headLine() const; protected: - explicit AbstractLinuxDeviceTester(QObject *parent = 0); -}; + int processFinished(int exitStatus); +private: + Internal::LinuxDeviceTesterPrivate *const d; +}; -class REMOTELINUX_EXPORT GenericLinuxDeviceTester : public AbstractLinuxDeviceTester +class REMOTELINUX_EXPORT AuthenticationTester : public LinuxDeviceTester { Q_OBJECT -public: - explicit GenericLinuxDeviceTester(QObject *parent = 0); - ~GenericLinuxDeviceTester(); - void testDevice(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration); - void stopTest(); +public: + AuthenticationTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration); - QSharedPointer<Utils::SshConnection> connection() const; +protected slots: + void handleStdOutput(const QByteArray &data); -private slots: - void handleConnected(); - void handleConnectionFailure(); - void handleProcessFinished(int exitStatus); - void handlePortsGatheringError(const QString &message); - void handlePortListReady(); +protected: + int processFinished(int exitStatus); private: - void setFinished(TestResult result); + bool m_authenticationSucceded; +}; + +class REMOTELINUX_EXPORT UsedPortsTester : public LinuxDeviceTester +{ + Q_OBJECT - Internal::GenericLinuxDeviceTesterPrivate * const d; +public: + UsedPortsTester(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration); + ~UsedPortsTester(); + + QString commandLine() const; + + void run(); + void cancel(); + +private: + RemoteLinuxUsedPortsGatherer *const gatherer; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinux.pro b/src/plugins/remotelinux/remotelinux.pro index 00990e0252..8852d46111 100644 --- a/src/plugins/remotelinux/remotelinux.pro +++ b/src/plugins/remotelinux/remotelinux.pro @@ -9,6 +9,7 @@ HEADERS += \ embeddedlinuxtargetfactory.h \ embeddedlinuxqtversion.h \ embeddedlinuxqtversionfactory.h \ + simplerunner.h \ remotelinuxplugin.h \ remotelinux_export.h \ linuxdeviceconfiguration.h \ @@ -68,6 +69,7 @@ SOURCES += \ embeddedlinuxtargetfactory.cpp \ embeddedlinuxqtversion.cpp \ embeddedlinuxqtversionfactory.cpp \ + simplerunner.cpp \ remotelinuxplugin.cpp \ linuxdeviceconfiguration.cpp \ linuxdeviceconfigurations.cpp \ diff --git a/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp b/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp index c38b29444d..d9a77c4e81 100644 --- a/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp +++ b/src/plugins/remotelinux/remotelinuxapplicationrunner.cpp @@ -62,7 +62,8 @@ class AbstractRemoteLinuxApplicationRunnerPrivate { public: AbstractRemoteLinuxApplicationRunnerPrivate(const RemoteLinuxRunConfiguration *runConfig) - : devConfig(runConfig->deviceConfig()), + : portsGatherer(runConfig->deviceConfig()), + devConfig(runConfig->deviceConfig()), remoteExecutable(runConfig->remoteExecutableFilePath()), appArguments(runConfig->arguments()), commandPrefix(runConfig->commandPrefix()), @@ -167,7 +168,7 @@ void AbstractRemoteLinuxApplicationRunner::stop() emit remoteProcessFinished(InvalidExitCode); break; case GatheringPorts: - d->portsGatherer.stop(); + d->portsGatherer.cancel(); setInactive(); emit remoteProcessFinished(InvalidExitCode); break; @@ -307,7 +308,7 @@ void AbstractRemoteLinuxApplicationRunner::handleRemoteProcessFinished(int exitS void AbstractRemoteLinuxApplicationRunner::setInactive() { - d->portsGatherer.stop(); + d->portsGatherer.cancel(); if (d->connection) { disconnect(d->connection.data(), 0, this, 0); SshConnectionManager::instance().releaseConnection(d->connection); @@ -422,7 +423,7 @@ void AbstractRemoteLinuxApplicationRunner::handleInitialCleanupDone(bool success } d->state = GatheringPorts; - d->portsGatherer.start(d->connection, d->devConfig); + d->portsGatherer.run(); } void AbstractRemoteLinuxApplicationRunner::handleInitializationsDone(bool success) diff --git a/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp b/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp index a239edfae0..e0d201ddde 100644 --- a/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp +++ b/src/plugins/remotelinux/remotelinuxusedportsgatherer.cpp @@ -33,6 +33,7 @@ #include "linuxdeviceconfiguration.h" #include "portlist.h" +#include <utils/ssh/sshconnectionmanager.h> #include <utils/ssh/sshremoteprocessrunner.h> #include <QtCore/QString> @@ -45,23 +46,32 @@ namespace Internal { class RemoteLinuxUsedPortsGathererPrivate { public: - RemoteLinuxUsedPortsGathererPrivate() : running(false) {} + RemoteLinuxUsedPortsGathererPrivate() + { } - SshRemoteProcessRunner procRunner; PortList portsToCheck; QList<int> usedPorts; - QByteArray remoteStdout; - QByteArray remoteStderr; - bool running; // TODO: Redundant due to being in sync with procRunner? + QByteArray keepSake; }; } // namespace Internal using namespace Internal; -RemoteLinuxUsedPortsGatherer::RemoteLinuxUsedPortsGatherer(QObject *parent) : - QObject(parent), d(new RemoteLinuxUsedPortsGathererPrivate) +RemoteLinuxUsedPortsGatherer::RemoteLinuxUsedPortsGatherer( + const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration) : + SimpleRunner(deviceConfiguration, + // Match + // 0: 0100007F:706E 00000000:0000 0A 00000000:00000000 00:00000000 00000000 0 0 8141 1 ce498900 300 0 0 2 -1 + // and report ^^^^ this local port number + QLatin1String("FILE=/proc/net/tcp ; " + "echo \"$SSH_CONNECTION\" | grep : > /dev/null && FILE=/proc/net/tcp6 ; " + "sed 's/^\\s\\+[0-9a-fA-F]\\+:\\s\\+[0-9a-fA-F]\\+:\\([0-9a-fA-F]\\+\\)\\s.*$/\\1/' $FILE")), + d(new RemoteLinuxUsedPortsGathererPrivate) { + d->portsToCheck = deviceConfiguration->freePorts(); + + connect(this, SIGNAL(aboutToStart()), this, SLOT(cleanup())); } RemoteLinuxUsedPortsGatherer::~RemoteLinuxUsedPortsGatherer() @@ -69,48 +79,6 @@ RemoteLinuxUsedPortsGatherer::~RemoteLinuxUsedPortsGatherer() delete d; } -void RemoteLinuxUsedPortsGatherer::start(const Utils::SshConnection::Ptr &connection, - const LinuxDeviceConfiguration::ConstPtr &devConf) -{ - if (d->running) - qWarning("Unexpected call of %s in running state", Q_FUNC_INFO); - d->portsToCheck = devConf->freePorts(); - d->usedPorts.clear(); - d->remoteStdout.clear(); - d->remoteStderr.clear(); - connect(&d->procRunner, SIGNAL(connectionError()), SLOT(handleConnectionError())); - connect(&d->procRunner, SIGNAL(processClosed(int)), SLOT(handleProcessClosed(int))); - connect(&d->procRunner, SIGNAL(processOutputAvailable(QByteArray)), - SLOT(handleRemoteStdOut(QByteArray))); - connect(&d->procRunner, SIGNAL(processErrorOutputAvailable(QByteArray)), - SLOT(handleRemoteStdErr(QByteArray))); - QString procFilePath; - int addressLength; - if (connection->ipProtocolVersion() == QAbstractSocket::IPv4Protocol) { - procFilePath = QLatin1String("/proc/net/tcp"); - addressLength = 8; - } else { - procFilePath = QLatin1String("/proc/net/tcp6"); - addressLength = 32; - } - const QString command = QString::fromLocal8Bit("sed " - "'s/.*: [[:xdigit:]]\\{%1\\}:\\([[:xdigit:]]\\{4\\}\\).*/\\1/g' %2") - .arg(addressLength).arg(procFilePath); - - // TODO: We should not use an SshRemoteProcessRunner here, because we have to check - // for the type of the connection before we can say what the exact command line is. - d->procRunner.run(command.toUtf8(), connection->connectionParameters()); - d->running = true; -} - -void RemoteLinuxUsedPortsGatherer::stop() -{ - if (!d->running) - return; - d->running = false; - disconnect(&d->procRunner, 0, this, 0); -} - int RemoteLinuxUsedPortsGatherer::getNextFreePort(PortList *freePorts) const { while (freePorts->hasMore()) { @@ -126,12 +94,20 @@ QList<int> RemoteLinuxUsedPortsGatherer::usedPorts() const return d->usedPorts; } -void RemoteLinuxUsedPortsGatherer::setupUsedPorts() +void RemoteLinuxUsedPortsGatherer::handleStdOutput(const QByteArray &output) { - QList<QByteArray> portStrings = d->remoteStdout.split('\n'); - portStrings.removeFirst(); + QByteArray data = d->keepSake + output; + + // make sure we only process complete lines: + int lastEol = output.lastIndexOf('\n'); + if (lastEol != output.count() - 1) { + d->keepSake = data.mid(lastEol + 1); + data = data.left(lastEol); + } + + QList<QByteArray> portStrings = data.split('\n'); foreach (const QByteArray &portString, portStrings) { - if (portString.isEmpty()) + if (portString.isEmpty() || portString.contains("local_address")) continue; bool ok; const int port = portString.toInt(&ok, 16); @@ -143,61 +119,32 @@ void RemoteLinuxUsedPortsGatherer::setupUsedPorts() Q_FUNC_INFO, portString.data()); } } - emit portListReady(); } -void RemoteLinuxUsedPortsGatherer::handleConnectionError() +void RemoteLinuxUsedPortsGatherer::cleanup() { - if (!d->running) - return; - emit error(tr("Connection error: %1").arg(d->procRunner.lastConnectionErrorString())); - stop(); + d->keepSake.clear(); + d->usedPorts.clear(); } -void RemoteLinuxUsedPortsGatherer::handleProcessClosed(int exitStatus) +int RemoteLinuxUsedPortsGatherer::processFinished(int exitStatus) { - if (!d->running) - return; - QString errMsg; - switch (exitStatus) { - case SshRemoteProcess::FailedToStart: - errMsg = tr("Could not start remote process: %1") - .arg(d->procRunner.processErrorString()); - break; - case SshRemoteProcess::KilledBySignal: - errMsg = tr("Remote process crashed: %1") - .arg(d->procRunner.processErrorString()); - break; - case SshRemoteProcess::ExitedNormally: - if (d->procRunner.processExitCode() == 0) { - setupUsedPorts(); - } else { - errMsg = tr("Remote process failed; exit code was %1.") - .arg(d->procRunner.processExitCode()); - } - break; - default: - Q_ASSERT_X(false, Q_FUNC_INFO, "Invalid exit status"); + if (!d->keepSake.isEmpty()) { + d->keepSake.append('\n'); + handleStdOutput(d->keepSake); } - if (!errMsg.isEmpty()) { - if (!d->remoteStderr.isEmpty()) { - errMsg += tr("\nRemote error output was: %1") - .arg(QString::fromUtf8(d->remoteStderr)); - } - emit error(errMsg); + if (usedPorts().isEmpty()) { + emit progressMessage("All specified ports are available.\n"); + } else { + QString portList; + foreach (const int port, usedPorts()) + portList += QString::number(port) + QLatin1String(", "); + portList.remove(portList.count() - 2, 2); + emit errorMessage(tr("The following specified ports are currently in use: %1\n") + .arg(portList)); } - stop(); -} - -void RemoteLinuxUsedPortsGatherer::handleRemoteStdOut(const QByteArray &output) -{ - d->remoteStdout += output; -} - -void RemoteLinuxUsedPortsGatherer::handleRemoteStdErr(const QByteArray &output) -{ - d->remoteStderr += output; + return SimpleRunner::processFinished(exitStatus); } } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/remotelinuxusedportsgatherer.h b/src/plugins/remotelinux/remotelinuxusedportsgatherer.h index a5a51362af..dec6b00669 100644 --- a/src/plugins/remotelinux/remotelinuxusedportsgatherer.h +++ b/src/plugins/remotelinux/remotelinuxusedportsgatherer.h @@ -33,9 +33,9 @@ #include "remotelinux_export.h" +#include "simplerunner.h" + #include <QtCore/QList> -#include <QtCore/QObject> -#include <QtCore/QSharedPointer> QT_FORWARD_DECLARE_CLASS(QString) @@ -51,33 +51,28 @@ namespace Internal { class RemoteLinuxUsedPortsGathererPrivate; } // namespace Internal -class REMOTELINUX_EXPORT RemoteLinuxUsedPortsGatherer : public QObject +class REMOTELINUX_EXPORT RemoteLinuxUsedPortsGatherer : public SimpleRunner { Q_OBJECT - Q_DISABLE_COPY(RemoteLinuxUsedPortsGatherer) + public: - explicit RemoteLinuxUsedPortsGatherer(QObject *parent = 0); + explicit RemoteLinuxUsedPortsGatherer(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration); ~RemoteLinuxUsedPortsGatherer(); - void start(const QSharedPointer<Utils::SshConnection> &connection, - const QSharedPointer<const LinuxDeviceConfiguration> &devConf); - void stop(); + int getNextFreePort(PortList *freePorts) const; // returns -1 if no more are left QList<int> usedPorts() const; -signals: - void error(const QString &errMsg); - void portListReady(); +protected slots: + void handleStdOutput(const QByteArray &output); + +protected: + int processFinished(int exitStatus); private slots: - void handleConnectionError(); - void handleProcessClosed(int exitStatus); - void handleRemoteStdOut(const QByteArray &output); - void handleRemoteStdErr(const QByteArray &output); + void cleanup(); private: - void setupUsedPorts(); - - Internal::RemoteLinuxUsedPortsGathererPrivate * const d; + Internal::RemoteLinuxUsedPortsGathererPrivate *const d; }; } // namespace RemoteLinux diff --git a/src/plugins/remotelinux/simplerunner.cpp b/src/plugins/remotelinux/simplerunner.cpp new file mode 100644 index 0000000000..cdebd869aa --- /dev/null +++ b/src/plugins/remotelinux/simplerunner.cpp @@ -0,0 +1,160 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@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 qt-info@nokia.com. +** +**************************************************************************/ + +#include "simplerunner.h" + +#include "linuxdeviceconfiguration.h" + +#include <utils/qtcassert.h> +#include <utils/ssh/sshremoteprocessrunner.h> +#include <utils/ssh/sshconnection.h> +#include <utils/ssh/sshconnectionmanager.h> + +using namespace Utils; + +namespace RemoteLinux { +namespace Internal { + +class SimpleRunnerPrivate +{ +public: + SimpleRunnerPrivate() : process(0), sshParameters(Utils::SshConnectionParameters::NoProxy) + { } + + QString commandline; + + SshRemoteProcessRunner *process; + Utils::SshConnectionParameters sshParameters; +}; + +} // namespace Internal + +using namespace Internal; + +SimpleRunner::SimpleRunner(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration, + const QString &commandline) : + d(new SimpleRunnerPrivate) +{ + QTC_ASSERT(!deviceConfiguration.isNull(), return); + d->commandline = commandline; + d->sshParameters = deviceConfiguration->sshParameters(); +} + +SimpleRunner::~SimpleRunner() +{ + delete d; +} + +QString SimpleRunner::commandLine() const +{ + return d->commandline; +} + +void SimpleRunner::run() +{ + QTC_ASSERT(!d->process, return); + + d->process = new SshRemoteProcessRunner(this); + + connect(d->process, SIGNAL(connectionError()), this, SLOT(handleConnectionFailure())); + connect(d->process, SIGNAL(processClosed(int)), this, SLOT(handleProcessFinished(int))); + connect(d->process, SIGNAL(processOutputAvailable(QByteArray)), this, SLOT(handleStdOutput(QByteArray))); + connect(d->process, SIGNAL(processErrorOutputAvailable(QByteArray)), + this, SLOT(handleStdError(QByteArray))); + + emit aboutToStart(); + d->process->run(d->commandline.toUtf8(), sshParameters()); + emit started(); +} + +void SimpleRunner::cancel() +{ + if (!d->process) + return; + + d->process->cancel(); + emit finished(-1); +} + +void SimpleRunner::handleConnectionFailure() +{ + QTC_ASSERT(d->process, return); + + emit errorMessage(tr("SSH connection failure: %1\n").arg(d->process->lastConnectionErrorString())); + delete d->process; + d->process = 0; + + emit finished(processFinished(SshRemoteProcess::FailedToStart)); +} + +void SimpleRunner::handleProcessFinished(int exitStatus) +{ + emit finished(processFinished(exitStatus)); +} + +void SimpleRunner::handleStdOutput(const QByteArray &data) +{ + if (data.isEmpty()) + return; + emit progressMessage(QString::fromUtf8(data)); +} + +void SimpleRunner::handleStdError(const QByteArray &data) +{ + if (data.isEmpty()) + return; + emit errorMessage(QString::fromUtf8(data)); +} + +int SimpleRunner::processFinished(int exitStatus) +{ + int exitCode = -1; + if (d->process) + exitCode = d->process->processExitCode(); + delete d->process; + d->process = 0; + + return (exitStatus == SshRemoteProcess::ExitedNormally && exitCode == 0) ? 0 : 1; +} + +void SimpleRunner::setCommandLine(const QString &cmd) +{ + QTC_ASSERT(d->commandline.isEmpty(), return); + d->commandline = cmd; +} + +SshConnectionParameters SimpleRunner::sshParameters() const +{ + return d->sshParameters; +} + +} // namespace RemoteLinux diff --git a/src/plugins/remotelinux/simplerunner.h b/src/plugins/remotelinux/simplerunner.h new file mode 100644 index 0000000000..056d19268b --- /dev/null +++ b/src/plugins/remotelinux/simplerunner.h @@ -0,0 +1,98 @@ +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@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 qt-info@nokia.com. +** +**************************************************************************/ + +#ifndef SIMPLERUNNER_H +#define SIMPLERUNNER_H + +#include "remotelinux_export.h" + +#include <utils/ssh/sshconnection.h> + +#include <QtCore/QObject> + +QT_FORWARD_DECLARE_CLASS(QString) + +namespace RemoteLinux { +class LinuxDeviceConfiguration; + +namespace Internal { +class SimpleRunnerPrivate; +} // namespace Internal + +// ----------------------------------------------------------------------- +// SimpleRunner: +// ----------------------------------------------------------------------- + +class REMOTELINUX_EXPORT SimpleRunner : public QObject +{ + Q_OBJECT + +public: + SimpleRunner(const QSharedPointer<const LinuxDeviceConfiguration> &deviceConfiguration, + const QString &commandline); + ~SimpleRunner(); + + virtual QString commandLine() const; + + virtual void run(); + virtual void cancel(); + +signals: + void aboutToStart(); + void started(); + void progressMessage(const QString &message); + void errorMessage(const QString &message); + // 0 on success, other value on failure. + void finished(int result); + +protected slots: + void handleProcessFinished(int exitStatus); + + virtual void handleConnectionFailure(); + virtual void handleStdOutput(const QByteArray &data); + virtual void handleStdError(const QByteArray &data); + + // 0 on success, any other value on failure. + virtual int processFinished(int exitStatus); + +protected: + void setCommandLine(const QString &cmd); + + Utils::SshConnectionParameters sshParameters() const; + +private: + Internal::SimpleRunnerPrivate *const d; +}; + +} // namespace RemoteLinux + +#endif // SIMPLERUNNER_H diff --git a/src/plugins/remotelinux/startgdbserverdialog.cpp b/src/plugins/remotelinux/startgdbserverdialog.cpp index 794fb6135f..879815f72c 100644 --- a/src/plugins/remotelinux/startgdbserverdialog.cpp +++ b/src/plugins/remotelinux/startgdbserverdialog.cpp @@ -103,14 +103,14 @@ public: QPushButton *closeButton; PathChooser *sysrootPathChooser; - RemoteLinuxUsedPortsGatherer gatherer; + RemoteLinuxUsedPortsGatherer *gatherer; SshRemoteProcessRunner runner; QSettings *settings; QString remoteCommandLine; }; StartGdbServerDialogPrivate::StartGdbServerDialogPrivate(StartGdbServerDialog *q) - : q(q), processList(0) + : q(q), processList(0), gatherer(0), settings(0) { settings = ICore::instance()->settings(); @@ -179,8 +179,6 @@ StartGdbServerDialog::StartGdbServerDialog(QWidget *parent) : d->deviceComboBox->setModel(devices); d->deviceComboBox->setCurrentIndex(d->settings->value(LastDevice).toInt()); - connect(&d->gatherer, SIGNAL(error(QString)), SLOT(portGathererError(QString))); - connect(&d->gatherer, SIGNAL(portListReady()), SLOT(portListReady())); if (devices->rowCount() == 0) { d->tableView->setEnabled(false); } else { @@ -215,6 +213,15 @@ StartGdbServerDialog::~StartGdbServerDialog() void StartGdbServerDialog::attachToDevice(int index) { LinuxDeviceConfigurations *devices = LinuxDeviceConfigurations::instance(); + + if (d->gatherer) + delete d->gatherer; + + d->gatherer = new RemoteLinuxUsedPortsGatherer(devices->deviceAt(index)); + connect(d->gatherer, SIGNAL(finished(RemoteLinux::LinuxDeviceTester::TestResult)), + this, SLOT(portListReady(RemoteLinux::LinuxDeviceTester::TestResult))); + connect(d->gatherer, SIGNAL(errorMessage(QString)), SLOT(portGathererError(QString))); + delete d->processList; d->processList = new GenericRemoteLinuxProcessList(devices->deviceAt(index)); d->proxyModel.setSourceModel(d->processList); @@ -250,6 +257,8 @@ void StartGdbServerDialog::updateProcessList() void StartGdbServerDialog::attachToProcess() { + QTC_ASSERT(d->gatherer, return); + const QModelIndexList &indexes = d->tableView->selectionModel()->selectedIndexes(); if (indexes.empty()) @@ -258,7 +267,7 @@ void StartGdbServerDialog::attachToProcess() LinuxDeviceConfiguration::ConstPtr device = d->currentDevice(); PortList ports = device->freePorts(); - const int port = d->gatherer.getNextFreePort(&ports); + const int port = d->gatherer->getNextFreePort(&ports); const int row = d->proxyModel.mapToSource(indexes.first()).row(); QTC_ASSERT(row >= 0, return); const int pid = d->processList->pidAt(row); @@ -312,7 +321,11 @@ void StartGdbServerDialog::portListReady() void StartGdbServerDialog::startGdbServer() { LinuxDeviceConfiguration::ConstPtr device = d->currentDevice(); - d->gatherer.start(SshConnection::create(device->sshParameters()), device); + if (d->gatherer) + delete d->gatherer; + d->gatherer = new RemoteLinuxUsedPortsGatherer(device); + + d->gatherer->run(); } void StartGdbServerDialog::attachToRemoteProcess() |