8 #include <QCoreApplication>
15 #include <QRegularExpression>
16 #include <QStringBuilder>
17 #include <QTextStream>
24 using namespace swift::config;
30 static const QString j(
".json");
34 const QString &CFileUtils::jsonWildcardAppendix()
36 static const QString jw(
"*" + jsonAppendix());
40 bool CFileUtils::writeStringToFile(
const QString &content,
const QString &fileNameAndPath)
42 if (fileNameAndPath.
isEmpty()) {
return false; }
43 QFile file(fileNameAndPath);
51 bool CFileUtils::writeByteArrayToFile(
const QByteArray &data,
const QString &fileNameAndPath)
53 if (fileNameAndPath.
isEmpty()) {
return false; }
54 QFile file(fileNameAndPath);
56 const qint64 c = file.
write(data);
58 return c == data.
size();
61 bool CFileUtils::writeStringToLockedFile(
const QString &content,
const QString &fileNameAndPath)
63 QLockFile lock(fileNameAndPath +
".lock");
64 if (!lock.
lock()) {
return false; }
65 return writeStringToFile(content, fileNameAndPath);
70 QFile file(fileNameAndPath);
80 QLockFile lock(fileNameAndPath +
".lock");
81 if (!lock.
lock()) {
return {}; }
82 return readFileToString(fileNameAndPath);
87 return readFileToString(appendFilePaths(filePath, fileName));
92 return readLockedFileToString(appendFilePaths(filePath, fileName));
111 return win ? CFileUtils::fixWindowsUncPath(appendFilePaths(path1, path2)) : appendFilePaths(path1, path2);
116 if (path.
endsWith(
'/')) {
return path; }
117 if (!path.
contains(
'/')) {
return path; }
123 QString p = normalizeFilePathToQtStandard(path);
125 if (i < 0) {
return p; }
126 if ((i + 1) >= path.
length()) {
return {}; }
127 return path.
mid(i + 1);
133 for (
const QString &path : paths) { stripped.
push_back(stripFileFromPath(path)); }
147 for (
const QString &path : paths) { stripped.
push_back(stripLeadingSlashOrDriveLetter(path)); }
153 if (path.
isEmpty()) {
return {}; }
154 if (path.
endsWith(
'/')) {
return CFileUtils::lastPathSegment(path.
left(path.
length() - 1)); }
155 if (!path.
contains(
'/')) {
return path; }
161 return CFileUtils::appendFilePaths(CFileUtils::appendFilePaths(path1, path2), path3);
167 return win ? CFileUtils::fixWindowsUncPath(
168 CFileUtils::appendFilePaths(CFileUtils::appendFilePaths(path1, path2), path3)) :
169 CFileUtils::appendFilePaths(CFileUtils::appendFilePaths(path1, path2), path3);
175 if (i < 0) {
return path; }
181 if (filePath.
isEmpty()) {
return {}; }
191 if (rootDirectory.
isEmpty() || rootDirectory ==
"/") {
return directories; }
193 const int p = rd.
length();
195 for (
const QString &dir : directories)
197 if (dir.startsWith(rd, cs) && dir.length() > p + 1) { relativeDirectories.
append(dir.mid(p + 1)); }
200 relativeDirectories.
append(dir);
203 return relativeDirectories;
215 if (dirs1Cleaned.
size() != dirs2Cleaned.
size()) {
return false; }
218 dirs1Cleaned.
sort(cs);
219 dirs2Cleaned.
sort(cs);
220 for (
const QString &d1 : dirs1)
232 bool CFileUtils::isFileNameCaseSensitive() {
return CFileUtils::osFileNameCaseSensitivity() ==
Qt::CaseSensitive; }
234 bool CFileUtils::matchesExcludeDirectory(
const QString &directoryPath,
const QString &excludePattern,
237 if (directoryPath.
isEmpty() || excludePattern.
isEmpty()) {
return false; }
238 const QString normalizedExcludePattern(normalizeFilePathToQtStandard(excludePattern));
239 return directoryPath.
contains(normalizedExcludePattern, cs);
242 bool CFileUtils::isExcludedDirectory(
const QDir &directory,
const QStringList &excludeDirectories,
245 if (excludeDirectories.
isEmpty()) {
return false; }
247 return isExcludedDirectory(d, excludeDirectories, cs);
253 if (excludeDirectories.
isEmpty()) {
return false; }
254 return isExcludedDirectory(fileInfo.
absoluteDir(), excludeDirectories, cs);
257 bool CFileUtils::isExcludedDirectory(
const QString &directoryPath,
const QStringList &excludeDirectories,
260 if (excludeDirectories.
isEmpty()) {
return false; }
261 for (
const QString &ex : excludeDirectories)
263 if (matchesExcludeDirectory(directoryPath, ex, cs)) {
return true; }
270 if (directories.
size() < 2) {
return directories; }
274 if (dirs.
size() < 2) {
return dirs; }
278 for (
const QString &path : std::as_const(dirs))
280 if (path.isEmpty()) {
continue; }
281 if (last.
isEmpty() || !path.startsWith(last, cs)) { result.
append(path); }
289 if (filesOrDirectory.
isEmpty()) {
return {}; }
290 for (
const QString &f : filesOrDirectory)
292 if (f.isEmpty()) {
continue; }
293 const QString fn(normalizeFilePathToQtStandard(f));
302 std::function<
bool(
const QFileInfo &)> predicate)
304 if (isExcludedDirectory(dir, excludeDirectories)) {
return QString(); }
308 auto it = std::find_if(result.cbegin(), result.cend(), predicate);
309 if (it != result.cend()) {
return it->filePath(); }
313 if (!result.isEmpty()) {
return result.first().filePath(); }
319 if (isExcludedDirectory(subdir, excludeDirectories)) {
continue; }
321 findFirstFile(subdir.filePath(),
true, nameFilters, excludeDirectories, predicate);
322 if (!first.
isEmpty()) {
return first; }
328 bool CFileUtils::containsFile(
const QDir &dir,
bool recursive,
const QStringList &nameFilters,
330 std::function<
bool(
const QFileInfo &)> predicate)
332 return !findFirstFile(dir, recursive, nameFilters, excludeDirectories, predicate).
isEmpty();
338 return findFirstFile(dir, recursive, nameFilters, excludeDirectories,
342 bool CFileUtils::containsFileNewerThan(
const QDateTime &time,
const QDir &dir,
bool recursive,
345 return !findFirstNewerThan(time, dir, recursive, nameFilters, excludeDirectories).
isEmpty();
348 QFileInfoList CFileUtils::enumerateFiles(
const QDir &dir,
bool recursive,
const QStringList &nameFilters,
350 std::function<
bool(
const QFileInfo &)> predicate)
352 if (isExcludedDirectory(dir, excludeDirectories)) {
return QFileInfoList(); }
356 result.erase(std::remove_if(result.begin(), result.end(), [=](
const auto &f) { return !predicate(f); }),
363 if (isExcludedDirectory(subdir, excludeDirectories)) {
continue; }
364 result += enumerateFiles(subdir.filePath(),
true, nameFilters, excludeDirectories, predicate);
373 if (isExcludedDirectory(dir, excludeDirectories)) {
return {}; }
374 const QFileInfoList files = enumerateFiles(dir, recursive, nameFilters, excludeDirectories);
375 if (files.isEmpty()) {
return {}; }
377 auto it = std::max_element(files.cbegin(), files.cend(), [](
const QFileInfo &a,
const QFileInfo &b) {
378 return a.lastModified() < b.lastModified();
386 if (isExcludedDirectory(dir, excludeDirectories)) {
return {}; }
387 const QFileInfoList files = enumerateFiles(dir, recursive, nameFilters, excludeDirectories);
388 if (files.isEmpty()) {
return {}; }
390 auto it = std::max_element(files.cbegin(), files.cend(), [](
const QFileInfo &a,
const QFileInfo &b) {
391 return a.birthTime() < b.birthTime();
406 for (
const QString &fn : fileNames)
417 for (
const QString &fn : fileNames)
427 switch (lockFile.
error())
437 return QStringLiteral(
"Lock open in another process (%1 %2 on %3)")
440 default:
return QStringLiteral(
"Bad error number");
447 if (!win) {
return filePath; }
448 if (!filePath.
startsWith(
'/')) {
return filePath; }
449 if (filePath.
startsWith(
"//")) {
return filePath; }
450 return QStringLiteral(
"/%1").
arg(filePath);
456 if (!win) {
return filePaths; }
459 for (
const QString &path : filePaths) { fixedPaths << fixWindowsUncPath(path); }
463 bool CFileUtils::isWindowsUncPath(
const QString &filePath)
469 const QString fp = fixWindowsUncPath(filePath);
475 if (!CFileUtils::isWindowsUncPath(filePath)) {
return {}; }
481 if (i < 0) {
return f; }
487 if (paths.
isEmpty()) {
return {}; }
490 const bool isCs = isFileNameCaseSensitive();
497 if (!lastMachine.
isEmpty() && p.contains(lastMachine, cs))
502 const QString m = isCs ? windowsUncMachine(p) : windowsUncMachine(p).toLower();
512 QString p = CFileUtils::fixWindowsUncPath(path);
516 QString CFileUtils::humanReadableFileSize(qint64 size)
520 static const QStringList units({
"KB",
"MB",
"GB",
"TB" });
523 QStringListIterator i(units);
524 double currentSize = size;
526 while (currentSize >= 1024.0 && i.hasNext())
529 currentSize /= 1024.0;
531 return QStringLiteral(
"%1 %2").
arg(currentSize, 0,
'f', 2).
arg(unit);
539 static const QStringList appendixes({
".exe",
".dmg",
".run" });
543 bool CFileUtils::isExecutableFile(
const QString &fileName)
545 for (
const QString &app : CFileUtils::executableSuffixes())
549 return CFileUtils::isSwiftInstaller(fileName);
552 bool CFileUtils::isSwiftInstaller(
const QString &fileName)
554 if (fileName.
isEmpty()) {
return false; }
static constexpr bool isRunningOnWindowsNtPlatform()
Running on Windows NT platform?
Build a QSet more efficiently when calling insert() in a for loop.
void insert(const T &value)
Add an element to the set. Runs in amortized constant time.
Free functions in swift::misc.
SWIFT_MISC_EXPORT bool stringCompare(const QString &c1, const QString &c2, Qt::CaseSensitivity cs)
String compare.
qsizetype size() const const
QString applicationFilePath()
QString absolutePath() const const
QString cleanPath(const QString &path)
QFileInfoList entryInfoList(QDir::Filters filters, QDir::SortFlags sort) const const
bool open(FILE *fh, QIODeviceBase::OpenMode mode, QFileDevice::FileHandleFlags handleFlags)
virtual void close() override
QDir absoluteDir() const const
QString absoluteFilePath() const const
QString baseName() const const
bool exists(const QString &path)
QString fileName() const const
QDateTime lastModified() const const
qint64 write(const QByteArray &data)
void append(QList< T > &&value)
QList< T >::const_reference at(qsizetype i) const const
bool isEmpty() const const
void push_back(QList< T >::parameter_type value)
qsizetype removeAll(const AT &t)
qsizetype size() const const
QLockFile::LockError error() const const
bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const const
bool isEmpty() const const
QString arg(Args &&... args) const const
bool contains(QChar ch, Qt::CaseSensitivity cs) const const
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
QString left(qsizetype n) &&
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) &&
QString number(double n, char format, int precision)
QString & replace(QChar before, QChar after, Qt::CaseSensitivity cs)
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype removeDuplicates()
void sort(Qt::CaseSensitivity cs)