forked from qt-creator/qt-creator
filepath: Move FileUtils:: function out of FilePath.cpp
Change-Id: If78c349b0145b86a76cd033e4dbc30b237ad917b Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -65,12 +65,6 @@ namespace Utils {
|
|||||||
|
|
||||||
static DeviceFileHooks s_deviceHooks;
|
static DeviceFileHooks s_deviceHooks;
|
||||||
|
|
||||||
/*! \class Utils::FileUtils
|
|
||||||
|
|
||||||
\brief The FileUtils class contains file and directory related convenience
|
|
||||||
functions.
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
static bool removeRecursivelyLocal(const FilePath &filePath, QString *error)
|
static bool removeRecursivelyLocal(const FilePath &filePath, QString *error)
|
||||||
{
|
{
|
||||||
@@ -78,9 +72,11 @@ static bool removeRecursivelyLocal(const FilePath &filePath, QString *error)
|
|||||||
QFileInfo fileInfo = filePath.toFileInfo();
|
QFileInfo fileInfo = filePath.toFileInfo();
|
||||||
if (!fileInfo.exists() && !fileInfo.isSymLink())
|
if (!fileInfo.exists() && !fileInfo.isSymLink())
|
||||||
return true;
|
return true;
|
||||||
QFile::setPermissions(filePath.toString(), fileInfo.permissions() | QFile::WriteUser);
|
|
||||||
|
QFile::setPermissions(fileInfo.absoluteFilePath(), fileInfo.permissions() | QFile::WriteUser);
|
||||||
|
|
||||||
if (fileInfo.isDir()) {
|
if (fileInfo.isDir()) {
|
||||||
QDir dir(filePath.toString());
|
QDir dir(fileInfo.absoluteFilePath());
|
||||||
dir.setPath(dir.canonicalPath());
|
dir.setPath(dir.canonicalPath());
|
||||||
if (dir.isRoot()) {
|
if (dir.isRoot()) {
|
||||||
if (error) {
|
if (error) {
|
||||||
@@ -122,85 +118,9 @@ static bool removeRecursivelyLocal(const FilePath &filePath, QString *error)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cleans part after optional :// scheme separator, similar to QDir::cleanPath()
|
void FilePath::setDeviceFileHooks(const DeviceFileHooks &hooks)
|
||||||
// - directory separators normalized (that is, platform-native
|
|
||||||
// separators converted to "/") and redundant ones removed, and "."s and ".."s
|
|
||||||
// resolved (as far as possible).
|
|
||||||
// Symbolic links are kept. This function does not return the
|
|
||||||
// canonical path, but rather the simplest version of the input.
|
|
||||||
// For example, "./local" becomes "local", "local/../bin" becomes
|
|
||||||
// "bin" and "/local/usr/../bin" becomes "/local/bin".
|
|
||||||
|
|
||||||
// FIXME: This should not use the host-platform dependent QDir::cleanPath()
|
|
||||||
|
|
||||||
static QString doCleanPath(const QString &input)
|
|
||||||
{
|
{
|
||||||
const int pos = input.indexOf("://");
|
s_deviceHooks = hooks;
|
||||||
if (pos == -1)
|
|
||||||
return QDir::cleanPath(input);
|
|
||||||
return input.left(pos + 3) + QDir::cleanPath(input.mid(pos + 3));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Copies the directory specified by \a srcFilePath recursively to \a tgtFilePath. \a tgtFilePath will contain
|
|
||||||
the target directory, which will be created. Example usage:
|
|
||||||
|
|
||||||
\code
|
|
||||||
QString error;
|
|
||||||
bool ok = Utils::FileUtils::copyRecursively("/foo/bar", "/foo/baz", &error);
|
|
||||||
if (!ok)
|
|
||||||
qDebug() << error;
|
|
||||||
\endcode
|
|
||||||
|
|
||||||
This will copy the contents of /foo/bar into to the baz directory under /foo, which will be created in the process.
|
|
||||||
|
|
||||||
\note The \a error parameter is optional.
|
|
||||||
|
|
||||||
Returns whether the operation succeeded.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool FileUtils::copyRecursively(const FilePath &srcFilePath, const FilePath &tgtFilePath, QString *error)
|
|
||||||
{
|
|
||||||
return copyRecursively(
|
|
||||||
srcFilePath, tgtFilePath, error, [](const FilePath &src, const FilePath &dest, QString *error) {
|
|
||||||
if (!src.copyFile(dest)) {
|
|
||||||
if (error) {
|
|
||||||
*error = QCoreApplication::translate("Utils::FileUtils",
|
|
||||||
"Could not copy file \"%1\" to \"%2\".")
|
|
||||||
.arg(src.toUserOutput(), dest.toUserOutput());
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/*!
|
|
||||||
Copies a file specified by \a srcFilePath to \a tgtFilePath only if \a srcFilePath is different
|
|
||||||
(file contents and last modification time).
|
|
||||||
|
|
||||||
Returns whether the operation succeeded.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath)
|
|
||||||
{
|
|
||||||
QTC_ASSERT(srcFilePath.exists(), return false);
|
|
||||||
QTC_ASSERT(srcFilePath.scheme() == tgtFilePath.scheme(), return false);
|
|
||||||
QTC_ASSERT(srcFilePath.host() == tgtFilePath.host(), return false);
|
|
||||||
|
|
||||||
if (tgtFilePath.exists()) {
|
|
||||||
const QDateTime srcModified = srcFilePath.lastModified();
|
|
||||||
const QDateTime tgtModified = tgtFilePath.lastModified();
|
|
||||||
if (srcModified == tgtModified) {
|
|
||||||
const QByteArray srcContents = srcFilePath.fileContents();
|
|
||||||
const QByteArray tgtContents = srcFilePath.fileContents();
|
|
||||||
if (srcContents == tgtContents)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
tgtFilePath.removeFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
return srcFilePath.copyFile(tgtFilePath);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
@@ -314,85 +234,6 @@ QString FilePath::shortNativePath() const
|
|||||||
return toUserOutput();
|
return toUserOutput();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString FileUtils::fileSystemFriendlyName(const QString &name)
|
|
||||||
{
|
|
||||||
QString result = name;
|
|
||||||
result.replace(QRegularExpression(QLatin1String("\\W")), QLatin1String("_"));
|
|
||||||
result.replace(QRegularExpression(QLatin1String("_+")), QLatin1String("_")); // compact _
|
|
||||||
result.remove(QRegularExpression(QLatin1String("^_*"))); // remove leading _
|
|
||||||
result.remove(QRegularExpression(QLatin1String("_+$"))); // remove trailing _
|
|
||||||
if (result.isEmpty())
|
|
||||||
result = QLatin1String("unknown");
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
int FileUtils::indexOfQmakeUnfriendly(const QString &name, int startpos)
|
|
||||||
{
|
|
||||||
static const QRegularExpression checkRegExp(QLatin1String("[^a-zA-Z0-9_.-]"));
|
|
||||||
return checkRegExp.match(name, startpos).capturedStart();
|
|
||||||
}
|
|
||||||
|
|
||||||
QString FileUtils::qmakeFriendlyName(const QString &name)
|
|
||||||
{
|
|
||||||
QString result = name;
|
|
||||||
|
|
||||||
// Remove characters that might trip up a build system (especially qmake):
|
|
||||||
int pos = indexOfQmakeUnfriendly(result);
|
|
||||||
while (pos >= 0) {
|
|
||||||
result[pos] = QLatin1Char('_');
|
|
||||||
pos = indexOfQmakeUnfriendly(result, pos);
|
|
||||||
}
|
|
||||||
return fileSystemFriendlyName(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileUtils::makeWritable(const FilePath &path)
|
|
||||||
{
|
|
||||||
return path.setPermissions(path.permissions() | QFile::WriteUser);
|
|
||||||
}
|
|
||||||
|
|
||||||
// makes sure that capitalization of directories is canonical on Windows and OS X.
|
|
||||||
// This mimics the logic in QDeclarative_isFileCaseCorrect
|
|
||||||
QString FileUtils::normalizedPathName(const QString &name)
|
|
||||||
{
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
const QString nativeSeparatorName(QDir::toNativeSeparators(name));
|
|
||||||
const auto nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16()); // MinGW
|
|
||||||
PIDLIST_ABSOLUTE file;
|
|
||||||
HRESULT hr = SHParseDisplayName(nameC, NULL, &file, 0, NULL);
|
|
||||||
if (FAILED(hr))
|
|
||||||
return name;
|
|
||||||
TCHAR buffer[MAX_PATH];
|
|
||||||
const bool success = SHGetPathFromIDList(file, buffer);
|
|
||||||
ILFree(file);
|
|
||||||
return success ? QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer)))
|
|
||||||
: name;
|
|
||||||
#elif defined(Q_OS_OSX)
|
|
||||||
return Internal::normalizePathName(name);
|
|
||||||
#else // do not try to handle case-insensitive file systems on Linux
|
|
||||||
return name;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool isRelativePathHelper(const QString &path, OsType osType)
|
|
||||||
{
|
|
||||||
if (path.startsWith('/'))
|
|
||||||
return false;
|
|
||||||
if (osType == OsType::OsTypeWindows) {
|
|
||||||
if (path.startsWith('\\'))
|
|
||||||
return false;
|
|
||||||
// Unlike QFileInfo, this won't accept a relative path with a drive letter.
|
|
||||||
// Such paths result in a royal mess anyway ...
|
|
||||||
if (path.length() >= 3 && path.at(1) == ':' && path.at(0).isLetter()
|
|
||||||
&& (path.at(2) == '/' || path.at(2) == '\\'))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FileUtils::isRelativePath(const QString &path)
|
|
||||||
{
|
|
||||||
return isRelativePathHelper(path, HostOsInfo::hostOs());
|
|
||||||
}
|
|
||||||
|
|
||||||
bool FilePath::isRelativePath() const
|
bool FilePath::isRelativePath() const
|
||||||
{
|
{
|
||||||
@@ -422,20 +263,6 @@ FilePath FilePath::cleanPath() const
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
FilePath FileUtils::commonPath(const FilePath &oldCommonPath, const FilePath &filePath)
|
|
||||||
{
|
|
||||||
FilePath newCommonPath = oldCommonPath;
|
|
||||||
while (!newCommonPath.isEmpty() && !filePath.isChildOf(newCommonPath))
|
|
||||||
newCommonPath = newCommonPath.parentDir();
|
|
||||||
return newCommonPath.canonicalPath();
|
|
||||||
}
|
|
||||||
|
|
||||||
FilePath FileUtils::homePath()
|
|
||||||
{
|
|
||||||
return FilePath::fromString(doCleanPath(QDir::homePath()));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*! \class Utils::FilePath
|
/*! \class Utils::FilePath
|
||||||
|
|
||||||
\brief The FilePath class is an abstraction for handles to objects
|
\brief The FilePath class is an abstraction for handles to objects
|
||||||
@@ -597,11 +424,6 @@ QUrl FilePath::toUrl() const
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FileUtils::setDeviceFileHooks(const DeviceFileHooks &hooks)
|
|
||||||
{
|
|
||||||
s_deviceHooks = hooks;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// \returns a QString to display to the user, including the device prefix
|
/// \returns a QString to display to the user, including the device prefix
|
||||||
/// Converts the separators to the native format of the system
|
/// Converts the separators to the native format of the system
|
||||||
/// this path belongs to.
|
/// this path belongs to.
|
||||||
@@ -1175,13 +997,11 @@ void FilePath::setFromString(const QString &filename)
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_data = "/";
|
m_data = "/";
|
||||||
|
return;
|
||||||
} else {
|
}
|
||||||
m_scheme.clear();
|
m_scheme.clear();
|
||||||
m_host.clear();
|
m_host.clear();
|
||||||
m_data = filename;
|
m_data = filename;
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -47,6 +47,7 @@ class tst_fileutils; // This becomes a friend of Utils::FilePath for testing pri
|
|||||||
|
|
||||||
namespace Utils {
|
namespace Utils {
|
||||||
|
|
||||||
|
class DeviceFileHooks;
|
||||||
class Environment;
|
class Environment;
|
||||||
class EnvironmentChange;
|
class EnvironmentChange;
|
||||||
|
|
||||||
@@ -222,6 +223,8 @@ public:
|
|||||||
[[nodiscard]] static QString specialPath(SpecialPathComponent component);
|
[[nodiscard]] static QString specialPath(SpecialPathComponent component);
|
||||||
[[nodiscard]] static FilePath specialFilePath(SpecialPathComponent component);
|
[[nodiscard]] static FilePath specialFilePath(SpecialPathComponent component);
|
||||||
|
|
||||||
|
static void setDeviceFileHooks(const DeviceFileHooks &hooks);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class ::tst_fileutils;
|
friend class ::tst_fileutils;
|
||||||
static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);
|
static QString calcRelativePath(const QString &absolutePath, const QString &absoluteAnchorPath);
|
||||||
@@ -238,6 +241,47 @@ inline size_t qHash(const Utils::FilePath &a, uint seed = 0)
|
|||||||
return a.hash(seed);
|
return a.hash(seed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 &)> isWritableFile;
|
||||||
|
std::function<bool(const FilePath &)> isFile;
|
||||||
|
std::function<bool(const FilePath &)> isDir;
|
||||||
|
std::function<bool(const FilePath &)> ensureWritableDir;
|
||||||
|
std::function<bool(const FilePath &)> ensureExistingFile;
|
||||||
|
std::function<bool(const FilePath &)> createDir;
|
||||||
|
std::function<bool(const FilePath &)> exists;
|
||||||
|
std::function<bool(const FilePath &)> removeFile;
|
||||||
|
std::function<bool(const FilePath &)> removeRecursively;
|
||||||
|
std::function<bool(const FilePath &, const FilePath &)> copyFile;
|
||||||
|
std::function<bool(const FilePath &, const FilePath &)> renameFile;
|
||||||
|
std::function<FilePath(const FilePath &, const FilePaths &)> searchInPath;
|
||||||
|
std::function<FilePath(const FilePath &)> symLinkTarget;
|
||||||
|
std::function<QString(const FilePath &)> mapToDevicePath;
|
||||||
|
std::function<void(const FilePath &,
|
||||||
|
const std::function<bool(const FilePath &)> &, // Abort on 'false' return.
|
||||||
|
const FileFilter &)> iterateDirectory;
|
||||||
|
std::function<QByteArray(const FilePath &, qint64, qint64)> fileContents;
|
||||||
|
std::function<bool(const FilePath &, const QByteArray &)> writeFileContents;
|
||||||
|
std::function<QDateTime(const FilePath &)> lastModified;
|
||||||
|
std::function<QFile::Permissions(const FilePath &)> permissions;
|
||||||
|
std::function<bool(const FilePath &, QFile::Permissions)> setPermissions;
|
||||||
|
std::function<OsType(const FilePath &)> osType;
|
||||||
|
std::function<Environment(const FilePath &)> environment;
|
||||||
|
std::function<qint64(const FilePath &)> fileSize;
|
||||||
|
std::function<qint64(const FilePath &)> bytesAvailable;
|
||||||
|
std::function<QString(const FilePath &)> deviceDisplayName;
|
||||||
|
|
||||||
|
template <class ...Args> using Continuation = std::function<void(Args...)>;
|
||||||
|
std::function<void(const Continuation<bool> &, const FilePath &, const FilePath &)> asyncCopyFile;
|
||||||
|
std::function<void(const Continuation<const QByteArray &> &, const FilePath &, qint64, qint64)> asyncFileContents;
|
||||||
|
std::function<void(const Continuation<bool> &, const FilePath &, const QByteArray &)> asyncWriteFileContents;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
@@ -254,4 +298,5 @@ struct QTCREATOR_UTILS_EXPORT hash<Utils::FilePath>
|
|||||||
using result_type = size_t;
|
using result_type = size_t;
|
||||||
result_type operator()(const argument_type &fn) const;
|
result_type operator()(const argument_type &fn) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace std
|
} // namespace std
|
||||||
|
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include "algorithm.h"
|
#include "algorithm.h"
|
||||||
#include "qtcassert.h"
|
#include "qtcassert.h"
|
||||||
|
#include "hostosinfo.h"
|
||||||
|
|
||||||
#include "fsengine/fileiconprovider.h"
|
#include "fsengine/fileiconprovider.h"
|
||||||
#include "fsengine/fsengine.h"
|
#include "fsengine/fsengine.h"
|
||||||
@@ -35,6 +36,7 @@
|
|||||||
#include <QDataStream>
|
#include <QDataStream>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QOperatingSystemVersion>
|
#include <QOperatingSystemVersion>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QTemporaryFile>
|
#include <QTemporaryFile>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QXmlStreamWriter>
|
#include <QXmlStreamWriter>
|
||||||
@@ -285,6 +287,13 @@ TempFileSaver::~TempFileSaver()
|
|||||||
QFile::remove(m_filePath.toString());
|
QFile::remove(m_filePath.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*! \class Utils::FileUtils
|
||||||
|
|
||||||
|
\brief The FileUtils class contains file and directory related convenience
|
||||||
|
functions.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
#ifdef QT_GUI_LIB
|
#ifdef QT_GUI_LIB
|
||||||
FileUtils::CopyAskingForOverwrite::CopyAskingForOverwrite(QWidget *dialogParent, const std::function<void (FilePath)> &postOperation)
|
FileUtils::CopyAskingForOverwrite::CopyAskingForOverwrite(QWidget *dialogParent, const std::function<void (FilePath)> &postOperation)
|
||||||
: m_parent(dialogParent)
|
: m_parent(dialogParent)
|
||||||
@@ -629,4 +638,178 @@ void FileUtils::iterateLsOutput(const FilePath &base,
|
|||||||
|
|
||||||
#endif // QT_WIDGETS_LIB
|
#endif // QT_WIDGETS_LIB
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Copies the directory specified by \a srcFilePath recursively to \a tgtFilePath. \a tgtFilePath will contain
|
||||||
|
the target directory, which will be created. Example usage:
|
||||||
|
|
||||||
|
\code
|
||||||
|
QString error;
|
||||||
|
bool ok = Utils::FileUtils::copyRecursively("/foo/bar", "/foo/baz", &error);
|
||||||
|
if (!ok)
|
||||||
|
qDebug() << error;
|
||||||
|
\endcode
|
||||||
|
|
||||||
|
This will copy the contents of /foo/bar into to the baz directory under /foo, which will be created in the process.
|
||||||
|
|
||||||
|
\note The \a error parameter is optional.
|
||||||
|
|
||||||
|
Returns whether the operation succeeded.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool FileUtils::copyRecursively(const FilePath &srcFilePath, const FilePath &tgtFilePath, QString *error)
|
||||||
|
{
|
||||||
|
return copyRecursively(
|
||||||
|
srcFilePath, tgtFilePath, error, [](const FilePath &src, const FilePath &dest, QString *error) {
|
||||||
|
if (!src.copyFile(dest)) {
|
||||||
|
if (error) {
|
||||||
|
*error = QCoreApplication::translate("Utils::FileUtils",
|
||||||
|
"Could not copy file \"%1\" to \"%2\".")
|
||||||
|
.arg(src.toUserOutput(), dest.toUserOutput());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Copies a file specified by \a srcFilePath to \a tgtFilePath only if \a srcFilePath is different
|
||||||
|
(file contents and last modification time).
|
||||||
|
|
||||||
|
Returns whether the operation succeeded.
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool FileUtils::copyIfDifferent(const FilePath &srcFilePath, const FilePath &tgtFilePath)
|
||||||
|
{
|
||||||
|
QTC_ASSERT(srcFilePath.exists(), return false);
|
||||||
|
QTC_ASSERT(srcFilePath.scheme() == tgtFilePath.scheme(), return false);
|
||||||
|
QTC_ASSERT(srcFilePath.host() == tgtFilePath.host(), return false);
|
||||||
|
|
||||||
|
if (tgtFilePath.exists()) {
|
||||||
|
const QDateTime srcModified = srcFilePath.lastModified();
|
||||||
|
const QDateTime tgtModified = tgtFilePath.lastModified();
|
||||||
|
if (srcModified == tgtModified) {
|
||||||
|
const QByteArray srcContents = srcFilePath.fileContents();
|
||||||
|
const QByteArray tgtContents = srcFilePath.fileContents();
|
||||||
|
if (srcContents == tgtContents)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
tgtFilePath.removeFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
return srcFilePath.copyFile(tgtFilePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileUtils::fileSystemFriendlyName(const QString &name)
|
||||||
|
{
|
||||||
|
QString result = name;
|
||||||
|
result.replace(QRegularExpression(QLatin1String("\\W")), QLatin1String("_"));
|
||||||
|
result.replace(QRegularExpression(QLatin1String("_+")), QLatin1String("_")); // compact _
|
||||||
|
result.remove(QRegularExpression(QLatin1String("^_*"))); // remove leading _
|
||||||
|
result.remove(QRegularExpression(QLatin1String("_+$"))); // remove trailing _
|
||||||
|
if (result.isEmpty())
|
||||||
|
result = QLatin1String("unknown");
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FileUtils::indexOfQmakeUnfriendly(const QString &name, int startpos)
|
||||||
|
{
|
||||||
|
static const QRegularExpression checkRegExp(QLatin1String("[^a-zA-Z0-9_.-]"));
|
||||||
|
return checkRegExp.match(name, startpos).capturedStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString FileUtils::qmakeFriendlyName(const QString &name)
|
||||||
|
{
|
||||||
|
QString result = name;
|
||||||
|
|
||||||
|
// Remove characters that might trip up a build system (especially qmake):
|
||||||
|
int pos = indexOfQmakeUnfriendly(result);
|
||||||
|
while (pos >= 0) {
|
||||||
|
result[pos] = QLatin1Char('_');
|
||||||
|
pos = indexOfQmakeUnfriendly(result, pos);
|
||||||
|
}
|
||||||
|
return fileSystemFriendlyName(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileUtils::makeWritable(const FilePath &path)
|
||||||
|
{
|
||||||
|
return path.setPermissions(path.permissions() | QFile::WriteUser);
|
||||||
|
}
|
||||||
|
|
||||||
|
// makes sure that capitalization of directories is canonical on Windows and macOS.
|
||||||
|
// This mimics the logic in QDeclarative_isFileCaseCorrect
|
||||||
|
QString FileUtils::normalizedPathName(const QString &name)
|
||||||
|
{
|
||||||
|
#ifdef Q_OS_WIN
|
||||||
|
const QString nativeSeparatorName(QDir::toNativeSeparators(name));
|
||||||
|
const auto nameC = reinterpret_cast<LPCTSTR>(nativeSeparatorName.utf16()); // MinGW
|
||||||
|
PIDLIST_ABSOLUTE file;
|
||||||
|
HRESULT hr = SHParseDisplayName(nameC, NULL, &file, 0, NULL);
|
||||||
|
if (FAILED(hr))
|
||||||
|
return name;
|
||||||
|
TCHAR buffer[MAX_PATH];
|
||||||
|
const bool success = SHGetPathFromIDList(file, buffer);
|
||||||
|
ILFree(file);
|
||||||
|
return success ? QDir::fromNativeSeparators(QString::fromUtf16(reinterpret_cast<const ushort *>(buffer)))
|
||||||
|
: name;
|
||||||
|
#elif defined(Q_OS_MACOS)
|
||||||
|
return Internal::normalizePathName(name);
|
||||||
|
#else // do not try to handle case-insensitive file systems on Linux
|
||||||
|
return name;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isRelativePathHelper(const QString &path, OsType osType)
|
||||||
|
{
|
||||||
|
if (path.startsWith('/'))
|
||||||
|
return false;
|
||||||
|
if (osType == OsType::OsTypeWindows) {
|
||||||
|
if (path.startsWith('\\'))
|
||||||
|
return false;
|
||||||
|
// Unlike QFileInfo, this won't accept a relative path with a drive letter.
|
||||||
|
// Such paths result in a royal mess anyway ...
|
||||||
|
if (path.length() >= 3 && path.at(1) == ':' && path.at(0).isLetter()
|
||||||
|
&& (path.at(2) == '/' || path.at(2) == '\\'))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileUtils::isRelativePath(const QString &path)
|
||||||
|
{
|
||||||
|
return isRelativePathHelper(path, HostOsInfo::hostOs());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cleans part after optional :// scheme separator, similar to QDir::cleanPath()
|
||||||
|
// - directory separators normalized (that is, platform-native
|
||||||
|
// separators converted to "/") and redundant ones removed, and "."s and ".."s
|
||||||
|
// resolved (as far as possible).
|
||||||
|
// Symbolic links are kept. This function does not return the
|
||||||
|
// canonical path, but rather the simplest version of the input.
|
||||||
|
// For example, "./local" becomes "local", "local/../bin" becomes
|
||||||
|
// "bin" and "/local/usr/../bin" becomes "/local/bin".
|
||||||
|
|
||||||
|
// FIXME: This should not use the host-platform dependent QDir::cleanPath()
|
||||||
|
|
||||||
|
QString doCleanPath(const QString &input)
|
||||||
|
{
|
||||||
|
const int pos = input.indexOf("://");
|
||||||
|
if (pos == -1)
|
||||||
|
return QDir::cleanPath(input);
|
||||||
|
return input.left(pos + 3) + QDir::cleanPath(input.mid(pos + 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath FileUtils::commonPath(const FilePath &oldCommonPath, const FilePath &filePath)
|
||||||
|
{
|
||||||
|
FilePath newCommonPath = oldCommonPath;
|
||||||
|
while (!newCommonPath.isEmpty() && !filePath.isChildOf(newCommonPath))
|
||||||
|
newCommonPath = newCommonPath.parentDir();
|
||||||
|
return newCommonPath.canonicalPath();
|
||||||
|
}
|
||||||
|
|
||||||
|
FilePath FileUtils::homePath()
|
||||||
|
{
|
||||||
|
return FilePath::fromString(doCleanPath(QDir::homePath()));
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
@@ -53,47 +53,6 @@ QT_END_NAMESPACE
|
|||||||
|
|
||||||
namespace Utils {
|
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 &)> isWritableFile;
|
|
||||||
std::function<bool(const FilePath &)> isFile;
|
|
||||||
std::function<bool(const FilePath &)> isDir;
|
|
||||||
std::function<bool(const FilePath &)> ensureWritableDir;
|
|
||||||
std::function<bool(const FilePath &)> ensureExistingFile;
|
|
||||||
std::function<bool(const FilePath &)> createDir;
|
|
||||||
std::function<bool(const FilePath &)> exists;
|
|
||||||
std::function<bool(const FilePath &)> removeFile;
|
|
||||||
std::function<bool(const FilePath &)> removeRecursively;
|
|
||||||
std::function<bool(const FilePath &, const FilePath &)> copyFile;
|
|
||||||
std::function<bool(const FilePath &, const FilePath &)> renameFile;
|
|
||||||
std::function<FilePath(const FilePath &, const FilePaths &)> searchInPath;
|
|
||||||
std::function<FilePath(const FilePath &)> symLinkTarget;
|
|
||||||
std::function<QString(const FilePath &)> mapToDevicePath;
|
|
||||||
std::function<void(const FilePath &,
|
|
||||||
const std::function<bool(const FilePath &)> &, // Abort on 'false' return.
|
|
||||||
const FileFilter &)> iterateDirectory;
|
|
||||||
std::function<QByteArray(const FilePath &, qint64, qint64)> fileContents;
|
|
||||||
std::function<bool(const FilePath &, const QByteArray &)> writeFileContents;
|
|
||||||
std::function<QDateTime(const FilePath &)> lastModified;
|
|
||||||
std::function<QFile::Permissions(const FilePath &)> permissions;
|
|
||||||
std::function<bool(const FilePath &, QFile::Permissions)> setPermissions;
|
|
||||||
std::function<OsType(const FilePath &)> osType;
|
|
||||||
std::function<Environment(const FilePath &)> environment;
|
|
||||||
std::function<qint64(const FilePath &)> fileSize;
|
|
||||||
std::function<qint64(const FilePath &)> bytesAvailable;
|
|
||||||
std::function<QString(const FilePath &)> deviceDisplayName;
|
|
||||||
|
|
||||||
template <class ...Args> using Continuation = std::function<void(Args...)>;
|
|
||||||
std::function<void(const Continuation<bool> &, const FilePath &, const FilePath &)> asyncCopyFile;
|
|
||||||
std::function<void(const Continuation<const QByteArray &> &, const FilePath &, qint64, qint64)> asyncFileContents;
|
|
||||||
std::function<void(const Continuation<bool> &, const FilePath &, const QByteArray &)> asyncWriteFileContents;
|
|
||||||
};
|
|
||||||
|
|
||||||
class QTCREATOR_UTILS_EXPORT FileUtils
|
class QTCREATOR_UTILS_EXPORT FileUtils
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -138,8 +97,6 @@ public:
|
|||||||
static QByteArray fileId(const FilePath &fileName);
|
static QByteArray fileId(const FilePath &fileName);
|
||||||
static FilePath homePath();
|
static FilePath homePath();
|
||||||
|
|
||||||
static void setDeviceFileHooks(const DeviceFileHooks &hooks);
|
|
||||||
|
|
||||||
static void iterateLsOutput(const FilePath &base,
|
static void iterateLsOutput(const FilePath &base,
|
||||||
const QStringList &entries,
|
const QStringList &entries,
|
||||||
const FileFilter &filter,
|
const FileFilter &filter,
|
||||||
@@ -328,5 +285,8 @@ private:
|
|||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FilePath &fn);
|
QTCREATOR_UTILS_EXPORT QTextStream &operator<<(QTextStream &s, const FilePath &fn);
|
||||||
|
|
||||||
|
bool isRelativePathHelper(const QString &path, OsType osType);
|
||||||
|
QString doCleanPath(const QString &input);
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
|
@@ -610,7 +610,7 @@ DeviceManager::DeviceManager(bool isInstance) : d(std::make_unique<DeviceManager
|
|||||||
return device->displayName();
|
return device->displayName();
|
||||||
};
|
};
|
||||||
|
|
||||||
FileUtils::setDeviceFileHooks(deviceHooks);
|
FilePath::setDeviceFileHooks(deviceHooks);
|
||||||
|
|
||||||
DeviceProcessHooks processHooks;
|
DeviceProcessHooks processHooks;
|
||||||
|
|
||||||
|
@@ -175,7 +175,7 @@ void tst_fsengine::initTestCase()
|
|||||||
|
|
||||||
deviceHooks.mapToDevicePath = [](const FilePath &filePath) { return filePath.path(); };
|
deviceHooks.mapToDevicePath = [](const FilePath &filePath) { return filePath.path(); };
|
||||||
|
|
||||||
FileUtils::setDeviceFileHooks(deviceHooks);
|
FilePath::setDeviceFileHooks(deviceHooks);
|
||||||
|
|
||||||
FSEngine::addDevice(FilePath::fromString("device://test"));
|
FSEngine::addDevice(FilePath::fromString("device://test"));
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user