You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
recyclarr/src/Recyclarr.TrashLib/Config/Parsing/PostProcessing/IncludePostProcessor.cs

106 lines
3.3 KiB

using Recyclarr.TrashLib.Config.Parsing.PostProcessing.ConfigMerging;
using Serilog.Context;
namespace Recyclarr.TrashLib.Config.Parsing.PostProcessing;
public class IncludePostProcessor : IConfigPostProcessor
{
private readonly ILogger _log;
private readonly ConfigParser _parser;
private readonly ConfigValidationExecutor _validator;
private readonly IYamlIncludeResolver _includeResolver;
public IncludePostProcessor(
ILogger log,
ConfigParser parser,
ConfigValidationExecutor validator,
IYamlIncludeResolver includeResolver)
{
_log = log;
_parser = parser;
_validator = validator;
_includeResolver = includeResolver;
}
public RootConfigYaml Process(RootConfigYaml config)
{
return new RootConfigYaml
{
Radarr = ProcessIncludes(config.Radarr, new RadarrConfigMerger(), SupportedServices.Radarr),
Sonarr = ProcessIncludes(config.Sonarr, new SonarrConfigMerger(), SupportedServices.Sonarr)
};
}
private IReadOnlyDictionary<string, T>? ProcessIncludes<T>(
IReadOnlyDictionary<string, T>? configs,
ServiceConfigMerger<T> merger,
SupportedServices serviceType)
where T : ServiceConfigYaml, new()
{
if (configs is null)
{
return null;
}
var mergedConfigs = new Dictionary<string, T>();
foreach (var (key, config) in configs)
{
if (config.Include is null)
{
mergedConfigs.Add(key, config);
continue;
}
// Combine all includes together first
var aggregateInclude = config.Include
.Select(x => LoadYamlInclude<T>(x, serviceType))
.Aggregate(new T(), merger.Merge);
// Merge the config into the aggregated includes so that root config values overwrite included values.
mergedConfigs.Add(key, merger.Merge(aggregateInclude, config) with
{
// No reason to keep these around anymore now that they have been merged
Include = null
});
}
return mergedConfigs;
}
private T LoadYamlInclude<T>(IYamlInclude includeType, SupportedServices serviceType)
where T : ServiceConfigYaml
{
var yamlFile = _includeResolver.GetIncludePath(includeType, serviceType);
using var logScope = LogContext.PushProperty(LogProperty.Scope, $"Include {yamlFile.Name}");
var configToMerge = _parser.Load<T>(yamlFile);
if (configToMerge is null)
{
throw new YamlIncludeException($"Failed to parse include file: {yamlFile.FullName}");
}
if (!_validator.Validate(configToMerge))
{
throw new YamlIncludeException($"Validation of included YAML failed: {yamlFile.FullName}");
}
if (configToMerge.BaseUrl is not null)
{
_log.Warning("`base_url` is not allowed in YAML includes");
}
if (configToMerge.ApiKey is not null)
{
_log.Warning("`api_key` is not allowed in YAML includes");
}
if (configToMerge.Include is not null)
{
_log.Warning("Nested `include` directives are not supported");
}
return configToMerge;
}
}