verison deletion feature
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include "minecraftversion.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QDirIterator>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QHash>
|
||||
@@ -27,6 +28,27 @@ QString versionJarPath(const QString &gameDir, const QString &id)
|
||||
return gameDir + "/versions/" + id + "/" + id + ".jar";
|
||||
}
|
||||
|
||||
QString versionsRoot(const QString &gameDir)
|
||||
{
|
||||
return gameDir + QStringLiteral("/versions");
|
||||
}
|
||||
|
||||
// Идентификатор версии — это имя папки, поэтому «чинить» его как sanitizeId()
|
||||
// нельзя: подстановка символов увела бы нас не в ту версию. Только проверяем.
|
||||
bool isSafeVersionId(const QString &id)
|
||||
{
|
||||
return !id.isEmpty() && !id.startsWith(u'.') && !id.contains(u'/') && !id.contains(u'\\');
|
||||
}
|
||||
|
||||
// Верхний объект <id>.json без разворачивания цепочки: нужен только inheritsFrom.
|
||||
QJsonObject readVersionObject(const QString &gameDir, const QString &id)
|
||||
{
|
||||
QFile file(versionJsonPath(gameDir, id));
|
||||
if (!file.open(QIODevice::ReadOnly))
|
||||
return {};
|
||||
return QJsonDocument::fromJson(file.readAll()).object();
|
||||
}
|
||||
|
||||
// org.lwjgl:lwjgl:3.3.1:natives-windows -> org/lwjgl/lwjgl/3.3.1/lwjgl-3.3.1-natives-windows.jar
|
||||
QString mavenToPath(const QString &name)
|
||||
{
|
||||
@@ -311,6 +333,68 @@ QStringList VersionLoader::installedVersions(const QString &gameDir)
|
||||
return result;
|
||||
}
|
||||
|
||||
QStringList VersionLoader::dependentsOf(const QString &gameDir, const QString &versionId)
|
||||
{
|
||||
if (versionId.isEmpty())
|
||||
return {};
|
||||
|
||||
// Одного уровня хватает: профили модлоадеров наследуются от ванильных версий,
|
||||
// а не друг от друга.
|
||||
QStringList result;
|
||||
const QStringList installed = installedVersions(gameDir);
|
||||
for (const QString &id : installed) {
|
||||
if (id == versionId)
|
||||
continue;
|
||||
const QJsonObject object = readVersionObject(gameDir, id);
|
||||
if (object.value(QStringLiteral("inheritsFrom")).toString() == versionId)
|
||||
result << id;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
qint64 VersionLoader::installedSize(const QString &gameDir, const QString &versionId)
|
||||
{
|
||||
if (!isSafeVersionId(versionId))
|
||||
return 0;
|
||||
|
||||
qint64 total = 0;
|
||||
QDirIterator it(versionsRoot(gameDir) + u'/' + versionId,
|
||||
QDir::Files | QDir::Hidden | QDir::System | QDir::NoSymLinks,
|
||||
QDirIterator::Subdirectories);
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
total += it.fileInfo().size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
bool VersionLoader::remove(const QString &gameDir, const QString &versionId, QString *error)
|
||||
{
|
||||
const QString root = versionsRoot(gameDir);
|
||||
if (gameDir.isEmpty() || !isSafeVersionId(versionId)) {
|
||||
if (error)
|
||||
*error = QObject::tr("недопустимый идентификатор версии");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Удаляем только внутри <gameDir>/versions: проверка id уже не пропустит «..»,
|
||||
// но цена ошибки — чужая папка, а проверка стоит одной строки.
|
||||
const QString dir = QDir::cleanPath(root + u'/' + versionId);
|
||||
if (!dir.startsWith(root + u'/')) {
|
||||
if (error)
|
||||
*error = QObject::tr("недопустимый идентификатор версии");
|
||||
return false;
|
||||
}
|
||||
if (!QDir(dir).exists())
|
||||
return true;
|
||||
if (!QDir(dir).removeRecursively()) {
|
||||
if (error)
|
||||
*error = QObject::tr("не удалось удалить %1").arg(QDir::toNativeSeparators(dir));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
MinecraftVersion VersionLoader::load(const QString &gameDir,
|
||||
const QString &versionId,
|
||||
const QSet<QString> &features,
|
||||
|
||||
Reference in New Issue
Block a user