refactor: Consistent exception handling in all command classes

- Consistently use ExitStatus enum.
- Where appropriate, do not handle exceptions in isolation in the
  command class itself. Rather, let exceptions through to the entrypoint
  so the centralized exception handler can deal with them.
pull/351/head
Robert Dailey 3 months ago
parent a4bb339f07
commit a1358014ad

@ -2,5 +2,6 @@
<profile version="1.0"> <profile version="1.0">
<option name="myName" value="Project Default" /> <option name="myName" value="Project Default" />
<inspection_tool class="JsonStandardCompliance" enabled="false" level="ERROR" enabled_by_default="false" /> <inspection_tool class="JsonStandardCompliance" enabled="false" level="ERROR" enabled_by_default="false" />
<inspection_tool class="SqlNoDataSourceInspection" enabled="false" level="WARNING" enabled_by_default="false" />
</profile> </profile>
</component> </component>

@ -1,6 +1,7 @@
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Console.Settings; using Recyclarr.Cli.Console.Settings;
using Recyclarr.Cli.Processors;
using Recyclarr.Cli.Processors.Config; using Recyclarr.Cli.Processors.Config;
using Recyclarr.Repo; using Recyclarr.Repo;
using Spectre.Console.Cli; using Spectre.Console.Cli;
@ -43,16 +44,15 @@ public class ConfigCreateCommand(ILogger log, IConfigCreationProcessor processor
{ {
await repoUpdater.UpdateAllRepositories(settings.CancellationToken); await repoUpdater.UpdateAllRepositories(settings.CancellationToken);
processor.Process(settings); processor.Process(settings);
return (int) ExitStatus.Succeeded;
} }
catch (FileExistsException e) catch (FileExistsException e)
{ {
log.Error(e, log.Error(e,
"The file {ConfigFile} already exists. Please choose another path or " + "The file {ConfigFile} already exists. Please choose another path or " +
"delete/move the existing file and run this command again", e.AttemptedPath); "delete/move the existing file and run this command again", e.AttemptedPath);
return 1;
} }
return 0; return (int) ExitStatus.Failed;
} }
} }

@ -1,7 +1,7 @@
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Processors;
using Recyclarr.Cli.Processors.Config; using Recyclarr.Cli.Processors.Config;
using Recyclarr.Config.Parsing.ErrorHandling;
using Recyclarr.Repo; using Recyclarr.Repo;
using Spectre.Console.Cli; using Spectre.Console.Cli;
@ -9,7 +9,7 @@ namespace Recyclarr.Cli.Console.Commands;
[UsedImplicitly] [UsedImplicitly]
[Description("List local configuration files.")] [Description("List local configuration files.")]
public class ConfigListLocalCommand(ILogger log, ConfigListLocalProcessor processor, IMultiRepoUpdater repoUpdater) public class ConfigListLocalCommand(ConfigListLocalProcessor processor, IMultiRepoUpdater repoUpdater)
: AsyncCommand<ConfigListLocalCommand.CliSettings> : AsyncCommand<ConfigListLocalCommand.CliSettings>
{ {
[SuppressMessage("Design", "CA1034:Nested types should not be visible")] [SuppressMessage("Design", "CA1034:Nested types should not be visible")]
@ -17,17 +17,8 @@ public class ConfigListLocalCommand(ILogger log, ConfigListLocalProcessor proces
public override async Task<int> ExecuteAsync(CommandContext context, CliSettings settings) public override async Task<int> ExecuteAsync(CommandContext context, CliSettings settings)
{ {
try await repoUpdater.UpdateAllRepositories(settings.CancellationToken);
{ processor.Process();
await repoUpdater.UpdateAllRepositories(settings.CancellationToken); return (int) ExitStatus.Succeeded;
processor.Process();
return 0;
}
catch (NoConfigurationFilesException e)
{
log.Error(e, "Unable to list local config files");
}
return 1;
} }
} }

@ -1,7 +1,7 @@
using System.ComponentModel; using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Processors;
using Recyclarr.Cli.Processors.Config; using Recyclarr.Cli.Processors.Config;
using Recyclarr.Config.Parsing.ErrorHandling;
using Recyclarr.Repo; using Recyclarr.Repo;
using Spectre.Console.Cli; using Spectre.Console.Cli;
@ -9,10 +9,7 @@ namespace Recyclarr.Cli.Console.Commands;
[UsedImplicitly] [UsedImplicitly]
[Description("List local configuration files.")] [Description("List local configuration files.")]
public class ConfigListTemplatesCommand( public class ConfigListTemplatesCommand(ConfigListTemplateProcessor processor, IMultiRepoUpdater repoUpdater)
ILogger log,
ConfigListTemplateProcessor processor,
IMultiRepoUpdater repoUpdater)
: AsyncCommand<ConfigListTemplatesCommand.CliSettings> : AsyncCommand<ConfigListTemplatesCommand.CliSettings>
{ {
[SuppressMessage("Design", "CA1034:Nested types should not be visible")] [SuppressMessage("Design", "CA1034:Nested types should not be visible")]
@ -27,18 +24,9 @@ public class ConfigListTemplatesCommand(
public override async Task<int> ExecuteAsync(CommandContext context, CliSettings settings) public override async Task<int> ExecuteAsync(CommandContext context, CliSettings settings)
{ {
try await repoUpdater.UpdateAllRepositories(settings.CancellationToken);
{ processor.Process(settings);
await repoUpdater.UpdateAllRepositories(settings.CancellationToken); return (int) ExitStatus.Succeeded;
processor.Process(settings);
return 0;
}
catch (NoConfigurationFilesException e)
{
log.Error(e, "Unable to list template files");
}
return 1;
} }
} }

@ -3,16 +3,13 @@ using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Console.Settings; using Recyclarr.Cli.Console.Settings;
using Recyclarr.Cli.Processors; using Recyclarr.Cli.Processors;
using Recyclarr.Cli.Processors.Delete; using Recyclarr.Cli.Processors.Delete;
using Recyclarr.Cli.Processors.ErrorHandling;
using Spectre.Console.Cli; using Spectre.Console.Cli;
namespace Recyclarr.Cli.Console.Commands; namespace Recyclarr.Cli.Console.Commands;
[Description("Delete things from services like Radarr & Sonarr")] [Description("Delete things from services like Radarr and Sonarr")]
[UsedImplicitly] [UsedImplicitly]
public class DeleteCustomFormatsCommand( public class DeleteCustomFormatsCommand(IDeleteCustomFormatsProcessor processor)
IDeleteCustomFormatsProcessor processor,
ConsoleExceptionHandler exceptionHandler)
: AsyncCommand<DeleteCustomFormatsCommand.CliSettings> : AsyncCommand<DeleteCustomFormatsCommand.CliSettings>
{ {
[UsedImplicitly] [UsedImplicitly]
@ -46,21 +43,7 @@ public class DeleteCustomFormatsCommand(
[SuppressMessage("Design", "CA1031:Do not catch general exception types")] [SuppressMessage("Design", "CA1031:Do not catch general exception types")]
public override async Task<int> ExecuteAsync(CommandContext context, CliSettings settings) public override async Task<int> ExecuteAsync(CommandContext context, CliSettings settings)
{ {
try await processor.Process(settings, settings.CancellationToken);
{
await processor.Process(settings, settings.CancellationToken);
}
catch (Exception e)
{
if (!await exceptionHandler.HandleException(e))
{
// This means we didn't handle the exception; rethrow it.
throw;
}
return (int) ExitStatus.Failed;
}
return (int) ExitStatus.Succeeded; return (int) ExitStatus.Succeeded;
} }
} }

@ -3,6 +3,7 @@ using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Console.Helpers; using Recyclarr.Cli.Console.Helpers;
using Recyclarr.Cli.Console.Settings; using Recyclarr.Cli.Console.Settings;
using Recyclarr.Cli.Pipelines.CustomFormat; using Recyclarr.Cli.Pipelines.CustomFormat;
using Recyclarr.Cli.Processors;
using Recyclarr.Repo; using Recyclarr.Repo;
using Recyclarr.TrashGuide; using Recyclarr.TrashGuide;
using Spectre.Console.Cli; using Spectre.Console.Cli;
@ -38,6 +39,6 @@ public class ListCustomFormatsCommand(CustomFormatDataLister lister, IMultiRepoU
{ {
await repoUpdater.UpdateAllRepositories(settings.CancellationToken, settings.Raw); await repoUpdater.UpdateAllRepositories(settings.CancellationToken, settings.Raw);
lister.List(settings); lister.List(settings);
return 0; return (int) ExitStatus.Succeeded;
} }
} }

@ -2,6 +2,7 @@ using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Console.Helpers; using Recyclarr.Cli.Console.Helpers;
using Recyclarr.Cli.Pipelines.MediaNaming; using Recyclarr.Cli.Pipelines.MediaNaming;
using Recyclarr.Cli.Processors;
using Recyclarr.Repo; using Recyclarr.Repo;
using Recyclarr.TrashGuide; using Recyclarr.TrashGuide;
using Spectre.Console.Cli; using Spectre.Console.Cli;
@ -27,6 +28,6 @@ public class ListMediaNamingCommand(MediaNamingDataLister lister, IMultiRepoUpda
{ {
await repoUpdater.UpdateAllRepositories(settings.CancellationToken); await repoUpdater.UpdateAllRepositories(settings.CancellationToken);
lister.ListNaming(settings.Service); lister.ListNaming(settings.Service);
return 0; return (int) ExitStatus.Succeeded;
} }
} }

@ -2,6 +2,7 @@ using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using Recyclarr.Cli.Console.Helpers; using Recyclarr.Cli.Console.Helpers;
using Recyclarr.Cli.Pipelines.QualitySize; using Recyclarr.Cli.Pipelines.QualitySize;
using Recyclarr.Cli.Processors;
using Recyclarr.Repo; using Recyclarr.Repo;
using Recyclarr.TrashGuide; using Recyclarr.TrashGuide;
using Spectre.Console.Cli; using Spectre.Console.Cli;
@ -28,6 +29,6 @@ public class ListQualitiesCommand(QualitySizeDataLister lister, IMultiRepoUpdate
{ {
await repoUpdater.UpdateAllRepositories(settings.CancellationToken); await repoUpdater.UpdateAllRepositories(settings.CancellationToken);
lister.ListQualities(settings.Service); lister.ListQualities(settings.Service);
return 0; return (int) ExitStatus.Succeeded;
} }
} }

@ -2,6 +2,7 @@ using System.ComponentModel;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Text; using System.Text;
using Recyclarr.Cli.Migration; using Recyclarr.Cli.Migration;
using Recyclarr.Cli.Processors;
using Spectre.Console; using Spectre.Console;
using Spectre.Console.Cli; using Spectre.Console.Cli;
@ -25,6 +26,7 @@ public class MigrateCommand(
{ {
migration.PerformAllMigrationSteps(settings.Debug); migration.PerformAllMigrationSteps(settings.Debug);
console.WriteLine("All migration steps completed"); console.WriteLine("All migration steps completed");
return (int) ExitStatus.Succeeded;
} }
catch (MigrationException e) catch (MigrationException e)
{ {
@ -44,14 +46,12 @@ public class MigrateCommand(
} }
console.Write(msg.ToString()); console.Write(msg.ToString());
return 1;
} }
catch (RequiredMigrationException ex) catch (RequiredMigrationException ex)
{ {
console.WriteLine($"ERROR: {ex.Message}"); console.WriteLine($"ERROR: {ex.Message}");
return 1;
} }
return 0; return (int) ExitStatus.Failed;
} }
} }

@ -42,7 +42,11 @@ internal static class Program
{ {
var log = scope.Resolve<ILogger>(); var log = scope.Resolve<ILogger>();
var exceptionHandler = new ConsoleExceptionHandler(log); var exceptionHandler = new ConsoleExceptionHandler(log);
await exceptionHandler.HandleException(e); if (!await exceptionHandler.HandleException(e))
{
log.Error(e, "Exiting due to fatal error");
}
return (int) ExitStatus.Failed; return (int) ExitStatus.Failed;
} }
} }

Loading…
Cancel
Save