refactor: Use IConsole instead of Console

pull/108/head
Robert Dailey 2 years ago
parent 956f370350
commit 3a5e1f0c5e

@ -1,6 +1,7 @@
using System.Reactive.Linq;
using System.Reactive.Subjects;
using System.Text;
using CliFx.Infrastructure;
namespace Common;
@ -9,6 +10,7 @@ namespace Common;
/// </summary>
public sealed class ProgressBar //: IProgress<double>
{
private readonly IConsole _console;
private readonly TimeSpan _animationInterval = TimeSpan.FromSeconds(1.0 / 8);
private const string Animation = @"|/-\";
private int _animationIndex;
@ -17,12 +19,14 @@ public sealed class ProgressBar //: IProgress<double>
public IObserver<float> ReportProgress => _reportProgress;
public string Description { get; set; } = "";
public ProgressBar()
public ProgressBar(IConsole console)
{
_console = console;
// A progress bar is only for temporary display in a console window.
// If the console output is redirected to a file, draw nothing.
// Otherwise, we'll end up with a lot of garbage in the target file.
if (!Console.IsOutputRedirected)
if (!_console.IsOutputRedirected)
{
_reportProgress.Sample(_animationInterval)
.Select(CalculateText)
@ -43,7 +47,7 @@ public sealed class ProgressBar //: IProgress<double>
return $"[{progressBlocks}{progressBlocksUnfilled}] {percent,3}% {currentAnimationFrame} {Description}";
}
private static void UpdateText(int previousTextLength, string text)
private void UpdateText(int previousTextLength, string text)
{
var outputBuilder = new StringBuilder();
outputBuilder.Append('\r');
@ -56,6 +60,6 @@ public sealed class ProgressBar //: IProgress<double>
outputBuilder.Append(' ', lengthDifference);
}
Console.Write(outputBuilder);
_console.Output.Write(outputBuilder);
}
}

@ -50,6 +50,7 @@ internal class CompositionRoot : ICompositionRoot
builder.RegisterModule<CacheAutofacModule>();
builder.RegisterType<CacheStoragePath>().As<ICacheStoragePath>();
builder.RegisterType<RepoUpdater>().As<IRepoUpdater>();
builder.RegisterType<ProgressBar>();
ConfigurationRegistrations(builder);
CommandRegistrations(builder);

@ -2,6 +2,12 @@ using Autofac;
namespace Recyclarr;
/// <remarks>
/// This class exists to make unit testing easier. Many methods for ILifetimeScope are extension
/// methods and make unit testing more difficult.
/// This class wraps Autofac to make it more
/// "mockable".
/// </remarks>
public interface IServiceLocatorProxy : IDisposable
{
ILifetimeScope Container { get; }

@ -1,3 +1,4 @@
using CliFx.Infrastructure;
using Common.Extensions;
using Serilog;
using TrashLib.Extensions;
@ -12,17 +13,20 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
private readonly ICachePersister _cache;
private readonly IGuideProcessor _guideProcessor;
private readonly IPersistenceProcessor _persistenceProcessor;
private readonly IConsole _console;
public CustomFormatUpdater(
ILogger log,
ICachePersister cache,
IGuideProcessor guideProcessor,
IPersistenceProcessor persistenceProcessor)
IPersistenceProcessor persistenceProcessor,
IConsole console)
{
Log = log;
_cache = cache;
_guideProcessor = guideProcessor;
_persistenceProcessor = persistenceProcessor;
_console = console;
}
private ILogger Log { get; }
@ -133,7 +137,7 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
private bool ValidateGuideDataAndCheckShouldProceed(RadarrConfiguration config)
{
Console.WriteLine("");
_console.Output.WriteLine("");
if (_guideProcessor.DuplicatedCustomFormats.Count > 0)
{
@ -151,7 +155,7 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
}
}
Console.WriteLine("");
_console.Output.WriteLine("");
}
if (_guideProcessor.CustomFormatsNotInGuide.Count > 0)
@ -162,7 +166,7 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
"warning");
Log.Warning("{CfList}", _guideProcessor.CustomFormatsNotInGuide);
Console.WriteLine("");
_console.Output.WriteLine("");
}
var cfsWithoutQualityProfiles = _guideProcessor.ConfigData
@ -175,7 +179,7 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
Log.Debug("These custom formats will be uploaded but are not associated to a quality profile in the " +
"config file: {UnassociatedCfs}", cfsWithoutQualityProfiles);
Console.WriteLine("");
_console.Output.WriteLine("");
}
// No CFs are defined in this item, or they are all invalid. Skip this whole instance.
@ -195,7 +199,7 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
Log.Information("{CfList}", tuple);
}
Console.WriteLine("");
_console.Output.WriteLine("");
}
if (_guideProcessor.CustomFormatsWithOutdatedNames.Count > 0)
@ -209,7 +213,7 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
Log.Warning(" - '{OldName}' -> '{NewName}'", oldName, newName);
}
Console.WriteLine("");
_console.Output.WriteLine("");
}
return true;
@ -217,34 +221,34 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
private void PreviewCustomFormats()
{
Console.WriteLine("");
Console.WriteLine("=========================================================");
Console.WriteLine(" >>> Custom Formats From Guide <<< ");
Console.WriteLine("=========================================================");
Console.WriteLine("");
_console.Output.WriteLine("");
_console.Output.WriteLine("=========================================================");
_console.Output.WriteLine(" >>> Custom Formats From Guide <<< ");
_console.Output.WriteLine("=========================================================");
_console.Output.WriteLine("");
const string format = "{0,-30} {1,-35}";
Console.WriteLine(format, "Custom Format", "Trash ID");
Console.WriteLine(string.Concat(Enumerable.Repeat('-', 1 + 30 + 35)));
_console.Output.WriteLine(format, "Custom Format", "Trash ID");
_console.Output.WriteLine(string.Concat(Enumerable.Repeat('-', 1 + 30 + 35)));
foreach (var cf in _guideProcessor.ProcessedCustomFormats)
{
Console.WriteLine(format, cf.Name, cf.TrashId);
_console.Output.WriteLine(format, cf.Name, cf.TrashId);
}
Console.WriteLine("");
Console.WriteLine("=========================================================");
Console.WriteLine(" >>> Quality Profile Assignments & Scores <<< ");
Console.WriteLine("=========================================================");
Console.WriteLine("");
_console.Output.WriteLine("");
_console.Output.WriteLine("=========================================================");
_console.Output.WriteLine(" >>> Quality Profile Assignments & Scores <<< ");
_console.Output.WriteLine("=========================================================");
_console.Output.WriteLine("");
const string profileFormat = "{0,-18} {1,-20} {2,-8}";
Console.WriteLine(profileFormat, "Profile", "Custom Format", "Score");
Console.WriteLine(string.Concat(Enumerable.Repeat('-', 2 + 18 + 20 + 8)));
_console.Output.WriteLine(profileFormat, "Profile", "Custom Format", "Score");
_console.Output.WriteLine(string.Concat(Enumerable.Repeat('-', 2 + 18 + 20 + 8)));
foreach (var (profileName, scoreMap) in _guideProcessor.ProfileScores)
{
Console.WriteLine(profileFormat, profileName, "", "");
_console.Output.WriteLine(profileFormat, profileName, "", "");
foreach (var (customFormat, score) in scoreMap.Mapping)
{
@ -258,10 +262,10 @@ internal class CustomFormatUpdater : ICustomFormatUpdater
continue;
}
Console.WriteLine(profileFormat, "", matchingCf.Name, score);
_console.Output.WriteLine(profileFormat, "", matchingCf.Name, score);
}
}
Console.WriteLine("");
_console.Output.WriteLine("");
}
}

@ -1,3 +1,4 @@
using CliFx.Infrastructure;
using Serilog;
using TrashLib.Radarr.Config;
using TrashLib.Radarr.QualityDefinition.Api;
@ -8,14 +9,19 @@ namespace TrashLib.Radarr.QualityDefinition;
internal class RadarrQualityDefinitionUpdater : IRadarrQualityDefinitionUpdater
{
private readonly IQualityDefinitionService _api;
private readonly IConsole _console;
private readonly IRadarrQualityDefinitionGuideParser _parser;
public RadarrQualityDefinitionUpdater(ILogger logger, IRadarrQualityDefinitionGuideParser parser,
IQualityDefinitionService api)
public RadarrQualityDefinitionUpdater(
ILogger logger,
IRadarrQualityDefinitionGuideParser parser,
IQualityDefinitionService api,
IConsole console)
{
Log = logger;
_parser = parser;
_api = api;
_console = console;
}
private ILogger Log { get; }
@ -53,19 +59,19 @@ internal class RadarrQualityDefinitionUpdater : IRadarrQualityDefinitionUpdater
await ProcessQualityDefinition(selectedQuality);
}
private static void PrintQualityPreview(IEnumerable<RadarrQualityData> quality)
private void PrintQualityPreview(IEnumerable<RadarrQualityData> quality)
{
Console.WriteLine("");
_console.Output.WriteLine("");
const string format = "{0,-20} {1,-10} {2,-15} {3,-15}";
Console.WriteLine(format, "Quality", "Min", "Max", "Preferred");
Console.WriteLine(format, "-------", "---", "---", "---------");
_console.Output.WriteLine(format, "Quality", "Min", "Max", "Preferred");
_console.Output.WriteLine(format, "-------", "---", "---", "---------");
foreach (var q in quality)
{
Console.WriteLine(format, q.Name, q.AnnotatedMin, q.AnnotatedMax, q.AnnotatedPreferred);
_console.Output.WriteLine(format, q.Name, q.AnnotatedMin, q.AnnotatedMax, q.AnnotatedPreferred);
}
Console.WriteLine("");
_console.Output.WriteLine("");
}
private async Task ProcessQualityDefinition(IEnumerable<RadarrQualityData> guideQuality)
@ -99,7 +105,7 @@ internal class RadarrQualityDefinitionUpdater : IRadarrQualityDefinitionUpdater
continue;
}
// Not using the original list again, so it's OK to modify the definition reftype objects in-place.
// Not using the original list again, so it's OK to modify the definition ref type objects in-place.
entry.MinSize = qualityData.MinForApi;
entry.MaxSize = qualityData.MaxForApi;
entry.PreferredSize = qualityData.PreferredForApi;

@ -1,4 +1,5 @@
using System.Text.RegularExpressions;
using CliFx.Infrastructure;
using Serilog;
using TrashLib.Sonarr.Api;
using TrashLib.Sonarr.Api.Objects;
@ -9,15 +10,20 @@ namespace TrashLib.Sonarr.QualityDefinition;
internal class SonarrQualityDefinitionUpdater : ISonarrQualityDefinitionUpdater
{
private readonly ISonarrApi _api;
private readonly IConsole _console;
private readonly ISonarrQualityDefinitionGuideParser _parser;
private readonly Regex _regexHybrid = new(@"720|1080", RegexOptions.Compiled);
public SonarrQualityDefinitionUpdater(ILogger logger, ISonarrQualityDefinitionGuideParser parser,
ISonarrApi api)
public SonarrQualityDefinitionUpdater(
ILogger logger,
ISonarrQualityDefinitionGuideParser parser,
ISonarrApi api,
IConsole console)
{
Log = logger;
_parser = parser;
_api = api;
_console = console;
}
private ILogger Log { get; }
@ -87,19 +93,19 @@ internal class SonarrQualityDefinitionUpdater : ISonarrQualityDefinitionUpdater
return hybrid;
}
private static void PrintQualityPreview(IEnumerable<SonarrQualityData> quality)
private void PrintQualityPreview(IEnumerable<SonarrQualityData> quality)
{
Console.WriteLine("");
_console.Output.WriteLine("");
const string format = "{0,-20} {1,-10} {2,-15}";
Console.WriteLine(format, "Quality", "Min", "Max");
Console.WriteLine(format, "-------", "---", "---");
_console.Output.WriteLine(format, "Quality", "Min", "Max");
_console.Output.WriteLine(format, "-------", "---", "---");
foreach (var q in quality)
{
Console.WriteLine(format, q.Name, q.AnnotatedMin, q.AnnotatedMax);
_console.Output.WriteLine(format, q.Name, q.AnnotatedMin, q.AnnotatedMax);
}
Console.WriteLine("");
_console.Output.WriteLine("");
}
private async Task ProcessQualityDefinition(IEnumerable<SonarrQualityData> guideQuality)
@ -132,7 +138,7 @@ internal class SonarrQualityDefinitionUpdater : ISonarrQualityDefinitionUpdater
continue;
}
// Not using the original list again, so it's OK to modify the definition reftype objects in-place.
// Not using the original list again, so it's OK to modify the definition ref type objects in-place.
entry.MinSize = qualityData.MinForApi;
entry.MaxSize = qualityData.MaxForApi;
newQuality.Add(entry);

@ -1,4 +1,5 @@
using System.Reactive.Linq;
using CliFx.Infrastructure;
using Common.Extensions;
using Serilog;
using TrashLib.ExceptionTypes;
@ -15,6 +16,7 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater
private readonly ISonarrApi _api;
private readonly ISonarrCompatibility _compatibility;
private readonly IReleaseProfileFilterPipeline _pipeline;
private readonly IConsole _console;
private readonly ISonarrGuideService _guide;
private readonly ILogger _log;
@ -23,13 +25,15 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater
ISonarrGuideService guide,
ISonarrApi api,
ISonarrCompatibility compatibility,
IReleaseProfileFilterPipeline pipeline)
IReleaseProfileFilterPipeline pipeline,
IConsole console)
{
_log = logger;
_guide = guide;
_api = api;
_compatibility = compatibility;
_pipeline = pipeline;
_console = console;
}
public async Task Process(bool isPreview, SonarrConfiguration config)
@ -56,7 +60,7 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater
if (isPreview)
{
Utils.PrintTermsAndScores(selectedProfile);
PrintTermsAndScores(selectedProfile);
continue;
}
@ -66,6 +70,59 @@ public class ReleaseProfileUpdater : IReleaseProfileUpdater
await ProcessReleaseProfiles(filteredProfiles);
}
private void PrintTermsAndScores(ReleaseProfileData profile)
{
void PrintPreferredTerms(string title, IReadOnlyCollection<PreferredTermData> preferredTerms)
{
if (preferredTerms.Count <= 0)
{
return;
}
_console.Output.WriteLine($" {title}:");
foreach (var (score, terms) in preferredTerms)
{
foreach (var term in terms)
{
_console.Output.WriteLine($" {score,-10} {term}");
}
}
_console.Output.WriteLine("");
}
void PrintTerms(string title, IReadOnlyCollection<TermData> terms)
{
if (terms.Count == 0)
{
return;
}
_console.Output.WriteLine($" {title}:");
foreach (var term in terms)
{
_console.Output.WriteLine($" {term}");
}
_console.Output.WriteLine("");
}
_console.Output.WriteLine("");
_console.Output.WriteLine(profile.Name);
_console.Output.WriteLine(" Include Preferred when Renaming?");
_console.Output.WriteLine(" " +
(profile.IncludePreferredWhenRenaming ? "YES" : "NO"));
_console.Output.WriteLine("");
PrintTerms("Must Contain", profile.Required);
PrintTerms("Must Not Contain", profile.Ignored);
PrintPreferredTerms("Preferred", profile.Preferred);
_console.Output.WriteLine("");
}
private async Task ProcessReleaseProfiles(
List<(ReleaseProfileData Profile, IReadOnlyCollection<string> Tags)> profilesAndTags)
{

@ -1,57 +0,0 @@
namespace TrashLib.Sonarr.ReleaseProfile;
public static class Utils
{
public static void PrintTermsAndScores(ReleaseProfileData profile)
{
static void PrintPreferredTerms(string title, IReadOnlyCollection<PreferredTermData> preferredTerms)
{
if (preferredTerms.Count <= 0)
{
return;
}
Console.WriteLine($" {title}:");
foreach (var (score, terms) in preferredTerms)
{
foreach (var term in terms)
{
Console.WriteLine($" {score,-10} {term}");
}
}
Console.WriteLine("");
}
static void PrintTerms(string title, IReadOnlyCollection<TermData> terms)
{
if (terms.Count == 0)
{
return;
}
Console.WriteLine($" {title}:");
foreach (var term in terms)
{
Console.WriteLine($" {term}");
}
Console.WriteLine("");
}
Console.WriteLine("");
Console.WriteLine(profile.Name);
Console.WriteLine(" Include Preferred when Renaming?");
Console.WriteLine(" " +
(profile.IncludePreferredWhenRenaming ? "YES" : "NO"));
Console.WriteLine("");
PrintTerms("Must Contain", profile.Required);
PrintTerms("Must Not Contain", profile.Ignored);
PrintPreferredTerms("Preferred", profile.Preferred);
Console.WriteLine("");
}
}

@ -9,15 +9,18 @@ public class GitRepositoryFactory : IGitRepositoryFactory
private readonly IFileUtilities _fileUtils;
private readonly IRepositoryStaticWrapper _staticWrapper;
private readonly Func<string, IGitRepository> _repoFactory;
private readonly Func<ProgressBar> _progressBarFactory;
public GitRepositoryFactory(
IFileUtilities fileUtils,
IRepositoryStaticWrapper staticWrapper,
Func<string, IGitRepository> repoFactory)
Func<string, IGitRepository> repoFactory,
Func<ProgressBar> progressBarFactory)
{
_fileUtils = fileUtils;
_staticWrapper = staticWrapper;
_repoFactory = repoFactory;
_progressBarFactory = progressBarFactory;
}
public IGitRepository CreateAndCloneIfNeeded(string repoUrl, string repoPath, string branch)
@ -36,10 +39,8 @@ public class GitRepositoryFactory : IGitRepositoryFactory
{
_fileUtils.DeleteReadOnlyDirectory(repoPath);
var progress = new ProgressBar
{
Description = "Fetching guide data\n"
};
var progress = _progressBarFactory();
progress.Description = "Fetching guide data\n";
_staticWrapper.Clone(repoUrl, repoPath, new CloneOptions
{

Loading…
Cancel
Save