Utils: Add FilePath::tmpDir and createTempFile

Change-Id: I6f3143e59a87edffeee5e08708ba721293a8a369
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
Marcus Tillmanns
2023-02-07 07:57:17 +01:00
parent 02777c4179
commit 516fce6f53
5 changed files with 162 additions and 0 deletions

View File

@@ -19,6 +19,8 @@
#include <QOperatingSystemVersion>
#include <QRegularExpression>
#include <QStorageInfo>
#include <QTemporaryFile>
#include <QRandomGenerator>
#ifdef Q_OS_WIN
#ifdef QTCREATOR_PCH_H
@@ -30,6 +32,8 @@
#include <qplatformdefs.h>
#endif
#include <algorithm>
namespace Utils {
// DeviceFileAccess
@@ -397,6 +401,15 @@ void DeviceFileAccess::asyncCopyFile(const FilePath &filePath,
cont(copyFile(filePath, target));
}
expected_str<FilePath> DeviceFileAccess::createTempFile(const FilePath &filePath)
{
Q_UNUSED(filePath)
QTC_CHECK(false);
return make_unexpected(Tr::tr("createTempFile is not implemented for \"%1\"")
.arg(filePath.toUserOutput()));
}
// DesktopDeviceFileAccess
DesktopDeviceFileAccess::~DesktopDeviceFileAccess() = default;
@@ -690,6 +703,16 @@ expected_str<qint64> DesktopDeviceFileAccess::writeFileContents(const FilePath &
return res;
}
expected_str<FilePath> DesktopDeviceFileAccess::createTempFile(const FilePath &filePath)
{
QTemporaryFile file(filePath.path());
file.setAutoRemove(false);
if (!file.open())
return make_unexpected(Tr::tr("Could not create temporary file in \"%1\" (%2)").arg(filePath.toUserOutput()).arg(file.errorString()));
return FilePath::fromString(file.fileName()).onDevice(filePath);
}
QDateTime DesktopDeviceFileAccess::lastModified(const FilePath &filePath) const
{
return QFileInfo(filePath.path()).lastModified();
@@ -965,6 +988,65 @@ expected_str<qint64> UnixDeviceFileAccess::writeFileContents(const FilePath &fil
return data.size();
}
expected_str<FilePath> UnixDeviceFileAccess::createTempFile(const FilePath &filePath)
{
if (!m_hasMkTemp.has_value())
m_hasMkTemp = runInShellSuccess({"which", {"mktemp"}, OsType::OsTypeLinux});
QString tmplate = filePath.path();
// Some mktemp implementations require a suffix of XXXXXX.
// They will only accept the template if at least the last 6 characters are X.
if (!tmplate.endsWith("XXXXXX"))
tmplate += ".XXXXXX";
if (m_hasMkTemp) {
const RunResult result = runInShell({"mktemp", {tmplate}, OsType::OsTypeLinux});
if (result.exitCode != 0) {
return make_unexpected(
Tr::tr("Failed creating temporary file \"%1\": %2")
.arg(filePath.toUserOutput(), QString::fromUtf8(result.stdErr)));
}
return FilePath::fromString(QString::fromUtf8(result.stdOut.trimmed())).onDevice(filePath);
}
// Manually create a temporary/unique file.
std::reverse_iterator<QChar *> firstX = std::find_if_not(std::rbegin(tmplate),
std::rend(tmplate),
[](QChar ch) { return ch == 'X'; });
static constexpr std::array<QChar, 62> chars = {'0', '1', '2', '3', '4', '5', '6', '7', '8',
'9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q',
'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R',
'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};
std::uniform_int_distribution<> dist(0, chars.size() - 1);
int maxTries = 10;
FilePath newPath;
do {
for (QChar *it = firstX.base(); it != std::end(tmplate); ++it) {
*it = chars[dist(*QRandomGenerator::global())];
}
newPath = FilePath::fromString(tmplate).onDevice(filePath);
if (--maxTries == 0) {
return make_unexpected(Tr::tr("Failed creating temporary file \"%1\" (too many tries)")
.arg(filePath.toUserOutput()));
}
} while (newPath.exists());
const expected_str<qint64> createResult = newPath.writeFileContents({});
if (!createResult)
return make_unexpected(createResult.error());
return newPath;
}
OsType UnixDeviceFileAccess::osType(const FilePath &filePath) const
{
Q_UNUSED(filePath)