From 1b6d42f719784aff002e7cda63309a14ce06fa45 Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Sat, 20 Aug 2022 11:31:58 -0500 Subject: [PATCH] refactor: Use metadata.json to find paths to CFs and RPs --- src/Recyclarr/CompositionRoot.cs | 2 +- .../LocalRepoCustomFormatJsonParserTest.cs | 10 ++++- .../LocalRepoReleaseProfileJsonParserTest.cs | 18 ++++++--- .../Guide/LocalRepoCustomFormatJsonParser.cs | 17 ++++----- src/TrashLib/Repo/IRepoMetadataParser.cs | 6 +++ src/TrashLib/Repo/IRepoPaths.cs | 9 +++++ src/TrashLib/Repo/IRepoPathsFactory.cs | 6 +++ src/TrashLib/Repo/RepoAutofacModule.cs | 14 +++++++ src/TrashLib/Repo/RepoMetadata.cs | 18 +++++++++ src/TrashLib/Repo/RepoMetadataParser.cs | 38 +++++++++++++++++++ src/TrashLib/Repo/RepoPaths.cs | 8 ++++ src/TrashLib/Repo/RepoPathsFactory.cs | 34 +++++++++++++++++ .../LocalRepoReleaseProfileJsonParser.cs | 21 +++++----- 13 files changed, 173 insertions(+), 28 deletions(-) create mode 100644 src/TrashLib/Repo/IRepoMetadataParser.cs create mode 100644 src/TrashLib/Repo/IRepoPaths.cs create mode 100644 src/TrashLib/Repo/IRepoPathsFactory.cs create mode 100644 src/TrashLib/Repo/RepoAutofacModule.cs create mode 100644 src/TrashLib/Repo/RepoMetadata.cs create mode 100644 src/TrashLib/Repo/RepoMetadataParser.cs create mode 100644 src/TrashLib/Repo/RepoPaths.cs create mode 100644 src/TrashLib/Repo/RepoPathsFactory.cs diff --git a/src/Recyclarr/CompositionRoot.cs b/src/Recyclarr/CompositionRoot.cs index 0e474be4..86c93986 100644 --- a/src/Recyclarr/CompositionRoot.cs +++ b/src/Recyclarr/CompositionRoot.cs @@ -43,13 +43,13 @@ internal class CompositionRoot : ICompositionRoot builder.RegisterModule(); builder.RegisterModule(); builder.RegisterModule(); + builder.RegisterModule(); // Needed for Autofac.Extras.Ordering builder.RegisterSource(); builder.RegisterModule(); builder.RegisterType().As(); - builder.RegisterType().As(); builder.RegisterType(); ConfigurationRegistrations(builder); diff --git a/src/TrashLib.Tests/Radarr/CustomFormat/Guide/LocalRepoCustomFormatJsonParserTest.cs b/src/TrashLib.Tests/Radarr/CustomFormat/Guide/LocalRepoCustomFormatJsonParserTest.cs index 1b3812bc..ce4db307 100644 --- a/src/TrashLib.Tests/Radarr/CustomFormat/Guide/LocalRepoCustomFormatJsonParserTest.cs +++ b/src/TrashLib.Tests/Radarr/CustomFormat/Guide/LocalRepoCustomFormatJsonParserTest.cs @@ -2,9 +2,12 @@ using System.IO.Abstractions; using System.IO.Abstractions.TestingHelpers; using AutoFixture.NUnit3; using FluentAssertions; +using NSubstitute; using NUnit.Framework; using TestLibrary.AutoFixture; using TrashLib.Radarr.CustomFormat.Guide; +using TrashLib.Repo; +using TrashLib.Startup; using TrashLib.TestLibrary; namespace TrashLib.Tests.Radarr.CustomFormat.Guide; @@ -16,10 +19,11 @@ public class LocalRepoCustomFormatJsonParserTest [Test, AutoMockData] public void Get_custom_format_json_works( [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, - [Frozen(Matching.ImplementedInterfaces)] TestAppPaths paths, + [Frozen] IAppPaths appPaths, + [Frozen] IRepoPaths repoPaths, LocalRepoCustomFormatJsonParser sut) { - var jsonDir = paths.RepoDirectory + var jsonDir = appPaths.RepoDirectory .SubDirectory("docs") .SubDirectory("json") .SubDirectory("radarr"); @@ -27,6 +31,8 @@ public class LocalRepoCustomFormatJsonParserTest fs.AddFile(jsonDir.File("first.json").FullName, new MockFileData("{'name':'first','trash_id':'1'}")); fs.AddFile(jsonDir.File("second.json").FullName, new MockFileData("{'name':'second','trash_id':'2'}")); + repoPaths.RadarrCustomFormatPaths.Returns(new[] {jsonDir}); + var results = sut.GetCustomFormatData(); results.Should().BeEquivalentTo(new[] diff --git a/src/TrashLib.Tests/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParserTest.cs b/src/TrashLib.Tests/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParserTest.cs index ac303caf..89a38c84 100644 --- a/src/TrashLib.Tests/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParserTest.cs +++ b/src/TrashLib.Tests/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParserTest.cs @@ -3,12 +3,14 @@ using System.IO.Abstractions.TestingHelpers; using AutoFixture.NUnit3; using FluentAssertions; using Newtonsoft.Json; +using NSubstitute; using NUnit.Framework; using TestLibrary; using TestLibrary.AutoFixture; +using TrashLib.Repo; using TrashLib.Sonarr.ReleaseProfile; using TrashLib.Sonarr.ReleaseProfile.Guide; -using TrashLib.TestLibrary; +using TrashLib.Startup; namespace TrashLib.Tests.Sonarr.ReleaseProfile.Guide; @@ -19,7 +21,8 @@ public class LocalRepoReleaseProfileJsonParserTest [Test, AutoMockData] public void Get_custom_format_json_works( [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, - [Frozen(Matching.ImplementedInterfaces)] TestAppPaths paths, + [Frozen] IAppPaths appPaths, + [Frozen] IRepoPaths repoPaths, LocalRepoReleaseProfileJsonParser sut) { static ReleaseProfileData MakeMockObject(string term) => new() @@ -38,7 +41,7 @@ public class LocalRepoReleaseProfileJsonParserTest var mockData1 = MakeMockObject("first"); var mockData2 = MakeMockObject("second"); - var baseDir = paths.RepoDirectory + var baseDir = appPaths.RepoDirectory .SubDirectory("docs") .SubDirectory("json") .SubDirectory("sonarr"); @@ -46,6 +49,8 @@ public class LocalRepoReleaseProfileJsonParserTest fs.AddFile(baseDir.File("first.json").FullName, MockFileData(mockData1)); fs.AddFile(baseDir.File("second.json").FullName, MockFileData(mockData2)); + repoPaths.SonarrReleaseProfilePaths.Returns(new[] {baseDir}); + var results = sut.GetReleaseProfileData(); results.Should().BeEquivalentTo(new[] @@ -58,10 +63,11 @@ public class LocalRepoReleaseProfileJsonParserTest [Test, AutoMockData] public void Json_exceptions_do_not_interrupt_parsing_other_files( [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, - [Frozen(Matching.ImplementedInterfaces)] TestAppPaths paths, + [Frozen] IAppPaths appPaths, + [Frozen] IRepoPaths repoPaths, LocalRepoReleaseProfileJsonParser sut) { - var rootPath = paths.RepoDirectory + var rootPath = appPaths.RepoDirectory .SubDirectory("docs") .SubDirectory("json") .SubDirectory("sonarr"); @@ -80,6 +86,8 @@ public class LocalRepoReleaseProfileJsonParserTest fs.AddFile(rootPath.File("0_bad_data.json").FullName, MockData.FromString(badData)); fs.AddFile(rootPath.File("1_good_data.json").FullName, MockData.FromJson(goodData)); + repoPaths.SonarrReleaseProfilePaths.Returns(new[] {rootPath}); + var results = sut.GetReleaseProfileData(); results.Should().BeEquivalentTo(new[] {goodData}); diff --git a/src/TrashLib/Radarr/CustomFormat/Guide/LocalRepoCustomFormatJsonParser.cs b/src/TrashLib/Radarr/CustomFormat/Guide/LocalRepoCustomFormatJsonParser.cs index cfa824cd..136e5eee 100644 --- a/src/TrashLib/Radarr/CustomFormat/Guide/LocalRepoCustomFormatJsonParser.cs +++ b/src/TrashLib/Radarr/CustomFormat/Guide/LocalRepoCustomFormatJsonParser.cs @@ -6,29 +6,28 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Serilog; using TrashLib.Radarr.CustomFormat.Models; -using TrashLib.Startup; +using TrashLib.Repo; namespace TrashLib.Radarr.CustomFormat.Guide; public class LocalRepoCustomFormatJsonParser : IRadarrGuideService { - private readonly IAppPaths _paths; + private readonly IRepoPathsFactory _pathsFactory; private readonly ILogger _log; - public LocalRepoCustomFormatJsonParser(IAppPaths paths, ILogger log) + public LocalRepoCustomFormatJsonParser(IRepoPathsFactory pathsFactory, ILogger log) { - _paths = paths; + _pathsFactory = pathsFactory; _log = log; } public ICollection GetCustomFormatData() { - var jsonDir = _paths.RepoDirectory - .SubDirectory("docs") - .SubDirectory("json") - .SubDirectory("radarr"); + var paths = _pathsFactory.Create(); + var jsonFiles = paths.RadarrCustomFormatPaths + .SelectMany(x => x.GetFiles("*.json")); - return jsonDir.EnumerateFiles("*.json").ToObservable() + return jsonFiles.ToObservable() .Select(x => Observable.Defer(() => LoadJsonFromFile(x))) .Merge(8) .NotNull() diff --git a/src/TrashLib/Repo/IRepoMetadataParser.cs b/src/TrashLib/Repo/IRepoMetadataParser.cs new file mode 100644 index 00000000..3a703643 --- /dev/null +++ b/src/TrashLib/Repo/IRepoMetadataParser.cs @@ -0,0 +1,6 @@ +namespace TrashLib.Repo; + +public interface IRepoMetadataParser +{ + RepoMetadata Deserialize(); +} diff --git a/src/TrashLib/Repo/IRepoPaths.cs b/src/TrashLib/Repo/IRepoPaths.cs new file mode 100644 index 00000000..dcb0bc6f --- /dev/null +++ b/src/TrashLib/Repo/IRepoPaths.cs @@ -0,0 +1,9 @@ +using System.IO.Abstractions; + +namespace TrashLib.Repo; + +public interface IRepoPaths +{ + IReadOnlyCollection RadarrCustomFormatPaths { get; } + IReadOnlyCollection SonarrReleaseProfilePaths { get; } +} diff --git a/src/TrashLib/Repo/IRepoPathsFactory.cs b/src/TrashLib/Repo/IRepoPathsFactory.cs new file mode 100644 index 00000000..f43cdc29 --- /dev/null +++ b/src/TrashLib/Repo/IRepoPathsFactory.cs @@ -0,0 +1,6 @@ +namespace TrashLib.Repo; + +public interface IRepoPathsFactory +{ + IRepoPaths Create(); +} diff --git a/src/TrashLib/Repo/RepoAutofacModule.cs b/src/TrashLib/Repo/RepoAutofacModule.cs new file mode 100644 index 00000000..5cdd556e --- /dev/null +++ b/src/TrashLib/Repo/RepoAutofacModule.cs @@ -0,0 +1,14 @@ +using Autofac; + +namespace TrashLib.Repo; + +public class RepoAutofacModule : Module +{ + protected override void Load(ContainerBuilder builder) + { + base.Load(builder); + builder.RegisterType().As(); + builder.RegisterType().As(); + builder.RegisterType().As().SingleInstance(); + } +} diff --git a/src/TrashLib/Repo/RepoMetadata.cs b/src/TrashLib/Repo/RepoMetadata.cs new file mode 100644 index 00000000..8bd2eb5e --- /dev/null +++ b/src/TrashLib/Repo/RepoMetadata.cs @@ -0,0 +1,18 @@ +namespace TrashLib.Repo; + +public record RadarrMetadata( + IReadOnlyCollection CustomFormats +); + +public record SonarrMetadata( + IReadOnlyCollection ReleaseProfiles +); + +public record JsonPaths( + RadarrMetadata Radarr, + SonarrMetadata Sonarr +); + +public record RepoMetadata( + JsonPaths JsonPaths +); diff --git a/src/TrashLib/Repo/RepoMetadataParser.cs b/src/TrashLib/Repo/RepoMetadataParser.cs new file mode 100644 index 00000000..3aa65bb9 --- /dev/null +++ b/src/TrashLib/Repo/RepoMetadataParser.cs @@ -0,0 +1,38 @@ +using System.IO.Abstractions; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; +using TrashLib.Startup; + +namespace TrashLib.Repo; + +public class RepoMetadataParser : IRepoMetadataParser +{ + private readonly IAppPaths _paths; + + public RepoMetadataParser(IAppPaths paths) + { + _paths = paths; + } + + public RepoMetadata Deserialize() + { + var serializer = JsonSerializer.Create(new JsonSerializerSettings + { + ContractResolver = new DefaultContractResolver + { + NamingStrategy = new SnakeCaseNamingStrategy() + } + }); + + var metadataFile = _paths.RepoDirectory.File("metadata.json"); + using var stream = new JsonTextReader(metadataFile.OpenText()); + + var metadata = serializer.Deserialize(stream); + if (metadata is null) + { + throw new InvalidDataException("Unable to deserialize metadata.json"); + } + + return metadata; + } +} diff --git a/src/TrashLib/Repo/RepoPaths.cs b/src/TrashLib/Repo/RepoPaths.cs new file mode 100644 index 00000000..7ffddf24 --- /dev/null +++ b/src/TrashLib/Repo/RepoPaths.cs @@ -0,0 +1,8 @@ +using System.IO.Abstractions; + +namespace TrashLib.Repo; + +public record RepoPaths( + IReadOnlyCollection RadarrCustomFormatPaths, + IReadOnlyCollection SonarrReleaseProfilePaths +) : IRepoPaths; diff --git a/src/TrashLib/Repo/RepoPathsFactory.cs b/src/TrashLib/Repo/RepoPathsFactory.cs new file mode 100644 index 00000000..e45d86ef --- /dev/null +++ b/src/TrashLib/Repo/RepoPathsFactory.cs @@ -0,0 +1,34 @@ +using System.IO.Abstractions; +using TrashLib.Startup; + +namespace TrashLib.Repo; + +public class RepoPathsFactory : IRepoPathsFactory +{ + private readonly IAppPaths _paths; + private readonly IFileSystem _fs; + private readonly Lazy _metadata; + + public RepoPathsFactory(IRepoMetadataParser parser, IAppPaths paths, IFileSystem fs) + { + _paths = paths; + _fs = fs; + _metadata = new Lazy(parser.Deserialize); + } + + private List ToDirectoryInfoList(IEnumerable listOfDirectories) + { + return listOfDirectories + .Select(x => _paths.RepoDirectory.SubDirectory(x)) + .Where(x => x.Exists) + .ToList(); + } + + public IRepoPaths Create() + { + var metadata = _metadata.Value; + return new RepoPaths( + ToDirectoryInfoList(metadata.JsonPaths.Radarr.CustomFormats), + ToDirectoryInfoList(metadata.JsonPaths.Sonarr.ReleaseProfiles)); + } +} diff --git a/src/TrashLib/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParser.cs b/src/TrashLib/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParser.cs index e55f220a..78bd3eaa 100644 --- a/src/TrashLib/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParser.cs +++ b/src/TrashLib/Sonarr/ReleaseProfile/Guide/LocalRepoReleaseProfileJsonParser.cs @@ -3,34 +3,33 @@ using Common.Extensions; using MoreLinq; using Newtonsoft.Json; using Serilog; +using TrashLib.Repo; using TrashLib.Sonarr.ReleaseProfile.Filters; -using TrashLib.Startup; namespace TrashLib.Sonarr.ReleaseProfile.Guide; public class LocalRepoReleaseProfileJsonParser : ISonarrGuideService { - private readonly IAppPaths _paths; + private readonly IRepoPathsFactory _pathFactory; private readonly ILogger _log; + private readonly IFileSystem _fs; private readonly Lazy> _data; - public LocalRepoReleaseProfileJsonParser(IAppPaths paths, ILogger log) + public LocalRepoReleaseProfileJsonParser(IRepoPathsFactory pathFactory, ILogger log, IFileSystem fs) { - _paths = paths; + _pathFactory = pathFactory; _log = log; + _fs = fs; _data = new Lazy>(GetReleaseProfileDataImpl); } private IEnumerable GetReleaseProfileDataImpl() { var converter = new TermDataConverter(); - var jsonDir = _paths.RepoDirectory - .SubDirectory("docs") - .SubDirectory("json") - .SubDirectory("sonarr"); - - var tasks = jsonDir.GetFiles("*.json") - .Select(f => LoadAndParseFile(f, converter)); + var paths = _pathFactory.Create(); + var tasks = paths.SonarrReleaseProfilePaths + .SelectMany(x => x.GetFiles("*.json")) + .Select(x => LoadAndParseFile(x, converter)); var data = Task.WhenAll(tasks).Result // Make non-nullable type and filter out null values