diff --git a/CHANGELOG.md b/CHANGELOG.md index d7605c9b..c3887ba7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- `create-config` would fail with `--path` specified. + ## [2.1.1] - 2022-05-29 ### Fixed diff --git a/src/Recyclarr.Tests/Command/CreateConfigCommandTest.cs b/src/Recyclarr.Tests/Command/CreateConfigCommandTest.cs index 2c534d3c..25042911 100644 --- a/src/Recyclarr.Tests/Command/CreateConfigCommandTest.cs +++ b/src/Recyclarr.Tests/Command/CreateConfigCommandTest.cs @@ -30,19 +30,4 @@ public class CreateConfigCommandTest file.Should().NotBeNull(); file.Contents.Should().NotBeEmpty(); } - - [Test, AutoMockData] - public async Task CreateConfig_SpecifyPath_FileIsCreated( - [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, - CreateConfigCommand cmd) - { - const string ymlPath = "some/other/path.yml"; - cmd.Path = ymlPath; - - await cmd.ExecuteAsync(Substitute.For()).ConfigureAwait(false); - - var file = fs.GetFile(ymlPath); - file.Should().NotBeNull(); - file.Contents.Should().NotBeEmpty(); - } } diff --git a/src/Recyclarr.Tests/Command/Initialization/DefaultAppDataSetupTest.cs b/src/Recyclarr.Tests/Command/Initialization/DefaultAppDataSetupTest.cs new file mode 100644 index 00000000..8e58ea15 --- /dev/null +++ b/src/Recyclarr.Tests/Command/Initialization/DefaultAppDataSetupTest.cs @@ -0,0 +1,66 @@ +using System.IO.Abstractions.TestingHelpers; +using AutoFixture.NUnit3; +using Common; +using FluentAssertions; +using NSubstitute; +using NUnit.Framework; +using Recyclarr.Command.Initialization; +using TestLibrary; +using TestLibrary.AutoFixture; +using TrashLib; + +namespace Recyclarr.Tests.Command.Initialization; + +[TestFixture] +[Parallelizable(ParallelScope.All)] +public class DefaultAppDataSetupTest +{ + [Test, AutoMockData] + public void Initialize_using_default_path( + [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, + [Frozen] IEnvironment env, + [Frozen] IAppPaths paths, + DefaultAppDataSetup sut) + { + paths.DefaultAppDataDirectoryName.Returns("app_data"); + env.GetFolderPath(Arg.Any(), Arg.Any()) + .Returns(FileUtils.NormalizePath("base/path")); + + sut.SetupDefaultPath(null, false); + + paths.Received().SetAppDataPath(FileUtils.NormalizePath("base/path/app_data")); + } + + [Test, AutoMockData] + public void Initialize_using_path_override( + [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, + [Frozen] IAppPaths paths, + DefaultAppDataSetup sut) + { + var overridePath = FileUtils.NormalizePath("/override/path"); + sut.SetupDefaultPath(overridePath, false); + + paths.Received().SetAppDataPath(overridePath); + fs.AllDirectories.Should().Contain(overridePath); + } + + [Test, AutoMockData] + public void Force_creation_uses_correct_behavior_when_disabled( + [Frozen] IEnvironment env, + DefaultAppDataSetup sut) + { + sut.SetupDefaultPath(null, false); + + env.Received().GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.None); + } + + [Test, AutoMockData] + public void Force_creation_uses_correct_behavior_when_enabled( + [Frozen] IEnvironment env, + DefaultAppDataSetup sut) + { + sut.SetupDefaultPath(null, true); + + env.Received().GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create); + } +} diff --git a/src/Recyclarr.Tests/Command/Initialization/Init/InitializeAppDataPathTest.cs b/src/Recyclarr.Tests/Command/Initialization/Init/InitializeAppDataPathTest.cs index 9c0dcfe9..a38bd2e0 100644 --- a/src/Recyclarr.Tests/Command/Initialization/Init/InitializeAppDataPathTest.cs +++ b/src/Recyclarr.Tests/Command/Initialization/Init/InitializeAppDataPathTest.cs @@ -2,10 +2,8 @@ using System.IO.Abstractions.TestingHelpers; using AutoFixture.NUnit3; using Common; using FluentAssertions; -using NSubstitute; using NUnit.Framework; using Recyclarr.Command; -using Recyclarr.Command.Initialization; using Recyclarr.Command.Initialization.Init; using TestLibrary.AutoFixture; using TrashLib; @@ -16,36 +14,6 @@ namespace Recyclarr.Tests.Command.Initialization.Init; [Parallelizable(ParallelScope.All)] public class InitializeAppDataPathTest { - [Test, AutoMockData] - public void Use_default_app_data_if_not_specified( - [Frozen] IEnvironment env, - [Frozen] IAppPaths paths, - [Frozen(Matching.ImplementedInterfaces)] MockFileSystem fs, - [Frozen(Matching.ImplementedInterfaces)] DefaultAppDataSetup appDataSetup, - SonarrCommand cmd, - InitializeAppDataPath sut) - { - paths.DefaultAppDataDirectoryName.Returns("recyclarr"); - env.GetFolderPath(Arg.Any(), Arg.Any()) - .Returns("app_data"); - - sut.Initialize(cmd); - - env.Received().GetFolderPath(Environment.SpecialFolder.ApplicationData, Environment.SpecialFolderOption.Create); - paths.Received().SetAppDataPath(fs.Path.Combine("app_data", "recyclarr")); - } - - [Test, AutoMockData] - public void Use_specified_app_data_if_user_provided( - [Frozen] IAppPaths paths, - SonarrCommand cmd, - InitializeAppDataPath sut) - { - cmd.AppDataDirectory = "path"; - sut.Initialize(cmd); - paths.Received().SetAppDataPath("path"); - } - [Test, AutoMockData] public void All_directories_are_created( [Frozen] IEnvironment env, diff --git a/src/Recyclarr.Tests/Migration/Steps/MigrateTrashUpdaterAppDataDirTest.cs b/src/Recyclarr.Tests/Migration/Steps/MigrateTrashUpdaterAppDataDirTest.cs index c36fd883..fcf182ee 100644 --- a/src/Recyclarr.Tests/Migration/Steps/MigrateTrashUpdaterAppDataDirTest.cs +++ b/src/Recyclarr.Tests/Migration/Steps/MigrateTrashUpdaterAppDataDirTest.cs @@ -1,5 +1,4 @@ using System.IO.Abstractions.TestingHelpers; -using System.Text.RegularExpressions; using AutoFixture.NUnit3; using FluentAssertions; using NUnit.Framework; diff --git a/src/Recyclarr/Command/CreateConfigCommand.cs b/src/Recyclarr/Command/CreateConfigCommand.cs index aed2ab07..59d51395 100644 --- a/src/Recyclarr/Command/CreateConfigCommand.cs +++ b/src/Recyclarr/Command/CreateConfigCommand.cs @@ -36,11 +36,11 @@ public class CreateConfigCommand : ICommand public ValueTask ExecuteAsync(IConsole console) { - _appDataSetup.SetupDefaultPath(); + _appDataSetup.SetupDefaultPath(Path, true); var reader = new ResourceDataReader(typeof(Program)); var ymlData = reader.ReadData("config-template.yml"); - var path = Path ?? _paths.ConfigPath; + var path = _paths.ConfigPath; if (_fs.File.Exists(path)) { diff --git a/src/Recyclarr/Command/Initialization/DefaultAppDataSetup.cs b/src/Recyclarr/Command/Initialization/DefaultAppDataSetup.cs index a582baf2..4aed0e08 100644 --- a/src/Recyclarr/Command/Initialization/DefaultAppDataSetup.cs +++ b/src/Recyclarr/Command/Initialization/DefaultAppDataSetup.cs @@ -1,4 +1,5 @@ using System.IO.Abstractions; +using CliFx.Exceptions; using Common; using TrashLib; @@ -17,16 +18,39 @@ public class DefaultAppDataSetup : IDefaultAppDataSetup _fs = fs; } - public void SetupDefaultPath(bool forceCreate = false) + public void SetupDefaultPath(string? appDataDirectoryOverride, bool forceCreate) { - var appData = _env.GetFolderPath(Environment.SpecialFolder.ApplicationData, - forceCreate ? Environment.SpecialFolderOption.Create : Environment.SpecialFolderOption.None); + // If the user did not explicitly specify an app data directory, perform some system introspection to verify if + // the user has a home directory. + if (string.IsNullOrEmpty(appDataDirectoryOverride)) + { + // If we can't even get the $HOME directory value, throw an exception. User must explicitly specify it with + // --app-data. + var home = _env.GetFolderPath(Environment.SpecialFolder.UserProfile); + if (string.IsNullOrEmpty(home)) + { + throw new CommandException( + "The system does not have a HOME directory, so the application cannot determine where to place " + + "data files. Please use the --app-data option to explicitly set a location for these files."); + } + + // Set app data path to application directory value (e.g. `$HOME/.config` on Linux) and ensure it is + // created. + var appData = _env.GetFolderPath(Environment.SpecialFolder.ApplicationData, + forceCreate ? Environment.SpecialFolderOption.Create : Environment.SpecialFolderOption.None); + + if (string.IsNullOrEmpty(appData)) + { + throw new DirectoryNotFoundException("Unable to find the default app data directory"); + } - if (string.IsNullOrEmpty(appData)) + _paths.SetAppDataPath(_fs.Path.Combine(appData, _paths.DefaultAppDataDirectoryName)); + } + else { - throw new DirectoryNotFoundException("Unable to find the default app data directory"); + // Ensure user-specified app data directory is created and use it. + _fs.Directory.CreateDirectory(appDataDirectoryOverride); + _paths.SetAppDataPath(appDataDirectoryOverride); } - - _paths.SetAppDataPath(_fs.Path.Combine(appData, _paths.DefaultAppDataDirectoryName)); } } diff --git a/src/Recyclarr/Command/Initialization/IDefaultAppDataSetup.cs b/src/Recyclarr/Command/Initialization/IDefaultAppDataSetup.cs index f545e904..f6714ce0 100644 --- a/src/Recyclarr/Command/Initialization/IDefaultAppDataSetup.cs +++ b/src/Recyclarr/Command/Initialization/IDefaultAppDataSetup.cs @@ -2,5 +2,5 @@ namespace Recyclarr.Command.Initialization; public interface IDefaultAppDataSetup { - void SetupDefaultPath(bool forceCreate = false); + void SetupDefaultPath(string? appDataDirectoryOverride, bool forceCreate); } diff --git a/src/Recyclarr/Command/Initialization/Init/InitializeAppDataPath.cs b/src/Recyclarr/Command/Initialization/Init/InitializeAppDataPath.cs index 5a965942..b435f978 100644 --- a/src/Recyclarr/Command/Initialization/Init/InitializeAppDataPath.cs +++ b/src/Recyclarr/Command/Initialization/Init/InitializeAppDataPath.cs @@ -1,6 +1,4 @@ using System.IO.Abstractions; -using CliFx.Exceptions; -using Common; using TrashLib; namespace Recyclarr.Command.Initialization.Init; @@ -9,47 +7,18 @@ public class InitializeAppDataPath : IServiceInitializer { private readonly IFileSystem _fs; private readonly IAppPaths _paths; - private readonly IEnvironment _env; private readonly IDefaultAppDataSetup _appDataSetup; - public InitializeAppDataPath( - IFileSystem fs, - IAppPaths paths, - IEnvironment env, - IDefaultAppDataSetup appDataSetup) + public InitializeAppDataPath(IFileSystem fs, IAppPaths paths, IDefaultAppDataSetup appDataSetup) { _fs = fs; _paths = paths; - _env = env; _appDataSetup = appDataSetup; } public void Initialize(ServiceCommand cmd) { - // If the user did not explicitly specify an app data directory, perform some system introspection to verify if - // the user has a home directory. - if (string.IsNullOrEmpty(cmd.AppDataDirectory)) - { - // If we can't even get the $HOME directory value, throw an exception. User must explicitly specify it with - // --app-data. - var home = _env.GetFolderPath(Environment.SpecialFolder.UserProfile); - if (string.IsNullOrEmpty(home)) - { - throw new CommandException( - "The system does not have a HOME directory, so the application cannot determine where to place " + - "data files. Please use the --app-data option to explicitly set a location for these files."); - } - - // Set app data path to application directory value (e.g. `$HOME/.config` on Linux) and ensure it is - // created. - _appDataSetup.SetupDefaultPath(true); - } - else - { - // Ensure user-specified app data directory is created and use it. - _fs.Directory.CreateDirectory(cmd.AppDataDirectory); - _paths.SetAppDataPath(cmd.AppDataDirectory); - } + _appDataSetup.SetupDefaultPath(cmd.AppDataDirectory, true); // Initialize other directories used throughout the application _fs.Directory.CreateDirectory(_paths.RepoDirectory); diff --git a/src/Recyclarr/Command/MigrateCommand.cs b/src/Recyclarr/Command/MigrateCommand.cs index adac6a19..251e17be 100644 --- a/src/Recyclarr/Command/MigrateCommand.cs +++ b/src/Recyclarr/Command/MigrateCommand.cs @@ -28,7 +28,7 @@ public class MigrateCommand : ICommand public ValueTask ExecuteAsync(IConsole console) { - _appDataSetup.SetupDefaultPath(); + _appDataSetup.SetupDefaultPath(null, false); PerformMigrations(); return ValueTask.CompletedTask; }