8 #include <QCoreApplication>
11 #include <QRegularExpression>
21 using namespace swift::config;
22 using namespace swift::misc::network;
26 bool CDirectoryUtils::isInApplicationDirectory(
const QString &path)
28 if (path.isEmpty()) {
return false; }
29 return path.contains(qApp->applicationDirPath(), CFileUtils::osFileNameCaseSensitivity());
32 bool CDirectoryUtils::isMacOSAppBundle()
35 qApp->applicationDirPath().contains(
"Contents/MacOS", Qt::CaseInsensitive);
39 QString CDirectoryUtils::decodeNormalizedDirectory(
const QString &directory)
41 return QUrl::fromPercentEncoding(directory.toUtf8());
44 QStringList CDirectoryUtils::getRelativeSubDirectories(
const QString &rootDir)
46 const QDir dir(rootDir);
47 if (!dir.exists()) {
return QStringList(); }
48 return dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot | QDir::NoSymLinks);
51 bool CDirectoryUtils::containsFileInDir(
const QString &dir,
const QString &filter,
bool recursively)
53 const QDir directory(dir);
54 if (!directory.exists()) {
return false; }
56 const QStringList nameFilter({ filter });
57 if (!directory.entryInfoList(nameFilter, QDir::Files | QDir::NoDot | QDir::NoDotDot).isEmpty()) {
return true; }
59 if (!recursively) {
return false; }
60 const QStringList relSubDirs = CDirectoryUtils::getRelativeSubDirectories(dir);
61 for (
const QString &relSubDir : relSubDirs)
63 const QString absSubDir = CFileUtils::appendFilePaths(directory.absolutePath(), relSubDir);
64 if (CDirectoryUtils::containsFileInDir(absSubDir, filter, recursively)) {
return true; }
69 bool CDirectoryUtils::existsUnemptyDirectory(
const QString &testDir)
71 if (testDir.isEmpty()) {
return false; }
72 const QDir dir(testDir);
73 if (!CDirectoryUtils::isDirExisting(dir)) {
return false; }
74 return !dir.isEmpty();
77 bool CDirectoryUtils::mkPathIfNotExisting(
const QString &dir)
80 if (d.exists()) {
return true; }
82 return mkDir.mkpath(dir);
85 QStringList CDirectoryUtils::getExistingUnemptyDirectories(
const QStringList &directories)
88 for (
const QString &dir : directories)
90 if (CDirectoryUtils::existsUnemptyDirectory(dir)) { dirs << dir; }
95 bool CDirectoryUtils::isDirExisting(
const QString &path)
99 const QString machine(CFileUtils::windowsUncMachine(path));
100 if (!canPingUncMachine(machine)) {
return false; }
102 return QDir(path).exists();
105 bool CDirectoryUtils::canPingUncMachine(
const QString &machine)
110 if (machine.isEmpty()) {
return false; }
111 const QString m = machine.toLower();
112 if (good.contains(m)) {
return true; }
115 const qint64 ts = bad.value(m);
116 const qint64 dt = QDateTime::currentSecsSinceEpoch() - ts;
117 if (dt < 1000 * 60) {
return false; }
122 const bool p = canPing(m);
125 good.insert(m, QDateTime::currentSecsSinceEpoch());
130 bad.insert(m, QDateTime::currentSecsSinceEpoch());
136 bool CDirectoryUtils::isDirExisting(
const QDir &dir)
138 if (!CFileUtils::isWindowsUncPath(dir.absolutePath())) {
return dir.exists(); }
139 return CDirectoryUtils::isDirExisting(dir.absolutePath());
142 bool CDirectoryUtils::isSameExistingDirectory(
const QString &dir1,
const QString &dir2)
144 if (dir1.isEmpty() || dir2.isEmpty()) {
return false; }
147 if (!d1.exists() || !d2.exists()) {
return false; }
148 return d1.absolutePath() == d2.absolutePath();
151 bool CDirectoryUtils::isSameOrSubDirectoryOf(
const QString &testDir,
const QString &dir2)
153 if (testDir.isEmpty() || dir2.isEmpty()) {
return false; }
155 return CDirectoryUtils::isSameOrSubDirectoryOf(testDir, d2);
158 bool CDirectoryUtils::isSameOrSubDirectoryOf(
const QString &dir1,
const QDir &parentDir)
162 if (d1 == parentDir) {
return true; }
170 bool CDirectoryUtils::isSameOrSubDirectoryOfStringBased(
const QString &testDir,
const QString &parentDir)
172 const Qt::CaseSensitivity cs = CFileUtils::osFileNameCaseSensitivity();
173 const QString td = CFileUtils::fixWindowsUncPath(QDir::cleanPath(testDir));
174 const QString pd = CFileUtils::fixWindowsUncPath(QDir::cleanPath(parentDir));
175 return td.contains(pd, cs);
178 QSet<QString> CDirectoryUtils::fileNamesToQSet(
const QFileInfoList &fileInfoList)
180 CSetBuilder<QString> sl;
181 for (
const QFileInfo &info : fileInfoList) { sl.insert(info.fileName()); }
185 QSet<QString> CDirectoryUtils::canonicalFileNamesToQSet(
const QFileInfoList &fileInfoList)
187 CSetBuilder<QString> sl;
188 for (
const QFileInfo &info : fileInfoList) { sl.insert(info.canonicalFilePath()); }
192 QSet<QString> CDirectoryUtils::filesToCanonicalNames(
const QSet<QString> &fileNames,
193 const QSet<QString> &canonicalFileNames)
195 CSetBuilder<QString> found;
196 if (fileNames.isEmpty())
return {};
197 for (
const QString &canonical : canonicalFileNames)
199 if (canonical.endsWith(
'/'))
continue;
200 const QString c = canonical.mid(1 + canonical.lastIndexOf(
'/'));
201 if (fileNames.contains(c)) { found.insert(canonical); }
206 int CDirectoryUtils::copyDirectoryRecursively(
const QString &fromDir,
const QString &toDir,
bool replaceOnConflict)
209 const QStringList fromFiles = dir.entryList(QDir::Files | QDir::NoDotAndDotDot);
210 if (!mkPathIfNotExisting(toDir)) {
return -1; }
213 for (
const QString ©File : fromFiles)
215 const QString from = CFileUtils::appendFilePaths(fromDir, copyFile);
216 const QString to = CFileUtils::appendFilePaths(toDir, copyFile);
217 if (QFile::exists(to))
219 if (!replaceOnConflict) {
continue; }
220 if (!QFile::remove(to)) {
return -1; }
222 if (!QFile::copy(from, to)) {
return -1; }
226 const QStringList subDirs = dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
227 for (
const QString ©Dir : subDirs)
229 const QString fromSubDir = CFileUtils::appendFilePaths(fromDir, copyDir);
230 const QString toSubDir = CFileUtils::appendFilePaths(toDir, copyDir);
231 if (!mkPathIfNotExisting(toDir)) {
return -1; }
233 const int c = copyDirectoryRecursively(fromSubDir, toSubDir, replaceOnConflict);
234 if (c < 0) {
return -1; }
240 CDirectoryUtils::DirComparison CDirectoryUtils::compareTwoDirectories(
const QString &dirSource,
241 const QString &dirTarget,
bool nestedDirs)
244 const QDir d1(dirSource);
245 const QDir d2(dirTarget);
247 QFileInfoList dSourceList;
248 QFileInfoList dTargetList;
249 if (d1.exists()) { dSourceList = d1.entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name); }
250 if (d2.exists()) { dTargetList = d2.entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name); }
253 const QSet<QString> sSourceFiles = CDirectoryUtils::fileNamesToQSet(dSourceList);
254 const QSet<QString> sTargetFiles = CDirectoryUtils::fileNamesToQSet(dTargetList);
257 const QSet<QString> sSourceCanonicalFiles = CDirectoryUtils::canonicalFileNamesToQSet(dSourceList);
258 const QSet<QString> sTargetCanonicalFiles = CDirectoryUtils::canonicalFileNamesToQSet(dTargetList);
260 QSet<QString> missingInTarget(sSourceFiles);
261 QSet<QString> missingInSource(sTargetFiles);
262 QSet<QString> sameNames(sSourceFiles);
263 missingInSource.subtract(sSourceFiles);
264 missingInTarget.subtract(sTargetFiles);
265 sameNames.intersect(sTargetFiles);
267 comp.source = sSourceCanonicalFiles;
268 comp.missingInSource = CDirectoryUtils::filesToCanonicalNames(missingInSource, sSourceCanonicalFiles);
269 comp.missingInTarget = CDirectoryUtils::filesToCanonicalNames(missingInTarget, sSourceCanonicalFiles);
270 comp.sameNameInSource = CDirectoryUtils::filesToCanonicalNames(sameNames, sSourceCanonicalFiles);
271 comp.sameNameInTarget = CDirectoryUtils::filesToCanonicalNames(sameNames, sTargetCanonicalFiles);
273 Q_ASSERT_X(comp.sameNameInSource.size() == comp.sameNameInTarget.size(), Q_FUNC_INFO,
274 "Same sets require same size");
275 QSet<QString>::const_iterator targetIt = comp.sameNameInTarget.cbegin();
276 for (
const QString &sourceFile : std::as_const(comp.sameNameInSource))
278 const QFileInfo source(sourceFile);
279 const QFileInfo target(*targetIt);
281 if (source.lastModified() == target.lastModified() && source.size() == target.size()) {
continue; }
283 if (source.lastModified() < target.lastModified())
285 comp.newerInTarget.insert(target.canonicalFilePath());
290 comp.newerInSource.insert(source.canonicalFilePath());
296 const QStringList relativeSubdirs = CDirectoryUtils::getRelativeSubDirectories(dirSource);
297 if (!relativeSubdirs.isEmpty())
299 for (
const QString &relativeSubdir : relativeSubdirs)
301 const QString sourceSubdir = CFileUtils::appendFilePaths(dirSource, relativeSubdir);
302 const QString targetSubdir = CFileUtils::appendFilePaths(dirTarget, relativeSubdir);
303 const DirComparison subComparison =
304 CDirectoryUtils::compareTwoDirectories(sourceSubdir, targetSubdir,
true);
305 comp.insert(subComparison);
314 void CDirectoryUtils::DirComparison::insert(
const CDirectoryUtils::DirComparison &otherComparison)
316 source += otherComparison.source;
317 missingInSource += otherComparison.missingInSource;
318 missingInTarget += otherComparison.missingInTarget;
319 newerInSource += otherComparison.newerInSource;
320 newerInTarget += otherComparison.newerInTarget;
321 sameNameInSource += otherComparison.sameNameInSource;
322 sameNameInTarget += otherComparison.sameNameInTarget;
static constexpr bool isRunningOnMacOSPlatform()
Running on MacOS platform?
static constexpr bool isRunningOnWindowsNtPlatform()
Running on Windows NT platform?
Free functions in swift::misc.