mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-03-31 12:55:33 +08:00
refs #887, directories available via CDirectoryUtils/relative paths
* relative cache/settings paths are available relativeFilePath * directories build in CDirectoryUtils * directory comparison in CDirectoryUtils * using CFileUtils to concatenate dir paths * using URL encoded string for normalized directory (as it can be decoded)
This commit is contained in:
@@ -1121,14 +1121,11 @@ namespace BlackCore
|
||||
// No crash handling for unit tests
|
||||
if (isUnitTest()) { return CStatusMessage(this).info("No crash handler for unit tests"); }
|
||||
|
||||
static const QString extension = CBuildConfig::isRunningOnWindowsNtPlatform() ? ".exe" : QString();
|
||||
static const QString handler = CDirectoryUtils::applicationDirectoryPath() % QLatin1Char('/') % "swift_crashpad_handler" + extension;
|
||||
static const QString crashpadPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) %
|
||||
QLatin1String("/org.swift-project/") %
|
||||
CDirectoryUtils::normalizedApplicationDirectory() %
|
||||
QLatin1String("/crashpad");
|
||||
static const QString database = crashpadPath % QLatin1String("/database");
|
||||
static const QString metrics = crashpadPath % QLatin1String("/metrics");
|
||||
static const QString crashpadHandler(CBuildConfig::isRunningOnWindowsNtPlatform() ? "swift_crashpad_handler.exe" : "swift_crashpad_handler");
|
||||
static const QString handler = CFileUtils::appendFilePaths(CDirectoryUtils::applicationDirectoryPath(), crashpadHandler);
|
||||
static const QString crashpadPath = CDirectoryUtils::getCrashpadDirectory();
|
||||
static const QString database = CFileUtils::appendFilePaths(crashpadPath, "/database");
|
||||
static const QString metrics = CFileUtils::appendFilePaths(crashpadPath, "/metrics");
|
||||
|
||||
if (!QFileInfo::exists(handler))
|
||||
{
|
||||
|
||||
@@ -103,13 +103,13 @@ namespace BlackMisc
|
||||
|
||||
const QString &CDataCache::persistentStore()
|
||||
{
|
||||
static const QString dir = getCacheRootDirectory() + "/data/cache/core";
|
||||
static const QString dir = CFileUtils::appendFilePaths(getCacheRootDirectory(), relativeFilePath());
|
||||
return dir;
|
||||
}
|
||||
|
||||
QString CDataCache::filenameForKey(const QString &key)
|
||||
{
|
||||
return persistentStore() + "/" + CValueCache::filenameForKey(key);
|
||||
return CFileUtils::appendFilePaths(persistentStore(), CValueCache::filenameForKey(key));
|
||||
}
|
||||
|
||||
QStringList CDataCache::enumerateStore() const
|
||||
@@ -174,6 +174,12 @@ namespace BlackMisc
|
||||
singleShot(0, &m_serializer, [this, key] { m_revision.sessionValue(key); });
|
||||
}
|
||||
|
||||
const QString CDataCache::relativeFilePath()
|
||||
{
|
||||
static const QString p("/data/cache/core");
|
||||
return p;
|
||||
}
|
||||
|
||||
QString lockFileError(const QLockFile &lock)
|
||||
{
|
||||
switch (lock.error())
|
||||
|
||||
@@ -285,6 +285,9 @@ namespace BlackMisc
|
||||
//! Method used for implementing session values.
|
||||
void sessionValue(const QString &key);
|
||||
|
||||
//! Relative file path in application data directory
|
||||
static const QString relativeFilePath();
|
||||
|
||||
private:
|
||||
CDataCache();
|
||||
|
||||
|
||||
@@ -10,9 +10,12 @@
|
||||
//! \cond PRIVATE
|
||||
|
||||
#include "blackmisc/directoryutils.h"
|
||||
|
||||
#include "blackmisc/fileutils.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QDir>
|
||||
#include <QUrl>
|
||||
#include <QSet>
|
||||
#include <QDateTime>
|
||||
#include <QRegularExpression>
|
||||
#include <QStandardPaths>
|
||||
|
||||
@@ -34,13 +37,11 @@ namespace BlackMisc
|
||||
|
||||
QString normalizedApplicationDirectoryImpl()
|
||||
{
|
||||
QString appDir = CDirectoryUtils::applicationDirectoryPath().toLower();
|
||||
QString appDir = CDirectoryUtils::applicationDirectoryPath();
|
||||
Q_ASSERT(appDir.size() > 0);
|
||||
// Remove leading '/' on Unix
|
||||
if (appDir.at(0) == '/') { appDir.remove(0, 1); }
|
||||
const QRegularExpression re("[:\\\\\\/]");
|
||||
appDir = appDir.replace(re, "_");
|
||||
return appDir;
|
||||
return QUrl::toPercentEncoding(appDir);
|
||||
}
|
||||
|
||||
const QString &CDirectoryUtils::normalizedApplicationDirectory()
|
||||
@@ -49,15 +50,146 @@ namespace BlackMisc
|
||||
return appDir;
|
||||
}
|
||||
|
||||
const QString &CDirectoryUtils::getLogDirectory()
|
||||
const QString &CDirectoryUtils::swiftApplicationDataDirectory()
|
||||
{
|
||||
static const QString logPath = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
|
||||
"/org.swift-project/" +
|
||||
CDirectoryUtils::normalizedApplicationDirectory() +
|
||||
"/logs";
|
||||
return logPath;
|
||||
static const QString p = CFileUtils::appendFilePaths(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "/org.swift-project/");
|
||||
return p;
|
||||
}
|
||||
|
||||
QFileInfoList CDirectoryUtils::swiftApplicationDataDirectories()
|
||||
{
|
||||
QDir swiftAppData(CDirectoryUtils::swiftApplicationDataDirectory()); // contains 1..n subdirs
|
||||
if (!swiftAppData.isReadable()) return QFileInfoList();
|
||||
return swiftAppData.entryInfoList({}, QDir::Dirs | QDir::NoDotAndDotDot, QDir::Time);
|
||||
}
|
||||
|
||||
QStringList CDirectoryUtils::swiftApplicationDataDirectoryList(bool withoutCurrent, bool beautify)
|
||||
{
|
||||
QStringList dirs;
|
||||
const QFileInfoList directories(CDirectoryUtils::swiftApplicationDataDirectories());
|
||||
for (const QFileInfo &info : directories)
|
||||
{
|
||||
if (withoutCurrent && info.filePath().contains(normalizedApplicationDirectory(), Qt::CaseInsensitive)) continue;
|
||||
dirs.append(beautify ?
|
||||
CDirectoryUtils::decodeNormalizedDirectory(info.fileName()) :
|
||||
info.fileName());
|
||||
}
|
||||
return dirs;
|
||||
}
|
||||
|
||||
const QString &CDirectoryUtils::swiftNormalizedApplicationDataDirectory()
|
||||
{
|
||||
static const QString p = CFileUtils::appendFilePaths(swiftApplicationDataDirectory(), normalizedApplicationDirectory());
|
||||
return p;
|
||||
}
|
||||
|
||||
const QString &CDirectoryUtils::getLogDirectory()
|
||||
{
|
||||
static const QString p = CFileUtils::appendFilePaths(swiftNormalizedApplicationDataDirectory(), "/logs");
|
||||
return p;
|
||||
}
|
||||
|
||||
const QString &CDirectoryUtils::getCrashpadDirectory()
|
||||
{
|
||||
static const QString p = CFileUtils::appendFilePaths(swiftNormalizedApplicationDataDirectory(), "/crashpad");
|
||||
return p;
|
||||
}
|
||||
|
||||
QString CDirectoryUtils::decodeNormalizedDirectory(const QString &directory)
|
||||
{
|
||||
return QUrl::fromPercentEncoding(directory.toUtf8());
|
||||
}
|
||||
|
||||
QSet<QString> CDirectoryUtils::fileNamesToQSet(const QFileInfoList &fileInfoList)
|
||||
{
|
||||
QSet<QString> sl;
|
||||
for (const QFileInfo &info : fileInfoList)
|
||||
{
|
||||
sl.insert(info.fileName());
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
|
||||
QSet<QString> CDirectoryUtils::canonicalFileNamesToQSet(const QFileInfoList &fileInfoList)
|
||||
{
|
||||
QSet<QString> sl;
|
||||
for (const QFileInfo &info : fileInfoList)
|
||||
{
|
||||
sl.insert(info.canonicalFilePath());
|
||||
}
|
||||
return sl;
|
||||
}
|
||||
|
||||
const QSet<QString> CDirectoryUtils::filesToCanonicalNames(const QSet<QString> &fileNames, const QSet<QString> &canonicalFileNames)
|
||||
{
|
||||
QSet<QString> found;
|
||||
if (fileNames.isEmpty()) return found;
|
||||
for (const QString &canonical : canonicalFileNames)
|
||||
{
|
||||
if (canonical.endsWith('/')) continue;
|
||||
const QString c = canonical.mid(1 + canonical.lastIndexOf('/'));
|
||||
if (fileNames.contains(c))
|
||||
{
|
||||
found.insert(canonical);
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
CDirectoryUtils::DirComparison CDirectoryUtils::compareTwoDirectories(const QString &dirSource, const QString &dirTarget)
|
||||
{
|
||||
DirComparison comp;
|
||||
const QDir d1(dirSource);
|
||||
const QDir d2(dirTarget);
|
||||
|
||||
if (!d1.exists() || !d2.exists()) { return comp; }
|
||||
const QFileInfoList dSourceList = d1.entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
|
||||
const QFileInfoList dTargetList = d2.entryInfoList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name);
|
||||
|
||||
// only names
|
||||
const QSet<QString> sSourceFiles = CDirectoryUtils::fileNamesToQSet(dSourceList);
|
||||
const QSet<QString> sTargetFiles = CDirectoryUtils::fileNamesToQSet(dTargetList);
|
||||
|
||||
// full paths
|
||||
const QSet<QString> sSourceCanonicalFiles = CDirectoryUtils::canonicalFileNamesToQSet(dSourceList);
|
||||
const QSet<QString> sTargetCanonicalFiles = CDirectoryUtils::canonicalFileNamesToQSet(dTargetList);
|
||||
|
||||
QSet<QString> missingInTarget(sSourceFiles);
|
||||
QSet<QString> missingInSource(sTargetFiles);
|
||||
QSet<QString> sameNames(sSourceFiles);
|
||||
missingInSource.subtract(sSourceFiles);
|
||||
missingInTarget.subtract(sTargetFiles);
|
||||
sameNames.intersect(sTargetFiles);
|
||||
|
||||
comp.source = sSourceCanonicalFiles;
|
||||
comp.missingInSource = CDirectoryUtils::filesToCanonicalNames(missingInSource, sSourceCanonicalFiles);
|
||||
comp.missingInTarget = CDirectoryUtils::filesToCanonicalNames(missingInTarget, sSourceCanonicalFiles);
|
||||
comp.sameNameInSource = CDirectoryUtils::filesToCanonicalNames(sameNames, sSourceCanonicalFiles);
|
||||
comp.sameNameInTarget = CDirectoryUtils::filesToCanonicalNames(sameNames, sTargetCanonicalFiles);
|
||||
|
||||
Q_ASSERT_X(comp.sameNameInSource.size() == comp.sameNameInTarget.size(), Q_FUNC_INFO, "Same sets require same size");
|
||||
QSet<QString>::const_iterator targetIt = comp.sameNameInTarget.begin();
|
||||
for (const QString &sourceFile : comp.sameNameInSource)
|
||||
{
|
||||
const QFileInfo source(sourceFile);
|
||||
const QFileInfo target(*targetIt++);
|
||||
if (source.lastModified() == target.lastModified() && source.size() == target.size())
|
||||
{
|
||||
// same
|
||||
}
|
||||
else if (source.lastModified() < target.lastModified())
|
||||
{
|
||||
comp.newerInTarget.insert(target.canonicalFilePath());
|
||||
}
|
||||
else
|
||||
{
|
||||
// source.lastModified() >= target.lastModified()
|
||||
comp.newerInSource.insert(source.canonicalFilePath());
|
||||
}
|
||||
}
|
||||
comp.ok = true;
|
||||
return comp;
|
||||
}
|
||||
} // ns
|
||||
|
||||
//! \endcond
|
||||
|
||||
@@ -13,7 +13,9 @@
|
||||
#define BLACKMISC_DIRECTORYUTILS_H
|
||||
|
||||
#include "blackmisc/blackmiscexport.h"
|
||||
#include <QSet>
|
||||
#include <QString>
|
||||
#include <QFileInfoList>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
@@ -27,14 +29,58 @@ namespace BlackMisc
|
||||
//! it takes Mac OS X app bundles into account and returns the directory of the bundle.
|
||||
static QString applicationDirectoryPath();
|
||||
|
||||
//! swift application data directory, contains 0..n swift installation directories
|
||||
static const QString &swiftApplicationDataDirectory();
|
||||
|
||||
//! swift application data sub directories
|
||||
static QFileInfoList swiftApplicationDataDirectories();
|
||||
|
||||
//! swift application data sub directories
|
||||
static QStringList swiftApplicationDataDirectoryList(bool withoutCurrent = false, bool beautify = false);
|
||||
|
||||
//! swift application data directory for one specific installation (a version)
|
||||
static const QString &swiftNormalizedApplicationDataDirectory();
|
||||
|
||||
//! Directory for log files
|
||||
//! \remark In BlackMisc so it can also be used from BlackMisc classes
|
||||
static const QString &getLogDirectory();
|
||||
|
||||
//! Directory for log files
|
||||
static const QString &getCrashpadDirectory();
|
||||
|
||||
//! Virtually the inverse operation of CDirectoryUtils::normalizedApplicationDirectory
|
||||
static QString decodeNormalizedDirectory(const QString &directory);
|
||||
|
||||
//! Result of directory comparison
|
||||
struct DirComparison
|
||||
{
|
||||
bool ok = false; //!< comparison ok
|
||||
QSet<QString> source; //!< all source files
|
||||
QSet<QString> missingInSource; //!< files not in source, but in target
|
||||
QSet<QString> missingInTarget; //!< files not in target, but in source
|
||||
QSet<QString> newerInSource; //!< file exists in target, but source is newer
|
||||
QSet<QString> newerInTarget; //!< file in target is newer
|
||||
QSet<QString> sameNameInSource; //!< file exists in source and target, source name
|
||||
QSet<QString> sameNameInTarget; //!< file exists in source and target, target name
|
||||
};
|
||||
|
||||
//! Compare 2 directories (only files, not subdirectories
|
||||
static DirComparison compareTwoDirectories(const QString &dirSource, const QString &dirTarget);
|
||||
|
||||
private:
|
||||
//! Returns the application directory of the calling executable as normalized string.
|
||||
//! \note There is no trailing '/'.
|
||||
//! \warning The normalization rules are implementation specific and could change over time.
|
||||
static const QString &normalizedApplicationDirectory();
|
||||
|
||||
//! Directory for log files
|
||||
//! \remark In BlackMisc so it can also be used from BlackMisc classes
|
||||
static const QString &getLogDirectory();
|
||||
//! Convert filenames to set
|
||||
static QSet<QString> fileNamesToQSet(const QFileInfoList &fileInfoList);
|
||||
|
||||
//! Convert canoncial filenames to set
|
||||
static QSet<QString> canonicalFileNamesToQSet(const QFileInfoList &fileInfoList);
|
||||
|
||||
//! File to canonical names
|
||||
static const QSet<QString> filesToCanonicalNames(const QSet<QString> &fileNames, const QSet<QString> &canonicalFileNames);
|
||||
};
|
||||
} // ns
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace BlackMisc
|
||||
|
||||
const QString &CSettingsCache::persistentStore()
|
||||
{
|
||||
static const QString dir = getCacheRootDirectory() + "/settings/core";
|
||||
static const QString dir = CFileUtils::appendFilePaths(getCacheRootDirectory(), relativeFilePath());
|
||||
return dir;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,13 @@ namespace BlackMisc
|
||||
|
||||
QString CSettingsCache::filenameForKey(const QString &key)
|
||||
{
|
||||
return persistentStore() + "/" + CValueCache::filenameForKey(key);
|
||||
return CFileUtils::appendFilePaths(persistentStore(), CValueCache::filenameForKey(key));
|
||||
}
|
||||
|
||||
const QString CSettingsCache::relativeFilePath()
|
||||
{
|
||||
static const QString p("/settings/core");
|
||||
return p;
|
||||
}
|
||||
|
||||
QStringList CSettingsCache::enumerateStore() const
|
||||
|
||||
@@ -53,6 +53,9 @@ namespace BlackMisc
|
||||
//! Return the filename where the value with the given key may be stored.
|
||||
static QString filenameForKey(const QString &key);
|
||||
|
||||
//! Relative file path in application data directory
|
||||
static const QString relativeFilePath();
|
||||
|
||||
//! Return all files where settings may be stored.
|
||||
QStringList enumerateStore() const;
|
||||
|
||||
|
||||
@@ -50,8 +50,7 @@ namespace BlackMisc
|
||||
//! \private
|
||||
std::pair<QString &, std::atomic<bool> &> getCacheRootDirectoryMutable()
|
||||
{
|
||||
static QString dir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) +
|
||||
"/org.swift-project/" + CDirectoryUtils::normalizedApplicationDirectory();
|
||||
static QString dir = CDirectoryUtils::swiftNormalizedApplicationDataDirectory();
|
||||
static std::atomic<bool> frozen { false };
|
||||
return { dir, frozen };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user