From 6f0aecac94a4ff1c3a2077f96eeb5c7f2e45455a Mon Sep 17 00:00:00 2001 From: Dave Walker Date: Wed, 21 Aug 2024 17:03:10 +0100 Subject: [PATCH] Added command line help to the lookup tool --- .../CommandLine/CommandLineOptionType.cs | 1 + .../Interfaces/ICommandLineParser.cs | 13 +++ .../Interfaces/IHelpGenerator.cs | 9 ++ .../CommandLine/CommandLineParser.cs | 25 ++++- .../Logic/HelpTabulator.cs | 43 +++++++++ .../MusicCatalogue.LookupTool.csproj | 7 +- src/MusicCatalogue.LookupTool/Program.cs | 94 ++++++++++--------- 7 files changed, 145 insertions(+), 47 deletions(-) create mode 100644 src/MusicCatalogue.Entities/Interfaces/ICommandLineParser.cs create mode 100644 src/MusicCatalogue.Entities/Interfaces/IHelpGenerator.cs create mode 100644 src/MusicCatalogue.LookupTool/Logic/HelpTabulator.cs diff --git a/src/MusicCatalogue.Entities/CommandLine/CommandLineOptionType.cs b/src/MusicCatalogue.Entities/CommandLine/CommandLineOptionType.cs index e9de84d..1d2eb32 100644 --- a/src/MusicCatalogue.Entities/CommandLine/CommandLineOptionType.cs +++ b/src/MusicCatalogue.Entities/CommandLine/CommandLineOptionType.cs @@ -3,6 +3,7 @@ public enum CommandLineOptionType { Unknown, + Help, Lookup, Import, Export, diff --git a/src/MusicCatalogue.Entities/Interfaces/ICommandLineParser.cs b/src/MusicCatalogue.Entities/Interfaces/ICommandLineParser.cs new file mode 100644 index 0000000..002e5e6 --- /dev/null +++ b/src/MusicCatalogue.Entities/Interfaces/ICommandLineParser.cs @@ -0,0 +1,13 @@ +using MusicCatalogue.Entities.CommandLine; + +namespace MusicCatalogue.Entities.Interfaces +{ + public interface ICommandLineParser + { + void Add(CommandLineOptionType optionType, bool isOperation, string name, string shortName, string description, int minimumNumberOfValues, int maximumNumberOfValues); + List? GetValues(CommandLineOptionType optionType); + bool IsPresent(CommandLineOptionType optionType); + void Help(); + void Parse(IEnumerable args); + } +} \ No newline at end of file diff --git a/src/MusicCatalogue.Entities/Interfaces/IHelpGenerator.cs b/src/MusicCatalogue.Entities/Interfaces/IHelpGenerator.cs new file mode 100644 index 0000000..ebf86da --- /dev/null +++ b/src/MusicCatalogue.Entities/Interfaces/IHelpGenerator.cs @@ -0,0 +1,9 @@ +using MusicCatalogue.Entities.CommandLine; + +namespace MusicCatalogue.Entities.Interfaces +{ + public interface IHelpGenerator + { + void Generate(IEnumerable options); + } +} diff --git a/src/MusicCatalogue.Logic/CommandLine/CommandLineParser.cs b/src/MusicCatalogue.Logic/CommandLine/CommandLineParser.cs index 5f0cd17..b6d8ad1 100644 --- a/src/MusicCatalogue.Logic/CommandLine/CommandLineParser.cs +++ b/src/MusicCatalogue.Logic/CommandLine/CommandLineParser.cs @@ -1,12 +1,19 @@ using MusicCatalogue.Entities.CommandLine; using MusicCatalogue.Entities.Exceptions; +using MusicCatalogue.Entities.Interfaces; namespace MusicCatalogue.Logic.CommandLine { - public class CommandLineParser + public class CommandLineParser : ICommandLineParser { private readonly List _options = new List(); private readonly Dictionary _values = new Dictionary(); + private readonly IHelpGenerator? _helpGenerator = null; + + public CommandLineParser() { } + + public CommandLineParser(IHelpGenerator generator) + => _helpGenerator = generator; /// /// Add an option to the available command line options @@ -70,6 +77,14 @@ public void Parse(IEnumerable args) CheckForSingleOperation(); } + /// + /// Return true if a command line option has been specified + /// + /// + /// + public bool IsPresent(CommandLineOptionType optionType) + => _values.ContainsKey(optionType); + /// /// Return the valus for the specified option type /// @@ -79,7 +94,7 @@ public void Parse(IEnumerable args) { List? values = null; - if (_values.ContainsKey(optionType)) + if (IsPresent(optionType)) { values = _values[optionType].Values; } @@ -87,6 +102,12 @@ public void Parse(IEnumerable args) return values; } + /// + /// Generate help + /// + public void Help() + => _helpGenerator?.Generate(_options); + /// /// Check that each supplied option has sufficient values with it /// diff --git a/src/MusicCatalogue.LookupTool/Logic/HelpTabulator.cs b/src/MusicCatalogue.LookupTool/Logic/HelpTabulator.cs new file mode 100644 index 0000000..965e2da --- /dev/null +++ b/src/MusicCatalogue.LookupTool/Logic/HelpTabulator.cs @@ -0,0 +1,43 @@ +using MusicCatalogue.Entities.CommandLine; +using MusicCatalogue.Entities.Interfaces; +using Spectre.Console; + +namespace MusicCatalogue.LookupTool.Logic +{ + + public class HelpTabulator : IHelpGenerator + { + /// + /// Tabulate a collection of available command line options + /// + /// + public void Generate(IEnumerable options) + { + var table = new Table(); + + table.AddColumn("Option"); + table.AddColumn("Short Form"); + table.AddColumn("Min Values"); + table.AddColumn("Max Values"); + table.AddColumn("Description"); + + foreach (var option in options) + { + var rowData = new string[] { + GetCellData(option.Name), + GetCellData(option.ShortName), + GetCellData(option.MinimumNumberOfValues.ToString()), + GetCellData(option.MaximumNumberOfValues.ToString()), + GetCellData(option.Description) + }; + + table.AddRow(rowData); + } + + AnsiConsole.Write(table); + } + + private string GetCellData(string value) + => $"[white]{value}[/]"; + } +} diff --git a/src/MusicCatalogue.LookupTool/MusicCatalogue.LookupTool.csproj b/src/MusicCatalogue.LookupTool/MusicCatalogue.LookupTool.csproj index b3584da..eef4ef3 100644 --- a/src/MusicCatalogue.LookupTool/MusicCatalogue.LookupTool.csproj +++ b/src/MusicCatalogue.LookupTool/MusicCatalogue.LookupTool.csproj @@ -3,9 +3,9 @@ Exe net8.0 - 1.24.0.0 - 1.24.0.0 - 1.24.0 + 1.25.0.0 + 1.25.0.0 + 1.25.0 enable enable false @@ -26,6 +26,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/src/MusicCatalogue.LookupTool/Program.cs b/src/MusicCatalogue.LookupTool/Program.cs index 3e868ad..ed4a83f 100644 --- a/src/MusicCatalogue.LookupTool/Program.cs +++ b/src/MusicCatalogue.LookupTool/Program.cs @@ -13,7 +13,7 @@ using System.Diagnostics; using System.Reflection; -namespace MusicCatalogue.LookupPoC +namespace MusicCatalogue.LookupTool { public static class Program { @@ -24,60 +24,70 @@ public static class Program /// public static async Task Main(string[] args) { - // Read the application settings - MusicApplicationSettings? settings = new MusicCatalogueConfigReader().Read("appsettings.json"); - - // Configure the log file - FileLogger logger = new FileLogger(); - logger.Initialise(settings!.LogFile, settings.MinimumLogLevel); - - // Get the version number and application title - Assembly assembly = Assembly.GetExecutingAssembly(); - FileVersionInfo info = FileVersionInfo.GetVersionInfo(assembly.Location); - var title = $"Music Catalogue Lookup Tool v{info.FileVersion}"; - - // Log the startup messages - Console.WriteLine($"{title}\n"); - logger.LogMessage(Severity.Info, new string('=', 80)); - logger.LogMessage(Severity.Info, title); try { // Parse the command line - CommandLineParser parser = new(); + CommandLineParser parser = new(new HelpTabulator()); + parser.Add(CommandLineOptionType.Help, true, "--help", "-h", "Show command line help", 0, 0); parser.Add(CommandLineOptionType.Lookup, true, "--lookup", "-l", "Lookup an album and display its details", 3, 3); parser.Add(CommandLineOptionType.Import, true, "--import", "-i", "Import data from a CSV format file", 1, 1); parser.Add(CommandLineOptionType.Export, true, "--export", "-e", "Export the collection or equipment register to a CSV file or Excel Workbook", 2, 2); parser.Parse(args); - // Configure the business logic factory - var context = new MusicCatalogueDbContextFactory().CreateDbContext(Array.Empty()); - var factory = new MusicCatalogueFactory(context); - - // If this is a lookup, look up the album details - var values = parser.GetValues(CommandLineOptionType.Lookup); - if (values != null) + // If help's been requested, show help and exit + if (parser.IsPresent(CommandLineOptionType.Help)) { - // Determine the target for new albums (catalogue or wish list) and lookup the album - var targetType = (TargetType)Enum.Parse(typeof(TargetType), values[2]); - var storeInWishList = targetType == TargetType.wishlist; - await new AlbumLookup(logger, factory, settings!).LookupAlbum(values[0], values[1], storeInWishList); + parser.Help(); } - - // If this is an import, import data from the specified CSV file - values = parser.GetValues(CommandLineOptionType.Import); - if (values != null) + else { - new DataImport(logger, factory).Import(values[0]); - } + // Read the application settings + MusicApplicationSettings? settings = new MusicCatalogueConfigReader().Read("appsettings.json"); - // If this is an export, export the collection to the specified file - values = parser.GetValues(CommandLineOptionType.Export); - if (values != null) - { - var exportType = (ExportType)Enum.Parse(typeof(ExportType), values[0]); - IDataExporter exporter = exportType == ExportType.music ? new CatalogueExporter(logger, factory) : new EquipmentExporter(logger, factory); - exporter.Export(values[1]); + // Configure the log file + FileLogger logger = new FileLogger(); + logger.Initialise(settings!.LogFile, settings.MinimumLogLevel); + + // Get the version number and application title + Assembly assembly = Assembly.GetExecutingAssembly(); + FileVersionInfo info = FileVersionInfo.GetVersionInfo(assembly.Location); + var title = $"Music Catalogue Lookup Tool v{info.FileVersion}"; + + // Log the startup messages + Console.WriteLine($"{title}\n"); + logger.LogMessage(Severity.Info, new string('=', 80)); + logger.LogMessage(Severity.Info, title); + + // Configure the business logic factory + var context = new MusicCatalogueDbContextFactory().CreateDbContext(Array.Empty()); + var factory = new MusicCatalogueFactory(context); + + // If this is a lookup, look up the album details + var values = parser.GetValues(CommandLineOptionType.Lookup); + if (values != null) + { + // Determine the target for new albums (catalogue or wish list) and lookup the album + var targetType = (TargetType)Enum.Parse(typeof(TargetType), values[2]); + var storeInWishList = targetType == TargetType.wishlist; + await new AlbumLookup(logger, factory, settings!).LookupAlbum(values[0], values[1], storeInWishList); + } + + // If this is an import, import data from the specified CSV file + values = parser.GetValues(CommandLineOptionType.Import); + if (values != null) + { + new DataImport(logger, factory).Import(values[0]); + } + + // If this is an export, export the collection to the specified file + values = parser.GetValues(CommandLineOptionType.Export); + if (values != null) + { + var exportType = (ExportType)Enum.Parse(typeof(ExportType), values[0]); + IDataExporter exporter = exportType == ExportType.music ? new CatalogueExporter(logger, factory) : new EquipmentExporter(logger, factory); + exporter.Export(values[1]); + } } } catch (Exception ex)