diff options
author | Marcus Tillmanns <marcus.tillmanns@qt.io> | 2024-02-09 14:34:48 +0100 |
---|---|---|
committer | Marcus Tillmanns <marcus.tillmanns@qt.io> | 2024-02-13 11:49:47 +0000 |
commit | e8ad29d3affd115573d7ee7a5621a6ca6e168911 (patch) | |
tree | 3ea9351cf9845777da6ce9433cefe5b6c93cdfe9 | |
parent | 39527bbcad1b933a49c3d1d13e8daee7d4772646 (diff) |
LinuxDevice: Add disconnected state
Change-Id: Ic2c909e3375a9fb025a335c1ca65621fa031d000
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
-rw-r--r-- | src/libs/utils/devicefileaccess.cpp | 93 | ||||
-rw-r--r-- | src/libs/utils/devicefileaccess.h | 2 | ||||
-rw-r--r-- | src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp | 3 | ||||
-rw-r--r-- | src/plugins/projectexplorer/devicesupport/idevice.cpp | 2 | ||||
-rw-r--r-- | src/plugins/projectexplorer/devicesupport/idevice.h | 6 | ||||
-rw-r--r-- | src/plugins/remotelinux/linuxdevice.cpp | 120 | ||||
-rw-r--r-- | src/plugins/remotelinux/linuxdevice.h | 10 | ||||
-rw-r--r-- | src/plugins/remotelinux/linuxdevicetester.cpp | 65 |
8 files changed, 278 insertions, 23 deletions
diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 0486ece19e..39bdc736e0 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -878,52 +878,73 @@ QByteArray DesktopDeviceFileAccess::fileId(const FilePath &filePath) const // UnixDeviceAccess +static Utils::unexpected<QString> make_unexpected_disconnected() +{ + return make_unexpected(Tr::tr("Device is not connected")); +} + UnixDeviceFileAccess::~UnixDeviceFileAccess() = default; bool UnixDeviceFileAccess::runInShellSuccess(const CommandLine &cmdLine, const QByteArray &stdInData) const { + if (disconnected()) + return false; return runInShell(cmdLine, stdInData).exitCode == 0; } bool UnixDeviceFileAccess::isExecutableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-x", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isReadableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-r", path, "-a", "-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isWritableFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-w", path, "-a", "-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isReadableDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-r", path, "-a", "-d", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isWritableDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-w", path, "-a", "-d", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-f", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; if (filePath.isRootPath()) return true; @@ -933,12 +954,16 @@ bool UnixDeviceFileAccess::isDirectory(const FilePath &filePath) const bool UnixDeviceFileAccess::isSymLink(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-h", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const { + if (disconnected()) + return false; const QStringList args = statArgs(filePath, "%h", "%l"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong() > 1; @@ -946,29 +971,39 @@ bool UnixDeviceFileAccess::hasHardLinks(const FilePath &filePath) const bool UnixDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"touch", {path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::createDirectory(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"mkdir", {"-p", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::exists(const FilePath &filePath) const { + if (disconnected()) + return false; const QString path = filePath.path(); return runInShellSuccess({"test", {"-e", path}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::removeFile(const FilePath &filePath) const { + if (disconnected()) + return false; return runInShellSuccess({"rm", {filePath.path()}, OsType::OsTypeLinux}); } bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString *error) const { + if (disconnected()) + return false; QTC_ASSERT(filePath.path().startsWith('/'), return false); const QString path = filePath.cleanPath().path(); @@ -989,6 +1024,8 @@ bool UnixDeviceFileAccess::removeRecursively(const FilePath &filePath, QString * expected_str<void> UnixDeviceFileAccess::copyFile(const FilePath &filePath, const FilePath &target) const { + if (disconnected()) + return make_unexpected_disconnected(); const RunResult result = runInShell( {"cp", {filePath.path(), target.path()}, OsType::OsTypeLinux}); @@ -1003,11 +1040,17 @@ expected_str<void> UnixDeviceFileAccess::copyFile(const FilePath &filePath, bool UnixDeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &target) const { + if (disconnected()) + return false; + return runInShellSuccess({"mv", {filePath.path(), target.path()}, OsType::OsTypeLinux}); } FilePath UnixDeviceFileAccess::symLinkTarget(const FilePath &filePath) const { + if (disconnected()) + return {}; + const RunResult result = runInShell( {"readlink", {"-n", "-e", filePath.path()}, OsType::OsTypeLinux}); const QString out = QString::fromUtf8(result.stdOut); @@ -1018,6 +1061,9 @@ expected_str<QByteArray> UnixDeviceFileAccess::fileContents(const FilePath &file qint64 limit, qint64 offset) const { + if (disconnected()) + return make_unexpected_disconnected(); + QStringList args = {"if=" + filePath.path()}; if (limit > 0 || offset > 0) { const qint64 gcd = std::gcd(limit, offset); @@ -1045,6 +1091,9 @@ expected_str<qint64> UnixDeviceFileAccess::writeFileContents(const FilePath &fil const QByteArray &data, qint64 offset) const { + if (disconnected()) + return make_unexpected_disconnected(); + QStringList args = {"of=" + filePath.path()}; if (offset != 0) { args.append("bs=1"); @@ -1061,6 +1110,9 @@ expected_str<qint64> UnixDeviceFileAccess::writeFileContents(const FilePath &fil expected_str<FilePath> UnixDeviceFileAccess::createTempFile(const FilePath &filePath) { + if (disconnected()) + return make_unexpected_disconnected(); + if (!m_hasMkTemp.has_value()) m_hasMkTemp = runInShellSuccess({"which", {"mktemp"}, OsType::OsTypeLinux}); @@ -1120,6 +1172,9 @@ expected_str<FilePath> UnixDeviceFileAccess::createTempFile(const FilePath &file QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const { + if (disconnected()) + return {}; + const RunResult result = runInShell( {"stat", {"-L", "-c", "%Y", filePath.path()}, OsType::OsTypeLinux}); qint64 secs = result.stdOut.toLongLong(); @@ -1131,6 +1186,9 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, const QString &linuxFormat, const QString &macFormat) const { + if (disconnected()) + return {}; + return (filePath.osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) << "-L" << filePath.path(); @@ -1138,6 +1196,9 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) const { + if (disconnected()) + return {}; + QStringList args = statArgs(filePath, "%a", "%p"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); @@ -1161,6 +1222,9 @@ QFile::Permissions UnixDeviceFileAccess::permissions(const FilePath &filePath) c bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permissions perms) const { + if (disconnected()) + return false; + const int flags = int(perms); return runInShellSuccess( {"chmod", {QString::number(flags, 16), filePath.path()}, OsType::OsTypeLinux}); @@ -1168,6 +1232,9 @@ bool UnixDeviceFileAccess::setPermissions(const FilePath &filePath, QFile::Permi qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const { + if (disconnected()) + return -1; + const QStringList args = statArgs(filePath, "%s", "%z"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); return result.stdOut.toLongLong(); @@ -1175,12 +1242,18 @@ qint64 UnixDeviceFileAccess::fileSize(const FilePath &filePath) const qint64 UnixDeviceFileAccess::bytesAvailable(const FilePath &filePath) const { + if (disconnected()) + return -1; + const RunResult result = runInShell({"df", {"-k", filePath.path()}, OsType::OsTypeLinux}); return FileUtils::bytesAvailableFromDFOutput(result.stdOut); } QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const { + if (disconnected()) + return {}; + const QStringList args = statArgs(filePath, "%D:%i", "%d:%i"); const RunResult result = runInShell({"stat", args, OsType::OsTypeLinux}); @@ -1192,6 +1265,9 @@ QByteArray UnixDeviceFileAccess::fileId(const FilePath &filePath) const FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const { + if (disconnected()) + return {}; + if (filePath.path() == "/") // TODO: Add FilePath::isRoot() { const FilePathInfo r{4096, @@ -1218,6 +1294,9 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, const FileFilter &filter, const FilePath::IterateDirCallback &callBack) const { + if (disconnected()) + return false; + QTC_CHECK(filePath.isAbsolutePath()); CommandLine cmdLine{"find", filter.asFindArguments(filePath.path()), OsType::OsTypeLinux}; @@ -1290,6 +1369,9 @@ void UnixDeviceFileAccess::findUsingLs(const QString ¤t, QStringList *found, const QString &start) const { + if (disconnected()) + return; + const RunResult result = runInShell( {"ls", {"-1", "-a", "-p", "--", current}, OsType::OsTypeLinux}); const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts); @@ -1349,6 +1431,9 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, const FilePath::IterateDirCallback &callBack, const FileFilter &filter) const { + if (disconnected()) + return; + // We try to use 'find' first, because that can filter better directly. // Unfortunately, it's not installed on all devices by default. if (m_tryUseFind) { @@ -1366,9 +1451,17 @@ void UnixDeviceFileAccess::iterateDirectory(const FilePath &filePath, Environment UnixDeviceFileAccess::deviceEnvironment() const { + if (disconnected()) + return {}; + const RunResult result = runInShell({"env", {}, OsType::OsTypeLinux}); const QString out = QString::fromUtf8(result.stdOut); return Environment(out.split('\n', Qt::SkipEmptyParts), OsTypeLinux); } +bool UnixDeviceFileAccess::disconnected() const +{ + return false; +} + } // namespace Utils diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index 5b7c766a8a..ba48454127 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -188,6 +188,8 @@ protected: QStringList *found, const QString &start) const; + virtual bool disconnected() const; + private: bool iterateWithFind(const FilePath &filePath, const FileFilter &filter, diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp index 3d2e86d445..a7405ef46e 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp @@ -312,6 +312,9 @@ void DeviceSettingsWidget::testDevice() dlg->setAttribute(Qt::WA_DeleteOnClose); dlg->setModal(true); dlg->show(); + connect(dlg, &QObject::destroyed, this, [this, id = device->id()] { + handleDeviceUpdated(id); + }); } void DeviceSettingsWidget::handleDeviceUpdated(Id id) diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index 9a79347da1..0fcdae1c91 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -593,7 +593,7 @@ QString IDevice::deviceStateToString() const QPixmap IDevice::deviceStateIcon() const { - switch (d->deviceState) { + switch (deviceState()) { case IDevice::DeviceReadyToUse: return Icons::DEVICE_READY_INDICATOR.pixmap(); case IDevice::DeviceConnected: return Icons::DEVICE_CONNECTED_INDICATOR.pixmap(); case IDevice::DeviceDisconnected: return Icons::DEVICE_DISCONNECTED_INDICATOR.pixmap(); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index c494387de4..6434b5b6dd 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -105,7 +105,7 @@ public: virtual ~IDevice(); - Ptr clone() const; + virtual Ptr clone() const; DeviceSettings *settings() const; @@ -154,9 +154,9 @@ public: virtual DeviceProcessSignalOperation::Ptr signalOperation() const; enum DeviceState { DeviceReadyToUse, DeviceConnected, DeviceDisconnected, DeviceStateUnknown }; - DeviceState deviceState() const; + virtual DeviceState deviceState() const; void setDeviceState(const DeviceState state); - QString deviceStateToString() const; + virtual QString deviceStateToString() const; QPixmap deviceStateIcon() const; static Utils::Id typeFromMap(const Utils::Store &map); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index a835ef30be..80b33c215f 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -21,12 +21,15 @@ #include <projectexplorer/devicesupport/processlist.h> #include <projectexplorer/devicesupport/sshparameters.h> #include <projectexplorer/devicesupport/sshsettings.h> +#include <projectexplorer/projectexplorerconstants.h> #include <utils/algorithm.h> +#include <utils/async.h> #include <utils/devicefileaccess.h> #include <utils/deviceshell.h> #include <utils/environment.h> #include <utils/hostosinfo.h> +#include <utils/infobar.h> #include <utils/port.h> #include <utils/portlist.h> #include <utils/process.h> @@ -292,6 +295,8 @@ public: Environment deviceEnvironment() const override; + bool disconnected() const override; + LinuxDevicePrivate *m_dev; }; @@ -307,7 +312,7 @@ public: explicit LinuxDevicePrivate(LinuxDevice *parent); ~LinuxDevicePrivate(); - bool setupShell(); + bool setupShell(const SshParameters &sshParameters); RunResult runInShell(const CommandLine &cmd, const QByteArray &stdInData = {}); void attachToSharedConnection(SshConnectionHandle *connectionHandle, @@ -319,6 +324,10 @@ public: void checkOsType(); void queryOsType(std::function<RunResult(const CommandLine &)> run); + void setDisconnected(bool disconnected); + bool disconnected() const; + bool checkDisconnectedWithWarning(); + LinuxDevice *q = nullptr; QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; @@ -327,6 +336,7 @@ public: QReadWriteLock m_environmentCacheLock; std::optional<Environment> m_environmentCache; + bool m_disconnected = false; }; void LinuxDevicePrivate::invalidateEnvironmentCache() @@ -358,14 +368,24 @@ Environment LinuxDevicePrivate::getEnvironment() RunResult LinuxDeviceFileAccess::runInShell(const CommandLine &cmdLine, const QByteArray &stdInData) const { + if (disconnected()) + return {-1, {}, Tr::tr("Device is disconnected.").toUtf8()}; return m_dev->runInShell(cmdLine, stdInData); } Environment LinuxDeviceFileAccess::deviceEnvironment() const { + if (disconnected()) + return {}; + return m_dev->getEnvironment(); } +bool LinuxDeviceFileAccess::disconnected() const +{ + return m_dev->checkDisconnectedWithWarning(); +} + // SshProcessImpl class SshProcessInterfacePrivate : public QObject @@ -1023,6 +1043,15 @@ LinuxDevice::~LinuxDevice() delete d; } +IDevice::Ptr LinuxDevice::clone() const +{ + IDevice::Ptr clone = IDevice::clone(); + Ptr linuxClone = std::dynamic_pointer_cast<LinuxDevice>(clone); + QTC_ASSERT(linuxClone, return clone); + linuxClone->d->setDisconnected(d->disconnected()); + return clone; +} + IDeviceWidget *LinuxDevice::createWidget() { return new Internal::GenericLinuxDeviceConfigurationWidget(shared_from_this()); @@ -1106,15 +1135,31 @@ void LinuxDevicePrivate::queryOsType(std::function<RunResult(const CommandLine & q->_setOsType(OsTypeLinux); } +void LinuxDevicePrivate::setDisconnected(bool disconnected) +{ + if (disconnected == m_disconnected) + return; + + m_disconnected = disconnected; + + if (m_disconnected) + m_handler->closeShell(); + +} + +bool LinuxDevicePrivate::disconnected() const +{ + return m_disconnected; +} + void LinuxDevicePrivate::checkOsType() { queryOsType([this](const CommandLine &cmd) { return runInShell(cmd); }); } // Call me with shell mutex locked -bool LinuxDevicePrivate::setupShell() +bool LinuxDevicePrivate::setupShell(const SshParameters &sshParameters) { - const SshParameters sshParameters = q->sshParameters(); if (m_handler->isRunning(sshParameters)) return true; @@ -1126,8 +1171,12 @@ bool LinuxDevicePrivate::setupShell() }, Qt::BlockingQueuedConnection, &ok); if (ok) { + setDisconnected(false); queryOsType([this](const CommandLine &cmd) { return m_handler->runInShell(cmd); }); + } else { + setDisconnected(true); } + return ok; } @@ -1135,11 +1184,43 @@ RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArra { QMutexLocker locker(&m_shellMutex); DEBUG(cmd.toUserOutput()); - const bool isSetup = setupShell(); + if (checkDisconnectedWithWarning()) + return {}; + const bool isSetup = setupShell(q->sshParameters()); + if (checkDisconnectedWithWarning()) + return {}; QTC_ASSERT(isSetup, return {}); return m_handler->runInShell(cmd, data); } +bool LinuxDevicePrivate::checkDisconnectedWithWarning() +{ + if (!disconnected()) + return false; + + QMetaObject::invokeMethod(Core::ICore::infoBar(), [id = q->id(), name = q->displayName()] { + if (!Core::ICore::infoBar()->canInfoBeAdded(id)) + return; + const QString warnStr + = Tr::tr("Device \"%1\" is currently marked as disconnected.").arg(name); + InfoBarEntry info(id, warnStr, InfoBarEntry::GlobalSuppression::Enabled); + info.setDetailsWidgetCreator([] { + const auto label = new QLabel(Tr::tr( + "The device was not available when trying to connect previously.<br>" + "No further connection attempts will be made until the device is manually reset " + "by running a successful connection test via the " + "<a href=\"dummy\">settings page</a>.")); + label->setWordWrap(true); + QObject::connect(label, &QLabel::linkActivated, [] { + Core::ICore::showOptionsDialog(ProjectExplorer::Constants::DEVICE_SETTINGS_PAGE_ID); + }); + return label; + }); + Core::ICore::infoBar()->addInfo(info); + }); + return true; +} + void LinuxDevicePrivate::attachToSharedConnection(SshConnectionHandle *connectionHandle, const SshParameters &sshParameters) { @@ -1522,6 +1603,37 @@ void LinuxDevice::checkOsType() d->checkOsType(); } +IDevice::DeviceState LinuxDevice::deviceState() const +{ + if (isDisconnected()) + return DeviceDisconnected; + return IDevice::deviceState(); +} + +QString LinuxDevice::deviceStateToString() const +{ + if (isDisconnected()) + return Tr::tr("Device is considered unconnected. Re-run device test to reset state."); + return IDevice::deviceStateToString(); +} + +bool LinuxDevice::isDisconnected() const +{ + return d->disconnected(); +} +void LinuxDevice::setDisconnected(bool disconnected) +{ + d->setDisconnected(disconnected); +} + +QFuture<bool> LinuxDevice::tryToConnect() +{ + return Utils::asyncRun([this] { + QMutexLocker locker(&d->m_shellMutex); + return d->setupShell(sshParameters()); + }); +} + namespace Internal { class LinuxDeviceFactory final : public IDeviceFactory diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index a6625cdea2..0bb2468eac 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -20,6 +20,8 @@ public: static Ptr create() { return Ptr(new LinuxDevice); } + IDevice::Ptr clone() const override; + ProjectExplorer::IDeviceWidget *createWidget() override; bool canCreateProcessModel() const override { return true; } @@ -42,6 +44,14 @@ public: class LinuxDevicePrivate *connectionAccess() const; void checkOsType() override; + DeviceState deviceState() const override; + QString deviceStateToString() const override; + + bool isDisconnected() const; + void setDisconnected(bool disconnected); + + QFuture<bool> tryToConnect(); + protected: LinuxDevice(); diff --git a/src/plugins/remotelinux/linuxdevicetester.cpp b/src/plugins/remotelinux/linuxdevicetester.cpp index 3d6c41cd65..f279bc0c38 100644 --- a/src/plugins/remotelinux/linuxdevicetester.cpp +++ b/src/plugins/remotelinux/linuxdevicetester.cpp @@ -3,6 +3,7 @@ #include "linuxdevicetester.h" +#include "linuxdevice.h" #include "remotelinuxtr.h" #include <projectexplorer/devicesupport/deviceusedportsgatherer.h> @@ -17,6 +18,8 @@ #include <utils/qtcassert.h> #include <utils/stringutils.h> +#include <QFutureWatcher> + using namespace ProjectExplorer; using namespace Tasking; using namespace Utils; @@ -43,9 +46,13 @@ public: const Storage<TransferStorage> &storage) const; GroupItem transferTasks() const; GroupItem commandTasks() const; + void runCommandTests(); + + bool isRunning() const { return m_connectionTest || m_taskTreeRunner.isRunning(); } GenericLinuxDeviceTester *q = nullptr; - IDevice::Ptr m_device; + LinuxDevice::Ptr m_device; + QFutureWatcher<bool> *m_connectionTest = nullptr; TaskTreeRunner m_taskTreeRunner; QStringList m_extraCommands; QList<GroupItem> m_extraTests; @@ -276,6 +283,20 @@ GroupItem GenericLinuxDeviceTesterPrivate::commandTasks() const return root; } +void GenericLinuxDeviceTesterPrivate::runCommandTests() +{ + const Group root { + echoTask("Hello"), // No quoting necessary + echoTask("Hello Remote World!"), // Checks quoting, too. + unameTask(), + gathererTask(), + transferTasks(), + m_extraTests, + commandTasks() + }; + m_taskTreeRunner.start(root); +} + } // namespace Internal using namespace Internal; @@ -302,26 +323,40 @@ void GenericLinuxDeviceTester::setExtraTests(const QList<GroupItem> &extraTests) void GenericLinuxDeviceTester::testDevice(const IDevice::Ptr &deviceConfiguration) { - QTC_ASSERT(!d->m_taskTreeRunner.isRunning(), return); + QTC_ASSERT(!d->isRunning(), return); - d->m_device = deviceConfiguration; + emit progressMessage(Tr::tr("Connecting to device...")); - const Group root { - d->echoTask("Hello"), // No quoting necessary - d->echoTask("Hello Remote World!"), // Checks quoting, too. - d->unameTask(), - d->gathererTask(), - d->transferTasks(), - d->m_extraTests, - d->commandTasks() - }; - d->m_taskTreeRunner.start(root); + d->m_device = std::static_pointer_cast<LinuxDevice>(deviceConfiguration); + + d->m_connectionTest = new QFutureWatcher<bool>(this); + d->m_connectionTest->setFuture(d->m_device->tryToConnect()); + + connect(d->m_connectionTest, &QFutureWatcher<bool>::finished, this, [this] { + const bool success = d->m_connectionTest->result(); + d->m_connectionTest->deleteLater(); + d->m_connectionTest = nullptr; + if (success) { + emit progressMessage(Tr::tr("Connected. Now doing extended checks.\n")); + d->runCommandTests(); + } else { + emit errorMessage( + Tr::tr("Basic connectivity test failed, device is considered unusable.")); + emit finished(TestFailure); + } + }); } void GenericLinuxDeviceTester::stopTest() { - QTC_ASSERT(d->m_taskTreeRunner.isRunning(), return); - d->m_taskTreeRunner.reset(); + QTC_ASSERT(d->isRunning(), return); + if (d->m_connectionTest) { + d->m_connectionTest->disconnect(); + d->m_connectionTest->cancel(); + d->m_connectionTest = nullptr; + } else { + d->m_taskTreeRunner.reset(); + } emit finished(TestFailure); } |