diff --git a/src/libs/utils/devicefileaccess.cpp b/src/libs/utils/devicefileaccess.cpp index 5cec46b9e2f..1e3c771ee7e 100644 --- a/src/libs/utils/devicefileaccess.cpp +++ b/src/libs/utils/devicefileaccess.cpp @@ -269,12 +269,6 @@ bool DeviceFileAccess::renameFile(const FilePath &filePath, const FilePath &targ return false; } -OsType DeviceFileAccess::osType(const FilePath &filePath) const -{ - Q_UNUSED(filePath) - return OsTypeOther; -} - FilePath DeviceFileAccess::symLinkTarget(const FilePath &filePath) const { Q_UNUSED(filePath) @@ -799,12 +793,6 @@ QByteArray DesktopDeviceFileAccess::fileId(const FilePath &filePath) const return result; } -OsType DesktopDeviceFileAccess::osType(const FilePath &filePath) const -{ - Q_UNUSED(filePath) - return HostOsInfo::hostOs(); -} - // UnixDeviceAccess UnixDeviceFileAccess::~UnixDeviceFileAccess() = default; @@ -1035,30 +1023,6 @@ expected_str UnixDeviceFileAccess::createTempFile(const FilePath &file return newPath; } -OsType UnixDeviceFileAccess::osType() const -{ - if (m_osType) - return *m_osType; - - const RunResult result = runInShell({"uname", {"-s"}, OsType::OsTypeLinux}); - QTC_ASSERT(result.exitCode == 0, return OsTypeLinux); - const QString osName = QString::fromUtf8(result.stdOut).trimmed(); - if (osName == "Darwin") - m_osType = OsTypeMac; - else if (osName == "Linux") - m_osType = OsTypeLinux; - else - m_osType = OsTypeOtherUnix; - - return *m_osType; -} - -OsType UnixDeviceFileAccess::osType(const FilePath &filePath) const -{ - Q_UNUSED(filePath); - return osType(); -} - QDateTime UnixDeviceFileAccess::lastModified(const FilePath &filePath) const { const RunResult result = runInShell( @@ -1072,7 +1036,7 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath, const QString &linuxFormat, const QString &macFormat) const { - return (osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) + return (filePath.osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat}) << "-L" << filePath.path(); } @@ -1150,7 +1114,7 @@ FilePathInfo UnixDeviceFileAccess::filePathInfo(const FilePath &filePath) const const RunResult stat = runInShell({"stat", args, OsType::OsTypeLinux}); return FileUtils::filePathInfoFromTriple(QString::fromLatin1(stat.stdOut), - osType() == OsTypeMac ? 8 : 16); + filePath.osType() == OsTypeMac ? 8 : 16); } // returns whether 'find' could be used. @@ -1165,7 +1129,7 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, // TODO: Using stat -L will always return the link target, not the link itself. // We may wan't to add the information that it is a link at some point. - const QString statFormat = osType() == OsTypeMac + const QString statFormat = filePath.osType() == OsTypeMac ? QLatin1String("-f \"%p %m %z\"") : QLatin1String("-c \"%f %Y %s\""); if (callBack.index() == 1) @@ -1192,7 +1156,7 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath, if (entries.isEmpty()) return true; - const int modeBase = osType() == OsTypeMac ? 8 : 16; + const int modeBase = filePath.osType() == OsTypeMac ? 8 : 16; const auto toFilePath = [&filePath, &callBack, modeBase](const QString &entry) { diff --git a/src/libs/utils/devicefileaccess.h b/src/libs/utils/devicefileaccess.h index e3a2acdb8fb..d57da462d2f 100644 --- a/src/libs/utils/devicefileaccess.h +++ b/src/libs/utils/devicefileaccess.h @@ -45,7 +45,6 @@ protected: const FilePath &target) const; virtual bool renameFile(const FilePath &filePath, const FilePath &target) const; - virtual OsType osType(const FilePath &filePath) const; virtual FilePath symLinkTarget(const FilePath &filePath) const; virtual FilePathInfo filePathInfo(const FilePath &filePath) const; virtual QDateTime lastModified(const FilePath &filePath) const; @@ -100,7 +99,6 @@ protected: expected_str copyFile(const FilePath &filePath, const FilePath &target) const override; bool renameFile(const FilePath &filePath, const FilePath &target) const override; - OsType osType(const FilePath &filePath) const override; FilePath symLinkTarget(const FilePath &filePath) const override; FilePathInfo filePathInfo(const FilePath &filePath) const override; QDateTime lastModified(const FilePath &filePath) const override; @@ -159,7 +157,6 @@ protected: bool renameFile(const FilePath &filePath, const FilePath &target) const override; FilePathInfo filePathInfo(const FilePath &filePath) const override; - OsType osType(const FilePath &filePath) const override; FilePath symLinkTarget(const FilePath &filePath) const override; QDateTime lastModified(const FilePath &filePath) const override; QFile::Permissions permissions(const FilePath &filePath) const override; @@ -194,14 +191,12 @@ private: const FileFilter &filter, QStringList *found) const; - Utils::OsType osType() const; QStringList statArgs(const FilePath &filePath, const QString &linuxFormat, const QString &macFormat) const; mutable bool m_tryUseFind = true; mutable std::optional m_hasMkTemp; - mutable std::optional m_osType; }; } // Utils diff --git a/src/libs/utils/filepath.cpp b/src/libs/utils/filepath.cpp index f117f4e8687..23450661903 100644 --- a/src/libs/utils/filepath.cpp +++ b/src/libs/utils/filepath.cpp @@ -1566,7 +1566,11 @@ bool FilePath::setPermissions(QFile::Permissions permissions) const OsType FilePath::osType() const { - return fileAccess()->osType(*this); + if (!needsDevice()) + return HostOsInfo::hostOs(); + + QTC_ASSERT(s_deviceHooks.osType, return HostOsInfo::hostOs()); + return s_deviceHooks.osType(*this); } bool FilePath::removeFile() const diff --git a/src/libs/utils/filepath.h b/src/libs/utils/filepath.h index 877e8beb8e9..0ecdc09dab9 100644 --- a/src/libs/utils/filepath.h +++ b/src/libs/utils/filepath.h @@ -291,6 +291,7 @@ public: std::function isSameDevice; std::function(const FilePath &)> localSource; std::function openTerminal; + std::function osType; }; // For testing diff --git a/src/libs/utils/osspecificaspects.h b/src/libs/utils/osspecificaspects.h index 0cc22efe5fe..c735f313abc 100644 --- a/src/libs/utils/osspecificaspects.h +++ b/src/libs/utils/osspecificaspects.h @@ -14,6 +14,36 @@ namespace Utils { // Add more as needed. enum OsType { OsTypeWindows, OsTypeLinux, OsTypeMac, OsTypeOtherUnix, OsTypeOther }; +inline QString osTypeToString(OsType osType) +{ + switch (osType) { + case OsTypeWindows: + return "Windows"; + case OsTypeLinux: + return "Linux"; + case OsTypeMac: + return "Mac"; + case OsTypeOtherUnix: + return "Other Unix"; + case OsTypeOther: + default: + return "Other"; + } +} + +inline OsType osTypeFromString(const QString &string) +{ + if (string == "Windows") + return OsTypeWindows; + if (string == "Linux") + return OsTypeLinux; + if (string == "Mac") + return OsTypeMac; + if (string == "Other Unix") + return OsTypeOtherUnix; + return OsTypeOther; +} + namespace OsSpecificAspects { inline QString withExecutableSuffix(OsType osType, const QString &executable) diff --git a/src/plugins/docker/dockerdevice.cpp b/src/plugins/docker/dockerdevice.cpp index 02770e89a7d..d0a8c4c8e97 100644 --- a/src/plugins/docker/dockerdevice.cpp +++ b/src/plugins/docker/dockerdevice.cpp @@ -126,7 +126,6 @@ public: RunResult runInShell(const CommandLine &cmdLine, const QByteArray &stdInData) const override; QString mapToDevicePath(const QString &hostPath) const override; - OsType osType(const FilePath &filePath) const override; DockerDevicePrivate *m_dev = nullptr; }; @@ -377,12 +376,6 @@ QString DockerDeviceFileAccess::mapToDevicePath(const QString &hostPath) const return newPath; } -OsType DockerDeviceFileAccess::osType(const FilePath &filePath) const -{ - QTC_ASSERT(m_dev, return UnixDeviceFileAccess::osType(filePath)); - return m_dev->q->osType(); -} - DockerDevice::DockerDevice(DockerSettings *settings, const DockerDeviceData &data) : d(new DockerDevicePrivate(this, settings, data)) { diff --git a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp index 53e1e5c4d73..ff3baf6148a 100644 --- a/src/plugins/projectexplorer/devicesupport/devicemanager.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicemanager.cpp @@ -443,6 +443,13 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_uniqueopenTerminal(env, filePath); }; + deviceHooks.osType = [](const FilePath &filePath) { + auto device = DeviceManager::deviceForPath(filePath); + if (!device) + return OsTypeLinux; + return device->osType(); + }; + DeviceProcessHooks processHooks; processHooks.processImplHook = [](const FilePath &filePath) -> ProcessInterface * { diff --git a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp index 27ad8252ab0..6de16afac00 100644 --- a/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp +++ b/src/plugins/projectexplorer/devicesupport/devicesettingswidget.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -182,6 +183,8 @@ void DeviceSettingsWidget::addDevice() if (device.isNull()) return; + Utils::asyncRun([device] { device->checkOsType(); }); + m_deviceManager->addDevice(device); m_removeConfigButton->setEnabled(true); m_configurationComboBox->setCurrentIndex(m_deviceManagerModel->indexOf(device)); diff --git a/src/plugins/projectexplorer/devicesupport/idevice.cpp b/src/plugins/projectexplorer/devicesupport/idevice.cpp index ab3a44f0d84..2e6e80801b5 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.cpp +++ b/src/plugins/projectexplorer/devicesupport/idevice.cpp @@ -93,6 +93,7 @@ static Id newId() const char DisplayNameKey[] = "Name"; const char TypeKey[] = "OsType"; +const char ClientOsTypeKey[] = "ClientOsType"; const char IdKey[] = "InternalId"; const char OriginKey[] = "Origin"; const char MachineTypeKey[] = "Type"; @@ -426,6 +427,8 @@ void IDevice::fromMap(const QVariantMap &map) d->type = typeFromMap(map); d->displayName.fromMap(map, DisplayNameKey); d->id = Id::fromSetting(map.value(QLatin1String(IdKey))); + d->osType = osTypeFromString( + map.value(QLatin1String(ClientOsTypeKey), osTypeToString(OsTypeLinux)).toString()); if (!d->id.isValid()) d->id = newId(); d->origin = static_cast(map.value(QLatin1String(OriginKey), ManuallyAdded).toInt()); @@ -472,6 +475,7 @@ QVariantMap IDevice::toMap() const QVariantMap map; d->displayName.toMap(map, DisplayNameKey); map.insert(QLatin1String(TypeKey), d->type.toString()); + map.insert(QLatin1String(ClientOsTypeKey), osTypeToString(d->osType)); map.insert(QLatin1String(IdKey), d->id.toSetting()); map.insert(QLatin1String(OriginKey), d->origin); @@ -504,9 +508,6 @@ IDevice::Ptr IDevice::clone() const device->d->deviceState = d->deviceState; device->d->deviceActions = d->deviceActions; device->d->deviceIcons = d->deviceIcons; - // Os type is only set in the constructor, always to the same value. - // But make sure we notice if that changes in the future (which it shouldn't). - QTC_CHECK(device->d->osType == d->osType); device->d->osType = d->osType; device->fromMap(toMap()); return device; diff --git a/src/plugins/projectexplorer/devicesupport/idevice.h b/src/plugins/projectexplorer/devicesupport/idevice.h index 6323b8589bb..2497bdcc452 100644 --- a/src/plugins/projectexplorer/devicesupport/idevice.h +++ b/src/plugins/projectexplorer/devicesupport/idevice.h @@ -221,6 +221,8 @@ public: virtual bool prepareForBuild(const Target *target); virtual std::optional clangdExecutable() const; + virtual void checkOsType(){}; + protected: IDevice(); diff --git a/src/plugins/remotelinux/linuxdevice.cpp b/src/plugins/remotelinux/linuxdevice.cpp index 760273e9ab5..191ee9d5d32 100644 --- a/src/plugins/remotelinux/linuxdevice.cpp +++ b/src/plugins/remotelinux/linuxdevice.cpp @@ -305,6 +305,9 @@ public: Environment getEnvironment(); void invalidateEnvironmentCache(); + void checkOsType(); + void queryOsType(std::function run); + LinuxDevice *q = nullptr; QThread m_shellThread; ShellThreadHandler *m_handler = nullptr; @@ -939,6 +942,12 @@ LinuxDevice::LinuxDevice() }}); } +void LinuxDevice::_setOsType(Utils::OsType osType) +{ + qCDebug(linuxDeviceLog) << "Setting OS type to" << osType << "for" << displayName(); + IDevice::setOsType(osType); +} + LinuxDevice::~LinuxDevice() { delete d; @@ -1045,6 +1054,23 @@ LinuxDevicePrivate::~LinuxDevicePrivate() QMetaObject::invokeMethod(&m_shellThread, closeShell, Qt::BlockingQueuedConnection); } +void LinuxDevicePrivate::queryOsType(std::function runInShell) +{ + const RunResult result = runInShell({"uname", {"-s"}, OsType::OsTypeLinux}); + if (result.exitCode != 0) + q->_setOsType(OsTypeOtherUnix); + const QString osName = QString::fromUtf8(result.stdOut).trimmed(); + if (osName == "Darwin") + q->_setOsType(OsTypeMac); + if (osName == "Linux") + q->_setOsType(OsTypeLinux); +} + +void LinuxDevicePrivate::checkOsType() +{ + queryOsType([this](const CommandLine &cmd) { return runInShell(cmd); }); +} + // Call me with shell mutex locked bool LinuxDevicePrivate::setupShell() { @@ -1058,6 +1084,10 @@ bool LinuxDevicePrivate::setupShell() QMetaObject::invokeMethod(m_handler, [this, sshParameters] { return m_handler->start(sshParameters); }, Qt::BlockingQueuedConnection, &ok); + + if (ok) { + queryOsType([this](const CommandLine &cmd) { return m_handler->runInShell(cmd); }); + } return ok; } @@ -1452,6 +1482,11 @@ LinuxDevicePrivate *LinuxDevice::connectionAccess() const return d; } +void LinuxDevice::checkOsType() +{ + d->checkOsType(); +} + namespace Internal { // Factory diff --git a/src/plugins/remotelinux/linuxdevice.h b/src/plugins/remotelinux/linuxdevice.h index fd111447201..d9dad9ba75f 100644 --- a/src/plugins/remotelinux/linuxdevice.h +++ b/src/plugins/remotelinux/linuxdevice.h @@ -42,11 +42,15 @@ public: const ProjectExplorer::FileTransferSetupData &setup) const override; class LinuxDevicePrivate *connectionAccess() const; + void checkOsType() override; protected: LinuxDevice(); + void _setOsType(Utils::OsType osType); + class LinuxDevicePrivate *d; + friend class LinuxDevicePrivate; }; namespace Internal { diff --git a/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp b/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp index 8aa9609057c..b5aef12d06c 100644 --- a/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp +++ b/tests/auto/utils/unixdevicefileaccess/tst_unixdevicefileaccess.cpp @@ -59,12 +59,6 @@ private slots: m_fileSizeTestFile.writeFileContents(QByteArray(1024, 'a')); } - void osType() - { - const auto osType = m_dfaPtr->osType({}); - QCOMPARE(osType, HostOsInfo::hostOs()); - } - void fileSize() { const auto size = m_dfaPtr->fileSize(m_fileSizeTestFile);