Skip to content

Commit 5f33967

Browse files
committed
split CliAction into sync and async types
1 parent 60687ff commit 5f33967

32 files changed

+306
-327
lines changed

src/System.CommandLine.Benchmarks/CommandLine/Perf_Parser_ParseResult.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
using System.Collections.Generic;
55
using System.CommandLine.Benchmarks.Helpers;
6+
using System.CommandLine.Invocation;
67
using System.IO;
78
using System.Linq;
89
using System.Text;
@@ -60,7 +61,7 @@ public string ParseResult_Diagram(BdnParam<ParseResult> parseResult)
6061
// clear the contents, so each benchmark has the same starting state
6162
stringBuilder.Clear();
6263

63-
parseResult.Value.Action!.Invoke(parseResult.Value);
64+
((SynchronousCliAction)parseResult.Value.Action)!.Invoke(parseResult.Value);
6465

6566
return stringBuilder.ToString();
6667
}
@@ -74,7 +75,7 @@ public async Task<string> ParseResult_DiagramAsync(BdnParam<ParseResult> parseRe
7475
// clear the contents, so each benchmark has the same starting state
7576
stringBuilder.Clear();
7677

77-
await parseResult.Value.Action!.InvokeAsync(parseResult.Value);
78+
await ((AsynchronousCliAction)parseResult.Value.Action!).InvokeAsync(parseResult.Value);
7879

7980
return stringBuilder.ToString();
8081
}

src/System.CommandLine.Hosting.Tests/HostingHandlerTest.cs

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
using System.Threading;
1+
using System.CommandLine.Invocation;
2+
using System.Threading;
23
using System.Threading.Tasks;
34
using FluentAssertions;
45
using Microsoft.Extensions.DependencyInjection;
@@ -101,8 +102,8 @@ public static async Task Invokes_DerivedClass()
101102
var service = new MyService();
102103

103104
var cmd = new CliRootCommand();
104-
cmd.Subcommands.Add(new MyCommand().UseCommandHandler<MyCommand.MyDerivedHandler>());
105-
cmd.Subcommands.Add(new MyOtherCommand().UseCommandHandler<MyOtherCommand.MyDerivedHandler>());
105+
cmd.Subcommands.Add(new MyCommand().UseCommandHandler<MyCommand.MyDerivedCliAction>());
106+
cmd.Subcommands.Add(new MyOtherCommand().UseCommandHandler<MyOtherCommand.MyDerivedCliAction>());
106107
var config = new CliConfiguration(cmd)
107108
.UseHost((builder) => {
108109
builder.ConfigureServices(services =>
@@ -118,15 +119,10 @@ public static async Task Invokes_DerivedClass()
118119
service.StringValue.Should().Be("TEST");
119120
}
120121

121-
public abstract class MyBaseHandler : CliAction
122+
public abstract class MyBaseCliAction : AsynchronousCliAction
122123
{
123124
public int IntOption { get; set; } // bound from option
124125

125-
public override int Invoke(ParseResult context)
126-
{
127-
return Act();
128-
}
129-
130126
public override Task<int> InvokeAsync(ParseResult context, CancellationToken cancellationToken)
131127
{
132128
return Task.FromResult(Act());
@@ -142,7 +138,7 @@ public MyCommand() : base(name: "mycommand")
142138
Options.Add(new CliOption<int>("--int-option")); // or nameof(Handler.IntOption).ToKebabCase() if you don't like the string literal
143139
}
144140

145-
public class MyHandler : CliAction
141+
public class MyHandler : AsynchronousCliAction
146142
{
147143
private readonly MyService service;
148144

@@ -152,25 +148,19 @@ public MyHandler(MyService service)
152148
}
153149

154150
public int IntOption { get; set; } // bound from option
155-
156-
public override int Invoke(ParseResult context)
157-
{
158-
service.Value = IntOption;
159-
return IntOption;
160-
}
161-
151+
162152
public override Task<int> InvokeAsync(ParseResult context, CancellationToken cancellationToken)
163153
{
164154
service.Value = IntOption;
165155
return Task.FromResult(IntOption);
166156
}
167157
}
168158

169-
public class MyDerivedHandler : MyBaseHandler
159+
public class MyDerivedCliAction : MyBaseCliAction
170160
{
171161
private readonly MyService service;
172162

173-
public MyDerivedHandler(MyService service)
163+
public MyDerivedCliAction(MyService service)
174164
{
175165
this.service = service;
176166
}
@@ -191,7 +181,7 @@ public MyOtherCommand() : base(name: "myothercommand")
191181
Arguments.Add(new CliArgument<string>("One") { Arity = ArgumentArity.ZeroOrOne });
192182
}
193183

194-
public class MyHandler : CliAction
184+
public class MyHandler : AsynchronousCliAction
195185
{
196186
private readonly MyService service;
197187

@@ -203,9 +193,7 @@ public MyHandler(MyService service)
203193
public int IntOption { get; set; } // bound from option
204194

205195
public string One { get; set; }
206-
207-
public override int Invoke(ParseResult context) => InvokeAsync(context, CancellationToken.None).GetAwaiter().GetResult();
208-
196+
209197
public override Task<int> InvokeAsync(ParseResult context, CancellationToken cancellationToken)
210198
{
211199
service.Value = IntOption;
@@ -214,11 +202,11 @@ public override Task<int> InvokeAsync(ParseResult context, CancellationToken can
214202
}
215203
}
216204

217-
public class MyDerivedHandler : MyBaseHandler
205+
public class MyDerivedCliAction : MyBaseCliAction
218206
{
219207
private readonly MyService service;
220208

221-
public MyDerivedHandler(MyService service)
209+
public MyDerivedCliAction(MyService service)
222210
{
223211
this.service = service;
224212
}

src/System.CommandLine.Hosting/HostingAction.cs

Lines changed: 16 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
using Microsoft.Extensions.DependencyInjection;
2-
using Microsoft.Extensions.Hosting;
1+
using System.CommandLine.Binding;
2+
using System.CommandLine.Invocation;
3+
using System.CommandLine.NamingConventionBinder;
34
using System.Linq;
45
using System.Threading;
56
using System.Threading.Tasks;
6-
using System.CommandLine.NamingConventionBinder;
7-
using System.CommandLine.Binding;
7+
using Microsoft.Extensions.DependencyInjection;
8+
using Microsoft.Extensions.Hosting;
89

910
namespace System.CommandLine.Hosting
1011
{
@@ -13,11 +14,11 @@ internal sealed class HostingAction : BindingHandler
1314
{
1415
private readonly Func<string[], IHostBuilder> _hostBuilderFactory;
1516
private readonly Action<IHostBuilder> _configureHost;
16-
private readonly CliAction _actualAction;
17+
private readonly AsynchronousCliAction _actualAction;
1718

1819
internal static void SetHandlers(CliCommand command, Func<string[], IHostBuilder> hostBuilderFactory, Action<IHostBuilder> configureHost)
1920
{
20-
command.Action = new HostingAction(hostBuilderFactory, configureHost, command.Action);
21+
command.Action = new HostingAction(hostBuilderFactory, configureHost, (AsynchronousCliAction)command.Action);
2122
command.TreatUnmatchedTokensAsErrors = false; // to pass unmatched Tokens to host builder factory
2223

2324
foreach (CliCommand subCommand in command.Subcommands)
@@ -26,30 +27,27 @@ internal static void SetHandlers(CliCommand command, Func<string[], IHostBuilder
2627
}
2728
}
2829

29-
private HostingAction(Func<string[], IHostBuilder> hostBuilderFactory, Action<IHostBuilder> configureHost, CliAction actualAction)
30+
private HostingAction(Func<string[], IHostBuilder> hostBuilderFactory, Action<IHostBuilder> configureHost, AsynchronousCliAction actualAction)
3031
{
3132
_hostBuilderFactory = hostBuilderFactory;
3233
_configureHost = configureHost;
3334
_actualAction = actualAction;
3435
}
3536

36-
public override BindingContext GetBindingContext(ParseResult parseResult)
37+
public override BindingContext GetBindingContext(ParseResult parseResult)
3738
=> _actualAction is BindingHandler bindingHandler
38-
? bindingHandler.GetBindingContext(parseResult)
39-
: base.GetBindingContext(parseResult);
39+
? bindingHandler.GetBindingContext(parseResult)
40+
: base.GetBindingContext(parseResult);
4041

41-
public async override Task<int> InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken = default)
42+
public override async Task<int> InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken = default)
4243
{
4344
var argsRemaining = parseResult.UnmatchedTokens;
4445
var hostBuilder = _hostBuilderFactory?.Invoke(argsRemaining.ToArray())
45-
?? new HostBuilder();
46+
?? new HostBuilder();
4647
hostBuilder.Properties[typeof(ParseResult)] = parseResult;
4748

4849
CliDirective configurationDirective = parseResult.Configuration.Directives.Single(d => d.Name == "config");
49-
hostBuilder.ConfigureHostConfiguration(config =>
50-
{
51-
config.AddCommandLineDirectives(parseResult, configurationDirective);
52-
});
50+
hostBuilder.ConfigureHostConfiguration(config => { config.AddCommandLineDirectives(parseResult, configurationDirective); });
5351
var bindingContext = GetBindingContext(parseResult);
5452
int registeredBefore = 0;
5553
hostBuilder.UseInvocationLifetime();
@@ -88,14 +86,13 @@ public async override Task<int> InvokeAsync(ParseResult parseResult, Cancellatio
8886
{
8987
return await _actualAction.InvokeAsync(parseResult, cancellationToken);
9088
}
89+
9190
return 0;
9291
}
9392
finally
9493
{
9594
await host.StopAsync(cancellationToken);
9695
}
9796
}
98-
99-
public override int Invoke(ParseResult parseResult) => InvokeAsync(parseResult).GetAwaiter().GetResult();
10097
}
101-
}
98+
}

src/System.CommandLine.Hosting/HostingExtensions.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.CommandLine.Binding;
2+
using System.CommandLine.Invocation;
23
using System.CommandLine.NamingConventionBinder;
34
using CommandHandler = System.CommandLine.NamingConventionBinder.CommandHandler;
45

@@ -54,7 +55,7 @@ public static OptionsBuilder<TOptions> BindCommandLine<TOptions>(
5455
public static CliCommand UseCommandHandler<THandler>(this CliCommand command)
5556
where THandler : CliAction
5657
{
57-
command.Action = CommandHandler.Create(typeof(THandler).GetMethod(nameof(CliAction.InvokeAsync)));
58+
command.Action = CommandHandler.Create(typeof(THandler).GetMethod(nameof(AsynchronousCliCommandAction.InvokeAsync)));
5859

5960
return command;
6061
}

src/System.CommandLine.NamingConventionBinder.Tests/ModelBindingCommandHandlerTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.Collections.Generic;
5+
using System.CommandLine.Invocation;
56
using System.CommandLine.Tests.Binding;
67
using System.CommandLine.Utility;
78
using System.IO;
@@ -87,7 +88,7 @@ public async Task Handler_method_receives_option_arguments_bound_to_the_specifie
8788
{
8889
var testCase = BindingCases[(type, variation)];
8990

90-
CliAction handler;
91+
AsynchronousCliAction handler;
9192
if (!useDelegate)
9293
{
9394
var captureMethod = GetType()

src/System.CommandLine.NamingConventionBinder.Tests/ParameterBindingTests.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.CommandLine.Binding;
5+
using System.CommandLine.Invocation;
56
using System.IO;
67
using System.Threading;
78
using System.Threading.Tasks;
@@ -397,19 +398,17 @@ void Execute(string fullnameOrNickname, int age)
397398
public async Task Method_invoked_is_matching_to_the_interface_implementation(Type type, int expectedResult)
398399
{
399400
var command = new CliCommand("command");
400-
command.Action = CommandHandler.Create(type.GetMethod(nameof(CliAction.InvokeAsync)));
401+
command.Action = CommandHandler.Create(type.GetMethod(nameof(AsynchronousCliAction.InvokeAsync)));
401402

402403
int result = await command.Parse("command").InvokeAsync();
403404

404405
result.Should().Be(expectedResult);
405406
}
406407

407-
public abstract class AbstractTestCommandHandler : CliAction
408+
public abstract class AbstractTestCommandHandler : AsynchronousCliAction
408409
{
409410
public abstract Task<int> DoJobAsync();
410-
411-
public override int Invoke(ParseResult context) => InvokeAsync(context, CancellationToken.None).GetAwaiter().GetResult();
412-
411+
413412
public override Task<int> InvokeAsync(ParseResult context, CancellationToken cancellationToken)
414413
=> DoJobAsync();
415414
}
@@ -420,10 +419,8 @@ public override Task<int> DoJobAsync()
420419
=> Task.FromResult(42);
421420
}
422421

423-
public class VirtualTestCommandHandler : CliAction
422+
public class VirtualTestCommandHandler : AsynchronousCliAction
424423
{
425-
public override int Invoke(ParseResult context) => 42;
426-
427424
public override Task<int> InvokeAsync(ParseResult context, CancellationToken cancellationToken)
428425
=> Task.FromResult(42);
429426
}

src/System.CommandLine.NamingConventionBinder/BindingContextExtensions.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) .NET Foundation and contributors. All rights reserved.
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System.CommandLine.Binding;
@@ -14,8 +14,6 @@ public static class BindingContextExtensions
1414
{
1515
private sealed class DummyStateHoldingHandler : BindingHandler
1616
{
17-
public override int Invoke(ParseResult parseResult) => 0;
18-
1917
public override Task<int> InvokeAsync(ParseResult parseResult, CancellationToken cancellationToken = default) => Task.FromResult(0);
2018
}
2119

src/System.CommandLine.NamingConventionBinder/BindingHandler.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
1-
using System.CommandLine.Binding;
1+
// Copyright (c) .NET Foundation and contributors. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
using System.CommandLine.Binding;
5+
using System.CommandLine.Invocation;
26

37
namespace System.CommandLine.NamingConventionBinder
48
{
5-
public abstract class BindingHandler : CliAction
9+
public abstract class BindingHandler : AsynchronousCliAction
610
{
711
private BindingContext? _bindingContext;
812

src/System.CommandLine.NamingConventionBinder/ModelBindingCommandHandler.cs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,4 @@ private void BindValueSource(ParameterInfo param, IValueSource valueSource)
129129
: _methodDescriptor.ParameterDescriptors
130130
.FirstOrDefault(x => x.ValueName == param.Name &&
131131
x.ValueType == param.ParameterType);
132-
133-
/// <inheritdoc />
134-
public override int Invoke(ParseResult parseResult) => InvokeAsync(parseResult, CancellationToken.None).GetAwaiter().GetResult();
135132
}

0 commit comments

Comments
 (0)