This commit is contained in:
2026-09-29 09:40:37 +03:00
parent 441021b9a6
commit 6567e731d1
34 changed files with 57 additions and 709 deletions
+1 -30
View File
@@ -18,8 +18,6 @@
#include <utility>
// Читатель архива вместе с разобранным оглавлением: fileInfoList() каждый раз
// заново разбирает центральный каталог zip, а записей в JDK десятки тысяч.
struct ZipExtraction
{
explicit ZipExtraction(const QString &path)
@@ -39,8 +37,6 @@ constexpr int kMaxParallel = 4;
constexpr int kMaxAttempts = 3;
constexpr int kProgressIntervalMs = 100;
// Записей zip за один проход таймера. Сотня файлов по паре мегабайт — это
// заметная, но ещё не видимая глазом задержка кадра.
constexpr int kZipChunk = 24;
bool isTransient(QNetworkReply::NetworkError error, int status)
@@ -59,8 +55,6 @@ bool isTransient(QNetworkReply::NetworkError error, int status)
}
}
// Путь из манифеста или архива не должен уводить за пределы папки сборки:
// «../../» в имени записи — известный способ подменить чужой файл.
bool isInside(const QString &root, const QString &path)
{
const QString normalizedRoot = QDir::cleanPath(root) + u'/';
@@ -76,7 +70,7 @@ void makeExecutable(const QString &path)
| QFileDevice::ExeOther);
}
} // namespace
}
JavaInstaller::JavaInstaller(QObject *parent)
: QObject(parent)
@@ -133,8 +127,6 @@ void JavaInstaller::install(const JavaRuntimeEntry &entry)
return;
}
// Переустановка поверх недокачанной прошлой попытки: старое дерево мешает
// и размером, и тем, что locateBinary нашла бы в нём чужой java.
if (!JavaRuntimeStore::remove(entry.id, &error)) {
emit failed(m_label, error);
return;
@@ -176,8 +168,6 @@ void JavaInstaller::cancel()
if (m_tar)
m_tar->kill();
// Прерванная установка оставляет дерево наполовину собранным: запускать из
// него нечего, а locateBinary могла бы найти в нём java.
if (m_active.isEmpty() && !m_reply && !m_tar) {
const QString label = m_label;
JavaRuntimeStore::remove(m_entry.id, nullptr);
@@ -186,8 +176,6 @@ void JavaInstaller::cancel()
}
}
// ── Temurin: один архив ─────────────────────────────────────────────────────
void JavaInstaller::beginArchive()
{
if (m_entry.archive != QLatin1String("zip")
@@ -287,8 +275,6 @@ void JavaInstaller::handleArchiveFinished(QNetworkReply *reply)
void JavaInstaller::startExtraction()
{
// Байты кончились, дальше считаем шаги: панель по нулевому итогу перестанет
// показывать мегабайты, а проценты продолжит.
m_bytesTotal = 0;
m_bytesSettled = 0;
setStage(Loc::text("java.progress.extracting").arg(m_entry.version));
@@ -333,7 +319,6 @@ void JavaInstaller::extractZipChunk()
QDir().mkpath(target);
continue;
}
// Ссылок в zip-сборках Temurin не бывает — под Unix они отдают tar.gz.
if (!info.isFile)
continue;
@@ -369,8 +354,6 @@ void JavaInstaller::extractZipChunk()
void JavaInstaller::startTarExtraction()
{
// tar есть в любой macOS и практически в любом дистрибутиве Linux; своего
// распаковщика gzip-tar в Qt нет, а тянуть ради него зависимость незачем.
m_tar = new QProcess(this);
m_tar->setWorkingDirectory(m_targetDir);
m_tar->setProgram(QStringLiteral("tar"));
@@ -418,8 +401,6 @@ void JavaInstaller::startTarExtraction()
m_tar->start();
}
// ── Mojang: дерево файлов ───────────────────────────────────────────────────
void JavaInstaller::beginMojang()
{
setStage(Loc::text("java.progress.fileList").arg(m_entry.version));
@@ -498,7 +479,6 @@ bool JavaInstaller::prepareTree(const QJsonObject &files)
}
if (type == QLatin1String("link")) {
// Ссылки создаём в конце: их цели ещё не скачаны.
m_links << qMakePair(target, node.value(QStringLiteral("target")).toString());
continue;
}
@@ -666,11 +646,7 @@ bool JavaInstaller::applyLinks()
continue;
if (!QDir().mkpath(QFileInfo(linkPath).absolutePath()))
continue;
// Цель относительна самой ссылке — QFile::link кладёт её как есть.
if (!QFile::link(link.second, linkPath)) {
// Под Windows символических ссылок в рантаймах Mojang нет, но если
// они появятся, копия работает не хуже.
const QString source =
QDir::cleanPath(QFileInfo(linkPath).absolutePath() + u'/' + link.second);
if (!QFile::copy(source, linkPath)) {
@@ -683,8 +659,6 @@ bool JavaInstaller::applyLinks()
return true;
}
// ── Завершение ──────────────────────────────────────────────────────────────
void JavaInstaller::complete()
{
setStage(Loc::text("java.progress.verifying"));
@@ -695,7 +669,6 @@ void JavaInstaller::complete()
return;
}
#if !defined(Q_OS_WIN)
// tar сохраняет права, а вот zip и файлы Mojang без флага executable — нет.
makeExecutable(javaPath);
#endif
@@ -713,7 +686,6 @@ void JavaInstaller::complete()
return;
}
// Архив нужен был только на распаковку — двести мегабайт в кэше ни к чему.
if (!m_archivePath.isEmpty())
QFile::remove(m_archivePath);
@@ -729,7 +701,6 @@ void JavaInstaller::fail(const QString &message)
m_zip.reset();
if (!m_archivePath.isEmpty())
QFile::remove(m_archivePath);
// Половина рантайма хуже, чем его отсутствие: следующая попытка начнётся с чистой папки.
JavaRuntimeStore::remove(m_entry.id, nullptr);
reset();
emit failed(label, message);