From ae59a95adf54a5e1446d5c9dcf639ad90d8e184e Mon Sep 17 00:00:00 2001 From: Matt Date: Mon, 5 Oct 2020 20:56:52 +1300 Subject: [PATCH] Improve validation failure reporting Consolidated validation exception Refactoring --- .../Extensions/Images/ImageExtensions.cs | 13 +++- .../Migration/001. Create cache table.sql | 2 +- Sanchez.Processing/Services/FileService.cs | 7 +- .../Exceptions/ValidationException.cs | 27 ------- Sanchez.Workflow/Extensions/StepExtensions.cs | 3 +- .../Extensions/WorkflowExtensions.cs | 3 +- .../Data/EquirectangularStitchWorkflowData.cs | 3 +- .../EquirectangularTimelapseWorkflowData.cs | 3 +- .../Models/Data/GeostationaryWorkflowData.cs | 7 +- Sanchez.Workflow/Models/Data/WorkflowData.cs | 4 +- Sanchez.Workflow/Services/WorkflowService.cs | 8 ++- .../Steps/Common/ColourCorrect.cs | 1 - .../Steps/Common/CreateActivity.cs | 1 - .../Steps/Common/GetSourceFiles.cs | 10 +-- .../Steps/Common/InitialiseProgressBar.cs | 1 - .../Common/InitialiseSatelliteRegistry.cs | 3 +- .../Steps/Common/InitialiseUnderlayCache.cs | 1 - .../Steps/Common/LoadImageSingle.cs | 1 - .../Steps/Common/LogCompletion.cs | 1 - .../Steps/Common/NormaliseImage.cs | 1 - Sanchez.Workflow/Steps/Common/SaveImage.cs | 1 - .../Steps/Common/SetWorkflowRegistration.cs | 1 - .../Steps/Common/ShouldWriteSingle.cs | 1 - .../Steps/Equirectangular/RegisterImages.cs | 1 - .../Equirectangular/SetWorkflowActivity.cs | 1 - .../Stitch/CalculateGlobalOffset.cs | 1 - .../Stitch/CalculateVisibleRange.cs | 1 - .../Steps/Equirectangular/Stitch/CropImage.cs | 1 - .../Equirectangular/Stitch/GetCropBounds.cs | 1 - .../Steps/Equirectangular/Stitch/LoadImage.cs | 1 - .../Equirectangular/Stitch/RenderUnderlay.cs | 1 - .../Stitch/SaveStitchedImage.cs | 1 - .../Equirectangular/Stitch/ShouldWrite.cs | 1 - .../Equirectangular/Stitch/StitchImages.cs | 1 - .../Stitch/ToEquirectangular.cs | 1 - .../Timelapse/CreateActivities.cs | 1 - .../Timelapse/InitialiseProgressBar.cs | 1 - .../Timelapse/PrepareTimeIntervals.cs | 1 - .../Timelapse/SetTargetTimestamp.cs | 1 - .../Steps/Geostationary/ApplyHaze.cs | 1 - .../Steps/Geostationary/RenderUnderlay.cs | 1 - .../Reprojected/ToGeostationary.cs | 1 - Sanchez/Bootstrapper.cs | 11 ++- Sanchez/Builders/LoggingBuilder.cs | 10 +-- Sanchez/Sanchez.csproj | 2 +- .../Services/ValidationExceptionWrapper.cs | 70 +++++++++++++++++++ .../Validators/CommandLineOptionsValidator.cs | 1 - 47 files changed, 119 insertions(+), 97 deletions(-) delete mode 100644 Sanchez.Shared/Exceptions/ValidationException.cs create mode 100644 Sanchez/Services/ValidationExceptionWrapper.cs diff --git a/Sanchez.Processing/Extensions/Images/ImageExtensions.cs b/Sanchez.Processing/Extensions/Images/ImageExtensions.cs index 9930d51..0de53bf 100644 --- a/Sanchez.Processing/Extensions/Images/ImageExtensions.cs +++ b/Sanchez.Processing/Extensions/Images/ImageExtensions.cs @@ -1,7 +1,9 @@ -using System.IO; +using System; +using System.IO; using System.Reflection; using System.Threading.Tasks; using ExifLibrary; +using FluentValidation; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; @@ -22,7 +24,14 @@ public static async Task SaveWithExifAsync(this Image image, string path } // Save image - await image.SaveAsync(path); + try + { + await image.SaveAsync(path); + } + catch (NotSupportedException) + { + throw new ValidationException($"Unsupported output file extension: {Path.GetExtension(path)}"); + } // Add EXIF metadata to image var version = Assembly.GetExecutingAssembly().GetName().Version; diff --git a/Sanchez.Processing/Resources/Migration/001. Create cache table.sql b/Sanchez.Processing/Resources/Migration/001. Create cache table.sql index 4fac303..c5cbe11 100644 --- a/Sanchez.Processing/Resources/Migration/001. Create cache table.sql +++ b/Sanchez.Processing/Resources/Migration/001. Create cache table.sql @@ -1,4 +1,4 @@ -CREATE TABLE UnderlayCache( +CREATE TABLE IF NOT EXISTS UnderlayCache( Id INTEGER PRIMARY KEY AUTOINCREMENT, Filename TEXT NOT NULL, Longitude NUMERIC, diff --git a/Sanchez.Processing/Services/FileService.cs b/Sanchez.Processing/Services/FileService.cs index 219790e..2b1e008 100644 --- a/Sanchez.Processing/Services/FileService.cs +++ b/Sanchez.Processing/Services/FileService.cs @@ -16,7 +16,7 @@ public interface IFileService /// can be a single file, a directory or a glob and wildcard pattern (such as source/**/*IR.jpg) /// List GetSourceFiles(); - + List ToRegistrations(List sourceFiles); /// @@ -76,7 +76,10 @@ public List GetSourceFiles() var absolutePath = Path.GetFullPath(_options.SourcePath!); // Source is a single file - if (!_options.MultipleSources) return new List { absolutePath }; + if (!_options.MultipleSources) + { + return File.Exists(absolutePath) ? new List { absolutePath } : new List(); + } // If the source is a directory, enumerate all files if (Directory.Exists(absolutePath)) diff --git a/Sanchez.Shared/Exceptions/ValidationException.cs b/Sanchez.Shared/Exceptions/ValidationException.cs deleted file mode 100644 index 23e3c84..0000000 --- a/Sanchez.Shared/Exceptions/ValidationException.cs +++ /dev/null @@ -1,27 +0,0 @@ -using System; -using FluentValidation.Results; - -namespace Sanchez.Shared.Exceptions -{ - /// - /// Exception thrown when a pre-condition hasn't been met. - /// - public class ValidationException : Exception - { - public ValidationResult? Result { get; } - - public ValidationException() : base(string.Empty) - { - } - - public ValidationException(ValidationResult result) => Result = result; - - public ValidationException(string? message, Exception? innerException) : base(message, innerException) - { - } - - public ValidationException(string message) : base(message) - { - } - } -} \ No newline at end of file diff --git a/Sanchez.Workflow/Extensions/StepExtensions.cs b/Sanchez.Workflow/Extensions/StepExtensions.cs index be7b27d..7ca8f1a 100644 --- a/Sanchez.Workflow/Extensions/StepExtensions.cs +++ b/Sanchez.Workflow/Extensions/StepExtensions.cs @@ -1,5 +1,4 @@ -using Sanchez.Workflow.Models; -using Sanchez.Workflow.Models.Data; +using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Steps.Common; using WorkflowCore.Interface; diff --git a/Sanchez.Workflow/Extensions/WorkflowExtensions.cs b/Sanchez.Workflow/Extensions/WorkflowExtensions.cs index 0d710b5..6ed84fe 100644 --- a/Sanchez.Workflow/Extensions/WorkflowExtensions.cs +++ b/Sanchez.Workflow/Extensions/WorkflowExtensions.cs @@ -1,5 +1,4 @@ -using Sanchez.Workflow.Models; -using Sanchez.Workflow.Models.Data; +using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using WorkflowCore.Interface; diff --git a/Sanchez.Workflow/Models/Data/EquirectangularStitchWorkflowData.cs b/Sanchez.Workflow/Models/Data/EquirectangularStitchWorkflowData.cs index 9428223..6ef4a94 100644 --- a/Sanchez.Workflow/Models/Data/EquirectangularStitchWorkflowData.cs +++ b/Sanchez.Workflow/Models/Data/EquirectangularStitchWorkflowData.cs @@ -1,11 +1,10 @@ using JetBrains.Annotations; -using Sanchez.Workflow.Workflows.Equirectangular; using SixLabors.ImageSharp; namespace Sanchez.Workflow.Models.Data { /// - /// Data backing . + /// Data backing . /// public class EquirectangularStitchWorkflowData : WorkflowData { diff --git a/Sanchez.Workflow/Models/Data/EquirectangularTimelapseWorkflowData.cs b/Sanchez.Workflow/Models/Data/EquirectangularTimelapseWorkflowData.cs index 8b59054..011849a 100644 --- a/Sanchez.Workflow/Models/Data/EquirectangularTimelapseWorkflowData.cs +++ b/Sanchez.Workflow/Models/Data/EquirectangularTimelapseWorkflowData.cs @@ -1,13 +1,12 @@ using System; using System.Collections.Generic; using JetBrains.Annotations; -using Sanchez.Workflow.Workflows.Equirectangular; using ShellProgressBar; namespace Sanchez.Workflow.Models.Data { /// - /// Data backing . + /// Data backing . /// public class EquirectangularTimelapseWorkflowData : EquirectangularStitchWorkflowData { diff --git a/Sanchez.Workflow/Models/Data/GeostationaryWorkflowData.cs b/Sanchez.Workflow/Models/Data/GeostationaryWorkflowData.cs index a305321..056ff8f 100644 --- a/Sanchez.Workflow/Models/Data/GeostationaryWorkflowData.cs +++ b/Sanchez.Workflow/Models/Data/GeostationaryWorkflowData.cs @@ -1,10 +1,7 @@ - -using Sanchez.Workflow.Workflows.Geostationary; - -namespace Sanchez.Workflow.Models.Data +namespace Sanchez.Workflow.Models.Data { /// - /// Data backing . + /// Data backing . /// public class GeostationaryWorkflowData : WorkflowData { diff --git a/Sanchez.Workflow/Models/Data/WorkflowData.cs b/Sanchez.Workflow/Models/Data/WorkflowData.cs index 807fa64..d5e0476 100644 --- a/Sanchez.Workflow/Models/Data/WorkflowData.cs +++ b/Sanchez.Workflow/Models/Data/WorkflowData.cs @@ -18,9 +18,9 @@ public interface IWorkflowData /// /// /// This is arguably a misuse of WorkflowCore data, as it should be able to be serialized. Add disposable - /// services and binary data breaks this pattern. + /// services and binary data breaks this pattern. In practice, this state needs to be available somewhere, + /// and the workflows aren't log enough to warrant having a persistence provider specified. /// - // TODO check if WorkflowCore has some sort of never serialize flag public abstract class WorkflowData : IWorkflowData, IDisposable { /// diff --git a/Sanchez.Workflow/Services/WorkflowService.cs b/Sanchez.Workflow/Services/WorkflowService.cs index 76bb020..be3a925 100644 --- a/Sanchez.Workflow/Services/WorkflowService.cs +++ b/Sanchez.Workflow/Services/WorkflowService.cs @@ -1,8 +1,8 @@ using System; using System.Threading; using System.Threading.Tasks; +using FluentValidation; using Sanchez.Processing.Models; -using Sanchez.Shared.Exceptions; using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Workflows.Equirectangular; @@ -31,7 +31,7 @@ public sealed class WorkflowService : IWorkflowService, IDisposable private readonly AutoResetEvent _resetEvent; private string? _workflowId; - private bool _initialised = false; + private bool _initialised; public WorkflowService( RenderOptions options, @@ -110,11 +110,13 @@ private void OnLifeCycleEvent(CancellationTokenSource cancellationToken, LifeCyc private void OnStepError(Exception exception, WorkflowInstance workflow) { + DisposeData(); + switch (exception) { case ValidationException validationException: Console.WriteLine(validationException.Message); - Log.Error(validationException.Message); + Log.Warning(validationException.Message); break; default: if (!_options.Verbose) Console.WriteLine("Unhandled failure; check logs for details, or run again with verbose logging (-v / --verbose)"); diff --git a/Sanchez.Workflow/Steps/Common/ColourCorrect.cs b/Sanchez.Workflow/Steps/Common/ColourCorrect.cs index 78f130f..0a0e555 100644 --- a/Sanchez.Workflow/Steps/Common/ColourCorrect.cs +++ b/Sanchez.Workflow/Steps/Common/ColourCorrect.cs @@ -2,7 +2,6 @@ using JetBrains.Annotations; using Sanchez.Processing.Models; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; diff --git a/Sanchez.Workflow/Steps/Common/CreateActivity.cs b/Sanchez.Workflow/Steps/Common/CreateActivity.cs index 8defd61..f46900e 100644 --- a/Sanchez.Workflow/Steps/Common/CreateActivity.cs +++ b/Sanchez.Workflow/Steps/Common/CreateActivity.cs @@ -5,7 +5,6 @@ using Sanchez.Processing.Models.Projections; using Sanchez.Processing.Services; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; diff --git a/Sanchez.Workflow/Steps/Common/GetSourceFiles.cs b/Sanchez.Workflow/Steps/Common/GetSourceFiles.cs index 58c4ffe..3a26170 100644 --- a/Sanchez.Workflow/Steps/Common/GetSourceFiles.cs +++ b/Sanchez.Workflow/Steps/Common/GetSourceFiles.cs @@ -1,10 +1,10 @@ using System.Collections.Generic; using System.IO; +using System.Linq; +using FluentValidation; using Sanchez.Processing.Models.Projections; using Sanchez.Processing.Services; -using Sanchez.Shared.Exceptions; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; @@ -23,11 +23,13 @@ public override ExecutionResult Run(IStepExecutionContext context) try { var sourceFiles = _fileService.GetSourceFiles(); + if (!sourceFiles.Any()) throw new ValidationException("No source files found"); + SourceRegistrations = _fileService.ToRegistrations(sourceFiles); } - catch (DirectoryNotFoundException e) + catch (DirectoryNotFoundException) { - throw new ValidationException("Source directory not found", e); + throw new ValidationException("Source directory not found"); } return ExecutionResult.Next(); diff --git a/Sanchez.Workflow/Steps/Common/InitialiseProgressBar.cs b/Sanchez.Workflow/Steps/Common/InitialiseProgressBar.cs index faecca6..824caab 100644 --- a/Sanchez.Workflow/Steps/Common/InitialiseProgressBar.cs +++ b/Sanchez.Workflow/Steps/Common/InitialiseProgressBar.cs @@ -4,7 +4,6 @@ using Sanchez.Processing.Helpers; using Sanchez.Processing.Models; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using ShellProgressBar; using WorkflowCore.Interface; diff --git a/Sanchez.Workflow/Steps/Common/InitialiseSatelliteRegistry.cs b/Sanchez.Workflow/Steps/Common/InitialiseSatelliteRegistry.cs index c64ce21..06fcf3c 100644 --- a/Sanchez.Workflow/Steps/Common/InitialiseSatelliteRegistry.cs +++ b/Sanchez.Workflow/Steps/Common/InitialiseSatelliteRegistry.cs @@ -1,10 +1,9 @@ using System; using System.Threading.Tasks; +using FluentValidation; using Microsoft.Extensions.Logging; using Sanchez.Processing.Services; -using Sanchez.Shared.Exceptions; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; diff --git a/Sanchez.Workflow/Steps/Common/InitialiseUnderlayCache.cs b/Sanchez.Workflow/Steps/Common/InitialiseUnderlayCache.cs index a83f6c8..4a36c3d 100644 --- a/Sanchez.Workflow/Steps/Common/InitialiseUnderlayCache.cs +++ b/Sanchez.Workflow/Steps/Common/InitialiseUnderlayCache.cs @@ -1,6 +1,5 @@ using Sanchez.Processing.Services.Underlay; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; diff --git a/Sanchez.Workflow/Steps/Common/LoadImageSingle.cs b/Sanchez.Workflow/Steps/Common/LoadImageSingle.cs index 5d6e6d0..ea2c3a3 100644 --- a/Sanchez.Workflow/Steps/Common/LoadImageSingle.cs +++ b/Sanchez.Workflow/Steps/Common/LoadImageSingle.cs @@ -2,7 +2,6 @@ using Ardalis.GuardClauses; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using WorkflowCore.Interface; diff --git a/Sanchez.Workflow/Steps/Common/LogCompletion.cs b/Sanchez.Workflow/Steps/Common/LogCompletion.cs index 66b3759..5eaf163 100644 --- a/Sanchez.Workflow/Steps/Common/LogCompletion.cs +++ b/Sanchez.Workflow/Steps/Common/LogCompletion.cs @@ -2,7 +2,6 @@ using JetBrains.Annotations; using Microsoft.Extensions.Logging; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using ShellProgressBar; diff --git a/Sanchez.Workflow/Steps/Common/NormaliseImage.cs b/Sanchez.Workflow/Steps/Common/NormaliseImage.cs index 50942c6..90a04de 100644 --- a/Sanchez.Workflow/Steps/Common/NormaliseImage.cs +++ b/Sanchez.Workflow/Steps/Common/NormaliseImage.cs @@ -3,7 +3,6 @@ using Sanchez.Processing.Models; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using WorkflowCore.Interface; diff --git a/Sanchez.Workflow/Steps/Common/SaveImage.cs b/Sanchez.Workflow/Steps/Common/SaveImage.cs index 651dd19..02eef09 100644 --- a/Sanchez.Workflow/Steps/Common/SaveImage.cs +++ b/Sanchez.Workflow/Steps/Common/SaveImage.cs @@ -5,7 +5,6 @@ using Sanchez.Processing.Extensions.Images; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using SixLabors.ImageSharp; diff --git a/Sanchez.Workflow/Steps/Common/SetWorkflowRegistration.cs b/Sanchez.Workflow/Steps/Common/SetWorkflowRegistration.cs index 71a68c6..8770b69 100644 --- a/Sanchez.Workflow/Steps/Common/SetWorkflowRegistration.cs +++ b/Sanchez.Workflow/Steps/Common/SetWorkflowRegistration.cs @@ -1,6 +1,5 @@ using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; diff --git a/Sanchez.Workflow/Steps/Common/ShouldWriteSingle.cs b/Sanchez.Workflow/Steps/Common/ShouldWriteSingle.cs index 1f02795..5dd51db 100644 --- a/Sanchez.Workflow/Steps/Common/ShouldWriteSingle.cs +++ b/Sanchez.Workflow/Steps/Common/ShouldWriteSingle.cs @@ -6,7 +6,6 @@ using Sanchez.Processing.Models.Projections; using Sanchez.Processing.Services; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using ShellProgressBar; diff --git a/Sanchez.Workflow/Steps/Equirectangular/RegisterImages.cs b/Sanchez.Workflow/Steps/Equirectangular/RegisterImages.cs index ccf955b..53ec483 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/RegisterImages.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/RegisterImages.cs @@ -6,7 +6,6 @@ using Sanchez.Processing.Models.Projections; using Sanchez.Processing.Services; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; diff --git a/Sanchez.Workflow/Steps/Equirectangular/SetWorkflowActivity.cs b/Sanchez.Workflow/Steps/Equirectangular/SetWorkflowActivity.cs index 99c6586..bb4aae3 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/SetWorkflowActivity.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/SetWorkflowActivity.cs @@ -1,6 +1,5 @@ using Sanchez.Processing.Models; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/CalculateGlobalOffset.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/CalculateGlobalOffset.cs index b9388b6..cdac5cc 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/CalculateGlobalOffset.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/CalculateGlobalOffset.cs @@ -2,7 +2,6 @@ using Ardalis.GuardClauses; using Sanchez.Processing.Models; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using WorkflowCore.Interface; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/CalculateVisibleRange.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/CalculateVisibleRange.cs index d0ad4bf..886324f 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/CalculateVisibleRange.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/CalculateVisibleRange.cs @@ -3,7 +3,6 @@ using Sanchez.Processing.Models; using Sanchez.Processing.Services; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using WorkflowCore.Interface; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/CropImage.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/CropImage.cs index fc0399c..d55e8a5 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/CropImage.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/CropImage.cs @@ -3,7 +3,6 @@ using Sanchez.Processing.Extensions; using Sanchez.Processing.Models; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using SixLabors.ImageSharp; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/GetCropBounds.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/GetCropBounds.cs index bc8777e..8133815 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/GetCropBounds.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/GetCropBounds.cs @@ -5,7 +5,6 @@ using Sanchez.Processing.Models; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using SixLabors.ImageSharp; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/LoadImage.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/LoadImage.cs index 8577400..8e0f4ef 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/LoadImage.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/LoadImage.cs @@ -5,7 +5,6 @@ using Ardalis.GuardClauses; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using ShellProgressBar; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/RenderUnderlay.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/RenderUnderlay.cs index 0d0b552..253bb40 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/RenderUnderlay.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/RenderUnderlay.cs @@ -8,7 +8,6 @@ using Sanchez.Processing.Models; using Sanchez.Processing.Services.Underlay; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using SixLabors.ImageSharp; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/SaveStitchedImage.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/SaveStitchedImage.cs index 9964936..7cd4c58 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/SaveStitchedImage.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/SaveStitchedImage.cs @@ -7,7 +7,6 @@ using Sanchez.Processing.Models; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using ShellProgressBar; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/ShouldWrite.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/ShouldWrite.cs index b7a3d96..72fa24d 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/ShouldWrite.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/ShouldWrite.cs @@ -7,7 +7,6 @@ using Sanchez.Processing.Models; using Sanchez.Processing.Services; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using ShellProgressBar; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/StitchImages.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/StitchImages.cs index 9011a02..a36350b 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/StitchImages.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/StitchImages.cs @@ -4,7 +4,6 @@ using Sanchez.Processing.Models; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using SixLabors.ImageSharp; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Stitch/ToEquirectangular.cs b/Sanchez.Workflow/Steps/Equirectangular/Stitch/ToEquirectangular.cs index f9b4257..e82547b 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Stitch/ToEquirectangular.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Stitch/ToEquirectangular.cs @@ -7,7 +7,6 @@ using Sanchez.Processing.Models.Angles; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using SixLabors.ImageSharp; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Timelapse/CreateActivities.cs b/Sanchez.Workflow/Steps/Equirectangular/Timelapse/CreateActivities.cs index 5bbb2e9..1f11e7d 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Timelapse/CreateActivities.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Timelapse/CreateActivities.cs @@ -7,7 +7,6 @@ using Sanchez.Processing.Models.Projections; using Sanchez.Processing.Services; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using WorkflowCore.Interface; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Timelapse/InitialiseProgressBar.cs b/Sanchez.Workflow/Steps/Equirectangular/Timelapse/InitialiseProgressBar.cs index 2b00665..71182e7 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Timelapse/InitialiseProgressBar.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Timelapse/InitialiseProgressBar.cs @@ -4,7 +4,6 @@ using JetBrains.Annotations; using Sanchez.Processing.Helpers; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using ShellProgressBar; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Timelapse/PrepareTimeIntervals.cs b/Sanchez.Workflow/Steps/Equirectangular/Timelapse/PrepareTimeIntervals.cs index 1d686f6..2282e66 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Timelapse/PrepareTimeIntervals.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Timelapse/PrepareTimeIntervals.cs @@ -5,7 +5,6 @@ using Sanchez.Processing.Models; using Sanchez.Processing.Models.Projections; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; diff --git a/Sanchez.Workflow/Steps/Equirectangular/Timelapse/SetTargetTimestamp.cs b/Sanchez.Workflow/Steps/Equirectangular/Timelapse/SetTargetTimestamp.cs index 51e3d85..d987f6c 100644 --- a/Sanchez.Workflow/Steps/Equirectangular/Timelapse/SetTargetTimestamp.cs +++ b/Sanchez.Workflow/Steps/Equirectangular/Timelapse/SetTargetTimestamp.cs @@ -1,6 +1,5 @@ using System; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using WorkflowCore.Interface; using WorkflowCore.Models; diff --git a/Sanchez.Workflow/Steps/Geostationary/ApplyHaze.cs b/Sanchez.Workflow/Steps/Geostationary/ApplyHaze.cs index 41dce23..0a23d0c 100644 --- a/Sanchez.Workflow/Steps/Geostationary/ApplyHaze.cs +++ b/Sanchez.Workflow/Steps/Geostationary/ApplyHaze.cs @@ -2,7 +2,6 @@ using Sanchez.Processing.ImageProcessing.ShadeEdges; using Sanchez.Processing.Models; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; diff --git a/Sanchez.Workflow/Steps/Geostationary/RenderUnderlay.cs b/Sanchez.Workflow/Steps/Geostationary/RenderUnderlay.cs index 6bf2615..62f31ab 100644 --- a/Sanchez.Workflow/Steps/Geostationary/RenderUnderlay.cs +++ b/Sanchez.Workflow/Steps/Geostationary/RenderUnderlay.cs @@ -7,7 +7,6 @@ using Sanchez.Processing.Models.Projections; using Sanchez.Processing.Services.Underlay; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using SixLabors.ImageSharp; diff --git a/Sanchez.Workflow/Steps/Geostationary/Reprojected/ToGeostationary.cs b/Sanchez.Workflow/Steps/Geostationary/Reprojected/ToGeostationary.cs index fc68f79..6f3c733 100644 --- a/Sanchez.Workflow/Steps/Geostationary/Reprojected/ToGeostationary.cs +++ b/Sanchez.Workflow/Steps/Geostationary/Reprojected/ToGeostationary.cs @@ -5,7 +5,6 @@ using Sanchez.Processing.ImageProcessing.Underlay; using Sanchez.Processing.Models; using Sanchez.Workflow.Extensions; -using Sanchez.Workflow.Models; using Sanchez.Workflow.Models.Data; using Sanchez.Workflow.Models.Steps; using SixLabors.ImageSharp; diff --git a/Sanchez/Bootstrapper.cs b/Sanchez/Bootstrapper.cs index 5f464ad..4dd75a4 100644 --- a/Sanchez/Bootstrapper.cs +++ b/Sanchez/Bootstrapper.cs @@ -7,15 +7,14 @@ using Ardalis.GuardClauses; using CommandLine; using Extend; +using FluentValidation; using Microsoft.Extensions.DependencyInjection; -using Microsoft.VisualBasic.CompilerServices; using Sanchez.Models.CommandLine; using Sanchez.Services; using Sanchez.Validators; using Newtonsoft.Json; using Newtonsoft.Json.Converters; using Sanchez.Processing.Models; -using Sanchez.Shared.Exceptions; using Sanchez.Workflow.Services; using Serilog; @@ -48,7 +47,7 @@ internal static async Task Main(params string[] args) .WithParsed(options => renderOptions = ParseGeostationaryOptions(options)); // Exit if required options not present - if (parser.Tag == ParserResultType.NotParsed) throw new ValidationException(); + if (parser.Tag == ParserResultType.NotParsed) throw new ValidationException("Unable to parse command line"); Guard.Against.Null(renderOptions, nameof(renderOptions)); // Disable stdout if required @@ -71,7 +70,7 @@ internal static async Task Main(params string[] args) { Log.Warning(e, "No image processing possible"); - if (e.Result != null) e.Result.Errors.ForEach(error => Console.Error.WriteLine(error.ErrorMessage)); + if (e.Errors != null) e.Errors.ForEach(error => Console.Error.WriteLine(error.ErrorMessage)); else if (!string.IsNullOrEmpty(e.Message)) await Console.Error.WriteLineAsync(e.Message); return -1; @@ -107,7 +106,7 @@ private static RenderOptions ParseGeostationaryOptions(GeostationaryOptions opti var validation = new GeostationaryOptionsValidator().Validate(options); if (validation.IsValid) return OptionsParser.Populate(options); - throw new ValidationException(validation); + throw new ValidationException(validation.Errors); } private static RenderOptions ParseReprojectOptions(EquirectangularOptions options) @@ -115,7 +114,7 @@ private static RenderOptions ParseReprojectOptions(EquirectangularOptions option var validation = new EquirectangularOptionsValidator().Validate(options); if (validation.IsValid) return OptionsParser.Populate(options); - throw new ValidationException(validation); + throw new ValidationException(validation.Errors); } private static void LogOptions(RenderOptions options) diff --git a/Sanchez/Builders/LoggingBuilder.cs b/Sanchez/Builders/LoggingBuilder.cs index dbf5f6b..15f555e 100644 --- a/Sanchez/Builders/LoggingBuilder.cs +++ b/Sanchez/Builders/LoggingBuilder.cs @@ -1,8 +1,10 @@ using System.IO; using Microsoft.Extensions.DependencyInjection; using Sanchez.Processing.Helpers; +using Sanchez.Services; using Sentry; using Serilog; +using Serilog.Core; using Serilog.Events; using Serilog.Exceptions; @@ -19,16 +21,16 @@ public static IServiceCollection ConfigureLogging(this IServiceCollection servic .MinimumLevel.Debug() .MinimumLevel.Override("WorkflowCore", LogEventLevel.Information) .WriteTo.RollingFile(Path.Combine(PathHelper.LogPath(), "sanchez-{Date}.log"), LogEventLevel.Information, fileSizeLimitBytes: 5 * 1024 * 1024) - .WriteTo.Sentry(o => + .WriteTo.ValidationWrapper(c => c.Sentry(o => { o.MinimumEventLevel = LogEventLevel.Error; o.Dsn = new Dsn("https://2d7d5615b9f249f7890e275774e9eaf6@o456714.ingest.sentry.io/5450049"); - }) + }), LogEventLevel.Debug, new LoggingLevelSwitch()) .Enrich.FromLogContext() .Enrich.WithExceptionDetails(); - + if (consoleLogging) builder.WriteTo.Console(); - + Log.Logger = builder.CreateLogger(); services.AddLogging(serviceBuilder => serviceBuilder.AddSerilog(dispose: true)); diff --git a/Sanchez/Sanchez.csproj b/Sanchez/Sanchez.csproj index 5b216ed..dc4f183 100644 --- a/Sanchez/Sanchez.csproj +++ b/Sanchez/Sanchez.csproj @@ -10,7 +10,7 @@ - 1701;1702;S3925 + 1701;1702;S3925;S3881 diff --git a/Sanchez/Services/ValidationExceptionWrapper.cs b/Sanchez/Services/ValidationExceptionWrapper.cs new file mode 100644 index 0000000..81ff63f --- /dev/null +++ b/Sanchez/Services/ValidationExceptionWrapper.cs @@ -0,0 +1,70 @@ +using System; +using System.Linq; +using FluentValidation; +using Serilog; +using Serilog.Configuration; +using Serilog.Core; +using Serilog.Events; + +namespace Sanchez.Services +{ + /// + /// Wraps log entries resulting from , reporting + /// as warning rather than error. This ensure that spurious Sentry.io reports aren't + /// made for user error. + /// + internal class ValidationExceptionWrapper : ILogEventSink, IDisposable + { + readonly ILogEventSink _wrappedSink; + + public ValidationExceptionWrapper(ILogEventSink wrappedSink) => _wrappedSink = wrappedSink; + + public void Emit(LogEvent logEvent) + { + // Report validation exceptions are warnings + if (logEvent.Exception is ValidationException) + { + var boosted = new LogEvent( + logEvent.Timestamp, + LogEventLevel.Warning, + logEvent.Exception, + logEvent.MessageTemplate, + logEvent.Properties + .Select(kvp => new LogEventProperty(kvp.Key, kvp.Value))); + + _wrappedSink.Emit(boosted); + } + else + { + _wrappedSink.Emit(logEvent); + } + } + + public void Dispose() + { + (_wrappedSink as IDisposable)?.Dispose(); + } + } + + static class LoggerSinkConfigurationExtensions + { + /// + /// Wraps log entries resulting from , reporting + /// as warning rather than error. This ensure that spurious Sentry.io reports aren't + /// made for user error. + /// + internal static LoggerConfiguration ValidationWrapper( + this LoggerSinkConfiguration lsc, + Action writeTo, + LogEventLevel minimumLevel, + LoggingLevelSwitch levelSwitch) + { + return LoggerSinkConfiguration.Wrap( + lsc, + wrapped => new ValidationExceptionWrapper(wrapped), + writeTo, + minimumLevel, + levelSwitch); + } + } +} \ No newline at end of file diff --git a/Sanchez/Validators/CommandLineOptionsValidator.cs b/Sanchez/Validators/CommandLineOptionsValidator.cs index 3ed8b6a..3bd9ccb 100644 --- a/Sanchez/Validators/CommandLineOptionsValidator.cs +++ b/Sanchez/Validators/CommandLineOptionsValidator.cs @@ -33,7 +33,6 @@ protected CommandLineOptionsValidator() .When(o => o.Timestamp != null) .WithMessage("Interval must be a positive value."); - // TODO test this RuleFor(o => o.IntervalMinutes) .GreaterThanOrEqualTo(o => o.ToleranceMinutes) .When(o => o.Timestamp != null)