From 5647070fd32785a6e0e17a095f6f33a1bce5a0ba Mon Sep 17 00:00:00 2001 From: Stevan Freeborn <65925598+StevanFreeborn@users.noreply.github.com> Date: Sat, 8 Mar 2025 19:31:56 -0600 Subject: [PATCH] feat: wip on remove config command --- .../Unit/AddConfigCommandTests.cs | 6 ++ .../Unit/AppSettingsTests.cs | 5 ++ .../Unit/RemoveConfigCommandTests.cs | 5 ++ .../Common/HostBuilderExtensions.cs | 11 +++- .../{ConfigCommand.cs => AddConfigCommand.cs} | 56 ++----------------- src/AltGen.Console/Config/AppSettings.cs | 38 +++++++++++++ src/AltGen.Console/Config/ConfigException.cs | 5 ++ src/AltGen.Console/Config/ProviderSettings.cs | 3 + .../Config/RemoveConfigCommand.cs | 28 +++++++++- 9 files changed, 102 insertions(+), 55 deletions(-) create mode 100644 src/AltGen.Console.Tests/Unit/AddConfigCommandTests.cs create mode 100644 src/AltGen.Console.Tests/Unit/AppSettingsTests.cs create mode 100644 src/AltGen.Console.Tests/Unit/RemoveConfigCommandTests.cs rename src/AltGen.Console/Config/{ConfigCommand.cs => AddConfigCommand.cs} (58%) create mode 100644 src/AltGen.Console/Config/AppSettings.cs create mode 100644 src/AltGen.Console/Config/ConfigException.cs create mode 100644 src/AltGen.Console/Config/ProviderSettings.cs diff --git a/src/AltGen.Console.Tests/Unit/AddConfigCommandTests.cs b/src/AltGen.Console.Tests/Unit/AddConfigCommandTests.cs new file mode 100644 index 0000000..2e68060 --- /dev/null +++ b/src/AltGen.Console.Tests/Unit/AddConfigCommandTests.cs @@ -0,0 +1,6 @@ +namespace AltGen.Console.Tests.Unit; + +public class AddConfigCommandTests +{ + +} \ No newline at end of file diff --git a/src/AltGen.Console.Tests/Unit/AppSettingsTests.cs b/src/AltGen.Console.Tests/Unit/AppSettingsTests.cs new file mode 100644 index 0000000..c7a67d0 --- /dev/null +++ b/src/AltGen.Console.Tests/Unit/AppSettingsTests.cs @@ -0,0 +1,5 @@ +namespace AltGen.Console.Tests.Unit; + +public class AppSettingsTests +{ +} \ No newline at end of file diff --git a/src/AltGen.Console.Tests/Unit/RemoveConfigCommandTests.cs b/src/AltGen.Console.Tests/Unit/RemoveConfigCommandTests.cs new file mode 100644 index 0000000..2a52faf --- /dev/null +++ b/src/AltGen.Console.Tests/Unit/RemoveConfigCommandTests.cs @@ -0,0 +1,5 @@ +namespace AltGen.Console.Tests.Unit; + +public class RemoveConfigCommandTests +{ +} \ No newline at end of file diff --git a/src/AltGen.Console/Common/HostBuilderExtensions.cs b/src/AltGen.Console/Common/HostBuilderExtensions.cs index 2418f36..97c686d 100644 --- a/src/AltGen.Console/Common/HostBuilderExtensions.cs +++ b/src/AltGen.Console/Common/HostBuilderExtensions.cs @@ -7,7 +7,16 @@ static class HostBuilderExtensions var registrar = new TypeRegistrar(builder); var app = new CommandApp(registrar); - app.Configure(static c => c.AddCommand("config")); + app.Configure(static c => + { + c.PropagateExceptions(); + + c.AddBranch("config", static c => + { + c.AddCommand("add"); + c.AddCommand("remove"); + }); + }); return app; } diff --git a/src/AltGen.Console/Config/ConfigCommand.cs b/src/AltGen.Console/Config/AddConfigCommand.cs similarity index 58% rename from src/AltGen.Console/Config/ConfigCommand.cs rename to src/AltGen.Console/Config/AddConfigCommand.cs index b9e0c0a..176b38c 100644 --- a/src/AltGen.Console/Config/ConfigCommand.cs +++ b/src/AltGen.Console/Config/AddConfigCommand.cs @@ -1,19 +1,9 @@ - -using Microsoft.Extensions.Configuration; - namespace AltGen.Console.Config; -// TODO: We should refactor this so that -// we have a config add and a config remove command -// the config add will have basically the same code -// as below but the config remove will just -// accept a provider identifier and remove it - -sealed class ConfigCommand( +sealed class AddConfigCommand( IAnsiConsole console, - IFileSystem fileSystem, - IConfiguration config -) : AsyncCommand + IFileSystem fileSystem +) : AsyncCommand { static readonly JsonSerializerOptions JsonOptions = new() { @@ -23,7 +13,6 @@ sealed class ConfigCommand( }; readonly IAnsiConsole _console = console; readonly IFileSystem _fileSystem = fileSystem; - readonly IConfiguration _config = config; public class Settings(IFileSystem filesystem) : CommandSettings { @@ -63,47 +52,10 @@ sealed class ConfigCommand( var existingJson = await _fileSystem.File.ReadAllTextAsync(settings.SettingsPath); var existingAppSettings = JsonSerializer.Deserialize(existingJson, JsonOptions) ?? throw new ConfigException("Failed to deserialize settings."); - var updatedAppSettings = existingAppSettings.Update(settings); + var updatedAppSettings = existingAppSettings.AddOrUpdateProvider(settings); var udpatedJson = JsonSerializer.Serialize(updatedAppSettings, JsonOptions); await _fileSystem.File.WriteAllTextAsync(settings.SettingsPath, udpatedJson); _console.MarkupLine($"[bold]{settings.Provider}[/] has been configured."); return 0; } -} - -record AppSettings(ProviderSettings[] Providers) -{ - public AppSettings Update(ConfigCommand.Settings settings) - { - var updatedProviders = Providers.Select(p => - { - if (p.Provider == settings.Provider) - { - return p with { Key = settings.Key, Default = settings.Default }; - } - - if (p.Provider != settings.Provider && settings.Default) - { - return p with { Default = false }; - } - - return p; - }); - - var provider = Providers.FirstOrDefault(p => p.Provider == settings.Provider); - - if (provider is null) - { - var newProvider = new ProviderSettings(settings.Provider, settings.Key, settings.Default); - return this with { Providers = [.. updatedProviders, newProvider] }; - } - - return this with { Providers = [.. updatedProviders] }; - } -} - -record ProviderSettings(string Provider, string Key, bool Default); - -class ConfigException(string message) : Exception(message) -{ } \ No newline at end of file diff --git a/src/AltGen.Console/Config/AppSettings.cs b/src/AltGen.Console/Config/AppSettings.cs new file mode 100644 index 0000000..9967e99 --- /dev/null +++ b/src/AltGen.Console/Config/AppSettings.cs @@ -0,0 +1,38 @@ +namespace AltGen.Console.Config; + +record AppSettings(ProviderSettings[] Providers) +{ + public AppSettings AddOrUpdateProvider(AddConfigCommand.Settings settings) + { + var updatedProviders = Providers.Select(p => + { + if (p.Provider == settings.Provider) + { + return p with { Key = settings.Key, Default = settings.Default }; + } + + if (p.Provider != settings.Provider && settings.Default) + { + return p with { Default = false }; + } + + return p; + }); + + var provider = Providers.FirstOrDefault(p => p.Provider == settings.Provider); + + if (provider is null) + { + var newProvider = new ProviderSettings(settings.Provider, settings.Key, settings.Default); + return this with { Providers = [.. updatedProviders, newProvider] }; + } + + return this with { Providers = [.. updatedProviders] }; + } + + public AppSettings RemoveProvider(RemoveConfigCommand.Settings settings) + { + var updatedProviders = Providers.Where(p => p.Provider != settings.Provider); + return this with { Providers = [.. updatedProviders] }; + } +} \ No newline at end of file diff --git a/src/AltGen.Console/Config/ConfigException.cs b/src/AltGen.Console/Config/ConfigException.cs new file mode 100644 index 0000000..418272e --- /dev/null +++ b/src/AltGen.Console/Config/ConfigException.cs @@ -0,0 +1,5 @@ +namespace AltGen.Console.Config; + +class ConfigException(string message) : Exception(message) +{ +} \ No newline at end of file diff --git a/src/AltGen.Console/Config/ProviderSettings.cs b/src/AltGen.Console/Config/ProviderSettings.cs new file mode 100644 index 0000000..acec697 --- /dev/null +++ b/src/AltGen.Console/Config/ProviderSettings.cs @@ -0,0 +1,3 @@ +namespace AltGen.Console.Config; + +record ProviderSettings(string Provider, string Key, bool Default); diff --git a/src/AltGen.Console/Config/RemoveConfigCommand.cs b/src/AltGen.Console/Config/RemoveConfigCommand.cs index b645230..47fdd8f 100644 --- a/src/AltGen.Console/Config/RemoveConfigCommand.cs +++ b/src/AltGen.Console/Config/RemoveConfigCommand.cs @@ -1,16 +1,40 @@ namespace AltGen.Console.Config; -sealed class RemoveConfigCommand() : AsyncCommand +sealed class RemoveConfigCommand( + IFileSystem fileSystem, + IAnsiConsole console +) : AsyncCommand { - public class Settings : CommandSettings + readonly IFileSystem _fileSystem = fileSystem; + readonly IAnsiConsole _console = console; + + public class Settings(IFileSystem fileSystem) : CommandSettings { + readonly IFileSystem _fileSystem = fileSystem; + [CommandArgument(1, "")] [Description("The provider to remove.")] public string Provider { get; init; } = string.Empty; + + public string SettingsPath => _fileSystem.Path.Combine(AppContext.BaseDirectory, "appsettings.json"); } public override async Task ExecuteAsync(CommandContext context, Settings settings) { + var exists = _fileSystem.Path.Exists(settings.SettingsPath); + + if (exists is false) + { + _console.MarkupLine("[bold]No existing settings found.[/]"); + return 1; + } + + var settingsJson = await _fileSystem.File.ReadAllTextAsync(settings.SettingsPath); + var appSettings = JsonSerializer.Deserialize(settingsJson) ?? throw new ConfigException("Failed to deserialize app settings."); + var updatedAppSettings = appSettings.RemoveProvider(settings); + var updatedJson = JsonSerializer.Serialize(updatedAppSettings); + await _fileSystem.File.WriteAllTextAsync(settings.SettingsPath, updatedJson); + _console.MarkupLine($"[bold]{settings.Provider}[/] has been removed."); return 0; } } \ No newline at end of file