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.
scoped-lifetime-instance-processing
Robert Dailey 3 weeks ago
parent 5bed784ed0
commit 8bca7111c4

@ -13,6 +13,13 @@ changes you may need to make.
[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
- **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.LogDirectory.Create();
paths.ConfigsDirectory.Create();
paths.IncludesDirectory.Create();
}
public void OnFinish()

@ -4,13 +4,43 @@ using Recyclarr.TrashGuide;
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)
{
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)
{
var include = (ConfigYamlInclude) includeDirective;
@ -20,16 +50,10 @@ public class ConfigIncludeProcessor(IFileSystem fs, IAppPaths paths) : IIncludeP
throw new YamlIncludeException("`config` property is required.");
}
var rooted = fs.Path.IsPathRooted(include.Config);
var configFile = rooted
? fs.FileInfo.New(include.Config)
: paths.ConfigsDirectory.File(include.Config);
if (!configFile.Exists)
var configFile = ConvertToAbsolute(include.Config);
if (configFile?.Exists != true)
{
var pathType = rooted ? "Absolute" : "Relative";
throw new YamlIncludeException($"{pathType} include path does not exist: {configFile.FullName}");
throw new YamlIncludeException($"Include path could not be resolved: {include.Config}");
}
return configFile;

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

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

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

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

Loading…
Cancel
Save