From d9862a767be219d37b3d5722da6291eb28b4d057 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 27 Apr 2021 12:05:13 +0200 Subject: [PATCH] FilePath: Prepare for implementation some remote functions The callback will be set from DeviceManager to re-route the implementation through matching IDevice instances. Change-Id: Ib210504008b8a3471452448a98378d4902e2cadf Reviewed-by: Qt CI Bot Reviewed-by: Eike Ziller --- src/libs/utils/fileutils.cpp | 163 ++++++++++++++++++++++++++++++++++- src/libs/utils/fileutils.h | 39 +++++++-- 2 files changed, 193 insertions(+), 9 deletions(-) diff --git a/src/libs/utils/fileutils.cpp b/src/libs/utils/fileutils.cpp index 7029c95f9ca..f9bb024e994 100644 --- a/src/libs/utils/fileutils.cpp +++ b/src/libs/utils/fileutils.cpp @@ -62,6 +62,8 @@ QT_END_NAMESPACE namespace Utils { +static DeviceFileHooks s_deviceHooks; + /*! \class Utils::CommandLine \brief The CommandLine class represents a command line of a QProcess @@ -318,6 +320,17 @@ FilePath FilePath::operator/(const QString &str) const return pathAppended(str); } +void FilePath::clear() +{ + m_data.clear(); + m_url.clear(); +} + +bool FilePath::isEmpty() const +{ + return m_data.isEmpty() && !m_url.isValid(); +} + /*! Like QDir::toNativeSeparators(), but use prefix '~' instead of $HOME on unix systems when an absolute path is given. @@ -421,6 +434,13 @@ FilePath FilePath::resolvePath(const QString &fileName) const return FilePath::fromString(QDir::cleanPath(toString() + QLatin1Char('/') + fileName)); } +FilePath FilePath::resolveSymlinkTarget() const +{ + // FIXME: implement + QTC_CHECK(false); + return *this; +} + FilePath FileUtils::commonPath(const FilePath &oldCommonPath, const FilePath &filePath) { FilePath newCommonPath = oldCommonPath; @@ -737,6 +757,11 @@ QUrl FilePath::toUrl() const return m_url; } +void FilePath::setDeviceFileHooks(const DeviceFileHooks &hooks) +{ + s_deviceHooks = hooks; +} + /// \returns a QString to display to the user /// Converts the separators to the native format QString FilePath::toUserOutput() const @@ -777,20 +802,117 @@ QString FilePath::fileNameWithPathComponents(int pathComponents) const return m_data; } +QString FilePath::path() const +{ + if (!m_data.isEmpty()) + return m_data; + return m_url.path(); +} + /// \returns a bool indicating whether a file with this /// FilePath exists. bool FilePath::exists() const { + QTC_ASSERT(!needsDevice(), return false); return !isEmpty() && QFileInfo::exists(m_data); } + + /// \returns a bool indicating whether a path is writable. -bool FilePath::isWritablePath() const +bool FilePath::isWritableDir() const { + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.isWritableDir, return false); + return s_deviceHooks.isReadableFile(*this); + } const QFileInfo fi{m_data}; return exists() && fi.isDir() && fi.isWritable(); } +bool FilePath::isExecutableFile() const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.isExecutableFile, return false); + return s_deviceHooks.isExecutableFile(*this); + } + const QFileInfo fi{m_data}; + return fi.exists() && fi.isExecutable() && !fi.isDir(); +} + +bool FilePath::isReadableFile() const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.isReadableFile, return false); + return s_deviceHooks.isReadableFile(*this); + } + const QFileInfo fi{m_data}; + return fi.exists() && fi.isReadable() && !fi.isDir(); +} + +bool FilePath::isReadableDir() const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.isReadableDir, return false); + return s_deviceHooks.isReadableDir(*this); + } + const QFileInfo fi{m_data}; + return fi.exists() && fi.isReadable() && fi.isDir(); +} + +bool FilePath::createDir() const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.createDir, return false); + return s_deviceHooks.createDir(*this); + } + QDir dir(m_data); + return dir.mkpath(dir.absolutePath()); +} + +QList FilePath::dirEntries(const QStringList &nameFilters, QDir::Filters filters) const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.dirEntries, return {}); + return s_deviceHooks.dirEntries(*this, nameFilters, filters); + } + + const QFileInfoList entryInfoList = QDir(toString()).entryInfoList(nameFilters, filters); + return Utils::transform(entryInfoList, &FilePath::fromFileInfo); +} + +QList FilePath::dirEntries(QDir::Filters filters) const +{ + return dirEntries({}, filters); +} + +QByteArray FilePath::fileContents(int maxSize) const +{ + if (needsDevice()) { + QTC_ASSERT(s_deviceHooks.fileContents, return {}); + return s_deviceHooks.fileContents(*this, maxSize); + } + + const QString path = toString(); + QFile f(path); + if (!f.exists()) + return {}; + + if (!f.open(QFile::ReadOnly)) + return {}; + + if (maxSize != -1) + return f.read(maxSize); + + return f.readAll(); +} + +bool FilePath::needsDevice() const +{ + return m_url.isValid(); +} + + /// Find the parent directory of a given directory. /// Returns an empty FilePath if the current directory is already @@ -1072,14 +1194,46 @@ QString FilePath::calcRelativePath(const QString &absolutePath, const QString &a return relativePath; } +FilePath FilePath::onDevice(const FilePath &deviceTemplate) const +{ + FilePath res = *this; + + if (res.m_url.isValid()) { + if (deviceTemplate.m_url.isValid()) { + const QString path = m_url.path(); + res.m_url = deviceTemplate.toUrl(); + res.m_url.setPath(path); + } else { + res.m_data = deviceTemplate.m_data; + res.m_url.clear(); + } + } else { + if (deviceTemplate.m_url.isValid()) { + res.m_url = deviceTemplate.m_url; + res.m_url.setPath(m_data); + res.m_data.clear(); + } else { + // Nothing to do. + } + } + return res; +} + FilePath FilePath::pathAppended(const QString &str) const { FilePath fn = *this; if (str.isEmpty()) return fn; - if (!isEmpty() && !m_data.endsWith(QLatin1Char('/'))) - fn.m_data.append('/'); - fn.m_data.append(str); + if (fn.m_url.isValid()) { + QString path = fn.m_url.path(); + if (!path.isEmpty() && !path.endsWith(QLatin1Char('/'))) + path.append('/'); + fn.m_url.setPath(path); + } else { + if (!fn.m_data.isEmpty() && !fn.m_data.endsWith(QLatin1Char('/'))) + fn.m_data.append('/'); + fn.m_data.append(str); + } return fn; } @@ -1173,6 +1327,7 @@ void withNtfsPermissions(const std::function &task) qt_ntfs_permission_lookup--; } #endif + } // namespace Utils std::hash::result_type diff --git a/src/libs/utils/fileutils.h b/src/libs/utils/fileutils.h index ef3447dc4a3..459b7b8c740 100644 --- a/src/libs/utils/fileutils.h +++ b/src/libs/utils/fileutils.h @@ -66,6 +66,18 @@ class tst_fileutils; namespace Utils { +class DeviceFileHooks +{ +public: + std::function isExecutableFile; + std::function isReadableFile; + std::function isReadableDir; + std::function isWritableDir; + std::function createDir; + std::function(const FilePath &, const QStringList &, QDir::Filters)> dirEntries; + std::function fileContents; +}; + class QTCREATOR_UTILS_EXPORT FilePath { public: @@ -79,6 +91,8 @@ public: static FilePath fromVariant(const QVariant &variant); QString toString() const; + FilePath onDevice(const FilePath &deviceTemplate) const; + QFileInfo toFileInfo() const; QVariant toVariant() const; QDir toDir() const; @@ -88,8 +102,20 @@ public: QString fileName() const; QString fileNameWithPathComponents(int pathComponents) const; + QString path() const; + + bool needsDevice() const; bool exists() const; - bool isWritablePath() const; + + bool isWritablePath() const { return isWritableDir(); } // Remove. + bool isWritableDir() const; + bool isExecutableFile() const; + bool isReadableFile() const; + bool isReadableDir() const; + bool createDir() const; + QList dirEntries(const QStringList &nameFilters, QDir::Filters filters) const; + QList dirEntries(QDir::Filters filters) const; + QByteArray fileContents(int maxSize = -1) const; FilePath parentDir() const; FilePath absolutePath() const; @@ -116,21 +142,24 @@ public: FilePath pathAppended(const QString &str) const; FilePath stringAppended(const QString &str) const; FilePath resolvePath(const QString &fileName) const; + FilePath resolveSymlinkTarget() const; FilePath canonicalPath() const; FilePath operator/(const QString &str) const; - void clear() { m_data.clear(); } - bool isEmpty() const { return m_data.isEmpty(); } + void clear(); + bool isEmpty() const; uint hash(uint seed) const; - // NOTE: FilePath operations on FilePath created from URL currenly - // do not work except for .toVariant() and .toUrl(). + // NOTE: Most FilePath operations on FilePath created from URL currently + // do not work. Among the working are .toVariant() and .toUrl(). static FilePath fromUrl(const QUrl &url); QUrl toUrl() const; + static void setDeviceFileHooks(const DeviceFileHooks &hooks); + private: friend class ::tst_fileutils; static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);