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 <qt_ci_bot@qt-project.org>
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2021-04-27 12:05:13 +02:00
parent f4a64fd8c8
commit d9862a767b
2 changed files with 193 additions and 9 deletions

View File

@@ -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> 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> 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<void()> &task)
qt_ntfs_permission_lookup--;
}
#endif
} // namespace Utils
std::hash<Utils::FilePath>::result_type

View File

@@ -66,6 +66,18 @@ class tst_fileutils;
namespace Utils {
class DeviceFileHooks
{
public:
std::function<bool(const FilePath &)> isExecutableFile;
std::function<bool(const FilePath &)> isReadableFile;
std::function<bool(const FilePath &)> isReadableDir;
std::function<bool(const FilePath &)> isWritableDir;
std::function<bool(const FilePath &)> createDir;
std::function<QList<FilePath>(const FilePath &, const QStringList &, QDir::Filters)> dirEntries;
std::function<QByteArray(const FilePath &, int)> 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<FilePath> dirEntries(const QStringList &nameFilters, QDir::Filters filters) const;
QList<FilePath> 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);