parent
cd6eda4055
commit
3840f9c5ab
@ -1,21 +0,0 @@
|
||||
using YamlDotNet.Core;
|
||||
|
||||
namespace Recyclarr.TrashLib.Config.Parsing;
|
||||
|
||||
public static class ConfigDeprecations
|
||||
{
|
||||
public static string? GetContextualErrorFromException(YamlException e)
|
||||
{
|
||||
if (e.Message.Contains("Expected 'MappingStart', got 'SequenceStart'"))
|
||||
{
|
||||
return "Found array-style list of instances instead of named-style. " +
|
||||
"Array-style lists of Sonarr/Radarr instances are not supported. " +
|
||||
"See: https://recyclarr.dev/wiki/upgrade-guide/v5.0/#instances-must-now-be-named";
|
||||
}
|
||||
|
||||
// "DEPRECATION: Support for using `reset_unmatched_scores` under `custom_formats.quality_profiles` " +
|
||||
// "will be removed in a future release. Move it to the top level `quality_profiles` instead"
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
using Recyclarr.TrashLib.Config.Yaml;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Recyclarr.TrashLib.Config.Parsing.ErrorHandling;
|
||||
|
||||
public class ConfigFeatureRemovalBehavior : IYamlBehavior
|
||||
{
|
||||
public void Setup(DeserializerBuilder builder)
|
||||
{
|
||||
builder.WithNodeTypeResolver(new FeatureRemovalChecker());
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
using YamlDotNet.Core;
|
||||
|
||||
namespace Recyclarr.TrashLib.Config.Parsing.ErrorHandling;
|
||||
|
||||
public static class ContextualMessages
|
||||
{
|
||||
public static string? GetContextualErrorFromException(YamlException e)
|
||||
{
|
||||
if (e.Message.Contains(
|
||||
"Property 'reset_unmatched_scores' not found on type " +
|
||||
$"'{typeof(QualityScoreConfigYaml).FullName}'"))
|
||||
{
|
||||
return
|
||||
"Usage of 'reset_unmatched_scores' inside 'quality_profiles' under 'custom_formats' is no " +
|
||||
"longer supported. Use the root-level 'quality_profiles' instead. " +
|
||||
"See: https://recyclarr.dev/wiki/upgrade-guide/v5.0#reset-unmatched-scores";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Recyclarr.TrashLib.Config.Parsing.ErrorHandling;
|
||||
|
||||
// Note: Backward breaking changes involving node removals cannot be handled here, since that will cause exceptions
|
||||
// before the Node Type Resolver gets invoked. Those are handled reactively by inspecting the YamlException object
|
||||
// passed to the ContextualMessages static class.
|
||||
public sealed class FeatureRemovalChecker : INodeTypeResolver
|
||||
{
|
||||
public bool Resolve(NodeEvent? nodeEvent, ref Type currentType)
|
||||
{
|
||||
if (IsDictionaryOfType(currentType, typeof(RadarrConfigYaml), typeof(SonarrConfigYaml)) &&
|
||||
nodeEvent is SequenceStart)
|
||||
{
|
||||
throw new FeatureRemovalException(
|
||||
"Found array-style list of instances instead of named-style. " +
|
||||
"Array-style lists of Sonarr/Radarr instances are not supported.",
|
||||
"https://recyclarr.dev/wiki/upgrade-guide/v5.0/#instances-must-now-be-named");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsDictionaryOfType(Type dictType, params Type[] valueTypes)
|
||||
{
|
||||
if (!dictType.IsGenericType || dictType.GetGenericTypeDefinition() != typeof(IReadOnlyDictionary<,>))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return valueTypes.Contains(dictType.GenericTypeArguments[1]);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace Recyclarr.TrashLib.Config.Parsing.ErrorHandling;
|
||||
|
||||
[Serializable]
|
||||
public class FeatureRemovalException : Exception
|
||||
{
|
||||
protected FeatureRemovalException(SerializationInfo info, StreamingContext context)
|
||||
: base(info, context)
|
||||
{
|
||||
}
|
||||
|
||||
public FeatureRemovalException(string message, string docLink)
|
||||
: base($"{message} See: {docLink}")
|
||||
{
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
namespace Recyclarr.TrashLib.Config.Parsing;
|
||||
namespace Recyclarr.TrashLib.Config.Parsing.ErrorHandling;
|
||||
|
||||
public class NoConfigurationFilesException : Exception
|
||||
{
|
@ -0,0 +1,29 @@
|
||||
using System.Reflection;
|
||||
using YamlDotNet.Core;
|
||||
using YamlDotNet.Core.Events;
|
||||
using YamlDotNet.Serialization;
|
||||
|
||||
namespace Recyclarr.TrashLib.Config.Parsing.ErrorHandling;
|
||||
|
||||
public sealed class SyntaxErrorHelper : INodeTypeResolver
|
||||
{
|
||||
private static readonly string[] CollectionKeywords = {"Collection", "List"};
|
||||
|
||||
public bool Resolve(NodeEvent? nodeEvent, ref Type currentType)
|
||||
{
|
||||
CheckSequenceAssignedToNonSequence(nodeEvent, currentType);
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the user tries to specify an array as the value for a node type that is not a list type, then we provide our
|
||||
// own exception type. The default error message that YamlDotNet would output doesn't make much sense to users: It
|
||||
// just says "no node type resolver could resolve the type", or something along those lines -- which isn't helpful!
|
||||
private static void CheckSequenceAssignedToNonSequence(ParsingEvent? nodeEvent, MemberInfo currentType)
|
||||
{
|
||||
if (nodeEvent is SequenceStart && !CollectionKeywords.Any(x => currentType.Name.Contains(x)))
|
||||
{
|
||||
throw new YamlException(nodeEvent.Start, nodeEvent.End,
|
||||
$"A list/array/sequence is not allowed for {currentType.Name}");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue