aboutsummaryrefslogtreecommitdiff
path: root/src/yuzu/user_data_migration.cpp
diff options
context:
space:
mode:
authorswurl <swurl@swurl.xyz>2025-05-10 15:40:15 +0000
committercrueter <crueter@noreply.localhost>2025-05-10 15:40:15 +0000
commit28d2b0638022531f315afb11e2ede8da9ca595be (patch)
treef2d7d65b619c4aae2de7470fb223f3aea96487c5 /src/yuzu/user_data_migration.cpp
parent09c72e9f98354e89ea8b49a882db8dae47dc3149 (diff)
Options for Data Migration (#95)
Copy, move, or link Co-authored-by: KeatonTheBot <onikeaton@gmail.com> Signed-off-by: swurl <swurl@swurl.xyz> Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/95 Co-authored-by: swurl <swurl@swurl.xyz> Co-committed-by: swurl <swurl@swurl.xyz>
Diffstat (limited to 'src/yuzu/user_data_migration.cpp')
-rw-r--r--src/yuzu/user_data_migration.cpp221
1 files changed, 166 insertions, 55 deletions
diff --git a/src/yuzu/user_data_migration.cpp b/src/yuzu/user_data_migration.cpp
index d890550222..1946254fb2 100644
--- a/src/yuzu/user_data_migration.cpp
+++ b/src/yuzu/user_data_migration.cpp
@@ -5,20 +5,25 @@
// SPDX-FileCopyrightText: Copyright 2025 eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
+#include "user_data_migration.h"
#include <QMessageBox>
#include <QPushButton>
#include <QString>
#include <QTranslator>
#include "common/fs/path_util.h"
-#include "user_data_migration.h"
+#include "migration_dialog.h"
// Needs to be included at the end due to https://bugreports.qt.io/browse/QTBUG-73263
+#include <QButtonGroup>
#include <QCheckBox>
+#include <QRadioButton>
#include <filesystem>
namespace fs = std::filesystem;
-UserDataMigrator::UserDataMigrator(QMainWindow* main_window) {
+UserDataMigrator::UserDataMigrator(
+ QMainWindow *main_window)
+{
// NOTE: Logging is not initialized yet, do not produce logs here.
// Check migration if config directory does not exist
@@ -29,25 +34,58 @@ UserDataMigrator::UserDataMigrator(QMainWindow* main_window) {
}
}
-void UserDataMigrator::ShowMigrationPrompt(QMainWindow* main_window) {
+void UserDataMigrator::ShowMigrationPrompt(
+ QMainWindow *main_window)
+{
namespace fs = std::filesystem;
- const QString migration_prompt_message =
- main_window->tr("Would you like to migrate your data for use in Eden?\n"
- "Select the corresponding button to migrate data from that emulator.\n"
- "(This may take a while; The old data will not be deleted)\n\n"
- "Clearing shader cache is recommended for all users.\nDo not uncheck unless you know what you're doing.");
+ const QString migration_prompt_message = main_window->tr(
+ "Would you like to migrate your data for use in Eden?\n"
+ "Select the corresponding button to migrate data from that emulator.\n"
+ "This may take a while.");
bool any_found = false;
- QMessageBox migration_prompt;
+ MigrationDialog migration_prompt;
migration_prompt.setWindowTitle(main_window->tr("Migration"));
- migration_prompt.setIcon(QMessageBox::Information);
QCheckBox *clear_shaders = new QCheckBox(&migration_prompt);
clear_shaders->setText(main_window->tr("Clear Shader Cache"));
+ clear_shaders->setToolTip(main_window->tr(
+ "Clearing shader cache is recommended for all users.\nDo not uncheck unless you know what "
+ "you're doing."));
clear_shaders->setChecked(true);
- migration_prompt.setCheckBox(clear_shaders);
+
+ QRadioButton *keep_old = new QRadioButton(&migration_prompt);
+ keep_old->setText(main_window->tr("Keep Old Data"));
+ keep_old->setToolTip(
+ main_window->tr("Keeps the old data directory. This is recommended if you aren't\n"
+ "space-constrained and want to keep separate data for the old emulator."));
+ keep_old->setChecked(true);
+
+ QRadioButton *clear_old = new QRadioButton(&migration_prompt);
+ clear_old->setText(main_window->tr("Clear Old Data"));
+ clear_old->setToolTip(main_window->tr("Deletes the old data directory.\nThis is recommended on "
+ "devices with space constraints."));
+ clear_old->setChecked(false);
+
+ QRadioButton *link = new QRadioButton(&migration_prompt);
+ link->setText(main_window->tr("Link Old Directory"));
+ link->setToolTip(
+ main_window->tr("Creates a filesystem link between the old directory and Eden directory.\n"
+ "This is recommended if you want to share data between emulators.."));
+ link->setChecked(false);
+
+ // Link and Clear Old are mutually exclusive
+ QButtonGroup *group = new QButtonGroup(&migration_prompt);
+ group->addButton(keep_old);
+ group->addButton(clear_old);
+ group->addButton(link);
+
+ migration_prompt.addBox(clear_shaders);
+ migration_prompt.addBox(keep_old);
+ migration_prompt.addBox(clear_old);
+ migration_prompt.addBox(link);
// Reflection would make this code 10x better
// but for now... MACRO MADNESS!!!!
@@ -55,10 +93,13 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow* main_window) {
QMap<QString, LegacyEmu> legacyMap;
QMap<QString, QAbstractButton *> buttonMap;
-#define EMU_MAP(name) const bool name##_found = fs::is_directory(Common::FS::GetLegacyPath(Common::FS::LegacyPath::name##Dir)); \
- legacyMap[main_window->tr(#name)] = LegacyEmu::name; \
- found[main_window->tr(#name)] = name##_found; \
- if (name##_found) any_found = true;
+#define EMU_MAP(name) \
+ const bool name##_found = fs::is_directory( \
+ Common::FS::GetLegacyPath(Common::FS::LegacyPath::name##Dir)); \
+ legacyMap[main_window->tr(#name)] = LegacyEmu::name; \
+ found[main_window->tr(#name)] = name##_found; \
+ if (name##_found) \
+ any_found = true;
EMU_MAP(Citron)
EMU_MAP(Sudachi)
@@ -68,30 +109,44 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow* main_window) {
#undef EMU_MAP
if (any_found) {
- QString promptText = main_window->tr("Eden has detected user data for the following emulators:");
+ QString promptText = main_window->tr(
+ "Eden has detected user data for the following emulators:");
QMapIterator iter(found);
while (iter.hasNext()) {
iter.next();
- if (!iter.value()) continue;
+ if (!iter.value())
+ continue;
- buttonMap[iter.key()] = migration_prompt.addButton(iter.key(), QMessageBox::YesRole);
+ buttonMap[iter.key()] = migration_prompt.addButton(iter.key());
promptText.append(main_window->tr("\n- %1").arg(iter.key()));
}
promptText.append(main_window->tr("\n\n"));
migration_prompt.setText(promptText + migration_prompt_message);
- migration_prompt.addButton(QMessageBox::No);
+ migration_prompt.addButton(main_window->tr("No"), true);
migration_prompt.exec();
+ MigrationStrategy strategy;
+ if (link->isChecked()) {
+ strategy = MigrationStrategy::Link;
+ } else if (clear_old->isChecked()) {
+ strategy = MigrationStrategy::Move;
+ } else {
+ strategy = MigrationStrategy::Copy;
+ }
+
QMapIterator buttonIter(buttonMap);
while (buttonIter.hasNext()) {
buttonIter.next();
if (buttonIter.value() == migration_prompt.clickedButton()) {
- MigrateUserData(main_window, legacyMap[iter.key()], clear_shaders->isChecked());
+ MigrateUserData(main_window,
+ legacyMap[buttonIter.key()],
+ clear_shaders->isChecked(),
+ strategy);
return;
}
}
@@ -104,31 +159,43 @@ void UserDataMigrator::ShowMigrationPrompt(QMainWindow* main_window) {
return;
}
-void UserDataMigrator::ShowMigrationCancelledMessage(QMainWindow* main_window) {
- QMessageBox::information(
- main_window, main_window->tr("Migration"),
- main_window
- ->tr("You can manually re-trigger this prompt by deleting the "
- "new config directory:\n"
- "%1")
- .arg(QString::fromStdString(Common::FS::GetEdenPathString(Common::FS::EdenPath::ConfigDir))),
- QMessageBox::Ok);
+void UserDataMigrator::ShowMigrationCancelledMessage(
+ QMainWindow *main_window)
+{
+ QMessageBox::information(main_window,
+ main_window->tr("Migration"),
+ main_window
+ ->tr("You can manually re-trigger this prompt by deleting the "
+ "new config directory:\n"
+ "%1")
+ .arg(QString::fromStdString(Common::FS::GetEdenPathString(
+ Common::FS::EdenPath::ConfigDir))),
+ QMessageBox::Ok);
}
-void UserDataMigrator::MigrateUserData(QMainWindow* main_window,
- const LegacyEmu selected_legacy_emu, const bool clear_shader_cache) {
+void UserDataMigrator::MigrateUserData(
+ QMainWindow *main_window,
+ const LegacyEmu selected_legacy_emu,
+ const bool clear_shader_cache,
+ const MigrationStrategy strategy)
+{
namespace fs = std::filesystem;
const auto copy_options = fs::copy_options::update_existing | fs::copy_options::recursive;
+ QString success_text = main_window->tr("Data was migrated successfully.");
+
std::string legacy_user_dir;
std::string legacy_config_dir;
std::string legacy_cache_dir;
-#define LEGACY_EMU(emu) case LegacyEmu::emu: \
- legacy_user_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##Dir).string(); \
- legacy_config_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##ConfigDir).string(); \
- legacy_cache_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##CacheDir).string(); \
- break;
+#define LEGACY_EMU(emu) \
+case LegacyEmu::emu: \
+ legacy_user_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##Dir).string(); \
+ legacy_config_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##ConfigDir) \
+ .string(); \
+ legacy_cache_dir = Common::FS::GetLegacyPath(Common::FS::LegacyPath::emu##CacheDir) \
+ .string(); \
+ break;
switch (selected_legacy_emu) {
LEGACY_EMU(Citron)
@@ -139,30 +206,74 @@ void UserDataMigrator::MigrateUserData(QMainWindow* main_window,
#undef LEGACY_EMU
- fs::copy(legacy_user_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir), copy_options);
+ fs::path eden_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::EdenDir);
+ fs::path config_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir);
+ fs::path cache_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir);
+ fs::path shader_dir = Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir);
- if (fs::is_directory(legacy_config_dir)) {
- fs::copy(legacy_config_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::ConfigDir),
- copy_options);
- }
- if (fs::is_directory(legacy_cache_dir)) {
- fs::copy(legacy_cache_dir, Common::FS::GetEdenPath(Common::FS::EdenPath::CacheDir),
- copy_options);
+ fs::remove_all(eden_dir);
+
+ switch (strategy) {
+ case MigrationStrategy::Link:
+ // Create symlinks/directory junctions if requested
+ fs::create_directory_symlink(legacy_user_dir, eden_dir);
+
+// Windows doesn't need any more links, because cache and config
+// are already children of the root directory
+#ifndef WIN32
+ if (fs::is_directory(legacy_config_dir)) {
+ fs::create_directory_symlink(legacy_config_dir, config_dir);
+ }
+
+ if (fs::is_directory(legacy_cache_dir)) {
+ fs::create_directory_symlink(legacy_cache_dir, cache_dir);
+ }
+#endif
+ break;
+ case MigrationStrategy::Move:
+ // Rename directories if deletion is requested (achieves the same result)
+ fs::rename(legacy_user_dir, eden_dir);
+
+// Windows doesn't need any more renames, because cache and config
+// are already children of the root directory
+#ifndef WIN32
+ if (fs::is_directory(legacy_config_dir)) {
+ fs::rename(legacy_config_dir, config_dir);
+ }
+
+ if (fs::is_directory(legacy_cache_dir)) {
+ fs::rename(legacy_cache_dir, cache_dir);
+ }
+#endif
+ break;
+ case MigrationStrategy::Copy:
+ default:
+ // Default behavior: copy
+ fs::copy(legacy_user_dir, eden_dir, copy_options);
+
+ if (fs::is_directory(legacy_config_dir)) {
+ fs::copy(legacy_config_dir, config_dir, copy_options);
+ }
+
+ if (fs::is_directory(legacy_cache_dir)) {
+ fs::copy(legacy_cache_dir, cache_dir, copy_options);
+ }
+
+ success_text.append(
+ main_window->tr("\n\nIf you wish to clean up the files which were left in the old "
+ "data location, you can do so by deleting the following directory:\n"
+ "%1").arg(QString::fromStdString(legacy_user_dir)));
+ break;
}
// Delete and re-create shader dir
if (clear_shader_cache) {
- fs::remove_all(Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir));
- fs::create_directory(Common::FS::GetEdenPath(Common::FS::EdenPath::ShaderDir));
+ fs::remove_all(shader_dir);
+ fs::create_directory(shader_dir);
}
- QMessageBox::information(
- main_window, main_window->tr("Migration"),
- main_window
- ->tr("Data was migrated successfully.\n\n"
- "If you wish to clean up the files which were left in the old "
- "data location, you can do so by deleting the following directory:\n"
- "%1")
- .arg(QString::fromStdString(legacy_user_dir)),
- QMessageBox::Ok);
+ QMessageBox::information(main_window,
+ main_window->tr("Migration"),
+ success_text,
+ QMessageBox::Ok);
}