feat: Introduce new includes dir for include templates

The prior method of supporting local include templates (files in
subdirectories under the `configs` directory) is deprecated.
pull/241/head
Robert Dailey 9 months ago
parent 5bed784ed0
commit 8bca7111c4

@ -13,6 +13,13 @@ changes you may need to make.
[breaking7]: https://recyclarr.dev/wiki/upgrade-guide/v7.0/ [breaking7]: https://recyclarr.dev/wiki/upgrade-guide/v7.0/
### Added
- YAML: New `includes` subdirectory intended to hold only include templates. Relative paths
specified in the `config` include directive are resolved starting at this new directory. Relative
paths to include templates located under the `configs` directory is now **DEPRECATED**. See the
"File Structure" page on the wiki for more details.
### Changed ### Changed
- **BREAKING**: The app data directory on OSX has changed. It now lives at `~/Library/Application - **BREAKING**: The app data directory on OSX has changed. It now lives at `~/Library/Application

@ -13,6 +13,7 @@ public class AppPathSetupTask(ILogger log, IAppPaths paths) : IBaseCommandSetupT
paths.CacheDirectory.Create(); paths.CacheDirectory.Create();
paths.LogDirectory.Create(); paths.LogDirectory.Create();
paths.ConfigsDirectory.Create(); paths.ConfigsDirectory.Create();
paths.IncludesDirectory.Create();
} }
public void OnFinish() public void OnFinish()

@ -4,13 +4,43 @@ using Recyclarr.TrashGuide;
namespace Recyclarr.Config.Parsing.PostProcessing.ConfigMerging; namespace Recyclarr.Config.Parsing.PostProcessing.ConfigMerging;
public class ConfigIncludeProcessor(IFileSystem fs, IAppPaths paths) : IIncludeProcessor public class ConfigIncludeProcessor(IFileSystem fs, IAppPaths paths, ILogger log) : IIncludeProcessor
{ {
public bool CanProcess(IYamlInclude includeDirective) public bool CanProcess(IYamlInclude includeDirective)
{ {
return includeDirective is ConfigYamlInclude; return includeDirective is ConfigYamlInclude;
} }
private IFileInfo? ConvertToAbsolute(string path)
{
if (fs.Path.IsPathRooted(path))
{
log.Debug("Path processed as absolute: {Path}", path);
return fs.FileInfo.New(path);
}
var fsPath = paths.IncludesDirectory.File(path);
if (fsPath.Exists)
{
log.Debug("Path rooted to the includes directory: {Path}", path);
return fsPath;
}
fsPath = paths.ConfigsDirectory.File(path);
// ReSharper disable once InvertIf
if (fsPath.Exists)
{
log.Warning(
"DEPRECATED: Include templates inside the `configs` directory are no longer supported. " +
"These files should be relocated to the new sibling `includes` directory instead. " +
"See: https://recyclarr.dev/wiki/upgrade-guide/v8.0/#include-dir");
return fsPath;
}
return null;
}
public IFileInfo GetPathToConfig(IYamlInclude includeDirective, SupportedServices serviceType) public IFileInfo GetPathToConfig(IYamlInclude includeDirective, SupportedServices serviceType)
{ {
var include = (ConfigYamlInclude) includeDirective; var include = (ConfigYamlInclude) includeDirective;
@ -20,16 +50,10 @@ public class ConfigIncludeProcessor(IFileSystem fs, IAppPaths paths) : IIncludeP
throw new YamlIncludeException("`config` property is required."); throw new YamlIncludeException("`config` property is required.");
} }
var rooted = fs.Path.IsPathRooted(include.Config); var configFile = ConvertToAbsolute(include.Config);
if (configFile?.Exists != true)
var configFile = rooted
? fs.FileInfo.New(include.Config)
: paths.ConfigsDirectory.File(include.Config);
if (!configFile.Exists)
{ {
var pathType = rooted ? "Absolute" : "Relative"; throw new YamlIncludeException($"Include path could not be resolved: {include.Config}");
throw new YamlIncludeException($"{pathType} include path does not exist: {configFile.FullName}");
} }
return configFile; return configFile;

@ -11,4 +11,5 @@ public class AppPaths(IDirectoryInfo appDataPath) : IAppPaths
public IDirectoryInfo ReposDirectory => AppDataDirectory.SubDirectory("repositories"); public IDirectoryInfo ReposDirectory => AppDataDirectory.SubDirectory("repositories");
public IDirectoryInfo CacheDirectory => AppDataDirectory.SubDirectory("cache"); public IDirectoryInfo CacheDirectory => AppDataDirectory.SubDirectory("cache");
public IDirectoryInfo ConfigsDirectory => AppDataDirectory.SubDirectory("configs"); public IDirectoryInfo ConfigsDirectory => AppDataDirectory.SubDirectory("configs");
public IDirectoryInfo IncludesDirectory => AppDataDirectory.SubDirectory("includes");
} }

@ -9,4 +9,5 @@ public interface IAppPaths
IDirectoryInfo ReposDirectory { get; } IDirectoryInfo ReposDirectory { get; }
IDirectoryInfo CacheDirectory { get; } IDirectoryInfo CacheDirectory { get; }
IDirectoryInfo ConfigsDirectory { get; } IDirectoryInfo ConfigsDirectory { get; }
IDirectoryInfo IncludesDirectory { get; }
} }

@ -76,7 +76,8 @@ internal class BaseCommandSetupIntegrationTest : CliIntegrationFixture
{ {
Paths.CacheDirectory.FullName, Paths.CacheDirectory.FullName,
Paths.LogDirectory.FullName, Paths.LogDirectory.FullName,
Paths.ConfigsDirectory.FullName Paths.ConfigsDirectory.FullName,
Paths.IncludesDirectory.FullName
}; };
Fs.LeafDirectories().Should().BeEquivalentTo(expectedDirs); Fs.LeafDirectories().Should().BeEquivalentTo(expectedDirs);

@ -35,7 +35,7 @@ public class ConfigIncludeProcessorTest
[Frozen] IAppPaths paths, [Frozen] IAppPaths paths,
ConfigIncludeProcessor sut) ConfigIncludeProcessor sut)
{ {
fs.AddEmptyFile(paths.ConfigsDirectory.File("foo/bar/config.yml")); fs.AddEmptyFile(paths.IncludesDirectory.File("foo/bar/config.yml"));
var includeDirective = new ConfigYamlInclude var includeDirective = new ConfigYamlInclude
{ {
@ -44,7 +44,7 @@ public class ConfigIncludeProcessorTest
var path = sut.GetPathToConfig(includeDirective, default); var path = sut.GetPathToConfig(includeDirective, default);
path.FullName.Should().Be(paths.ConfigsDirectory.File("foo/bar/config.yml").FullName); path.FullName.Should().Be(paths.IncludesDirectory.File("foo/bar/config.yml").FullName);
} }
[Test, AutoMockData] [Test, AutoMockData]
@ -78,7 +78,7 @@ public class ConfigIncludeProcessorTest
var act = () => sut.GetPathToConfig(includeDirective, default); var act = () => sut.GetPathToConfig(includeDirective, default);
act.Should().Throw<YamlIncludeException>().WithMessage("Relative*not exist*"); act.Should().Throw<YamlIncludeException>();
} }
[Test, AutoMockData] [Test, AutoMockData]
@ -95,6 +95,6 @@ public class ConfigIncludeProcessorTest
var act = () => sut.GetPathToConfig(includeDirective, default); var act = () => sut.GetPathToConfig(includeDirective, default);
act.Should().Throw<YamlIncludeException>().WithMessage("Absolute*not exist*"); act.Should().Throw<YamlIncludeException>();
} }
} }

Loading…
Cancel
Save