1
-
2
- using Microsoft . Extensions . DependencyInjection ;
1
+ using Microsoft . Extensions . DependencyInjection ;
3
2
using Microsoft . Extensions . Hosting ;
4
- using System ;
5
3
using System . Collections . Generic ;
6
- using System . CommandLine ;
7
4
using System . CommandLine . Invocation ;
8
5
using System . CommandLine . NamingConventionBinder ;
9
6
using System . CommandLine . Parsing ;
10
7
using System . ComponentModel ;
11
8
using System . ComponentModel . DataAnnotations ;
12
- using System . IO ;
13
- using System . IO . Compression ;
14
9
using System . Linq ;
15
10
using System . Reflection ;
16
11
using System . Threading ;
@@ -22,14 +17,62 @@ namespace System.CommandLine
22
17
public class AliasAttribute : Attribute
23
18
{
24
19
public string Alias { get ; }
20
+
25
21
public AliasAttribute ( string alias )
26
22
{
27
23
Alias = alias ;
28
24
}
29
25
}
30
26
27
+ [ AttributeUsage ( AttributeTargets . Property ) ]
28
+ public class ArgumentAttribute : Attribute
29
+ {
30
+ }
31
+
31
32
public static class COmmandExtensions
32
33
{
34
+ public static Dictionary < string , Argument > AddArguments ( this Command command )
35
+ {
36
+ var output = new Dictionary < string , Argument > ( ) ;
37
+
38
+ foreach ( var prop in command . GetType ( ) . GetProperties ( ) )
39
+ {
40
+ var val = prop . GetValue ( command ) ;
41
+ if ( val is Option option )
42
+ {
43
+ if ( prop . GetCustomAttribute < RequiredAttribute > ( ) is RequiredAttribute )
44
+ {
45
+ option . IsRequired = true ;
46
+ }
47
+
48
+ command . Add ( option ) ;
49
+ }
50
+ else if ( prop . GetCustomAttributes < ArgumentAttribute > ( ) . Any ( ) )
51
+ {
52
+ var argumentAttribute = prop . GetCustomAttributes < ArgumentAttribute > ( ) . FirstOrDefault ( ) ;
53
+
54
+ if ( argumentAttribute == null )
55
+ continue ;
56
+
57
+ var argument =
58
+ typeof ( COmmandExtensions ) . GetMethod ( nameof ( CreateArgument ) , 1 , new [ ] { typeof ( string ) } )
59
+ ? . MakeGenericMethod ( prop . PropertyType ) . Invoke ( null ,
60
+ new object [ ]
61
+ {
62
+ prop . GetCustomAttribute < DescriptionAttribute > ( ) ? . Description
63
+ } ) ;
64
+
65
+
66
+ if ( argument is not Argument a ) continue ;
67
+
68
+ output . Add ( prop . Name , a ) ;
69
+ command . Add ( a ) ;
70
+ }
71
+ }
72
+
73
+ return output ;
74
+ }
75
+
33
76
public static Dictionary < string , Option > AddOptions ( this Command command )
34
77
{
35
78
var o = new Dictionary < string , Option > ( ) ;
@@ -43,15 +86,25 @@ public static Dictionary<string, Option> AddOptions(this Command command)
43
86
{
44
87
option . IsRequired = true ;
45
88
}
89
+
46
90
command . Add ( option ) ;
47
91
}
48
92
else if ( prop . GetCustomAttributes < AliasAttribute > ( ) . Any ( ) )
49
93
{
50
94
var aliass = prop . GetCustomAttributes < AliasAttribute > ( ) ;
51
- var op = typeof ( COmmandExtensions ) . GetMethod ( nameof ( CreateOption ) , 1 , new [ ] { typeof ( string ) , typeof ( string ) } )
52
- . MakeGenericMethod ( prop . PropertyType ) . Invoke ( null , new object [ ] { aliass . First ( ) . Alias , prop . GetCustomAttribute < DescriptionAttribute > ( ) . Description } ) as Option ;
95
+ var op = typeof ( COmmandExtensions )
96
+ . GetMethod ( nameof ( CreateOption ) , 1 , new [ ] { typeof ( string ) , typeof ( string ) } )
97
+ . MakeGenericMethod ( prop . PropertyType ) . Invoke ( null ,
98
+ new object [ ]
99
+ {
100
+ aliass . First ( ) . Alias , prop . GetCustomAttribute < DescriptionAttribute > ( ) . Description
101
+ } ) as Option ;
102
+
53
103
foreach ( var a in aliass . Skip ( 1 ) )
104
+ {
54
105
op . AddAlias ( a . Alias ) ;
106
+ }
107
+
55
108
o [ prop . Name ] = op ;
56
109
57
110
command . Add ( op ) ;
@@ -60,42 +113,51 @@ public static Dictionary<string, Option> AddOptions(this Command command)
60
113
61
114
return o ;
62
115
}
116
+
63
117
public static Option < T > CreateOption < T > ( string alias , string description )
64
118
{
65
119
return new Option < T > ( alias , description ) ;
66
120
}
67
121
68
- public static ICommandHandler Create ( Command cmd , IEnumerable < Command > commands , Func < ParseResult , IConsole , Task < int > > runner )
122
+ public static Argument < T > CreateArgument < T > ( string description )
123
+ {
124
+ return new Argument < T > { Description = description } ;
125
+ }
126
+
127
+ public static ICommandHandler Create ( Command cmd , IEnumerable < Command > commands ,
128
+ Func < ParseResult , IConsole , Task < int > > runner )
69
129
{
70
130
foreach ( var command in commands )
71
131
cmd . Add ( command ) ;
72
132
73
133
var options = cmd . AddOptions ( ) ;
74
-
134
+ var arguments = cmd . AddArguments ( ) ;
75
135
76
136
Task < int > Run ( ParseResult parsed , IConsole console )
77
137
{
78
-
79
138
foreach ( var o in options )
80
139
{
81
140
cmd . GetType ( ) . GetProperty ( o . Key ) . SetValue ( cmd , parsed . GetValueForOption ( o . Value ) ) ;
82
141
}
142
+ foreach ( var ( key , argument ) in arguments )
143
+ {
144
+ cmd . GetType ( ) . GetProperty ( key ) ! . SetValue ( cmd , parsed . GetValueForArgument ( argument ) ) ;
145
+ }
83
146
84
147
return runner ( parsed , console ) ;
85
148
}
86
149
87
150
88
- return CommandHandler . Create < ParseResult , IConsole > ( Run ) ;
89
-
90
-
151
+ return CommandHandler . Create < ParseResult , IConsole > ( Run ) ;
91
152
}
92
-
93
153
}
154
+
94
155
internal sealed class ConsoleHostedService < TApp > : IHostedService where TApp : RootCommand
95
156
{
96
157
private readonly IHostApplicationLifetime appLifetime ;
97
158
private readonly TApp app ;
98
159
public int Result = 0 ;
160
+
99
161
public ConsoleHostedService (
100
162
IHostApplicationLifetime appLifetime ,
101
163
IServiceProvider serviceProvider ,
@@ -109,46 +171,48 @@ public ConsoleHostedService(
109
171
public Task StartAsync ( CancellationToken cancellationToken )
110
172
{
111
173
return app . InvokeAsync ( System . Environment . GetCommandLineArgs ( ) . Skip ( 1 ) . ToArray ( ) )
112
- . ContinueWith ( result =>
113
- {
114
- Result = result . Result ;
115
- appLifetime . StopApplication ( ) ;
116
-
117
- } ) ;
174
+ . ContinueWith ( result =>
175
+ {
176
+ Result = result . Result ;
177
+ appLifetime . StopApplication ( ) ;
178
+ } ) ;
118
179
}
119
180
120
181
public Task StopAsync ( CancellationToken cancellationToken )
121
182
{
122
-
123
183
return Task . CompletedTask ;
124
184
}
125
185
}
186
+
126
187
public static class Extensions
127
188
{
128
189
public static T GetValue < T > ( this Argument < T > argument , ParseResult parser )
129
190
=> parser . GetValueForArgument ( argument ) ;
191
+
130
192
public static T GetValue < T > ( this Option < T > argument , ParseResult parser )
131
- => parser . GetValueForOption ( argument ) ;
132
-
193
+ => parser . GetValueForOption ( argument ) ;
194
+
133
195
public static IServiceCollection AddCommand < TCommand > ( this IServiceCollection services ) where TCommand : Command
134
196
{
135
197
return services . AddSingleton < Command , TCommand > ( ) ;
136
198
}
137
- public static IServiceCollection AddConsoleApp < TCommand > ( this IServiceCollection services ) where TCommand : RootCommand
199
+
200
+ public static IServiceCollection AddConsoleApp < TCommand > ( this IServiceCollection services )
201
+ where TCommand : RootCommand
138
202
{
139
203
services . AddSingleton < ConsoleHostedService < TCommand > > ( ) ;
140
204
services . AddHostedService ( sp => sp . GetRequiredService < ConsoleHostedService < TCommand > > ( ) ) ;
141
205
return services . AddSingleton < TCommand > ( ) ;
142
206
}
207
+
143
208
public static IHostBuilder AddConsoleApp < TCommand > ( this IHostBuilder hostbuilder ) where TCommand : RootCommand
144
209
{
145
- hostbuilder . ConfigureServices ( ( _ , services ) => services . AddConsoleApp < TCommand > ( ) ) ;
210
+ hostbuilder . ConfigureServices ( ( _ , services ) => services . AddConsoleApp < TCommand > ( ) ) ;
146
211
147
212
return hostbuilder ;
148
-
149
213
}
150
214
151
- public static async Task < int > RunConsoleApp < TApp > ( this IHost host ) where TApp : RootCommand
215
+ public static async Task < int > RunConsoleApp < TApp > ( this IHost host ) where TApp : RootCommand
152
216
{
153
217
var app = host . Services . GetRequiredService < ConsoleHostedService < TApp > > ( ) ;
154
218
await host . RunAsync ( ) ;
0 commit comments