Do migration automatically at startup

This commit is contained in:
Alex Barney 2019-11-29 18:04:47 -06:00
commit c965acaa2d
3 changed files with 81 additions and 10 deletions

View file

@ -28,7 +28,7 @@ namespace Ryujinx
string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys"); string userProfilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), ".switch", "prod.keys");
if (!File.Exists(appDataPath) && !File.Exists(userProfilePath)) if (!File.Exists(appDataPath) && !File.Exists(userProfilePath))
{ {
GtkDialog.CreateErrorDialog($"Key file was not found. Please refer to `KEYS.md` for more info"); GtkDialog.CreateErrorDialog("Key file was not found. Please refer to `KEYS.md` for more info");
} }
MainWindow mainWindow = new MainWindow(); MainWindow mainWindow = new MainWindow();

View file

@ -94,6 +94,12 @@ namespace Ryujinx.Ui
_device = new HLE.Switch(_renderer, _audioOut); _device = new HLE.Switch(_renderer, _audioOut);
bool continueAfterMigration = Migration.TryMigrateForStartup(this, _device);
if (!continueAfterMigration)
{
End();
}
_treeView = _gameTable; _treeView = _gameTable;
Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json")); Configuration.Load(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Config.json"));

View file

@ -1,18 +1,21 @@
using LibHac; using Gtk;
using LibHac;
using LibHac.Common; using LibHac.Common;
using LibHac.Fs; using LibHac.Fs;
using LibHac.Fs.Shim; using LibHac.Fs.Shim;
using LibHac.FsSystem; using LibHac.FsSystem;
using LibHac.FsSystem.Save; using LibHac.FsSystem.Save;
using LibHac.Ncm; using LibHac.Ncm;
using Ryujinx.HLE;
using Ryujinx.HLE.Utilities; using Ryujinx.HLE.Utilities;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using Switch = Ryujinx.HLE.Switch;
namespace Ryujinx.Ui namespace Ryujinx.Ui
{ {
internal class Migration internal class Migration
@ -24,26 +27,85 @@ namespace Ryujinx.Ui
Device = device; Device = device;
} }
public void Migrate() public static bool TryMigrateForStartup(Window parentWindow, Switch device)
{
const int responseYes = -8;
if (!IsMigrationNeeded(device.FileSystem.GetBasePath()))
{
return true;
}
int dialogResponse;
using (MessageDialog dialog = new MessageDialog(parentWindow, DialogFlags.Modal, MessageType.Question,
ButtonsType.YesNo, "What's this?"))
{
dialog.Title = "Data Migration Needed";
dialog.Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png");
dialog.Text =
"The folder structure of Ryujinx's RyuFs folder has been updated. Your RyuFs folder must be migrated to the new structure. Would you like to do the migration now?\n\n" +
"Select \"Yes\" to automatically perform the migration. A backup of your old saves will be placed in your RyuFs folder.\n\n" +
"Selecting \"No\" will exit Ryujinx without changing the contents of your RyuFs folder.";
dialogResponse = dialog.Run();
}
if (dialogResponse != responseYes)
{
return false;
}
try
{
Migration migration = new Migration(device);
int saveCount = migration.Migrate();
using MessageDialog dialogSuccess = new MessageDialog(parentWindow, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, null)
{
Title = "Migration Success",
Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"),
Text = $"Data migration was successful. {saveCount} saves were migrated.",
};
dialogSuccess.Run();
return true;
}
catch (HorizonResultException ex)
{
GtkDialog.CreateErrorDialog(ex.Message);
return false;
}
}
// Returns the number of saves migrated
public int Migrate()
{ {
string basePath = Device.FileSystem.GetBasePath(); string basePath = Device.FileSystem.GetBasePath();
string backupPath = Path.Combine(basePath, "Migration backup (Can delete if successful)"); string backupPath = Path.Combine(basePath, "Migration backup (Can delete if successful)");
string backupUserSavePath = Path.Combine(backupPath, "nand/user/save"); string backupUserSavePath = Path.Combine(backupPath, "nand/user/save");
if (!IsMigrationNeeded(basePath)) if (!IsMigrationNeeded(basePath))
return; return 0;
BackupSaves(basePath, backupPath); BackupSaves(basePath, backupPath);
MigrateDirectories(basePath); MigrateDirectories(basePath);
MigrateSaves(Device.System.FsClient, backupUserSavePath); return MigrateSaves(Device.System.FsClient, backupUserSavePath);
} }
private static bool IsMigrationNeeded(string basePath) private static bool IsMigrationNeeded(string basePath)
{ {
return !Directory.Exists(Path.Combine(basePath, "bis")) && bool missingNewDirs = !Directory.Exists(Path.Combine(basePath, "bis")) &&
!Directory.Exists(Path.Combine(basePath, "sdcard")); !Directory.Exists(Path.Combine(basePath, "sdcard"));
bool hasOldDirs = Directory.Exists(Path.Combine(basePath, "nand")) ||
Directory.Exists(Path.Combine(basePath, "sdmc"));
return missingNewDirs && hasOldDirs;
} }
private static void MigrateDirectories(string basePath) private static void MigrateDirectories(string basePath)
@ -91,11 +153,12 @@ namespace Ryujinx.Ui
} }
} }
private static void MigrateSaves(FileSystemClient fsClient, string rootSaveDir) // Returns the number of saves migrated
private static int MigrateSaves(FileSystemClient fsClient, string rootSaveDir)
{ {
if (!Directory.Exists(rootSaveDir)) if (!Directory.Exists(rootSaveDir))
{ {
return; return 0;
} }
SaveFinder finder = new SaveFinder(); SaveFinder finder = new SaveFinder();
@ -110,6 +173,8 @@ namespace Ryujinx.Ui
throw new HorizonResultException(migrateResult, $"Error migrating save {save.Path}"); throw new HorizonResultException(migrateResult, $"Error migrating save {save.Path}");
} }
} }
return finder.Saves.Count;
} }
private static Result MigrateSave(FileSystemClient fs, SaveToMigrate save) private static Result MigrateSave(FileSystemClient fs, SaveToMigrate save)