Skip to content

Commit 1e179b3

Browse files
committed
Feat: Add logging and improve command instance creation
Introduced logging using Microsoft.Extensions.Logging for better diagnostics during command handling. Refactored instance creation logic into a new `TryCreateCommandInstance` method to improve readability and error handling. Added null checks and fallback behavior to handle scenarios where services or commands cannot be resolved.
1 parent 0179530 commit 1e179b3

File tree

2 files changed

+44
-13
lines changed

2 files changed

+44
-13
lines changed

src/CodeOfChaos.CliArgsParser/CliParser.cs

+43-13
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Imports
33
// ---------------------------------------------------------------------------------------------------------------------
44
using Microsoft.Extensions.DependencyInjection;
5+
using Microsoft.Extensions.Logging;
6+
using System.Diagnostics.CodeAnalysis;
57
using System.Text.RegularExpressions;
68

79
namespace CodeOfChaos.CliArgsParser;
@@ -11,17 +13,19 @@ namespace CodeOfChaos.CliArgsParser;
1113
public partial class CliParser : ICliParser {
1214
public required Lazy<IServiceProvider>? ServiceProvider { get; init; }
1315
public required ICommandProvider CommandProvider { get; init; }
14-
15-
[GeneratedRegex(@"\s+")] private static partial Regex FindEmptySpacesRegex { get; }
1616

17+
private ILogger<CliParser>? Logger => ServiceProvider?.Value.GetService<ILogger<CliParser>>();
18+
19+
[GeneratedRegex(@"\s+")] private static partial Regex FindEmptySpacesRegex { get; }
20+
1721
// -----------------------------------------------------------------------------------------------------------------
1822
// Methods
1923
// -----------------------------------------------------------------------------------------------------------------
20-
internal CliParser() { }
24+
internal CliParser() {}
2125
public static CliParserBuilder CreateBuilder() {
2226
return new CliParserBuilder();
2327
}
24-
28+
2529
public ValueTask ExecuteAsync(string[] args, CancellationToken ct = default) => ExecuteAsync(ArgsInputHelper.ToOneLine(args), ct);
2630
public async ValueTask ExecuteAsync(string input, CancellationToken ct = default) {
2731
input = input.Replace("\\\"", "\"");
@@ -32,21 +36,47 @@ public async ValueTask ExecuteAsync(string input, CancellationToken ct = default
3236
await Task.WhenAll(tasks);
3337
return;
3438
}
35-
39+
3640
string[] tokens = FindEmptySpacesRegex.Split(input);
3741
string commandName = tokens[0];
3842
string parameterInput = string.Join(" ", tokens.Skip(1));
3943

40-
if (!CommandProvider.TryGetCommand(commandName, out Type? commandType)) throw new Exception("no Command found");
41-
42-
ICliCommand? command = ServiceProvider is not null
43-
? (ICliCommand?)ActivatorUtilities.CreateInstance(ServiceProvider.Value, commandType)
44-
: Activator.CreateInstance(commandType) as ICliCommand;
44+
if (!CommandProvider.TryGetCommand(commandName, out Type? commandType)) {
45+
if (Logger is null) throw new Exception($"Could not find command by name {commandName}");
46+
Logger.LogWarning("Could not find command by name {name}", commandName);
47+
return;
48+
}
49+
50+
if (!TryCreateCommandInstance(commandType, out ICliCommand? command)) {
51+
if (Logger is null) throw new Exception($"Could not instantiate command with type {commandType.FullName}");
52+
Logger.LogWarning("Could not instantiate command with type {type}", commandType.FullName);
53+
return;
54+
55+
}
4556

46-
47-
if (command is null) throw new Exception("no Command found");
48-
4957
ParameterDictionary parameterDictionary = ParameterDictionary.FromString(parameterInput);
5058
await command.StartExecution(parameterDictionary, ct);
5159
}
60+
61+
private bool TryCreateCommandInstance(Type commandType, [NotNullWhen(true)] out ICliCommand? command) {
62+
try {
63+
if (ServiceProvider is null) {
64+
object? directInstance = Activator.CreateInstance(commandType);
65+
command = directInstance as ICliCommand;
66+
return command is not null;
67+
}
68+
69+
IServiceScope scope = ServiceProvider.Value.CreateScope();
70+
object diInstance = ActivatorUtilities.CreateInstance(scope.ServiceProvider, commandType);
71+
command = diInstance as ICliCommand;
72+
return command is not null;
73+
}
74+
catch (Exception e) {
75+
// Throw if we cant log
76+
if (Logger is null) throw;
77+
Logger.LogWarning(e, "Failed to create command instance");
78+
command = null;
79+
return false;
80+
}
81+
}
5282
}

src/CodeOfChaos.CliArgsParser/CodeOfChaos.CliArgsParser.csproj

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
<ItemGroup>
3535
<PackageReference Include="CodeOfChaos.Extensions" Version="0.66.1" />
3636
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="9.0.5" />
37+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="9.0.5" />
3738
</ItemGroup>
3839

3940
</Project>

0 commit comments

Comments
 (0)