aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcus Tillmanns <marcus.tillmanns@qt.io>2024-02-09 14:34:48 +0100
committerMarcus Tillmanns <marcus.tillmanns@qt.io>2024-02-13 11:49:47 +0000
commite8ad29d3affd115573d7ee7a5621a6ca6e168911 (patch)
tree3ea9351cf9845777da6ce9433cefe5b6c93cdfe9
parent39527bbcad1b933a49c3d1d13e8daee7d4772646 (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.cpp93
-rw-r--r--src/libs/utils/devicefileaccess.h2
-rw-r--r--src/plugins/projectexplorer/devicesupport/devicesettingspage.cpp3
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.cpp2
-rw-r--r--src/plugins/projectexplorer/devicesupport/idevice.h6
-rw-r--r--src/plugins/remotelinux/linuxdevice.cpp120
-rw-r--r--src/plugins/remotelinux/linuxdevice.h10
-rw-r--r--src/plugins/remotelinux/linuxdevicetester.cpp65
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 &current,
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);
}