Utils: ensureWritableDir returns expected_str

Allows calling code to get better feedback to user.

Change-Id: I6d11787d314921dc052e87a8348683b221a17425
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-06-20 14:59:37 +02:00
parent 0bc14bfd7d
commit 39837d9c26
7 changed files with 80 additions and 63 deletions

View File

@@ -18,10 +18,10 @@
#include <QCoreApplication>
#include <QOperatingSystemVersion>
#include <QRandomGenerator>
#include <QRegularExpression>
#include <QStorageInfo>
#include <QTemporaryFile>
#include <QRandomGenerator>
#ifdef Q_OS_WIN
#ifdef QTCREATOR_PCH_H
@@ -113,11 +113,22 @@ bool DeviceFileAccess::hasHardLinks(const FilePath &filePath) const
return false;
}
bool DeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const
expected_str<void> DeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const
{
if (isWritableDirectory(filePath))
return true;
return createDirectory(filePath);
return {};
if (exists(filePath)) {
return make_unexpected(Tr::tr("Path \"%1\" exists but is not a writable directory.")
.arg(filePath.toUserOutput()));
}
const bool result = createDirectory(filePath);
if (result)
return {};
return make_unexpected(
Tr::tr("Failed to create directory \"%1\".").arg(filePath.toUserOutput()));
}
bool DeviceFileAccess::ensureExistingFile(const FilePath &filePath) const
@@ -166,31 +177,24 @@ expected_str<void> DeviceFileAccess::copyFile(const FilePath &filePath, const Fi
expected_str<void> copyRecursively_fallback(const FilePath &src, const FilePath &target)
{
QString error;
expected_str<void> result;
src.iterateDirectory(
[&target, &src, &error](const FilePath &path) {
[&target, &src, &result](const FilePath &path) {
const FilePath relative = path.relativePathFrom(src);
const FilePath targetPath = target.pathAppended(relative.path());
if (!targetPath.parentDir().ensureWritableDir()) {
error = QString("Could not create directory %1")
.arg(targetPath.parentDir().toUserOutput());
result = targetPath.parentDir().ensureWritableDir();
if (!result)
return IterationPolicy::Stop;
}
const expected_str<void> result = path.copyFile(targetPath);
if (!result) {
error = result.error();
result = path.copyFile(targetPath);
if (!result)
return IterationPolicy::Stop;
}
return IterationPolicy::Continue;
},
{{"*"}, QDir::NoDotAndDotDot | QDir::Files, QDirIterator::Subdirectories});
if (error.isEmpty())
return {};
return make_unexpected(error);
return result;
}
expected_str<void> DeviceFileAccess::copyRecursively(const FilePath &src,
@@ -200,12 +204,12 @@ expected_str<void> DeviceFileAccess::copyRecursively(const FilePath &src,
return make_unexpected(
Tr::tr("Cannot copy from \"%1\", it is not a directory.").arg(src.toUserOutput()));
}
if (!target.ensureWritableDir()) {
return make_unexpected(
Tr::tr("Cannot copy \"%1\" to \"%2\", it is not a writable directory.")
.arg(src.toUserOutput())
.arg(target.toUserOutput()));
const expected_str<void> result = target.ensureWritableDir();
if (!result) {
return make_unexpected(Tr::tr("Cannot copy \"%1\" to \"%2\": %3")
.arg(src.toUserOutput())
.arg(target.toUserOutput())
.arg(result.error()));
}
#ifdef UTILS_STATIC_LIBRARY
@@ -386,7 +390,6 @@ expected_str<FilePath> DeviceFileAccess::createTempFile(const FilePath &filePath
Tr::tr("createTempFile is not implemented for \"%1\".").arg(filePath.toUserOutput()));
}
// DesktopDeviceFileAccess
DesktopDeviceFileAccess::~DesktopDeviceFileAccess() = default;
@@ -513,12 +516,23 @@ bool DesktopDeviceFileAccess::hasHardLinks(const FilePath &filePath) const
return false;
}
bool DesktopDeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const
expected_str<void> DesktopDeviceFileAccess::ensureWritableDirectory(const FilePath &filePath) const
{
const QFileInfo fi(filePath.path());
if (fi.isDir() && fi.isWritable())
return true;
return QDir().mkpath(filePath.path());
return {};
if (fi.exists()) {
return make_unexpected(Tr::tr("Path \"%1\" exists but is not a writable directory.")
.arg(filePath.toUserOutput()));
}
const bool result = QDir().mkpath(filePath.path());
if (result)
return {};
return make_unexpected(
Tr::tr("Failed to create directory \"%1\".").arg(filePath.toUserOutput()));
}
bool DesktopDeviceFileAccess::ensureExistingFile(const FilePath &filePath) const
@@ -945,7 +959,9 @@ expected_str<void> UnixDeviceFileAccess::copyFile(const FilePath &filePath,
if (result.exitCode != 0) {
return make_unexpected(Tr::tr("Failed to copy file \"%1\" to \"%2\": %3")
.arg(filePath.toUserOutput(), target.toUserOutput(), QString::fromUtf8(result.stdErr)));
.arg(filePath.toUserOutput(),
target.toUserOutput(),
QString::fromUtf8(result.stdErr)));
}
return {};
}
@@ -1080,7 +1096,8 @@ QStringList UnixDeviceFileAccess::statArgs(const FilePath &filePath,
const QString &linuxFormat,
const QString &macFormat) const
{
return (filePath.osType() == OsTypeMac ? QStringList{"-f", macFormat} : QStringList{"-c", linuxFormat})
return (filePath.osType() == OsTypeMac ? QStringList{"-f", macFormat}
: QStringList{"-c", linuxFormat})
<< "-L" << filePath.path();
}
@@ -1173,8 +1190,8 @@ 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 = filePath.osType() == OsTypeMac
? QLatin1String("-f \"%p %m %z\"") : QLatin1String("-c \"%f %Y %s\"");
const QString statFormat = filePath.osType() == OsTypeMac ? QLatin1String("-f \"%p %m %z\"")
: QLatin1String("-c \"%f %Y %s\"");
if (callBack.index() == 1)
cmdLine.addArgs(QString(R"(-exec echo -n \"{}\"" " \; -exec stat -L %1 "{}" \;)")
@@ -1202,24 +1219,23 @@ bool UnixDeviceFileAccess::iterateWithFind(const FilePath &filePath,
const int modeBase = filePath.osType() == OsTypeMac ? 8 : 16;
const auto toFilePath =
[&filePath, &callBack, modeBase](const QString &entry) {
if (callBack.index() == 0)
return std::get<0>(callBack)(filePath.withNewPath(entry));
const auto toFilePath = [&filePath, &callBack, modeBase](const QString &entry) {
if (callBack.index() == 0)
return std::get<0>(callBack)(filePath.withNewPath(entry));
const QString fileName = entry.mid(1, entry.lastIndexOf('\"') - 1);
const QString infos = entry.mid(fileName.length() + 3);
const QString fileName = entry.mid(1, entry.lastIndexOf('\"') - 1);
const QString infos = entry.mid(fileName.length() + 3);
const FilePathInfo fi = FileUtils::filePathInfoFromTriple(infos, modeBase);
if (!fi.fileFlags)
return IterationPolicy::Continue;
const FilePathInfo fi = FileUtils::filePathInfoFromTriple(infos, modeBase);
if (!fi.fileFlags)
return IterationPolicy::Continue;
const FilePath fp = filePath.withNewPath(fileName);
// Do not return the entry for the directory we are searching in.
if (fp.path() == filePath.path())
return IterationPolicy::Continue;
return std::get<1>(callBack)(fp, fi);
};
const FilePath fp = filePath.withNewPath(fileName);
// Do not return the entry for the directory we are searching in.
if (fp.path() == filePath.path())
return IterationPolicy::Continue;
return std::get<1>(callBack)(fp, fi);
};
// Remove the first line, this can be the directory we are searching in.
// as long as we do not specify "mindepth > 0"
@@ -1238,7 +1254,8 @@ void UnixDeviceFileAccess::findUsingLs(const QString &current,
const FileFilter &filter,
QStringList *found) const
{
const RunResult result = runInShell({"ls", {"-1", "-a", "-p", "--", current}, OsType::OsTypeLinux});
const RunResult result = runInShell(
{"ls", {"-1", "-a", "-p", "--", current}, OsType::OsTypeLinux});
const QStringList entries = QString::fromUtf8(result.stdOut).split('\n', Qt::SkipEmptyParts);
for (QString entry : entries) {
const QChar last = entry.back();
@@ -1317,4 +1334,4 @@ Environment UnixDeviceFileAccess::deviceEnvironment() const
return Environment(out.split('\n', Qt::SkipEmptyParts), OsTypeLinux);
}
} // Utils
} // namespace Utils