refactor: Make AppPaths injectable

This lays the groundwork to allow application paths to be overridden at
runtime.
pull/76/head
Robert Dailey 3 years ago
parent 1c63121c4e
commit 042fe618c1

@ -0,0 +1,12 @@
using Autofac;
namespace Common;
public class CommonAutofacModule : Module
{
protected override void Load(ContainerBuilder builder)
{
builder.RegisterType<DefaultEnvironment>().As<IEnvironment>();
builder.RegisterType<FileUtilities>().As<IFileUtilities>();
}
}

@ -0,0 +1,9 @@
namespace Common;
internal class DefaultEnvironment : IEnvironment
{
public string GetFolderPath(Environment.SpecialFolder folder)
{
return Environment.GetFolderPath(folder);
}
}

@ -0,0 +1,6 @@
namespace Common;
public interface IEnvironment
{
public string GetFolderPath(Environment.SpecialFolder folder);
}

@ -1,9 +1,12 @@
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers;
using AutoFixture.NUnit3;
using CliFx.Infrastructure;
using FluentAssertions;
using NSubstitute;
using NUnit.Framework;
using Recyclarr.Command;
using Serilog;
using TestLibrary.AutoFixture;
using TrashLib;
// ReSharper disable MethodHasAsyncOverload
@ -13,32 +16,33 @@ namespace Recyclarr.Tests.Command;
[Parallelizable(ParallelScope.All)]
public class CreateConfigCommandTest
{
[Test]
public async Task CreateConfig_DefaultPath_FileIsCreated()
[Test, AutoMockData]
public async Task Config_file_created_when_using_default_path(
[Frozen] IAppPaths paths,
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs,
CreateConfigCommand cmd)
{
var logger = Substitute.For<ILogger>();
var filesystem = Substitute.For<IFileSystem>();
var cmd = new CreateConfigCommand(logger, filesystem);
const string ymlPath = "path/recyclarr.yml";
paths.ConfigPath.Returns(ymlPath);
await cmd.ExecuteAsync(Substitute.For<IConsole>());
await cmd.ExecuteAsync(Substitute.For<IConsole>()).ConfigureAwait(false);
filesystem.File.Received().Exists(Arg.Is<string>(s => s.EndsWith("recyclarr.yml")));
filesystem.File.Received().WriteAllText(Arg.Is<string>(s => s.EndsWith("recyclarr.yml")), Arg.Any<string>());
var file = fs.GetFile(ymlPath);
file.Should().NotBeNull();
file.Contents.Should().NotBeEmpty();
}
[Test]
public async Task CreateConfig_SpecifyPath_FileIsCreated()
[Test, AutoMockData]
public async Task CreateConfig_SpecifyPath_FileIsCreated(
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs,
CreateConfigCommand cmd)
{
var logger = Substitute.For<ILogger>();
var filesystem = Substitute.For<IFileSystem>();
var cmd = new CreateConfigCommand(logger, filesystem)
{
Path = "some/other/path.yml"
};
const string ymlPath = "some/other/path.yml";
cmd.Path = ymlPath;
await cmd.ExecuteAsync(Substitute.For<IConsole>()).ConfigureAwait(false);
filesystem.File.Received().Exists(Arg.Is("some/other/path.yml"));
filesystem.File.Received().WriteAllText(Arg.Is("some/other/path.yml"), Arg.Any<string>());
var file = fs.GetFile(ymlPath);
file.Should().NotBeNull();
file.Contents.Should().NotBeEmpty();
}
}

@ -13,7 +13,7 @@ public class ServiceInitializationAndCleanupTest
{
[Test, AutoMockData]
public async Task Cleanup_happens_when_exception_occurs_in_action(
IServiceCommand cmd,
ServiceCommand cmd,
IServiceCleaner cleaner)
{
var sut = new ServiceInitializationAndCleanup(
@ -28,7 +28,7 @@ public class ServiceInitializationAndCleanupTest
[Test, AutoMockData]
public async Task Cleanup_happens_when_exception_occurs_in_init(
IServiceCommand cmd,
ServiceCommand cmd,
IServiceInitializer init,
IServiceCleaner cleaner)
{

@ -1,7 +1,12 @@
using System.IO.Abstractions;
using System.IO.Abstractions.TestingHelpers;
using AutoFixture.NUnit3;
using FluentAssertions;
using MoreLinq.Extensions;
using NSubstitute;
using NUnit.Framework;
using Recyclarr.Logging;
using TestLibrary.AutoFixture;
using TrashLib;
namespace Recyclarr.Tests;
@ -9,33 +14,28 @@ namespace Recyclarr.Tests;
[Parallelizable(ParallelScope.All)]
public class LogJanitorTest
{
[Test]
public void Keep_correct_number_of_newest_log_files()
[Test, AutoMockData]
public void Keep_correct_number_of_newest_log_files(
[Frozen] IAppPaths paths,
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs,
LogJanitor janitor)
{
var fs = Substitute.For<IFileSystem>();
var janitor = new LogJanitor(fs);
const string logDir = "C:\\logs";
paths.LogDirectory.Returns(logDir);
var testFileInfoList = new[]
var testFiles = new[]
{
Substitute.For<IFileInfo>(),
Substitute.For<IFileInfo>(),
Substitute.For<IFileInfo>(),
Substitute.For<IFileInfo>()
$"{logDir}\\trash_2021-05-15_19-00-00",
$"{logDir}\\trash_2021-05-15_20-00-00",
$"{logDir}\\trash_2021-05-15_21-00-00",
$"{logDir}\\trash_2021-05-15_22-00-00"
};
testFileInfoList[0].Name.Returns("trash_2021-05-15_19-00-00");
testFileInfoList[1].Name.Returns("trash_2021-05-15_20-00-00");
testFileInfoList[2].Name.Returns("trash_2021-05-15_21-00-00");
testFileInfoList[3].Name.Returns("trash_2021-05-15_22-00-00");
fs.DirectoryInfo.FromDirectoryName(Arg.Any<string>()).GetFiles()
.Returns(testFileInfoList);
testFiles.ForEach(x => fs.AddFile(x, new MockFileData("")));
janitor.DeleteOldestLogFiles(2);
testFileInfoList[0].Received().Delete();
testFileInfoList[1].Received().Delete();
testFileInfoList[2].DidNotReceive().Delete();
testFileInfoList[3].DidNotReceive().Delete();
fs.FileExists(testFiles[2]).Should().BeTrue();
fs.FileExists(testFiles[3]).Should().BeTrue();
}
}

@ -1,15 +1,23 @@
namespace Recyclarr;
using System.IO.Abstractions;
using TrashLib;
internal static class AppPaths
{
public static string AppDataPath { get; } =
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "recyclarr");
namespace Recyclarr;
public static string DefaultConfigPath { get; } = Path.Combine(AppContext.BaseDirectory, "recyclarr.yml");
internal class AppPaths : IAppPaths
{
private readonly IFileSystem _fs;
public static string DefaultSettingsPath { get; } = Path.Combine(AppDataPath, "settings.yml");
public AppPaths(IFileSystem fs)
{
_fs = fs;
}
public static string LogDirectory { get; } = Path.Combine(AppDataPath, "logs");
public void SetAppDataPath(string path) => AppDataPath = path;
public static string RepoDirectory { get; } = Path.Combine(AppDataPath, "repo");
public string AppDataPath { get; private set; } = "";
public string ConfigPath => _fs.Path.Combine(AppContext.BaseDirectory, "recyclarr.yml");
public string SettingsPath => _fs.Path.Combine(AppDataPath, "settings.yml");
public string LogDirectory => _fs.Path.Combine(AppDataPath, "logs");
public string RepoDirectory => _fs.Path.Combine(AppDataPath, "repo");
public string CacheDirectory => _fs.Path.Combine(AppDataPath, "cache");
}

@ -6,6 +6,7 @@ using CliFx.Infrastructure;
using Common;
using JetBrains.Annotations;
using Serilog;
using TrashLib;
namespace Recyclarr.Command;
@ -13,35 +14,42 @@ namespace Recyclarr.Command;
[UsedImplicitly]
public class CreateConfigCommand : ICommand
{
private readonly IFileSystem _fileSystem;
private readonly IFileSystem _fs;
private readonly IAppPaths _paths;
private readonly ILogger _log;
private string? _path;
public CreateConfigCommand(ILogger logger, IFileSystem fileSystem)
public CreateConfigCommand(ILogger logger, IFileSystem fs, IAppPaths paths)
{
Log = logger;
_fileSystem = fileSystem;
_log = logger;
_fs = fs;
_paths = paths;
}
private ILogger Log { get; }
[CommandOption("path", 'p', Description =
"Path where the new YAML file should be created. Must include the filename (e.g. path/to/config.yml). " +
"File must not already exist. If not specified, uses the default path of `recyclarr.yml` right next to the " +
"executable.")]
public string Path { get; [UsedImplicitly] set; } = AppPaths.DefaultConfigPath;
public string Path
{
get => _path ?? _paths.ConfigPath;
set => _path = value;
}
public ValueTask ExecuteAsync(IConsole console)
{
var reader = new ResourceDataReader(typeof(Program));
var ymlData = reader.ReadData("config-template.yml");
if (_fileSystem.File.Exists(Path))
if (_fs.File.Exists(Path))
{
throw new CommandException($"The file {Path} already exists. Please choose another path or " +
"delete/move the existing file and run this command again.");
}
_fileSystem.File.WriteAllText(Path, ymlData);
Log.Information("Created configuration at: {Path}", Path);
_fs.Directory.CreateDirectory(_fs.Path.GetDirectoryName(Path));
_fs.File.WriteAllText(Path, ymlData);
_log.Information("Created configuration at: {Path}", Path);
return default;
}
}

@ -2,5 +2,5 @@
public interface IServiceInitializationAndCleanup
{
Task Execute(IServiceCommand cmd, Func<Task> logic);
Task Execute(ServiceCommand cmd, Func<Task> logic);
}

@ -2,5 +2,5 @@
public interface IServiceInitializer
{
void Initialize(IServiceCommand cmd);
void Initialize(ServiceCommand cmd);
}

@ -15,7 +15,7 @@ public class ServiceInitializationAndCleanup : IServiceInitializationAndCleanup
_cleaners = cleaners;
}
public async Task Execute(IServiceCommand cmd, Func<Task> logic)
public async Task Execute(ServiceCommand cmd, Func<Task> logic)
{
try
{

@ -5,6 +5,7 @@ using Newtonsoft.Json;
using Serilog;
using Serilog.Core;
using Serilog.Events;
using TrashLib;
using TrashLib.Config.Settings;
using TrashLib.Extensions;
using TrashLib.Repo;
@ -18,22 +19,25 @@ internal class ServiceInitializer : IServiceInitializer
private readonly ISettingsPersister _settingsPersister;
private readonly ISettingsProvider _settingsProvider;
private readonly IRepoUpdater _repoUpdater;
private readonly IAppPaths _paths;
public ServiceInitializer(
ILogger log,
LoggingLevelSwitch loggingLevelSwitch,
ISettingsPersister settingsPersister,
ISettingsProvider settingsProvider,
IRepoUpdater repoUpdater)
IRepoUpdater repoUpdater,
IAppPaths paths)
{
_log = log;
_loggingLevelSwitch = loggingLevelSwitch;
_settingsPersister = settingsPersister;
_settingsProvider = settingsProvider;
_repoUpdater = repoUpdater;
_paths = paths;
}
public void Initialize(IServiceCommand cmd)
public void Initialize(ServiceCommand cmd)
{
// Must happen first because everything can use the logger.
_loggingLevelSwitch.MinimumLevel = cmd.Debug ? LogEventLevel.Debug : LogEventLevel.Information;
@ -43,6 +47,11 @@ internal class ServiceInitializer : IServiceInitializer
SetupHttp();
_repoUpdater.UpdateRepo();
if (!cmd.Config.Any())
{
cmd.Config = new[] {_paths.ConfigPath};
}
}
private void SetupHttp()

@ -13,7 +13,7 @@ internal class ServicePreInitializer : IServiceInitializer
_migration = migration;
}
public void Initialize(IServiceCommand cmd)
public void Initialize(ServiceCommand cmd)
{
// Migrations are performed before we process command line arguments because we cannot instantiate any service
// objects via the DI container before migration logic is performed. This is due to the fact that migration

@ -10,13 +10,19 @@ namespace Recyclarr.Command;
internal class RadarrCommand : ServiceCommand, IRadarrCommand
{
private readonly Lazy<RadarrService> _service;
public override string CacheStoragePath { get; } =
Path.Combine(AppPaths.AppDataPath, "cache", "radarr");
private readonly string? _cacheStoragePath;
public override string Name => "Radarr";
public RadarrCommand(IServiceInitializationAndCleanup init, Lazy<RadarrService> service)
public sealed override string CacheStoragePath
{
get => _cacheStoragePath ?? _service.Value.DefaultCacheStoragePath;
protected init => _cacheStoragePath = value;
}
public RadarrCommand(
IServiceInitializationAndCleanup init,
Lazy<RadarrService> service)
: base(init)
{
_service = service;

@ -21,10 +21,9 @@ public abstract class ServiceCommand : ICommand, IServiceCommand
[CommandOption("config", 'c', Description =
"One or more YAML config files to use. All configs will be used and settings are additive. " +
"If not specified, the script will look for `recyclarr.yml` in the same directory as the executable.")]
public ICollection<string> Config { get; [UsedImplicitly] set; } =
new List<string> {AppPaths.DefaultConfigPath};
public ICollection<string> Config { get; [UsedImplicitly] set; } = new List<string>();
public abstract string CacheStoragePath { get; }
public abstract string CacheStoragePath { get; protected init; }
public abstract string Name { get; }
protected ServiceCommand(IServiceInitializationAndCleanup init)

@ -1,5 +1,7 @@
using Recyclarr.Config;
using System.IO.Abstractions;
using Recyclarr.Config;
using Serilog;
using TrashLib;
using TrashLib.Extensions;
using TrashLib.Radarr.Config;
using TrashLib.Radarr.CustomFormat;
@ -11,6 +13,8 @@ public class RadarrService : ServiceBase<IRadarrCommand>
{
private readonly IConfigurationLoader<RadarrConfiguration> _configLoader;
private readonly Func<ICustomFormatUpdater> _customFormatUpdaterFactory;
private readonly IFileSystem _fs;
private readonly IAppPaths _paths;
private readonly ILogger _log;
private readonly Func<IRadarrQualityDefinitionUpdater> _qualityUpdaterFactory;
@ -18,14 +22,20 @@ public class RadarrService : ServiceBase<IRadarrCommand>
ILogger log,
IConfigurationLoader<RadarrConfiguration> configLoader,
Func<IRadarrQualityDefinitionUpdater> qualityUpdaterFactory,
Func<ICustomFormatUpdater> customFormatUpdaterFactory)
Func<ICustomFormatUpdater> customFormatUpdaterFactory,
IFileSystem fs,
IAppPaths paths)
{
_log = log;
_configLoader = configLoader;
_qualityUpdaterFactory = qualityUpdaterFactory;
_customFormatUpdaterFactory = customFormatUpdaterFactory;
_fs = fs;
_paths = paths;
}
public string DefaultCacheStoragePath => _fs.Path.Combine(_paths.CacheDirectory, "radarr");
protected override async Task Process(IRadarrCommand cmd)
{
foreach (var config in _configLoader.LoadMany(cmd.Config, "radarr"))

@ -1,6 +1,8 @@
using CliFx.Exceptions;
using System.IO.Abstractions;
using CliFx.Exceptions;
using Recyclarr.Config;
using Serilog;
using TrashLib;
using TrashLib.Extensions;
using TrashLib.Sonarr;
using TrashLib.Sonarr.Config;
@ -16,21 +18,29 @@ public class SonarrService : ServiceBase<ISonarrCommand>
private readonly Func<IReleaseProfileUpdater> _profileUpdaterFactory;
private readonly Func<ISonarrQualityDefinitionUpdater> _qualityUpdaterFactory;
private readonly IReleaseProfileLister _lister;
private readonly IFileSystem _fs;
private readonly IAppPaths _paths;
public SonarrService(
ILogger log,
IConfigurationLoader<SonarrConfiguration> configLoader,
Func<IReleaseProfileUpdater> profileUpdaterFactory,
Func<ISonarrQualityDefinitionUpdater> qualityUpdaterFactory,
IReleaseProfileLister lister)
IReleaseProfileLister lister,
IFileSystem fs,
IAppPaths paths)
{
_log = log;
_configLoader = configLoader;
_profileUpdaterFactory = profileUpdaterFactory;
_qualityUpdaterFactory = qualityUpdaterFactory;
_lister = lister;
_fs = fs;
_paths = paths;
}
public string DefaultCacheStoragePath => _fs.Path.Combine(_paths.CacheDirectory, "sonarr");
protected override async Task Process(ISonarrCommand cmd)
{
if (cmd.ListReleaseProfiles)

@ -1,15 +1,18 @@
using CliFx.Attributes;
using System.IO.Abstractions;
using CliFx.Attributes;
using JetBrains.Annotations;
using Recyclarr.Command.Initialization;
using Recyclarr.Command.Services;
using TrashLib;
namespace Recyclarr.Command;
[Command("sonarr", Description = "Perform operations on a Sonarr instance")]
[UsedImplicitly]
internal class SonarrCommand : ServiceCommand, ISonarrCommand
public class SonarrCommand : ServiceCommand, ISonarrCommand
{
private readonly Lazy<SonarrService> _service;
private readonly string? _cacheStoragePath;
[CommandOption("list-release-profiles", Description =
"List available release profiles from the guide in YAML format.")]
@ -22,12 +25,19 @@ internal class SonarrCommand : ServiceCommand, ISonarrCommand
"Note that not every release profile has terms that may be filtered.")]
public string? ListTerms { get; [UsedImplicitly] set; } = "empty";
public override string CacheStoragePath { get; } =
Path.Combine(AppPaths.AppDataPath, "cache", "sonarr");
public sealed override string CacheStoragePath
{
get => _cacheStoragePath ?? _service.Value.DefaultCacheStoragePath;
protected init => _cacheStoragePath = value;
}
public override string Name => "Sonarr";
public SonarrCommand(IServiceInitializationAndCleanup init, Lazy<SonarrService> service)
public SonarrCommand(
IServiceInitializationAndCleanup init,
Lazy<SonarrService> service,
IFileSystem fs,
IAppPaths paths)
: base(init)
{
_service = service;

@ -14,10 +14,10 @@ using Recyclarr.Logging;
using Recyclarr.Migration;
using Serilog;
using Serilog.Core;
using TrashLib;
using TrashLib.Cache;
using TrashLib.Config;
using TrashLib.Radarr;
using TrashLib.Radarr.Config;
using TrashLib.Repo;
using TrashLib.Sonarr;
using TrashLib.Startup;
@ -43,7 +43,7 @@ public static class CompositionRoot
builder.RegisterModule<ConfigAutofacModule>();
builder.RegisterType<ObjectFactory>().As<IObjectFactory>();
builder.RegisterType<ResourcePaths>().As<IResourcePaths>();
builder.RegisterType<AppPaths>().As<IAppPaths>().SingleInstance();
builder.RegisterGeneric(typeof(ConfigurationLoader<>))
.WithProperty(new AutowiringParameter())
@ -80,7 +80,6 @@ public static class CompositionRoot
builder.RegisterSource<OrderedRegistrationSource>();
builder.RegisterType<FileSystem>().As<IFileSystem>();
builder.RegisterType<FileUtilities>().As<IFileUtilities>();
builder.RegisterType<SystemConsole>().As<IConsole>().SingleInstance();
builder.RegisterModule<CacheAutofacModule>();
@ -91,6 +90,7 @@ public static class CompositionRoot
CommandRegistrations(builder);
SetupLogging(builder);
builder.RegisterModule<CommonAutofacModule>();
builder.RegisterModule<SonarrAutofacModule>();
builder.RegisterModule<RadarrAutofacModule>();
builder.RegisterModule<VersionControlAutofacModule>();

@ -1,19 +1,24 @@
using System.IO.Abstractions;
using TrashLib;
namespace Recyclarr.Logging;
public class LogJanitor : ILogJanitor
{
private readonly IFileSystem _fileSystem;
private readonly IFileSystem _fs;
private readonly IAppPaths _paths;
public LogJanitor(IFileSystem fileSystem)
public LogJanitor(IFileSystem fs, IAppPaths paths)
{
_fileSystem = fileSystem;
_fs = fs;
_paths = paths;
}
public void DeleteOldestLogFiles(int numberOfNewestToKeep)
{
foreach (var file in _fileSystem.DirectoryInfo.FromDirectoryName(AppPaths.LogDirectory).GetFiles()
var dir = _fs.Directory.CreateDirectory(_paths.LogDirectory);
foreach (var file in dir.GetFiles()
.OrderByDescending(f => f.Name)
.Skip(numberOfNewestToKeep))
{

@ -1,23 +1,26 @@
using System.IO.Abstractions;
using Serilog;
using Serilog.Core;
using TrashLib;
namespace Recyclarr.Logging;
public class LoggerFactory
{
private readonly IFileSystem _fs;
private readonly IAppPaths _paths;
private readonly LoggingLevelSwitch _logLevel;
public LoggerFactory(IFileSystem fs, LoggingLevelSwitch logLevel)
public LoggerFactory(IFileSystem fs, IAppPaths paths, LoggingLevelSwitch logLevel)
{
_fs = fs;
_paths = paths;
_logLevel = logLevel;
}
public ILogger Create()
{
var logPath = _fs.Path.Combine(AppPaths.LogDirectory, $"trash_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log");
var logPath = _fs.Path.Combine(_paths.LogDirectory, $"trash_{DateTime.Now:yyyy-MM-dd_HH-mm-ss}.log");
const string consoleTemplate = "[{Level:u3}] {Message:lj}{NewLine}{Exception}";

@ -18,14 +18,12 @@ internal static class Program
{
_container = CompositionRoot.Setup();
var console = _container.Resolve<IConsole>();
var status = await new CliApplicationBuilder()
.AddCommands(GetRegisteredCommandTypes())
.SetExecutableName(ExecutableName)
.SetVersion(BuildVersion())
.UseTypeActivator(type => CliTypeActivator.ResolveType(_container, type))
.UseConsole(console)
.UseConsole(_container.Resolve<IConsole>())
.Build()
.RunAsync();

@ -1,9 +0,0 @@
using TrashLib.Radarr.Config;
namespace Recyclarr;
public class ResourcePaths : IResourcePaths
{
public string RepoPath => AppPaths.RepoDirectory;
public string SettingsPath => AppPaths.DefaultSettingsPath;
}

@ -6,7 +6,6 @@ using NUnit.Framework;
using TestLibrary.AutoFixture;
using TrashLib.Config;
using TrashLib.Config.Settings;
using TrashLib.Radarr.Config;
using YamlDotNet.Serialization;
namespace TrashLib.Tests.Config.Settings;
@ -18,7 +17,7 @@ public class SettingsPersisterTest
[Test, AutoMockData]
public void Load_should_create_settings_file_if_not_exists(
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fileSystem,
[Frozen] IResourcePaths paths,
[Frozen] IAppPaths paths,
SettingsPersister sut)
{
paths.SettingsPath.Returns("test_path");
@ -33,7 +32,7 @@ public class SettingsPersisterTest
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fileSystem,
[Frozen(Matching.ImplementedInterfaces)] YamlSerializerFactory serializerFactory,
[Frozen(Matching.ImplementedInterfaces)] SettingsProvider settingsProvider,
[Frozen] IResourcePaths paths,
[Frozen] IAppPaths paths,
SettingsPersister sut)
{
paths.SettingsPath.Returns("test_path");
@ -48,7 +47,7 @@ public class SettingsPersisterTest
public void Load_data_correctly_when_file_exists(
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fileSystem,
[Frozen] IYamlSerializerFactory serializerFactory,
[Frozen] IResourcePaths paths,
[Frozen] IAppPaths paths,
SettingsPersister sut)
{
// For this test, it doesn't really matter if the YAML data matches what SettingsValue expects;

@ -4,7 +4,6 @@ using FluentAssertions;
using NSubstitute;
using NUnit.Framework;
using TestLibrary.AutoFixture;
using TrashLib.Radarr.Config;
using TrashLib.Radarr.CustomFormat.Guide;
namespace TrashLib.Tests.Radarr.CustomFormat.Guide;
@ -15,11 +14,11 @@ public class LocalRepoCustomFormatJsonParserTest
{
[Test, AutoMockData]
public void Get_custom_format_json_works(
[Frozen] IResourcePaths paths,
[Frozen] IAppPaths paths,
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fileSystem,
LocalRepoCustomFormatJsonParser sut)
{
paths.RepoPath.Returns("");
paths.RepoDirectory.Returns("");
fileSystem.AddFile("docs/json/radarr/first.json", new MockFileData("first"));
fileSystem.AddFile("docs/json/radarr/second.json", new MockFileData("second"));

@ -5,7 +5,6 @@ using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
using TestLibrary.AutoFixture;
using TrashLib.Radarr.Config;
using TrashLib.Sonarr.ReleaseProfile;
using TrashLib.Sonarr.ReleaseProfile.Guide;
@ -17,7 +16,7 @@ public class LocalRepoReleaseProfileJsonParserTest
{
[Test, AutoMockData]
public void Get_custom_format_json_works(
[Frozen] IResourcePaths paths,
[Frozen] IAppPaths paths,
[Frozen(Matching.ImplementedInterfaces)] MockFileSystem fileSystem,
LocalRepoReleaseProfileJsonParser sut)
{
@ -37,7 +36,7 @@ public class LocalRepoReleaseProfileJsonParserTest
var mockData1 = MakeMockObject("first");
var mockData2 = MakeMockObject("second");
paths.RepoPath.Returns("");
paths.RepoDirectory.Returns("");
fileSystem.AddFile("docs/json/sonarr/first.json", MockFileData(mockData1));
fileSystem.AddFile("docs/json/sonarr/second.json", MockFileData(mockData2));

@ -1,17 +1,16 @@
using System.IO.Abstractions;
using TrashLib.Radarr.Config;
namespace TrashLib.Config.Settings;
public class SettingsPersister : ISettingsPersister
{
private readonly IResourcePaths _paths;
private readonly IAppPaths _paths;
private readonly ISettingsProvider _settingsProvider;
private readonly IYamlSerializerFactory _serializerFactory;
private readonly IFileSystem _fileSystem;
public SettingsPersister(
IResourcePaths paths,
IAppPaths paths,
ISettingsProvider settingsProvider,
IYamlSerializerFactory serializerFactory,
IFileSystem fileSystem)

@ -0,0 +1,12 @@
namespace TrashLib;
public interface IAppPaths
{
void SetAppDataPath(string path);
string AppDataPath { get; }
string ConfigPath { get; }
string SettingsPath { get; }
string LogDirectory { get; }
string RepoDirectory { get; }
string CacheDirectory { get; }
}

@ -1,7 +0,0 @@
namespace TrashLib.Radarr.Config;
public interface IResourcePaths
{
string RepoPath { get; }
string SettingsPath { get; }
}

@ -1,14 +1,13 @@
using System.IO.Abstractions;
using TrashLib.Radarr.Config;
namespace TrashLib.Radarr.CustomFormat.Guide;
public class LocalRepoCustomFormatJsonParser : IRadarrGuideService
{
private readonly IFileSystem _fileSystem;
private readonly IResourcePaths _paths;
private readonly IAppPaths _paths;
public LocalRepoCustomFormatJsonParser(IFileSystem fileSystem, IResourcePaths paths)
public LocalRepoCustomFormatJsonParser(IFileSystem fileSystem, IAppPaths paths)
{
_fileSystem = fileSystem;
_paths = paths;
@ -16,7 +15,7 @@ public class LocalRepoCustomFormatJsonParser : IRadarrGuideService
public IEnumerable<string> GetCustomFormatJson()
{
var jsonDir = Path.Combine(_paths.RepoPath, "docs/json/radarr");
var jsonDir = Path.Combine(_paths.RepoDirectory, "docs/json/radarr");
var tasks = _fileSystem.Directory.GetFiles(jsonDir, "*.json")
.Select(f => _fileSystem.File.ReadAllTextAsync(f));

@ -2,7 +2,6 @@ using Common;
using LibGit2Sharp;
using Serilog;
using TrashLib.Config.Settings;
using TrashLib.Radarr.Config;
using VersionControl;
namespace TrashLib.Repo;
@ -16,7 +15,7 @@ public class RepoUpdater : IRepoUpdater
public RepoUpdater(
ILogger log,
IResourcePaths paths,
IAppPaths paths,
IGitRepositoryFactory repositoryFactory,
IFileUtilities fileUtils,
ISettingsProvider settingsProvider)
@ -25,7 +24,7 @@ public class RepoUpdater : IRepoUpdater
_repositoryFactory = repositoryFactory;
_fileUtils = fileUtils;
_settingsProvider = settingsProvider;
RepoPath = paths.RepoPath;
RepoPath = paths.RepoDirectory;
}
public string RepoPath { get; }

@ -3,17 +3,16 @@ using Common.Extensions;
using Common.FluentValidation;
using MoreLinq;
using Newtonsoft.Json;
using TrashLib.Radarr.Config;
namespace TrashLib.Sonarr.ReleaseProfile.Guide;
public class LocalRepoReleaseProfileJsonParser : ISonarrGuideService
{
private readonly IFileSystem _fileSystem;
private readonly IResourcePaths _paths;
private readonly IAppPaths _paths;
private readonly Lazy<IEnumerable<ReleaseProfileData>> _data;
public LocalRepoReleaseProfileJsonParser(IFileSystem fileSystem, IResourcePaths paths)
public LocalRepoReleaseProfileJsonParser(IFileSystem fileSystem, IAppPaths paths)
{
_fileSystem = fileSystem;
_paths = paths;
@ -23,7 +22,7 @@ public class LocalRepoReleaseProfileJsonParser : ISonarrGuideService
private IEnumerable<ReleaseProfileData> GetReleaseProfileDataImpl()
{
var converter = new TermDataConverter();
var jsonDir = Path.Combine(_paths.RepoPath, "docs/json/sonarr");
var jsonDir = _fileSystem.Path.Combine(_paths.RepoDirectory, "docs/json/sonarr");
var tasks = _fileSystem.Directory.GetFiles(jsonDir, "*.json")
.Select(async f =>
{

Loading…
Cancel
Save