diff --git a/src/Common.Tests/Extensions/FileSystemExtensionsTest.cs b/src/Common.Tests/Extensions/FileSystemExtensionsTest.cs index 54a1d4aa..416fd387 100644 --- a/src/Common.Tests/Extensions/FileSystemExtensionsTest.cs +++ b/src/Common.Tests/Extensions/FileSystemExtensionsTest.cs @@ -58,8 +58,8 @@ public class FileSystemExtensionsTest var fs = NewMockFileSystem(files, dirs, @"C:\root\path"); fs.MergeDirectory( - fs.DirectoryInfo.FromDirectoryName("path1"), - fs.DirectoryInfo.FromDirectoryName("path2")); + fs.DirectoryInfo.New("path1"), + fs.DirectoryInfo.New("path2")); fs.AllDirectories.Select(MockUnixSupport.Path).Should() .NotContain(x => x.Contains("path1") || x.Contains("empty")); @@ -80,8 +80,8 @@ public class FileSystemExtensionsTest var fs = NewMockFileSystem(files, @"C:\root\path"); var act = () => fs.MergeDirectory( - fs.DirectoryInfo.FromDirectoryName("path1"), - fs.DirectoryInfo.FromDirectoryName("path2")); + fs.DirectoryInfo.New("path1"), + fs.DirectoryInfo.New("path2")); act.Should().Throw(); } @@ -102,8 +102,8 @@ public class FileSystemExtensionsTest var fs = NewMockFileSystem(files, dirs, @"C:\root\path"); var act = () => fs.MergeDirectory( - fs.DirectoryInfo.FromDirectoryName("path1"), - fs.DirectoryInfo.FromDirectoryName("path2")); + fs.DirectoryInfo.New("path1"), + fs.DirectoryInfo.New("path2")); act.Should().Throw(); } diff --git a/src/Common.Tests/JsonUtilsTest.cs b/src/Common.Tests/JsonUtilsTest.cs index 1c03d357..b12d24ff 100644 --- a/src/Common.Tests/JsonUtilsTest.cs +++ b/src/Common.Tests/JsonUtilsTest.cs @@ -2,6 +2,7 @@ using System.IO.Abstractions; using System.IO.Abstractions.Extensions; using System.IO.Abstractions.TestingHelpers; using FluentAssertions; +using NSubstitute; using NUnit.Framework; using Serilog; using Serilog.Events; @@ -91,4 +92,14 @@ public class JsonUtilsTest .Which.RenderMessage() .Should().Match("*does_not_exist*"); } + + [Test] + public void Null_paths_are_ignored() + { + var result = JsonUtils.GetJsonFilesInDirectories( + new IDirectoryInfo?[] {null, null}, + Substitute.For()); + + result.Should().BeEmpty(); + } } diff --git a/src/Common/Extensions/FileSystemExtensions.cs b/src/Common/Extensions/FileSystemExtensions.cs index 936b19f7..c8fb77a0 100644 --- a/src/Common/Extensions/FileSystemExtensions.cs +++ b/src/Common/Extensions/FileSystemExtensions.cs @@ -6,6 +6,21 @@ namespace Common.Extensions; public static class FileSystemExtensions { + public static void CreateParentDirectory(this IFileInfo f) + { + var parent = f.Directory; + parent?.Create(); + } + + public static void CreateParentDirectory(this IFileSystem fs, string? path) + { + var dirName = fs.Path.GetDirectoryName(path); + if (dirName is not null) + { + fs.Directory.CreateDirectory(dirName); + } + } + public static void MergeDirectory(this IFileSystem fs, IDirectoryInfo targetDir, IDirectoryInfo destDir, IConsole? console = null) { @@ -22,7 +37,7 @@ public static class FileSystemExtensions if ((dir.Attributes & FileAttributes.ReparsePoint) != 0) { var newPath = RelocatePath(dir.FullName, targetDir.FullName, destDir.FullName); - fs.Directory.CreateDirectory(fs.Path.GetDirectoryName(newPath)); + fs.CreateParentDirectory(newPath); console?.Output.WriteLine($" - Symlink: {dir.FullName} :: TO :: {newPath}"); dir.MoveTo(newPath); continue; @@ -32,7 +47,7 @@ public static class FileSystemExtensions foreach (var file in dir.EnumerateFiles()) { var newPath = RelocatePath(file.FullName, targetDir.FullName, destDir.FullName); - fs.Directory.CreateDirectory(fs.Path.GetDirectoryName(newPath)); + fs.CreateParentDirectory(newPath); console?.Output.WriteLine($" - Moving: {file.FullName} :: TO :: {newPath}"); file.MoveTo(newPath); } diff --git a/src/Common/FileUtilities.cs b/src/Common/FileUtilities.cs index 3dfd622d..b5cd468e 100644 --- a/src/Common/FileUtilities.cs +++ b/src/Common/FileUtilities.cs @@ -25,7 +25,7 @@ public class FileUtilities : IFileUtilities foreach (var fileName in Directory.EnumerateFiles(directory)) { - var fileInfo = _fileSystem.FileInfo.FromFileName(fileName); + var fileInfo = _fileSystem.FileInfo.New(fileName); fileInfo.Attributes = FileAttributes.Normal; fileInfo.Delete(); } diff --git a/src/Common/JsonUtils.cs b/src/Common/JsonUtils.cs index b8f58927..dda46062 100644 --- a/src/Common/JsonUtils.cs +++ b/src/Common/JsonUtils.cs @@ -1,13 +1,14 @@ using System.IO.Abstractions; +using Common.Extensions; using Serilog; namespace Common; public static class JsonUtils { - public static IEnumerable GetJsonFilesInDirectories(IEnumerable dirs, ILogger log) + public static IEnumerable GetJsonFilesInDirectories(IEnumerable dirs, ILogger log) { - var dirsThatExist = dirs.ToLookup(x => x.Exists); + var dirsThatExist = dirs.NotNull().ToLookup(x => x.Exists); foreach (var dir in dirsThatExist[false]) { diff --git a/src/Recyclarr/Command/CreateConfigCommand.cs b/src/Recyclarr/Command/CreateConfigCommand.cs index 39a7f483..d3daeb6b 100644 --- a/src/Recyclarr/Command/CreateConfigCommand.cs +++ b/src/Recyclarr/Command/CreateConfigCommand.cs @@ -3,6 +3,7 @@ using Autofac; using CliFx.Attributes; using CliFx.Exceptions; using Common; +using Common.Extensions; using JetBrains.Annotations; using Serilog; using TrashLib.Startup; @@ -28,7 +29,7 @@ public class CreateConfigCommand : BaseCommand var reader = new ResourceDataReader(typeof(Program)); var ymlData = reader.ReadData("config-template.yml"); var configFile = AppDataDirectory is not null - ? fs.FileInfo.FromFileName(AppDataDirectory) + ? fs.FileInfo.New(AppDataDirectory) : paths.ConfigPath; if (configFile.Exists) @@ -37,7 +38,7 @@ public class CreateConfigCommand : BaseCommand "delete/move the existing file and run this command again."); } - fs.Directory.CreateDirectory(configFile.DirectoryName); + configFile.CreateParentDirectory(); await using var stream = configFile.CreateText(); await stream.WriteAsync(ymlData); log.Information("Created configuration at: {Path}", configFile); diff --git a/src/TrashLib.Tests/Cache/ServiceCacheTest.cs b/src/TrashLib.Tests/Cache/ServiceCacheTest.cs index a9adbbb4..537d0abe 100644 --- a/src/TrashLib.Tests/Cache/ServiceCacheTest.cs +++ b/src/TrashLib.Tests/Cache/ServiceCacheTest.cs @@ -51,7 +51,7 @@ public class ServiceCacheTest const string testJsonPath = "cacheFile.json"; fs.AddFile(testJsonPath, new MockFileData(testJson)); - storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.FromFileName(testJsonPath)); + storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.New(testJsonPath)); var obj = sut.Load(); @@ -85,7 +85,7 @@ public class ServiceCacheTest [Frozen] ICacheStoragePath storage, ServiceCache sut) { - storage.CalculatePath(default!).ReturnsForAnyArgs(_ => fs.FileInfo.FromFileName($"{ValidObjectName}.json")); + storage.CalculatePath(default!).ReturnsForAnyArgs(_ => fs.FileInfo.New($"{ValidObjectName}.json")); sut.Save(new ObjectWithAttribute {TestValue = "Foo"}); @@ -103,7 +103,7 @@ public class ServiceCacheTest ServiceCache sut) { const string testJsonPath = "cacheFile.json"; - storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.FromFileName(testJsonPath)); + storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.New(testJsonPath)); sut.Save(new ObjectWithAttribute {TestValue = "Foo"}); @@ -140,10 +140,10 @@ public class ServiceCacheTest [Frozen] ICacheStoragePath storage, ServiceCache sut) { - storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.FromFileName("Foo.json")); + storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.New("Foo.json")); sut.Save(new ObjectWithAttribute {TestValue = "Foo"}); - storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.FromFileName("Bar.json")); + storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.New("Bar.json")); sut.Save(new ObjectWithAttribute {TestValue = "Bar"}); var expectedFiles = new[] {"*Foo.json", "*Bar.json"}; @@ -159,7 +159,7 @@ public class ServiceCacheTest [Frozen] ICacheStoragePath storage, ServiceCache sut) { - storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.FromFileName("cacheFile.json")); + storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.New("cacheFile.json")); fs.AddFile("cacheFile.json", new MockFileData("")); Action act = () => sut.Load(); @@ -187,7 +187,7 @@ public class ServiceCacheTest "; fs.AddFile("cacheFile.json", new MockFileData(cacheJson)); - storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.FromFileName("cacheFile.json")); + storage.CalculatePath(default!).ReturnsForAnyArgs(fs.FileInfo.New("cacheFile.json")); var result = sut.Load(); diff --git a/src/TrashLib/Cache/ServiceCache.cs b/src/TrashLib/Cache/ServiceCache.cs index 7313fb62..4f383e5a 100644 --- a/src/TrashLib/Cache/ServiceCache.cs +++ b/src/TrashLib/Cache/ServiceCache.cs @@ -1,6 +1,7 @@ using System.IO.Abstractions; using System.Reflection; using System.Text.RegularExpressions; +using Common.Extensions; using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Serilog; @@ -55,7 +56,7 @@ public class ServiceCache : IServiceCache public void Save(T obj) where T : class { var path = PathFromAttribute(); - path.Directory.Create(); + path.CreateParentDirectory(); var serializer = JsonSerializer.Create(_jsonSettings); diff --git a/src/TrashLib/Config/Settings/SettingsProvider.cs b/src/TrashLib/Config/Settings/SettingsProvider.cs index 1cc4b898..488b3a69 100644 --- a/src/TrashLib/Config/Settings/SettingsProvider.cs +++ b/src/TrashLib/Config/Settings/SettingsProvider.cs @@ -1,3 +1,4 @@ +using Common.Extensions; using TrashLib.Startup; namespace TrashLib.Config.Settings; @@ -36,7 +37,7 @@ public class SettingsProvider : ISettingsProvider "# For the settings file reference guide, visit the link to the wiki below:\n" + "# https://github.com/recyclarr/recyclarr/wiki/Settings-Reference\n"; - _paths.SettingsPath.Directory.Create(); + _paths.SettingsPath.CreateParentDirectory(); using var stream = _paths.SettingsPath.CreateText(); stream.Write(fileData); } diff --git a/src/TrashLib/Startup/DefaultAppDataSetup.cs b/src/TrashLib/Startup/DefaultAppDataSetup.cs index 65268cee..a31c5636 100644 --- a/src/TrashLib/Startup/DefaultAppDataSetup.cs +++ b/src/TrashLib/Startup/DefaultAppDataSetup.cs @@ -18,7 +18,7 @@ public class DefaultAppDataSetup public IAppPaths CreateAppPaths(string? appDataDirectoryOverride = null, bool forceCreate = true) { var appDir = GetAppDataDirectory(appDataDirectoryOverride, forceCreate); - return new AppPaths(_fs.DirectoryInfo.FromDirectoryName(appDir)); + return new AppPaths(_fs.DirectoryInfo.New(appDir)); } private string GetAppDataDirectory(string? appDataDirectoryOverride, bool forceCreate)