feat: add app settings manager to do the reading and writing

This commit is contained in:
Stevan Freeborn
2025-03-14 22:02:22 -05:00
parent e9b9f7fc13
commit 414e712f51
14 changed files with 229 additions and 214 deletions
+1
View File
@@ -11,6 +11,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
<InternalsVisibleTo Include="$(AssemblyName).Tests" /> <InternalsVisibleTo Include="$(AssemblyName).Tests" />
</ItemGroup> </ItemGroup>
@@ -2,35 +2,28 @@ namespace AltGen.Console.Tests.Unit;
public class AddConfigCommandTests : IDisposable public class AddConfigCommandTests : IDisposable
{ {
readonly Mock<IFileSystem> _fileSystem = new(); readonly Mock<IAppSettingsManager> _mockSettingsManager = new();
readonly TestConsole _testConsole = new(); readonly TestConsole _testConsole = new();
readonly AddConfigCommand _sut; readonly AddConfigCommand _sut;
public AddConfigCommandTests() public AddConfigCommandTests()
{ {
_sut = new AddConfigCommand(_testConsole, _fileSystem.Object); _sut = new AddConfigCommand(_testConsole, _mockSettingsManager.Object);
} }
[Fact] [Fact]
public async Task ExecuteAsync_WhenSettingsDoNotExist_ItShouldCreateSettings() public async Task ExecuteAsync_WhenSettingsDoNotExist_ItShouldCreateSettings()
{ {
var testSettingsPath = "appsettings.json";
var expectedAppSettings = new AppSettings([ var expectedAppSettings = new AppSettings([
new("provider", "key", false) new("provider", "key", false)
]); ]);
var expectedJson = JsonSerializer.Serialize(expectedAppSettings, JsonOptions.Default);
_mockSettingsManager
_fileSystem .Setup(static x => x.AppSettingsExist())
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>()))
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.File.Exists(It.IsAny<string>()))
.Returns(false); .Returns(false);
var commandSettings = new AddConfigCommand.Settings(_fileSystem.Object) var commandSettings = new AddConfigCommand.Settings()
{ {
Provider = "provider", Provider = "provider",
Key = "key", Key = "key",
@@ -40,39 +33,36 @@ public class AddConfigCommandTests : IDisposable
result.Should().Be(0); result.Should().Be(0);
_fileSystem _mockSettingsManager.Verify(
.Verify( static x => x.SaveAppSettingsAsync(It.Is<AppSettings>(
x => x.File.WriteAllTextAsync(testSettingsPath, expectedJson, default), static x => x.Providers[0].Provider == "provider" &&
Times.Once x.Providers[0].Key == "key" &&
); x.Providers[0].Default == false
)),
Times.Once
);
} }
[Fact] [Fact]
public async Task ExecuteAsync_WhenSettingsExist_ItShouldUpdateSettings() public async Task ExecuteAsync_WhenSettingsExist_ItShouldUpdateSettings()
{ {
var testSettingsPath = "appsettings.json";
var existingAppSettings = new AppSettings([ var existingAppSettings = new AppSettings([
new("existing", "existing", false) new("existing", "existing", false)
]); ]);
var existingJson = JsonSerializer.Serialize(existingAppSettings, JsonOptions.Default);
var expectedAppSettings = new AppSettings([ var expectedAppSettings = new AppSettings([
new("existing", "key", true) new("existing", "key", true)
]); ]);
var expectedJson = JsonSerializer.Serialize(expectedAppSettings, JsonOptions.Default);
_fileSystem _mockSettingsManager
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>())) .Setup(static x => x.AppSettingsExist())
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.File.Exists(It.IsAny<string>()))
.Returns(true); .Returns(true);
_fileSystem _mockSettingsManager
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default)) .Setup(static x => x.GetAppSettingsAsync())
.ReturnsAsync(existingJson); .ReturnsAsync(existingAppSettings);
var commandSettings = new AddConfigCommand.Settings(_fileSystem.Object) var commandSettings = new AddConfigCommand.Settings()
{ {
Provider = "existing", Provider = "existing",
Key = "key", Key = "key",
@@ -83,39 +73,14 @@ public class AddConfigCommandTests : IDisposable
result.Should().Be(0); result.Should().Be(0);
_fileSystem _mockSettingsManager.Verify(
.Verify( static x => x.SaveAppSettingsAsync(It.Is<AppSettings>(
x => x.File.WriteAllTextAsync(testSettingsPath, expectedJson, default), static x => x.Providers[0].Provider == "existing" &&
Times.Once x.Providers[0].Key == "key" &&
); x.Providers[0].Default == true
} )),
Times.Once
[Fact] );
public async Task ExecuteAsync_WhenSettingsExistButCanNotBeDeserialized_ItShouldThrow()
{
var testSettingsPath = "appsettings.json";
_fileSystem
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>()))
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.File.Exists(It.IsAny<string>()))
.Returns(true);
_fileSystem
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default))
.ReturnsAsync("null");
var commandSettings = new AddConfigCommand.Settings(_fileSystem.Object)
{
Provider = "provider",
Key = "key",
};
var act = async () => await _sut.ExecuteAsync(null!, commandSettings);
await act.Should().ThrowAsync<ConfigException>();
} }
public void Dispose() public void Dispose()
@@ -0,0 +1,100 @@
namespace AltGen.Console.Tests.Unit;
public class AppSettingsManagerTests
{
readonly Mock<IFileSystem> _mockFileSystem = new();
readonly AppSettingsManager _sut;
public AppSettingsManagerTests()
{
_mockFileSystem
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>()))
.Returns("path");
_sut = new AppSettingsManager(_mockFileSystem.Object);
}
[Fact]
public void AppSettingsExist_WhenSettingsDoNotExist_ItShouldReturnFalse()
{
_mockFileSystem
.Setup(static x => x.Path.Exists(It.IsAny<string>()))
.Returns(false);
var result = _sut.AppSettingsExist();
result.Should().BeFalse();
}
[Fact]
public void AppSettingsExist_WhenSettingsExist_ItShouldReturnTrue()
{
_mockFileSystem
.Setup(static x => x.Path.Exists(It.IsAny<string>()))
.Returns(true);
var result = _sut.AppSettingsExist();
result.Should().BeTrue();
}
[Fact]
public async Task GetAppSettingsAsync_WhenSettingsExist_ItShouldReturnSettings()
{
var testSettings = new AppSettings([
new("provider", "key", false)
]);
var json = JsonSerializer.Serialize(testSettings, JsonOptions.Default);
_mockFileSystem
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default))
.ReturnsAsync(json);
var result = await _sut.GetAppSettingsAsync();
result.Should().BeEquivalentTo(testSettings);
}
[Fact]
public async Task GetAppSettingsAsync_WhenDeserializingSettingsIsNull_ItShouldReturnEmptySettings()
{
_mockFileSystem
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default))
.ReturnsAsync("null");
var result = await _sut.GetAppSettingsAsync();
result.Should().BeEquivalentTo(new AppSettings([]));
}
[Fact]
public async Task GetAppSettingsAsync_WhenSettingsDoNotExist_ItShouldThrow()
{
_mockFileSystem
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default))
.ThrowsAsync(new FileNotFoundException());
var action = _sut.GetAppSettingsAsync;
await action.Should().ThrowAsync<FileNotFoundException>();
}
[Fact]
public async Task SaveAppSettingsAsync_WhenCalled_ItShouldSaveSettings()
{
_mockFileSystem
.Setup(static x => x.File.WriteAllTextAsync(It.IsAny<string>(), It.IsAny<string>(), default))
.Returns(Task.CompletedTask);
var testSettings = new AppSettings([
new("provider", "key", false)
]);
var json = JsonSerializer.Serialize(testSettings, JsonOptions.Default);
await _sut.SaveAppSettingsAsync(testSettings);
_mockFileSystem.Verify(x => x.File.WriteAllTextAsync(It.IsAny<string>(), json, default), Times.Once);
}
}
@@ -2,14 +2,12 @@ namespace AltGen.Console.Tests.Unit;
public class AppSettingsTests public class AppSettingsTests
{ {
readonly Mock<IFileSystem> _fileSystemMock = new();
[Fact] [Fact]
public void AddOrUpdateProvider_WhenProviderDoesNotExist_ItShouldAddProvider() public void AddOrUpdateProvider_WhenProviderDoesNotExist_ItShouldAddProvider()
{ {
var providerSettings = new ProviderSettings("provider", "key", true); var providerSettings = new ProviderSettings("provider", "key", true);
var commandSettings = new AddConfigCommand.Settings(_fileSystemMock.Object) var commandSettings = new AddConfigCommand.Settings()
{ {
Provider = providerSettings.Provider, Provider = providerSettings.Provider,
Key = providerSettings.Key, Key = providerSettings.Key,
@@ -29,7 +27,7 @@ public class AppSettingsTests
var providerSettings = new ProviderSettings("provider", "key", true); var providerSettings = new ProviderSettings("provider", "key", true);
var existingProviderSettings = new ProviderSettings("provider", "key", false); var existingProviderSettings = new ProviderSettings("provider", "key", false);
var commandSettings = new AddConfigCommand.Settings(_fileSystemMock.Object) var commandSettings = new AddConfigCommand.Settings()
{ {
Provider = providerSettings.Provider, Provider = providerSettings.Provider,
Key = providerSettings.Key, Key = providerSettings.Key,
@@ -48,7 +46,7 @@ public class AppSettingsTests
var providerSettings = new ProviderSettings("claude", "key", true); var providerSettings = new ProviderSettings("claude", "key", true);
var existingProviderSettings = new ProviderSettings("gemini", "key", true); var existingProviderSettings = new ProviderSettings("gemini", "key", true);
var commandSettings = new AddConfigCommand.Settings(_fileSystemMock.Object) var commandSettings = new AddConfigCommand.Settings()
{ {
Provider = providerSettings.Provider, Provider = providerSettings.Provider,
Key = providerSettings.Key, Key = providerSettings.Key,
@@ -69,7 +67,7 @@ public class AppSettingsTests
{ {
var existingProviderSettings = new ProviderSettings("provider", "key", true); var existingProviderSettings = new ProviderSettings("provider", "key", true);
var commandSettings = new RemoveConfigCommand.Settings(_fileSystemMock.Object) var commandSettings = new RemoveConfigCommand.Settings()
{ {
Provider = existingProviderSettings.Provider, Provider = existingProviderSettings.Provider,
}; };
@@ -2,26 +2,20 @@ namespace AltGen.Console.Tests.Unit;
public class ListConfigCommandTests : IDisposable public class ListConfigCommandTests : IDisposable
{ {
readonly Mock<IFileSystem> _fileSystem = new(); readonly Mock<IAppSettingsManager> _mockSettingsManager = new();
readonly TestConsole _testConsole = new(); readonly TestConsole _testConsole = new();
readonly ListConfigCommand _sut; readonly ListConfigCommand _sut;
public ListConfigCommandTests() public ListConfigCommandTests()
{ {
_sut = new ListConfigCommand(_testConsole, _fileSystem.Object); _sut = new ListConfigCommand(_testConsole, _mockSettingsManager.Object);
} }
[Fact] [Fact]
public async Task ExecuteAsync_WhenSettingsDoNotExist_ItShouldOutputNoSettings() public async Task ExecuteAsync_WhenSettingsDoNotExist_ItShouldOutputNoSettings()
{ {
var testSettingsPath = "appsettings.json"; _mockSettingsManager
.Setup(static x => x.AppSettingsExist())
_fileSystem
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>()))
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.File.Exists(It.IsAny<string>()))
.Returns(false); .Returns(false);
var result = await _sut.ExecuteAsync(null!); var result = await _sut.ExecuteAsync(null!);
@@ -37,23 +31,17 @@ public class ListConfigCommandTests : IDisposable
[Fact] [Fact]
public async Task ExecuteAsync_WhenSettingsExist_ItShouldOutputSettings() public async Task ExecuteAsync_WhenSettingsExist_ItShouldOutputSettings()
{ {
var testSettingsPath = "appsettings.json";
var testSettings = new AppSettings([ var testSettings = new AppSettings([
new("provider", "key", false) new("provider", "key", false)
]); ]);
var testSettingsJson = JsonSerializer.Serialize(testSettings, JsonOptions.Default);
_fileSystem _mockSettingsManager
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>())) .Setup(static x => x.AppSettingsExist())
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.File.Exists(It.IsAny<string>()))
.Returns(true); .Returns(true);
_fileSystem _mockSettingsManager
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default)) .Setup(static x => x.GetAppSettingsAsync())
.ReturnsAsync(testSettingsJson); .ReturnsAsync(testSettings);
var result = await _sut.ExecuteAsync(null!); var result = await _sut.ExecuteAsync(null!);
@@ -68,23 +56,17 @@ public class ListConfigCommandTests : IDisposable
[Fact] [Fact]
public async Task ExecuteAsync_WhenSettingsExistAndDefault_ItShouldOutputSettings() public async Task ExecuteAsync_WhenSettingsExistAndDefault_ItShouldOutputSettings()
{ {
var testSettingsPath = "appsettings.json";
var testSettings = new AppSettings([ var testSettings = new AppSettings([
new("provider", "key", true) new("provider", "key", true)
]); ]);
var testSettingsJson = JsonSerializer.Serialize(testSettings, JsonOptions.Default);
_fileSystem _mockSettingsManager
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>())) .Setup(static x => x.AppSettingsExist())
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.File.Exists(It.IsAny<string>()))
.Returns(true); .Returns(true);
_fileSystem _mockSettingsManager
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default)) .Setup(static x => x.GetAppSettingsAsync())
.ReturnsAsync(testSettingsJson); .ReturnsAsync(testSettings);
var result = await _sut.ExecuteAsync(null!); var result = await _sut.ExecuteAsync(null!);
@@ -96,28 +78,6 @@ public class ListConfigCommandTests : IDisposable
.Contain("provider key (default)"); .Contain("provider key (default)");
} }
[Fact]
public async Task ExecuteAsync_WhenSettingsCanNotBeDeserialized_ItShouldThrowConfigException()
{
var testSettingsPath = "appsettings.json";
_fileSystem
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>()))
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.File.Exists(It.IsAny<string>()))
.Returns(true);
_fileSystem
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default))
.ReturnsAsync("null");
var action = async () => await _sut.ExecuteAsync(null!);
await action.Should().ThrowAsync<ConfigException>();
}
public void Dispose() public void Dispose()
{ {
_testConsole.Dispose(); _testConsole.Dispose();
@@ -2,29 +2,23 @@ namespace AltGen.Console.Tests.Unit;
public class RemoveConfigCommandTests : IDisposable public class RemoveConfigCommandTests : IDisposable
{ {
readonly Mock<IFileSystem> _fileSystem = new(); readonly Mock<IAppSettingsManager> _mockSettingsManager = new();
readonly TestConsole _testConsole = new(); readonly TestConsole _testConsole = new();
readonly RemoveConfigCommand _sut; readonly RemoveConfigCommand _sut;
public RemoveConfigCommandTests() public RemoveConfigCommandTests()
{ {
_sut = new RemoveConfigCommand(_fileSystem.Object, _testConsole); _sut = new RemoveConfigCommand(_testConsole, _mockSettingsManager.Object);
} }
[Fact] [Fact]
public async Task ExecuteAsync_WhenSettingsDoNotExist_ItShouldThrow() public async Task ExecuteAsync_WhenSettingsDoNotExist_ItShouldThrow()
{ {
var testSettingsPath = "appsettings.json"; _mockSettingsManager
.Setup(static x => x.AppSettingsExist())
_fileSystem
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>()))
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.Path.Exists(It.IsAny<string>()))
.Returns(false); .Returns(false);
var commandSettings = new RemoveConfigCommand.Settings(_fileSystem.Object) var commandSettings = new RemoveConfigCommand.Settings()
{ {
Provider = "provider", Provider = "provider",
}; };
@@ -38,23 +32,17 @@ public class RemoveConfigCommandTests : IDisposable
[Fact] [Fact]
public async Task ExecuteAsync_WhenProviderDoesNotExist_ItShouldDoNothing() public async Task ExecuteAsync_WhenProviderDoesNotExist_ItShouldDoNothing()
{ {
var testSettingsPath = "appsettings.json";
var testSettings = new AppSettings([]); var testSettings = new AppSettings([]);
var testSettingsJson = JsonSerializer.Serialize(testSettings, JsonOptions.Default);
_fileSystem _mockSettingsManager
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>())) .Setup(static x => x.AppSettingsExist())
.Returns(testSettingsPath);
_fileSystem
.Setup(static x => x.Path.Exists(It.IsAny<string>()))
.Returns(true); .Returns(true);
_fileSystem _mockSettingsManager
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default)) .Setup(static x => x.GetAppSettingsAsync())
.ReturnsAsync(testSettingsJson); .ReturnsAsync(testSettings);
var commandSettings = new RemoveConfigCommand.Settings(_fileSystem.Object) var commandSettings = new RemoveConfigCommand.Settings()
{ {
Provider = "provider", Provider = "provider",
}; };
@@ -63,35 +51,27 @@ public class RemoveConfigCommandTests : IDisposable
result.Should().Be(0); result.Should().Be(0);
_fileSystem _mockSettingsManager.Verify(x => x.SaveAppSettingsAsync(testSettings), Times.Once);
.Verify(
x => x.File.WriteAllTextAsync(testSettingsPath, testSettingsJson, default),
Times.Once
);
} }
[Fact] [Fact]
public async Task ExecuteAsync_WhenProviderExists_ItShouldRemoveProviderFromSettings() public async Task ExecuteAsync_WhenProviderExists_ItShouldRemoveProviderFromSettings()
{ {
var testSettingsPath = "appsettings.json";
var testSettings = new AppSettings([ var testSettings = new AppSettings([
new("provider", "key", false) new("provider", "key", false)
]); ]);
var testSettingsJson = JsonSerializer.Serialize(testSettings, JsonOptions.Default);
_fileSystem var expectedSettings = new AppSettings([]);
.Setup(static x => x.Path.Combine(It.IsAny<string>(), It.IsAny<string>()))
.Returns(testSettingsPath);
_fileSystem _mockSettingsManager
.Setup(static x => x.Path.Exists(It.IsAny<string>())) .Setup(static x => x.AppSettingsExist())
.Returns(true); .Returns(true);
_fileSystem _mockSettingsManager
.Setup(static x => x.File.ReadAllTextAsync(It.IsAny<string>(), default)) .Setup(static x => x.GetAppSettingsAsync())
.ReturnsAsync(testSettingsJson); .ReturnsAsync(testSettings);
var commandSettings = new RemoveConfigCommand.Settings(_fileSystem.Object) var commandSettings = new RemoveConfigCommand.Settings()
{ {
Provider = "provider", Provider = "provider",
}; };
@@ -100,14 +80,7 @@ public class RemoveConfigCommandTests : IDisposable
result.Should().Be(0); result.Should().Be(0);
var expectedSettings = new AppSettings([]); _mockSettingsManager.Verify(x => x.SaveAppSettingsAsync(expectedSettings), Times.Once);
var expectedSettingsJson = JsonSerializer.Serialize(expectedSettings, JsonOptions.Default);
_fileSystem
.Verify(
x => x.File.WriteAllTextAsync(testSettingsPath, expectedSettingsJson, default),
Times.Once
);
} }
public void Dispose() public void Dispose()
+1
View File
@@ -17,6 +17,7 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
<InternalsVisibleTo Include="$(AssemblyName).Tests" /> <InternalsVisibleTo Include="$(AssemblyName).Tests" />
</ItemGroup> </ItemGroup>
+7 -18
View File
@@ -2,16 +2,14 @@ namespace AltGen.Console.Config;
sealed class AddConfigCommand( sealed class AddConfigCommand(
IAnsiConsole console, IAnsiConsole console,
IFileSystem fileSystem IAppSettingsManager settingsManager
) : AsyncCommand<AddConfigCommand.Settings> ) : AsyncCommand<AddConfigCommand.Settings>
{ {
readonly IAnsiConsole _console = console; readonly IAnsiConsole _console = console;
readonly IFileSystem _fileSystem = fileSystem; readonly IAppSettingsManager _settingsManager = settingsManager;
public class Settings(IFileSystem filesystem) : CommandSettings public class Settings : CommandSettings
{ {
readonly IFileSystem _fileSystem = filesystem;
[CommandArgument(1, "<provider>")] [CommandArgument(1, "<provider>")]
[Description("The provider to configure.")] [Description("The provider to configure.")]
public string Provider { get; init; } = string.Empty; public string Provider { get; init; } = string.Empty;
@@ -23,32 +21,23 @@ sealed class AddConfigCommand(
[CommandOption("-d|--default")] [CommandOption("-d|--default")]
[Description("Set the provider as the default.")] [Description("Set the provider as the default.")]
public bool Default { get; init; } public bool Default { get; init; }
public string SettingsPath => _fileSystem.Path.Combine(AppContext.BaseDirectory, AppSettings.SettingsFileName);
} }
public override async Task<int> ExecuteAsync(CommandContext context, Settings settings) public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
{ {
var settingsExist = _fileSystem.File.Exists(settings.SettingsPath); if (_settingsManager.AppSettingsExist() is false)
if (settingsExist is false)
{ {
var appSettings = new AppSettings([ var appSettings = new AppSettings([
new(settings.Provider, settings.Key, settings.Default) new(settings.Provider, settings.Key, settings.Default)
]); ]);
await _settingsManager.SaveAppSettingsAsync(appSettings);
var json = JsonSerializer.Serialize(appSettings, JsonOptions.Default);
await _fileSystem.File.WriteAllTextAsync(settings.SettingsPath, json);
_console.MarkupLine($"[bold]{settings.Provider}[/] has been configured."); _console.MarkupLine($"[bold]{settings.Provider}[/] has been configured.");
return 0; return 0;
} }
var existingJson = await _fileSystem.File.ReadAllTextAsync(settings.SettingsPath); var existingAppSettings = await _settingsManager.GetAppSettingsAsync();
var existingAppSettings = JsonSerializer.Deserialize<AppSettings>(existingJson, JsonOptions.Default)
?? throw new ConfigException("Failed to deserialize settings.");
var updatedAppSettings = existingAppSettings.AddOrUpdateProvider(settings); var updatedAppSettings = existingAppSettings.AddOrUpdateProvider(settings);
var udpatedJson = JsonSerializer.Serialize(updatedAppSettings, JsonOptions.Default); await _settingsManager.SaveAppSettingsAsync(updatedAppSettings);
await _fileSystem.File.WriteAllTextAsync(settings.SettingsPath, udpatedJson);
_console.MarkupLine($"[bold]{settings.Provider}[/] has been configured."); _console.MarkupLine($"[bold]{settings.Provider}[/] has been configured.");
return 0; return 0;
} }
@@ -0,0 +1,30 @@
namespace AltGen.Console.Config;
class AppSettingsManager(IFileSystem fileSystem) : IAppSettingsManager
{
const string SettingsFileName = "appsettings.json";
readonly IFileSystem _fileSystem = fileSystem;
public bool AppSettingsExist()
{
return _fileSystem.Path.Exists(SettingsFileName);
}
public async Task<AppSettings> GetAppSettingsAsync()
{
var existingJson = await _fileSystem.File.ReadAllTextAsync(GetSettingsPath());
var existingAppSettings = JsonSerializer.Deserialize<AppSettings>(existingJson, JsonOptions.Default) ?? new AppSettings([]);
return existingAppSettings;
}
public async Task SaveAppSettingsAsync(AppSettings appSettings)
{
var json = JsonSerializer.Serialize(appSettings, JsonOptions.Default);
await _fileSystem.File.WriteAllTextAsync(GetSettingsPath(), json);
}
string GetSettingsPath()
{
return _fileSystem.Path.Combine(AppContext.BaseDirectory, SettingsFileName);
}
}
@@ -0,0 +1,8 @@
namespace AltGen.Console.Config;
interface IAppSettingsManager
{
bool AppSettingsExist();
Task<AppSettings> GetAppSettingsAsync();
Task SaveAppSettingsAsync(AppSettings appSettings);
}
@@ -1,25 +1,23 @@
namespace AltGen.Console.Config; namespace AltGen.Console.Config;
sealed class ListConfigCommand(IAnsiConsole console, IFileSystem fileSystem) : AsyncCommand sealed class ListConfigCommand(
IAnsiConsole console,
IAppSettingsManager settingsManager
) : AsyncCommand
{ {
readonly IAnsiConsole _console = console; readonly IAnsiConsole _console = console;
readonly IFileSystem _fileSystem = fileSystem; readonly IAppSettingsManager _settingsManager = settingsManager;
public override async Task<int> ExecuteAsync(CommandContext context) public override async Task<int> ExecuteAsync(CommandContext context)
{ {
var settingsPath = _fileSystem.Path.Combine(AppContext.BaseDirectory, AppSettings.SettingsFileName); if (_settingsManager.AppSettingsExist() is false)
var settingsExist = _fileSystem.File.Exists(settingsPath);
if (settingsExist is false)
{ {
_console.MarkupLine("No settings found."); _console.MarkupLine("No settings found.");
return 0; return 0;
} }
var settingsJson = await _fileSystem.File.ReadAllTextAsync(settingsPath); var appSettings = await _settingsManager.GetAppSettingsAsync();
var appSettings = JsonSerializer.Deserialize<AppSettings>(settingsJson, JsonOptions.Default)
?? throw new ConfigException("Failed to deserialize settings.");
foreach (var provider in appSettings.Providers) foreach (var provider in appSettings.Providers)
{ {
@@ -1,39 +1,30 @@
namespace AltGen.Console.Config; namespace AltGen.Console.Config;
sealed class RemoveConfigCommand( sealed class RemoveConfigCommand(
IFileSystem fileSystem, IAnsiConsole console,
IAnsiConsole console IAppSettingsManager settingsManager
) : AsyncCommand<RemoveConfigCommand.Settings> ) : AsyncCommand<RemoveConfigCommand.Settings>
{ {
readonly IFileSystem _fileSystem = fileSystem;
readonly IAnsiConsole _console = console; readonly IAnsiConsole _console = console;
readonly IAppSettingsManager _settingsManager = settingsManager;
public class Settings(IFileSystem fileSystem) : CommandSettings public class Settings : CommandSettings
{ {
readonly IFileSystem _fileSystem = fileSystem;
[CommandArgument(1, "<provider>")] [CommandArgument(1, "<provider>")]
[Description("The provider to remove.")] [Description("The provider to remove.")]
public string Provider { get; init; } = string.Empty; public string Provider { get; init; } = string.Empty;
public string SettingsPath => _fileSystem.Path.Combine(AppContext.BaseDirectory, AppSettings.SettingsFileName);
} }
public override async Task<int> ExecuteAsync(CommandContext context, Settings settings) public override async Task<int> ExecuteAsync(CommandContext context, Settings settings)
{ {
var exists = _fileSystem.Path.Exists(settings.SettingsPath); if (_settingsManager.AppSettingsExist() is false)
if (exists is false)
{ {
throw new ConfigException("No existing settings found."); throw new ConfigException("No existing settings found.");
} }
var settingsJson = await _fileSystem.File.ReadAllTextAsync(settings.SettingsPath); var appSettings = await _settingsManager.GetAppSettingsAsync();
var appSettings = JsonSerializer.Deserialize<AppSettings>(settingsJson, JsonOptions.Default)
?? throw new ConfigException("Failed to deserialize app settings.");
var updatedAppSettings = appSettings.RemoveProvider(settings); var updatedAppSettings = appSettings.RemoveProvider(settings);
var updatedJson = JsonSerializer.Serialize(updatedAppSettings, JsonOptions.Default); await _settingsManager.SaveAppSettingsAsync(updatedAppSettings);
await _fileSystem.File.WriteAllTextAsync(settings.SettingsPath, updatedJson);
_console.MarkupLine($"[bold]{settings.Provider}[/] has been removed."); _console.MarkupLine($"[bold]{settings.Provider}[/] has been removed.");
return 0; return 0;
} }
@@ -1,4 +1,4 @@
interface IAltGenService interface IAltGenService
{ {
Task<string> GenerateAltTextAsync(GenerateAltTextRequest req); Task<string> GenerateAltTextAsync(GenerateAltTextRequest req);
} }
+1
View File
@@ -3,6 +3,7 @@
.ConfigureServices(static (_, services) => .ConfigureServices(static (_, services) =>
{ {
services.AddSingleton<IFileSystem, FileSystem>(); services.AddSingleton<IFileSystem, FileSystem>();
services.AddSingleton<IAppSettingsManager, AppSettingsManager>();
services.AddSingleton(AnsiConsole.Console); services.AddSingleton(AnsiConsole.Console);
services.AddHttpClient<IAltGenService, AltGenService>() services.AddHttpClient<IAltGenService, AltGenService>()
.AddStandardResilienceHandler(); .AddStandardResilienceHandler();