Files
Qt_DesktopPet/src/workspace/WorkspaceScanner.cpp
T

126 lines
3.6 KiB
C++

#include "WorkspaceScanner.h"
#include <QDir>
#include <QFileInfo>
#include <QStringList>
#include <QVector>
namespace
{
struct PendingDirectory
{
QString path;
int depth = 0;
};
}
WorkspaceScanner::WorkspaceScanner(int maxDepth, int maxEntries)
: m_maxDepth(maxDepth)
, m_maxEntries(maxEntries)
{
}
QVector<WorkspaceFileInfo> WorkspaceScanner::scan(const QString &workspaceRoot, QString *errorMessage) const
{
if (!WorkspaceAccessPolicy::validateWorkspaceRoot(workspaceRoot, errorMessage))
{
return {};
}
const WorkspaceAccessPolicy policy(workspaceRoot);
QVector<WorkspaceFileInfo> files;
QVector<PendingDirectory> pending;
pending.append({policy.workspaceRoot(), 0});
while (!pending.isEmpty() && files.size() < m_maxEntries)
{
const PendingDirectory current = pending.takeLast();
QString directoryError;
if (!policy.canReadDirectory(current.path, &directoryError))
{
continue;
}
const QFileInfoList entries = QDir(current.path).entryInfoList(
QDir::NoDotAndDotDot | QDir::AllEntries | QDir::Hidden,
QDir::DirsFirst | QDir::Name);
for (const QFileInfo &entry : entries)
{
if (files.size() >= m_maxEntries)
{
break;
}
if (entry.isHidden())
{
continue;
}
const QString absolutePath = entry.absoluteFilePath();
if (entry.isDir())
{
if (shouldSkipDirectory(policy, absolutePath))
{
continue;
}
files.append(fileInfoForPath(policy, absolutePath));
if (current.depth + 1 <= m_maxDepth)
{
pending.append({absolutePath, current.depth + 1});
}
continue;
}
if (entry.isFile())
{
if (policy.hasSymlinkSegment(absolutePath))
{
continue;
}
files.append(fileInfoForPath(policy, absolutePath));
}
}
}
return files;
}
bool WorkspaceScanner::shouldSkipDirectory(const WorkspaceAccessPolicy &policy, const QString &path) const
{
const QFileInfo info(path);
const QString name = info.fileName().toLower();
static const QStringList skipped = {
QStringLiteral(".git"),
QStringLiteral(".vs"),
QStringLiteral(".idea"),
QStringLiteral("build"),
QStringLiteral("cmake-build-debug"),
QStringLiteral("cmake-build-release"),
QStringLiteral("node_modules"),
QStringLiteral("dist"),
QStringLiteral("release"),
QStringLiteral("release_packages"),
QStringLiteral("logs"),
};
return skipped.contains(name)
|| policy.isSystemPath(path)
|| policy.hasSymlinkSegment(path);
}
WorkspaceFileInfo WorkspaceScanner::fileInfoForPath(const WorkspaceAccessPolicy &policy, const QString &path) const
{
const QFileInfo info(path);
WorkspaceFileInfo file;
file.absolutePath = policy.normalizePath(path);
file.relativePath = policy.toRelativePath(file.absolutePath);
file.fileName = info.fileName();
file.suffix = info.suffix();
file.sizeBytes = info.size();
file.lastModified = info.lastModified();
file.isDirectory = info.isDir();
file.isTextFile = !file.isDirectory && policy.isSupportedTextFile(file.absolutePath) && !policy.isSensitiveFile(file.absolutePath);
file.isHidden = info.isHidden();
return file;
}