From f6622a4cbbfce8eb382088fe470fe9152c3f5109 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 14 Jan 2025 18:48:41 +0200 Subject: [PATCH] implement packignore for curseforge/modrinth export Signed-off-by: Trial97 --- launcher/ui/dialogs/ExportPackDialog.cpp | 117 +++++++++++++++-------- launcher/ui/dialogs/ExportPackDialog.h | 13 ++- 2 files changed, 84 insertions(+), 46 deletions(-) diff --git a/launcher/ui/dialogs/ExportPackDialog.cpp b/launcher/ui/dialogs/ExportPackDialog.cpp index 879d19a53..846c11a1a 100644 --- a/launcher/ui/dialogs/ExportPackDialog.cpp +++ b/launcher/ui/dialogs/ExportPackDialog.cpp @@ -29,104 +29,105 @@ #include #include #include -#include "FastFileIconProvider.h" #include "FileSystem.h" #include "MMCZip.h" #include "modplatform/modrinth/ModrinthPackExportTask.h" ExportPackDialog::ExportPackDialog(InstancePtr instance, QWidget* parent, ModPlatform::ResourceProvider provider) - : QDialog(parent), instance(instance), ui(new Ui::ExportPackDialog), m_provider(provider) + : QDialog(parent), m_instance(instance), m_ui(new Ui::ExportPackDialog), m_provider(provider) { Q_ASSERT(m_provider == ModPlatform::ResourceProvider::MODRINTH || m_provider == ModPlatform::ResourceProvider::FLAME); - ui->setupUi(this); - ui->name->setPlaceholderText(instance->name()); - ui->name->setText(instance->settings()->get("ExportName").toString()); - ui->version->setText(instance->settings()->get("ExportVersion").toString()); - ui->optionalFiles->setChecked(instance->settings()->get("ExportOptionalFiles").toBool()); + m_ui->setupUi(this); + m_ui->name->setPlaceholderText(instance->name()); + m_ui->name->setText(instance->settings()->get("ExportName").toString()); + m_ui->version->setText(instance->settings()->get("ExportVersion").toString()); + m_ui->optionalFiles->setChecked(instance->settings()->get("ExportOptionalFiles").toBool()); if (m_provider == ModPlatform::ResourceProvider::MODRINTH) { setWindowTitle(tr("Export Modrinth Pack")); - ui->authorLabel->hide(); - ui->author->hide(); + m_ui->authorLabel->hide(); + m_ui->author->hide(); - ui->summary->setPlainText(instance->settings()->get("ExportSummary").toString()); + m_ui->summary->setPlainText(instance->settings()->get("ExportSummary").toString()); } else { setWindowTitle(tr("Export CurseForge Pack")); - ui->summaryLabel->hide(); - ui->summary->hide(); + m_ui->summaryLabel->hide(); + m_ui->summary->hide(); - ui->author->setText(instance->settings()->get("ExportAuthor").toString()); + m_ui->author->setText(instance->settings()->get("ExportAuthor").toString()); } // ensure a valid pack is generated // the name and version fields mustn't be empty - connect(ui->name, &QLineEdit::textEdited, this, &ExportPackDialog::validate); - connect(ui->version, &QLineEdit::textEdited, this, &ExportPackDialog::validate); + connect(m_ui->name, &QLineEdit::textEdited, this, &ExportPackDialog::validate); + connect(m_ui->version, &QLineEdit::textEdited, this, &ExportPackDialog::validate); // the instance name can technically be empty validate(); QFileSystemModel* model = new QFileSystemModel(this); - model->setIconProvider(&icons); + model->setIconProvider(&m_icons); // use the game root - everything outside cannot be exported const QDir root(instance->gameRoot()); - proxy = new FileIgnoreProxy(instance->gameRoot(), this); - proxy->ignoreFilesWithPath().insert({ "logs", "crash-reports", ".cache", ".fabric", ".quilt" }); - proxy->ignoreFilesWithName().append({ ".DS_Store", "thumbs.db", "Thumbs.db" }); - proxy->setSourceModel(model); + m_proxy = new FileIgnoreProxy(instance->gameRoot(), this); + m_proxy->ignoreFilesWithPath().insert({ "logs", "crash-reports", ".cache", ".fabric", ".quilt" }); + m_proxy->ignoreFilesWithName().append({ ".DS_Store", "thumbs.db", "Thumbs.db" }); + m_proxy->setSourceModel(model); + loadPackIgnore(); const QDir::Filters filter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden); for (const QString& file : root.entryList(filter)) { if (!(file == "mods" || file == "coremods" || file == "datapacks" || file == "config" || file == "options.txt" || file == "servers.dat")) - proxy->blockedPaths().insert(file); + m_proxy->blockedPaths().insert(file); } MinecraftInstance* mcInstance = dynamic_cast(instance.get()); if (mcInstance) { for (auto& resourceModel : mcInstance->resourceLists()) if (resourceModel->indexDir().exists()) - proxy->ignoreFilesWithPath().insert(root.relativeFilePath(resourceModel->indexDir().absolutePath())); + m_proxy->ignoreFilesWithPath().insert(root.relativeFilePath(resourceModel->indexDir().absolutePath())); } - ui->files->setModel(proxy); - ui->files->setRootIndex(proxy->mapFromSource(model->index(instance->gameRoot()))); - ui->files->sortByColumn(0, Qt::AscendingOrder); + m_ui->files->setModel(m_proxy); + m_ui->files->setRootIndex(m_proxy->mapFromSource(model->index(instance->gameRoot()))); + m_ui->files->sortByColumn(0, Qt::AscendingOrder); model->setFilter(filter); model->setRootPath(instance->gameRoot()); - QHeaderView* headerView = ui->files->header(); + QHeaderView* headerView = m_ui->files->header(); headerView->setSectionResizeMode(QHeaderView::ResizeToContents); headerView->setSectionResizeMode(0, QHeaderView::Stretch); - ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel")); - ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK")); + m_ui->buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("Cancel")); + m_ui->buttonBox->button(QDialogButtonBox::Ok)->setText(tr("OK")); } ExportPackDialog::~ExportPackDialog() { - delete ui; + delete m_ui; } void ExportPackDialog::done(int result) { - auto settings = instance->settings(); - settings->set("ExportName", ui->name->text()); - settings->set("ExportVersion", ui->version->text()); - settings->set("ExportOptionalFiles", ui->optionalFiles->isChecked()); + savePackIgnore(); + auto settings = m_instance->settings(); + settings->set("ExportName", m_ui->name->text()); + settings->set("ExportVersion", m_ui->version->text()); + settings->set("ExportOptionalFiles", m_ui->optionalFiles->isChecked()); if (m_provider == ModPlatform::ResourceProvider::MODRINTH) - settings->set("ExportSummary", ui->summary->toPlainText()); + settings->set("ExportSummary", m_ui->summary->toPlainText()); else - settings->set("ExportAuthor", ui->author->text()); + settings->set("ExportAuthor", m_ui->author->text()); if (result == Accepted) { - const QString name = ui->name->text().isEmpty() ? instance->name() : ui->name->text(); + const QString name = m_ui->name->text().isEmpty() ? m_instance->name() : m_ui->name->text(); const QString filename = FS::RemoveInvalidFilenameChars(name); QString output; @@ -148,11 +149,11 @@ void ExportPackDialog::done(int result) Task* task; if (m_provider == ModPlatform::ResourceProvider::MODRINTH) { - task = new ModrinthPackExportTask(name, ui->version->text(), ui->summary->toPlainText(), ui->optionalFiles->isChecked(), - instance, output, std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1)); + task = new ModrinthPackExportTask(name, m_ui->version->text(), m_ui->summary->toPlainText(), m_ui->optionalFiles->isChecked(), + m_instance, output, std::bind(&FileIgnoreProxy::filterFile, m_proxy, std::placeholders::_1)); } else { - task = new FlamePackExportTask(name, ui->version->text(), ui->author->text(), ui->optionalFiles->isChecked(), instance, output, - std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1)); + task = new FlamePackExportTask(name, m_ui->version->text(), m_ui->author->text(), m_ui->optionalFiles->isChecked(), m_instance, + output, std::bind(&FileIgnoreProxy::filterFile, m_proxy, std::placeholders::_1)); } connect(task, &Task::failed, @@ -174,6 +175,38 @@ void ExportPackDialog::done(int result) void ExportPackDialog::validate() { - ui->buttonBox->button(QDialogButtonBox::Ok) - ->setDisabled(m_provider == ModPlatform::ResourceProvider::MODRINTH && ui->version->text().isEmpty()); + m_ui->buttonBox->button(QDialogButtonBox::Ok) + ->setDisabled(m_provider == ModPlatform::ResourceProvider::MODRINTH && m_ui->version->text().isEmpty()); +} + +QString ExportPackDialog::ignoreFileName() +{ + return FS::PathCombine(m_instance->instanceRoot(), ".packignore"); +} + +void ExportPackDialog::loadPackIgnore() +{ + auto filename = ignoreFileName(); + QFile ignoreFile(filename); + if (!ignoreFile.open(QIODevice::ReadOnly)) { + return; + } + auto ignoreData = ignoreFile.readAll(); + auto string = QString::fromUtf8(ignoreData); +#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) + m_proxy->setBlockedPaths(string.split('\n', Qt::SkipEmptyParts)); +#else + m_proxy->setBlockedPaths(string.split('\n', QString::SkipEmptyParts)); +#endif +} + +void ExportPackDialog::savePackIgnore() +{ + auto ignoreData = m_proxy->blockedPaths().toStringList().join('\n').toUtf8(); + auto filename = ignoreFileName(); + try { + FS::write(filename, ignoreData); + } catch (const Exception& e) { + qWarning() << e.cause(); + } } diff --git a/launcher/ui/dialogs/ExportPackDialog.h b/launcher/ui/dialogs/ExportPackDialog.h index 830c24d25..8931922a9 100644 --- a/launcher/ui/dialogs/ExportPackDialog.h +++ b/launcher/ui/dialogs/ExportPackDialog.h @@ -41,9 +41,14 @@ class ExportPackDialog : public QDialog { void validate(); private: - const InstancePtr instance; - Ui::ExportPackDialog* ui; - FileIgnoreProxy* proxy; - FastFileIconProvider icons; + void loadPackIgnore(); + void savePackIgnore(); + QString ignoreFileName(); + + private: + const InstancePtr m_instance; + Ui::ExportPackDialog* m_ui; + FileIgnoreProxy* m_proxy; + FastFileIconProvider m_icons; const ModPlatform::ResourceProvider m_provider; };