Allow game folder migration to fail gracefully when cleanup cannot completely succeed

This commit is contained in:
Dean Herbert
2022-02-10 18:48:37 +09:00
parent 7081c418dd
commit 44f2d8a448
5 changed files with 66 additions and 20 deletions

View File

@ -33,7 +33,8 @@ namespace osu.Game.IO
/// A general purpose migration method to move the storage to a different location.
/// <param name="newStorage">The target storage of the migration.</param>
/// </summary>
public virtual void Migrate(Storage newStorage)
/// <returns>Whether cleanup could complete.</returns>
public virtual bool Migrate(Storage newStorage)
{
var source = new DirectoryInfo(GetFullPath("."));
var destination = new DirectoryInfo(newStorage.GetFullPath("."));
@ -57,17 +58,20 @@ namespace osu.Game.IO
CopyRecursive(source, destination);
ChangeTargetStorage(newStorage);
DeleteRecursive(source);
return DeleteRecursive(source);
}
protected void DeleteRecursive(DirectoryInfo target, bool topLevelExcludes = true)
protected bool DeleteRecursive(DirectoryInfo target, bool topLevelExcludes = true)
{
bool allFilesDeleted = true;
foreach (System.IO.FileInfo fi in target.GetFiles())
{
if (topLevelExcludes && IgnoreFiles.Contains(fi.Name))
continue;
AttemptOperation(() => fi.Delete());
allFilesDeleted &= AttemptOperation(() => fi.Delete(), throwOnFailure: false);
}
foreach (DirectoryInfo dir in target.GetDirectories())
@ -75,11 +79,13 @@ namespace osu.Game.IO
if (topLevelExcludes && IgnoreDirectories.Contains(dir.Name))
continue;
AttemptOperation(() => dir.Delete(true));
allFilesDeleted &= AttemptOperation(() => dir.Delete(true), throwOnFailure: false);
}
if (target.GetFiles().Length == 0 && target.GetDirectories().Length == 0)
AttemptOperation(target.Delete);
allFilesDeleted &= AttemptOperation(target.Delete, throwOnFailure: false);
return allFilesDeleted;
}
protected void CopyRecursive(DirectoryInfo source, DirectoryInfo destination, bool topLevelExcludes = true)
@ -110,19 +116,25 @@ namespace osu.Game.IO
/// </summary>
/// <param name="action">The action to perform.</param>
/// <param name="attempts">The number of attempts (250ms wait between each).</param>
protected static void AttemptOperation(Action action, int attempts = 10)
/// <param name="throwOnFailure">Whether to throw an exception on failure. If <c>false</c>, will silently fail.</param>
protected static bool AttemptOperation(Action action, int attempts = 10, bool throwOnFailure = true)
{
while (true)
{
try
{
action();
return;
return true;
}
catch (Exception)
{
if (attempts-- == 0)
throw;
{
if (throwOnFailure)
throw;
return false;
}
}
Thread.Sleep(250);