Skip to content

Commit

Permalink
Move stable import handling into its own class
Browse files Browse the repository at this point in the history
  • Loading branch information
peppy committed Nov 25, 2021
1 parent 2bfc473 commit 6cab7b8
Show file tree
Hide file tree
Showing 13 changed files with 122 additions and 72 deletions.
5 changes: 0 additions & 5 deletions osu.Game/Beatmaps/BeatmapManager.cs
Expand Up @@ -225,11 +225,6 @@ public bool IsAvailableLocally(BeatmapSetInfo model)
remove => beatmapModelManager.ItemRemoved -= value;
}

public Task ImportFromStableAsync(StableStorage stableStorage)
{
return beatmapModelManager.ImportFromStableAsync(stableStorage);
}

public void Export(BeatmapSetInfo item)
{
beatmapModelManager.Export(item);
Expand Down
4 changes: 0 additions & 4 deletions osu.Game/Beatmaps/BeatmapModelManager.cs
Expand Up @@ -58,10 +58,6 @@ public class BeatmapModelManager : ArchiveModelManager<BeatmapSetInfo, BeatmapSe

protected override string[] HashableFileTypes => new[] { ".osu" };

protected override string ImportFromStablePath => ".";

protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage();

private readonly BeatmapStore beatmaps;
private readonly RulesetStore rulesets;

Expand Down
34 changes: 0 additions & 34 deletions osu.Game/Database/ArchiveModelManager.cs
Expand Up @@ -728,47 +728,13 @@ private IEnumerable<(string original, string shortened)> getShortenedFilenames(A

#region osu-stable import

/// <summary>
/// The relative path from osu-stable's data directory to import items from.
/// </summary>
protected virtual string ImportFromStablePath => null;

/// <summary>
/// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in <see cref="ImportFromStablePath"/>.
/// </summary>
protected virtual IEnumerable<string> GetStableImportPaths(Storage storage) => storage.GetDirectories(ImportFromStablePath)
.Select(path => storage.GetFullPath(path));

/// <summary>
/// Whether this specified path should be removed after successful import.
/// </summary>
/// <param name="path">The path for consideration. May be a file or a directory.</param>
/// <returns>Whether to perform deletion.</returns>
protected virtual bool ShouldDeleteArchive(string path) => false;

public Task ImportFromStableAsync(StableStorage stableStorage)
{
var storage = PrepareStableStorage(stableStorage);

// Handle situations like when the user does not have a Skins folder.
if (!storage.ExistsDirectory(ImportFromStablePath))
{
string fullPath = storage.GetFullPath(ImportFromStablePath);

Logger.Log(@$"Folder ""{fullPath}"" not available in the target osu!stable installation to import {HumanisedModelName}s.", LoggingTarget.Information, LogLevel.Error);
return Task.CompletedTask;
}

return Task.Run(async () => await Import(GetStableImportPaths(storage).ToArray()).ConfigureAwait(false));
}

/// <summary>
/// Run any required traversal operations on the stable storage location before performing operations.
/// </summary>
/// <param name="stableStorage">The stable storage.</param>
/// <returns>The usable storage. Return the unchanged <paramref name="stableStorage"/> if no traversal is required.</returns>
protected virtual Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage;

#endregion

/// <summary>
Expand Down
7 changes: 0 additions & 7 deletions osu.Game/Database/IModelManager.cs
Expand Up @@ -4,8 +4,6 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using osu.Game.IO;

namespace osu.Game.Database
{
Expand All @@ -26,11 +24,6 @@ public interface IModelManager<TModel>
/// </summary>
event Action<TModel> ItemRemoved;

/// <summary>
/// This is a temporary method and will likely be replaced by a full-fledged (and more correctly placed) migration process in the future.
/// </summary>
Task ImportFromStableAsync(StableStorage stableStorage);

/// <summary>
/// Exports an item to a legacy (.zip based) package.
/// </summary>
Expand Down
18 changes: 18 additions & 0 deletions osu.Game/Database/StableBeatmapImporter.cs
@@ -0,0 +1,18 @@
using osu.Framework.Platform;
using osu.Game.Beatmaps;
using osu.Game.IO;

namespace osu.Game.Database
{
public class StableBeatmapImporter : StableImporter<BeatmapSetInfo>
{
protected override string ImportFromStablePath => ".";

protected override Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage.GetSongStorage();

public StableBeatmapImporter(IModelImporter<BeatmapSetInfo> importer)
: base(importer)
{
}
}
}
10 changes: 7 additions & 3 deletions osu.Game/Database/StableImportManager.cs
Expand Up @@ -51,18 +51,22 @@ public async Task ImportFromStableAsync(StableContent content)
var stableStorage = await getStableStorage().ConfigureAwait(false);
var importTasks = new List<Task>();

var beatmapImporter = new StableBeatmapImporter(beatmaps);
var skinImporter = new StableSkinImporter(skins);
var scoreImporter = new StableScoreImporter(scores);

Task beatmapImportTask = Task.CompletedTask;
if (content.HasFlagFast(StableContent.Beatmaps))
importTasks.Add(beatmapImportTask = beatmaps.ImportFromStableAsync(stableStorage));
importTasks.Add(beatmapImportTask = beatmapImporter.ImportFromStableAsync(stableStorage));

if (content.HasFlagFast(StableContent.Skins))
importTasks.Add(skins.ImportFromStableAsync(stableStorage));
importTasks.Add(skinImporter.ImportFromStableAsync(stableStorage));

if (content.HasFlagFast(StableContent.Collections))
importTasks.Add(beatmapImportTask.ContinueWith(_ => collections.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));

if (content.HasFlagFast(StableContent.Scores))
importTasks.Add(beatmapImportTask.ContinueWith(_ => scores.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));
importTasks.Add(beatmapImportTask.ContinueWith(_ => scoreImporter.ImportFromStableAsync(stableStorage), TaskContinuationOptions.OnlyOnRanToCompletion));

await Task.WhenAll(importTasks.ToArray()).ConfigureAwait(false);
}
Expand Down
60 changes: 60 additions & 0 deletions osu.Game/Database/StableImporter.cs
@@ -0,0 +1,60 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.

using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using osu.Framework.Logging;
using osu.Framework.Platform;
using osu.Game.IO;

namespace osu.Game.Database
{
/// <summary>
/// A class which handled importing various user data from osu-stable.
/// </summary>
public class StableImporter<TModel>
where TModel : class
{
/// <summary>
/// The relative path from osu-stable's data directory to import items from.
/// </summary>
protected virtual string ImportFromStablePath => null;

/// <summary>
/// Select paths to import from stable where all paths should be absolute. Default implementation iterates all directories in <see cref="ImportFromStablePath"/>.
/// </summary>
protected virtual IEnumerable<string> GetStableImportPaths(Storage storage) => storage.GetDirectories(ImportFromStablePath)
.Select(path => storage.GetFullPath(path));

protected readonly IModelImporter<TModel> Importer;

public StableImporter(IModelImporter<TModel> importer)
{
Importer = importer;
}

public Task ImportFromStableAsync(StableStorage stableStorage)
{
var storage = PrepareStableStorage(stableStorage);

// Handle situations like when the user does not have a Skins folder.
if (!storage.ExistsDirectory(ImportFromStablePath))
{
string fullPath = storage.GetFullPath(ImportFromStablePath);

Logger.Log(@$"Folder ""{fullPath}"" not available in the target osu!stable installation to import {Importer.HumanisedModelName}s.", LoggingTarget.Information, LogLevel.Error);
return Task.CompletedTask;
}

return Task.Run(async () => await Importer.Import(GetStableImportPaths(storage).ToArray()).ConfigureAwait(false));
}

/// <summary>
/// Run any required traversal operations on the stable storage location before performing operations.
/// </summary>
/// <param name="stableStorage">The stable storage.</param>
/// <returns>The usable storage. Return the unchanged <paramref name="stableStorage"/> if no traversal is required.</returns>
protected virtual Storage PrepareStableStorage(StableStorage stableStorage) => stableStorage;
}
}
23 changes: 23 additions & 0 deletions osu.Game/Database/StableScoreImporter.cs
@@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using osu.Framework.Platform;
using osu.Game.Scoring;

namespace osu.Game.Database
{
public class StableScoreImporter : StableImporter<ScoreInfo>
{
protected override string ImportFromStablePath => Path.Combine("Data", "r");

protected override IEnumerable<string> GetStableImportPaths(Storage storage)
=> storage.GetFiles(ImportFromStablePath).Where(p => Importer.HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false))
.Select(path => storage.GetFullPath(path));

public StableScoreImporter(IModelImporter<ScoreInfo> importer)
: base(importer)
{
}
}
}
14 changes: 14 additions & 0 deletions osu.Game/Database/StableSkinImporter.cs
@@ -0,0 +1,14 @@
using osu.Game.Skinning;

namespace osu.Game.Database
{
public class StableSkinImporter : StableImporter<SkinInfo>
{
protected override string ImportFromStablePath => "Skins";

public StableSkinImporter(IModelImporter<SkinInfo> importer)
: base(importer)
{
}
}
}
6 changes: 0 additions & 6 deletions osu.Game/Scoring/ScoreManager.cs
Expand Up @@ -15,7 +15,6 @@
using osu.Game.Beatmaps;
using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.IO;
using osu.Game.IO.Archives;
using osu.Game.Online.API;
using osu.Game.Overlays.Notifications;
Expand Down Expand Up @@ -263,11 +262,6 @@ public Action<Notification> PostNotification
remove => scoreModelManager.ItemRemoved -= value;
}

public Task ImportFromStableAsync(StableStorage stableStorage)
{
return scoreModelManager.ImportFromStableAsync(stableStorage);
}

public void Export(ScoreInfo item)
{
scoreModelManager.Export(item);
Expand Down
6 changes: 0 additions & 6 deletions osu.Game/Scoring/ScoreModelManager.cs
Expand Up @@ -26,8 +26,6 @@ public class ScoreModelManager : ArchiveModelManager<ScoreInfo, ScoreFileInfo>

protected override string[] HashableFileTypes => new[] { ".osr" };

protected override string ImportFromStablePath => Path.Combine("Data", "r");

private readonly RulesetStore rulesets;
private readonly Func<BeatmapManager> beatmaps;

Expand Down Expand Up @@ -81,9 +79,5 @@ public override void ExportModelTo(ScoreInfo model, Stream outputStream)
using (var inputStream = Files.Storage.GetStream(file.FileInfo.GetStoragePath()))
inputStream.CopyTo(outputStream);
}

protected override IEnumerable<string> GetStableImportPaths(Storage storage)
=> storage.GetFiles(ImportFromStablePath).Where(p => HandledExtensions.Any(ext => Path.GetExtension(p)?.Equals(ext, StringComparison.OrdinalIgnoreCase) ?? false))
.Select(path => storage.GetFullPath(path));
}
}
5 changes: 0 additions & 5 deletions osu.Game/Skinning/SkinManager.cs
Expand Up @@ -301,11 +301,6 @@ public Task<ILive<SkinInfo>> Import(SkinInfo item, ArchiveReader archive = null,
remove => skinModelManager.ItemRemoved -= value;
}

public Task ImportFromStableAsync(StableStorage stableStorage)
{
return skinModelManager.ImportFromStableAsync(stableStorage);
}

public void Export(SkinInfo item)
{
skinModelManager.Export(item);
Expand Down
2 changes: 0 additions & 2 deletions osu.Game/Skinning/SkinModelManager.cs
Expand Up @@ -34,8 +34,6 @@ public SkinModelManager(Storage storage, DatabaseContextFactory contextFactory,

protected override string[] HashableFileTypes => new[] { ".ini", ".json" };

protected override string ImportFromStablePath => "Skins";

protected override bool ShouldDeleteArchive(string path) => Path.GetExtension(path)?.ToLowerInvariant() == @".osk";

protected override SkinInfo CreateModel(ArchiveReader archive) => new SkinInfo { Name = archive.Name ?? @"No name" };
Expand Down

0 comments on commit 6cab7b8

Please sign in to comment.