Merge pull request #1391 from Trial97/prism_export2

This commit is contained in:
Sefa Eyeoglu 2023-08-02 19:27:14 +02:00 committed by GitHub
commit 01e17806f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 161 deletions

View File

@ -26,6 +26,7 @@
#include <QMessageBox> #include <QMessageBox>
#include <QtConcurrentRun> #include <QtConcurrentRun>
#include <algorithm> #include <algorithm>
#include <iterator>
#include <memory> #include <memory>
#include "Json.h" #include "Json.h"
#include "MMCZip.h" #include "MMCZip.h"
@ -64,20 +65,11 @@ void FlamePackExportTask::executeTask()
bool FlamePackExportTask::abort() bool FlamePackExportTask::abort()
{ {
if (task != nullptr) { if (task) {
task->abort(); task->abort();
task = nullptr;
emitAborted(); emitAborted();
return true; return true;
} }
if (buildZipFuture.isRunning()) {
buildZipFuture.cancel();
// NOTE: Here we don't do `emitAborted()` because it will be done when `buildZipFuture` actually cancels, which may not occur
// immediately.
return true;
}
return false; return false;
} }
@ -336,89 +328,40 @@ void FlamePackExportTask::buildZip()
setStatus(tr("Adding files...")); setStatus(tr("Adding files..."));
setProgress(4, 5); setProgress(4, 5);
buildZipFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this]() { auto zipTask = makeShared<MMCZip::ExportToZipTask>(output, gameRoot, files, "overrides/", true);
QuaZip zip(output); zipTask->addExtraFile("manifest.json", generateIndex());
if (!zip.open(QuaZip::mdCreate)) { zipTask->addExtraFile("modlist.html", generateHTML());
QFile::remove(output);
return BuildZipResult(tr("Could not create file"));
}
if (buildZipFuture.isCanceled()) QStringList exclude;
return BuildZipResult(); std::transform(resolvedFiles.keyBegin(), resolvedFiles.keyEnd(), std::back_insert_iterator(exclude),
[this](QString file) { return gameRoot.relativeFilePath(file); });
zipTask->setExcludeFiles(exclude);
QuaZipFile indexFile(&zip); auto progressStep = std::make_shared<TaskStepProgress>();
if (!indexFile.open(QIODevice::WriteOnly, QuaZipNewInfo("manifest.json"))) { connect(zipTask.get(), &Task::finished, this, [this, progressStep] {
QFile::remove(output);
return BuildZipResult(tr("Could not create index"));
}
indexFile.write(generateIndex());
QuaZipFile modlist(&zip);
if (!modlist.open(QIODevice::WriteOnly, QuaZipNewInfo("modlist.html"))) {
QFile::remove(output);
return BuildZipResult(tr("Could not create index"));
}
QString content = "";
for (auto mod : resolvedFiles) {
if (mod.isMod) {
content += QString(TEMPLATE)
.replace("{name}", mod.name.toHtmlEscaped())
.replace("{url}", ModPlatform::getMetaURL(ModPlatform::ResourceProvider::FLAME, mod.addonId).toHtmlEscaped())
.replace("{authors}", !mod.authors.isEmpty() ? QString(" (by %1)").arg(mod.authors).toHtmlEscaped() : "");
}
}
content = "<ul>" + content + "</ul>";
modlist.write(content.toUtf8());
auto progressStep = std::make_shared<TaskStepProgress>();
size_t progress = 0;
for (const QFileInfo& file : files) {
if (buildZipFuture.isCanceled()) {
QFile::remove(output);
progressStep->state = TaskStepState::Failed;
stepProgress(*progressStep);
return BuildZipResult();
}
progressStep->update(progress, files.length());
stepProgress(*progressStep);
const QString relative = gameRoot.relativeFilePath(file.absoluteFilePath());
if (!resolvedFiles.contains(file.absoluteFilePath()) &&
!JlCompress::compressFile(&zip, file.absoluteFilePath(), "overrides/" + relative)) {
QFile::remove(output);
return BuildZipResult(tr("Could not read and compress %1").arg(relative));
}
progress++;
}
zip.close();
if (zip.getZipError() != 0) {
QFile::remove(output);
progressStep->state = TaskStepState::Failed;
stepProgress(*progressStep);
return BuildZipResult(tr("A zip error occurred"));
}
progressStep->state = TaskStepState::Succeeded; progressStep->state = TaskStepState::Succeeded;
stepProgress(*progressStep); stepProgress(*progressStep);
return BuildZipResult();
}); });
connect(&buildZipWatcher, &QFutureWatcher<BuildZipResult>::finished, this, &FlamePackExportTask::finish);
buildZipWatcher.setFuture(buildZipFuture);
}
void FlamePackExportTask::finish() connect(zipTask.get(), &Task::succeeded, this, &FlamePackExportTask::emitSucceeded);
{ connect(zipTask.get(), &Task::aborted, this, &FlamePackExportTask::emitAborted);
if (buildZipFuture.isCanceled()) connect(zipTask.get(), &Task::failed, this, [this, progressStep](QString reason) {
emitAborted(); progressStep->state = TaskStepState::Failed;
else { stepProgress(*progressStep);
const BuildZipResult result = buildZipFuture.result(); emitFailed(reason);
if (result.has_value()) });
emitFailed(result.value()); connect(zipTask.get(), &Task::stepProgress, this, &FlamePackExportTask::propagateStepProgress);
else
emitSucceeded(); connect(zipTask.get(), &Task::progress, this, [this, progressStep](qint64 current, qint64 total) {
} progressStep->update(current, total);
stepProgress(*progressStep);
});
connect(zipTask.get(), &Task::status, this, [this, progressStep](QString status) {
progressStep->status = status;
stepProgress(*progressStep);
});
task.reset(zipTask);
zipTask->start();
} }
QByteArray FlamePackExportTask::generateIndex() QByteArray FlamePackExportTask::generateIndex()
@ -471,3 +414,18 @@ QByteArray FlamePackExportTask::generateIndex()
return QJsonDocument(obj).toJson(QJsonDocument::Compact); return QJsonDocument(obj).toJson(QJsonDocument::Compact);
} }
QByteArray FlamePackExportTask::generateHTML()
{
QString content = "";
for (auto mod : resolvedFiles) {
if (mod.isMod) {
content += QString(TEMPLATE)
.replace("{name}", mod.name.toHtmlEscaped())
.replace("{url}", ModPlatform::getMetaURL(ModPlatform::ResourceProvider::FLAME, mod.addonId).toHtmlEscaped())
.replace("{authors}", !mod.authors.isEmpty() ? QString(" (by %1)").arg(mod.authors).toHtmlEscaped() : "");
}
}
content = "<ul>" + content + "</ul>";
return content.toUtf8();
}

View File

@ -19,8 +19,6 @@
#pragma once #pragma once
#include <QFuture>
#include <QFutureWatcher>
#include "BaseInstance.h" #include "BaseInstance.h"
#include "MMCZip.h" #include "MMCZip.h"
#include "minecraft/MinecraftInstance.h" #include "minecraft/MinecraftInstance.h"
@ -52,7 +50,6 @@ class FlamePackExportTask : public Task {
const QString output; const QString output;
const MMCZip::FilterFunction filter; const MMCZip::FilterFunction filter;
typedef std::optional<QString> BuildZipResult;
struct ResolvedFile { struct ResolvedFile {
int addonId; int addonId;
int version; int version;
@ -76,15 +73,13 @@ class FlamePackExportTask : public Task {
QMap<QString, HashInfo> pendingHashes{}; QMap<QString, HashInfo> pendingHashes{};
QMap<QString, ResolvedFile> resolvedFiles{}; QMap<QString, ResolvedFile> resolvedFiles{};
Task::Ptr task; Task::Ptr task;
QFuture<BuildZipResult> buildZipFuture;
QFutureWatcher<BuildZipResult> buildZipWatcher;
void collectFiles(); void collectFiles();
void collectHashes(); void collectHashes();
void makeApiRequest(); void makeApiRequest();
void getProjectsInfo(); void getProjectsInfo();
void buildZip(); void buildZip();
void finish();
QByteArray generateIndex(); QByteArray generateIndex();
QByteArray generateHTML();
}; };

View File

@ -55,20 +55,11 @@ void ModrinthPackExportTask::executeTask()
bool ModrinthPackExportTask::abort() bool ModrinthPackExportTask::abort()
{ {
if (task != nullptr) { if (task) {
task->abort(); task->abort();
task = nullptr;
emitAborted(); emitAborted();
return true; return true;
} }
if (buildZipFuture.isRunning()) {
buildZipFuture.cancel();
// NOTE: Here we don't do `emitAborted()` because it will be done when `buildZipFuture` actually cancels, which may not occur
// immediately.
return true;
}
return false; return false;
} }
@ -205,63 +196,36 @@ void ModrinthPackExportTask::buildZip()
{ {
setStatus(tr("Adding files...")); setStatus(tr("Adding files..."));
buildZipFuture = QtConcurrent::run(QThreadPool::globalInstance(), [this]() { auto zipTask = makeShared<MMCZip::ExportToZipTask>(output, gameRoot, files, "overrides/", true);
QuaZip zip(output); zipTask->addExtraFile("modrinth.index.json", generateIndex());
if (!zip.open(QuaZip::mdCreate)) {
QFile::remove(output);
return BuildZipResult(tr("Could not create file"));
}
if (buildZipFuture.isCanceled()) zipTask->setExcludeFiles(resolvedFiles.keys());
return BuildZipResult();
QuaZipFile indexFile(&zip); auto progressStep = std::make_shared<TaskStepProgress>();
if (!indexFile.open(QIODevice::WriteOnly, QuaZipNewInfo("modrinth.index.json"))) { connect(zipTask.get(), &Task::finished, this, [this, progressStep] {
QFile::remove(output); progressStep->state = TaskStepState::Succeeded;
return BuildZipResult(tr("Could not create index")); stepProgress(*progressStep);
}
indexFile.write(generateIndex());
size_t progress = 0;
for (const QFileInfo& file : files) {
if (buildZipFuture.isCanceled()) {
QFile::remove(output);
return BuildZipResult();
}
setProgress(progress, files.length());
const QString relative = gameRoot.relativeFilePath(file.absoluteFilePath());
if (!resolvedFiles.contains(relative) && !JlCompress::compressFile(&zip, file.absoluteFilePath(), "overrides/" + relative)) {
QFile::remove(output);
return BuildZipResult(tr("Could not read and compress %1").arg(relative));
}
progress++;
}
zip.close();
if (zip.getZipError() != 0) {
QFile::remove(output);
return BuildZipResult(tr("A zip error occurred"));
}
return BuildZipResult();
}); });
connect(&buildZipWatcher, &QFutureWatcher<BuildZipResult>::finished, this, &ModrinthPackExportTask::finish);
buildZipWatcher.setFuture(buildZipFuture);
}
void ModrinthPackExportTask::finish() connect(zipTask.get(), &Task::succeeded, this, &ModrinthPackExportTask::emitSucceeded);
{ connect(zipTask.get(), &Task::aborted, this, &ModrinthPackExportTask::emitAborted);
if (buildZipFuture.isCanceled()) connect(zipTask.get(), &Task::failed, this, [this, progressStep](QString reason) {
emitAborted(); progressStep->state = TaskStepState::Failed;
else { stepProgress(*progressStep);
const BuildZipResult result = buildZipFuture.result(); emitFailed(reason);
if (result.has_value()) });
emitFailed(result.value()); connect(zipTask.get(), &Task::stepProgress, this, &ModrinthPackExportTask::propagateStepProgress);
else
emitSucceeded(); connect(zipTask.get(), &Task::progress, this, [this, progressStep](qint64 current, qint64 total) {
} progressStep->update(current, total);
stepProgress(*progressStep);
});
connect(zipTask.get(), &Task::status, this, [this, progressStep](QString status) {
progressStep->status = status;
stepProgress(*progressStep);
});
task.reset(zipTask);
zipTask->start();
} }
QByteArray ModrinthPackExportTask::generateIndex() QByteArray ModrinthPackExportTask::generateIndex()

View File

@ -56,22 +56,17 @@ class ModrinthPackExportTask : public Task {
const QString output; const QString output;
const MMCZip::FilterFunction filter; const MMCZip::FilterFunction filter;
typedef std::optional<QString> BuildZipResult;
ModrinthAPI api; ModrinthAPI api;
QFileInfoList files; QFileInfoList files;
QMap<QString, QString> pendingHashes; QMap<QString, QString> pendingHashes;
QMap<QString, ResolvedFile> resolvedFiles; QMap<QString, ResolvedFile> resolvedFiles;
Task::Ptr task; Task::Ptr task;
QFuture<BuildZipResult> buildZipFuture;
QFutureWatcher<BuildZipResult> buildZipWatcher;
void collectFiles(); void collectFiles();
void collectHashes(); void collectHashes();
void makeApiRequest(); void makeApiRequest();
void parseApiResponse(const std::shared_ptr<QByteArray> response); void parseApiResponse(const std::shared_ptr<QByteArray> response);
void buildZip(); void buildZip();
void finish();
QByteArray generateIndex(); QByteArray generateIndex();
}; };