-
Notifications
You must be signed in to change notification settings - Fork 401
Add generic host builder pattern [WIP] #919
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
Currently, I'm looking for the recommended way to add CommandLineHost.CreateDefaultBuilder()
.ConfigureCommandLineDefaults((CommandLineBuilder builder) =>
{
builder.AddCommand(rootCmd);
}) |
@NikiforovAll you probably figured most of this out, but for anyone else. Since the CommandLineBuilder is created before configuration, it already has a root command with the default (exe, help, version). AddCommand adds what you intend as a subcommand, which is not what is intended. I see two solutions. @jonsequitur needs to weigh in: 1 Create a 'ReplaceRootCommand' method that wipes out everything except configuration in the builder and forces the new root command, or otherwise be able to set the RootCommand after the builder is created. (See Note below) I think we should only do the first if we need to, but I think we need to. I'm just getting my head around this, but isn't this code likely:
Note It isn't exactly this simple because creating the root prior to configuring the builder means the root isn't configured correctly. So I think we may need a pattern like:
Where ConfigureRoot is either separate or inline code, but is where you add your options/subcommands. In StarFruit, I would expect this to be in a library method for all defaults, or when there is configuration of either StarFruit or System.CommandLine, it would look like:
Of course, someone may have a more clever idea. |
It makes sense to allow the |
CommandBuilder has room for an empty constructor. Would you then suggest a SetCommand method? (as opposed to a mutable Command) RootCommandBuilder looks like it would take a breaking change, but if SetCommand is present and cleans out the builder, maybe it doesn't matter. Unless SetCommand should fail if Command is not null.
|
Something like this would probably match the existing patterns for these things: builder.UseRootCommand(new RootCommand()) This way it's still chainable and you could also, if you wanted, put the whole command structure in there: commandLineBuilder.UseRootCommand(new RootCommand
{
new Command("apple"),
new Command("banana")
}) |
There are some other issues I'd like to look at later, but the problematic code is:
The builder has a command at this point. The philosophy is that the builder always has a command. So, does the following work:
This is what I have in mind for StarFruit (with whatever name we land on)
I believe everything within the command is mutable, although replacing the command in the builder is not possible, for reasons that I think remain valid. Do you see any issues with this approach? |
I think using the mutability of a |
I am out of time this morning, but this is how far I got on your test:
|
@KathleenDollard Sorry for not communicating the status of current PR. Currently, I'm waiting for design and final thoughts in #918 (+ #918 (comment)) This happens because it is only possible to access I stumbled on the cyclic dependency between I see two possible solutions:
// step 1
Parser parser = commandLineBuilder.Build();
ParseResult parseResult = parser.Parse(Args);
// access invocation from parseResult
host.ConfigureServices(services =>
{
services.TryAddSingleton<InvocationContext>(invocation);
//...
});
// step 2 inject IHost to CommandLineBuilder right before execution
// src\System.CommandLine.Hosting\DefaultBuilder\CommandLineExecutorService.cs:36
public async Task StartAsync(CancellationToken cancellationToken)
{
invocation.BindingContext.AddService(typeof(IHost), _ => host);
//...
await parseResult.InvokeAsync();
appLifetime.StopApplication();
}
|
Hi @jonsequitur,
Here is my take on it. What do you think? Is it the right direction?
Closes #918