Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ using MinimalCli;

public class HelloWorld
{
// Just decorate the method with the command attribute!
[Handler("hello")]
// Just decorate the method with the RootHandler attribute!
[RootHandler]
public void Execute(string message)
{
Console.WriteLine("Hello World! {0}", message);
Expand Down Expand Up @@ -74,6 +74,7 @@ using MinimalCli;

public class MyCommand
{
// use the handler attribute to add additional commands
[Handler("my-command")]
public void Run(string myArgument, string? myOption = null)
{
Expand Down
2 changes: 1 addition & 1 deletion src/HelloWorld/HelloWorldClass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Hello;

public class HelloWorldClass
{
[Handler("hello-world")]
[RootHandler]
public void Execute(
string message,
string option1 = "opt 1 default value",
Expand Down
5 changes: 2 additions & 3 deletions src/HelloWorld/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,8 @@
"HelloWorld": {
"commandName": "Project",
//"commandLineArgs": "-h"
"commandLineArgs": "hi -h"
//"commandLineArgs": "hi \"Hello everybody..\" --option1 \"My Option 1\" --option2 \"My Option 2\""

"commandLineArgs": "\"Hello everybody..\""
//"commandLineArgs": "\"Hello everybody..\" --option1 \"My Option 1\" --option2 \"My Option 2\""
}
}
}
9 changes: 6 additions & 3 deletions src/MinimalCli.Core/Bindings/CommandBindingFactory.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
using System.Collections.Generic;

namespace MinimalCli.Bindings;
namespace MinimalCli.Bindings;

public class CommandBindingFactory
{
Expand All @@ -11,6 +9,11 @@ public CommandBindingFactory()
this.options = [];
}

public void AddRootCommand(CommandOptions rootOptions)
{
this.options.Add(rootOptions.Command.Name, rootOptions);
}

public void AddCommandOptions(string commandName, CommandOptions options)
{
this.options.Add(commandName, options);
Expand Down
6 changes: 1 addition & 5 deletions src/MinimalCli.Core/MinimalCommandLineApp.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System.Collections.Generic;
using MinimalCli.Bindings;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand All @@ -13,19 +11,17 @@
{
private readonly string[] args;
private readonly CommandExecutionMode cmdExecutionMode;
private readonly IReadOnlyList<CommandOptions> commandOptionsCollection;

private CommandExecutorCli CliCommandExecutor => this.Services.GetRequiredService<CommandExecutorCli>();
private CommandExecutorShell ShellCommandExecutor => this.Services.GetRequiredService<CommandExecutorShell>();

internal MinimalCommandLineApp(MinimalCommandLineBuilder builder, IReadOnlyList<CommandOptions> commandOptionsCollection, string[] args)
internal MinimalCommandLineApp(MinimalCommandLineBuilder builder, string[] args)

Check warning on line 18 in src/MinimalCli.Core/MinimalCommandLineApp.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'RootCommand' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.

Check warning on line 18 in src/MinimalCli.Core/MinimalCommandLineApp.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable property 'RootCommand' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the property as nullable.
{
this.Host = builder.builder.Build();
this.commandOptionsCollection = commandOptionsCollection;
this.cmdExecutionMode = builder.cmdExecutionMode;
this.Configuration = builder.Configuration;
this.args = args;
this.RootCommand = builder.RootCommand;

Check warning on line 24 in src/MinimalCli.Core/MinimalCommandLineApp.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference assignment.

Check warning on line 24 in src/MinimalCli.Core/MinimalCommandLineApp.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference assignment.
}

internal readonly Dictionary<string, Func<ParseResult, object?>> ArgumentParsers = new();
Expand Down
19 changes: 16 additions & 3 deletions src/MinimalCli.Core/MinimalCommandLineBuilder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
using Microsoft.Extensions.Diagnostics.Metrics;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System.Collections.Generic;
using MinimalCli.Bindings;
using System.Linq;

namespace MinimalCli;

Expand Down Expand Up @@ -47,7 +47,7 @@ public TOptions TryRegisterCommandOptions<TOptions>()
return newOptions;
}

internal RootCommand RootCommand { get; } = new();
internal RootCommand? RootCommand { get; private set; }
public MinimalCommandLineApp Build()
{
// add required services
Expand All @@ -58,6 +58,19 @@ public MinimalCommandLineApp Build()
CommandBindingFactory cmdBindingFactory = new();
this.Services.AddSingleton(cmdBindingFactory);

// check if there was a generated root command
var rootOptions = commandOptionsCollection.FirstOrDefault(opt => opt.Command is RootCommand);
if (rootOptions is not null)
{
this.RootCommand = (RootCommand)rootOptions.Command;
cmdBindingFactory.AddRootCommand(rootOptions);
commandOptionsCollection.Remove(rootOptions);
ParameterBinding[] bindings = rootOptions.SetupCommandParameterBindings();
}
else
{
this.RootCommand = new();
}
// NOTES: going to have to create a factory to get the correct instance of the CommandOptions
// for the command that was invoked, inside the Handler(serivces) function, can call
// var factory = services.GetRequiredService<CommandOptionsFactory>();
Expand Down Expand Up @@ -107,7 +120,7 @@ public MinimalCommandLineApp Build()
}

// pass in args from builder
MinimalCommandLineApp app = new(this, this.commandOptionsCollection, this.args);
MinimalCommandLineApp app = new(this, this.args);

return app;
}
Expand Down
10 changes: 10 additions & 0 deletions src/MinimalCli.Core/RootHandlerAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace MinimalCli;

/// <summary>
/// Designates this method as the root handler for the command. This will become the default command if no other command matches.
/// </summary>
[AttributeUsage(AttributeTargets.Method)]
public sealed class RootHandlerAttribute : Attribute
{
public RootHandlerAttribute() { }
}
13 changes: 13 additions & 0 deletions src/MinimalCli.SourceGenerator/ArgumentBinding.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using MinimalCli.SourceGeneration.Conventions;

namespace MinimalCli.SourceGeneration;

internal record ArgumentBinding(string OriginalParameterName, string Type, string? DefaultValueConstant, bool IsCollectionType)
: ParameterBinding(OriginalParameterName, Type, DefaultValueConstant, IsCollectionType)
{
/// <summary>
/// The Argument name in title case, e.g. "myParameterName" becomes "My Parameter Name"
/// </summary>
public string ConventionalArgumentName
=> ParameterNameConversion.ToArgumentName(this.OriginalParameterName);
}
Loading