22// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33// This file has been modified from the original form. See Notice.txt in the project root for more information.
44
5- using System ;
6- using System . Collections ;
75using System . Collections . Generic ;
86using System . ComponentModel . DataAnnotations ;
9- using System . IO ;
10- using System . Linq ;
11- using System . Text ;
12- using System . Threading . Tasks ;
137
148namespace McMaster . Extensions . CommandLineUtils
159{
1610 partial class CommandLineApplication
1711 {
18- // used to keep track of arguments added from the response file
19- private int _responseFileArgsEnd = - 1 ;
20-
2112 private int Execute ( List < string > args )
2213 {
23- CommandLineApplication command = this ;
24- CommandOption option = null ;
25- IEnumerator < CommandArgument > arguments = null ;
26-
27- for ( var index = 0 ; index < args . Count ; index ++ )
28- {
29- var arg = args [ index ] ;
30-
31- if ( command . ResponseFileHandling != ResponseFileHandling . Disabled && index > _responseFileArgsEnd && arg . Length > 1 && arg [ 0 ] == '@' )
32- {
33- var path = arg . Substring ( 1 ) ;
34- var fullPath = Path . IsPathRooted ( path )
35- ? path
36- : Path . Combine ( command . WorkingDirectory , path ) ;
37-
38- IList < string > rspArgs ;
39- try
40- {
41- rspArgs = ResponseFileParser . Parse ( fullPath , command . ResponseFileHandling ) ;
42- }
43- catch ( Exception ex )
44- {
45- throw new CommandParsingException ( this , $ "Could not parse the response file '{ arg } '", ex ) ;
46- }
47-
48- args . InsertRange ( index + 1 , rspArgs ) ;
49- _responseFileArgsEnd = index + rspArgs . Count ;
50- continue ;
51- }
52-
53- var processed = false ;
54- if ( ! processed && option == null )
55- {
56- string [ ] longOption = null ;
57- string [ ] shortOption = null ;
58-
59- if ( arg != null )
60- {
61- if ( arg . StartsWith ( "--" ) )
62- {
63- longOption = arg . Substring ( 2 ) . Split ( new [ ] { ':' , '=' } , 2 ) ;
64- }
65- else if ( arg . StartsWith ( "-" ) )
66- {
67- shortOption = arg . Substring ( 1 ) . Split ( new [ ] { ':' , '=' } , 2 ) ;
68- }
69- }
70-
71- if ( longOption != null )
72- {
73- processed = true ;
74- var longOptionName = longOption [ 0 ] ;
75- option = command . GetOptions ( ) . SingleOrDefault ( opt => string . Equals ( opt . LongName , longOptionName , StringComparison . Ordinal ) ) ;
76-
77- if ( option == null )
78- {
79- if ( string . IsNullOrEmpty ( longOptionName ) && ! command . ThrowOnUnexpectedArgument && AllowArgumentSeparator )
80- {
81- // skip over the '--' argument separator
82- index ++ ;
83- }
84-
85- HandleUnexpectedArg ( command , args , index , argTypeName : "option" ) ;
86- break ;
87- }
88-
89- // If we find a help/version option, show information and stop parsing
90- if ( command . OptionHelp == option )
91- {
92- command . ShowHelp ( ) ;
93- option . TryParse ( null ) ;
94- var parent = command ;
95- while ( parent . Parent != null ) parent = parent . Parent ;
96- parent . SelectedCommand = command ;
97- if ( StopParsingAfterHelpOption )
98- {
99- return 0 ;
100- }
101- }
102- else if ( command . OptionVersion == option )
103- {
104- command . ShowVersion ( ) ;
105- option . TryParse ( null ) ;
106- var parent = command ;
107- while ( parent . Parent != null ) parent = parent . Parent ;
108- parent . SelectedCommand = command ;
109- if ( StopParsingAfterVersionOption )
110- {
111- return 0 ;
112- }
113- }
114-
115- if ( longOption . Length == 2 )
116- {
117- if ( ! option . TryParse ( longOption [ 1 ] ) )
118- {
119- command . ShowHint ( ) ;
120- throw new CommandParsingException ( command , $ "Unexpected value '{ longOption [ 1 ] } ' for option '{ option . LongName } '") ;
121- }
122- option = null ;
123- }
124- else if ( option . OptionType == CommandOptionType . NoValue )
125- {
126- // No value is needed for this option
127- option . TryParse ( null ) ;
128- option = null ;
129- }
130- }
131-
132- if ( shortOption != null )
133- {
134- processed = true ;
135- option = command . GetOptions ( ) . SingleOrDefault ( opt => string . Equals ( opt . ShortName , shortOption [ 0 ] , StringComparison . Ordinal ) ) ;
136-
137- // If not a short option, try symbol option
138- if ( option == null )
139- {
140- option = command . GetOptions ( ) . SingleOrDefault ( opt => string . Equals ( opt . SymbolName , shortOption [ 0 ] , StringComparison . Ordinal ) ) ;
141- }
142-
143- if ( option == null )
144- {
145- HandleUnexpectedArg ( command , args , index , argTypeName : "option" ) ;
146- break ;
147- }
148-
149- // If we find a help/version option, show information and stop parsing
150- if ( command . OptionHelp == option )
151- {
152- command . ShowHelp ( ) ;
153- option . TryParse ( null ) ;
154- var parent = command ;
155- while ( parent . Parent != null ) parent = parent . Parent ;
156- parent . SelectedCommand = command ;
157- if ( StopParsingAfterHelpOption )
158- {
159- return 0 ;
160- }
161- }
162- else if ( command . OptionVersion == option )
163- {
164- command . ShowVersion ( ) ;
165- option . TryParse ( null ) ;
166- var parent = command ;
167- while ( parent . Parent != null ) parent = parent . Parent ;
168- parent . SelectedCommand = command ;
169- if ( StopParsingAfterVersionOption )
170- {
171- return 0 ;
172- }
173- }
174-
175- if ( shortOption . Length == 2 )
176- {
177- if ( ! option . TryParse ( shortOption [ 1 ] ) )
178- {
179- command . ShowHint ( ) ;
180- throw new CommandParsingException ( command , $ "Unexpected value '{ shortOption [ 1 ] } ' for option '{ option . LongName } '") ;
181- }
182- option = null ;
183- }
184- else if ( option . OptionType == CommandOptionType . NoValue )
185- {
186- // No value is needed for this option
187- option . TryParse ( null ) ;
188- option = null ;
189- }
190- }
191- }
192-
193- if ( ! processed && option != null )
194- {
195- processed = true ;
196- if ( ! option . TryParse ( arg ) )
197- {
198- command . ShowHint ( ) ;
199- throw new CommandParsingException ( command , $ "Unexpected value '{ arg } ' for option '{ option . LongName } '") ;
200- }
201- option = null ;
202- }
203-
204- if ( ! processed && arguments == null )
205- {
206- var currentCommand = command ;
207- foreach ( var subcommand in command . Commands )
208- {
209- if ( string . Equals ( subcommand . Name , arg , StringComparison . OrdinalIgnoreCase ) )
210- {
211- processed = true ;
212- command = subcommand ;
213- break ;
214- }
215- }
216-
217- // If we detect a subcommand
218- if ( command != currentCommand )
219- {
220- processed = true ;
221- }
222- }
223- if ( ! processed )
224- {
225- if ( arguments == null )
226- {
227- arguments = new CommandArgumentEnumerator ( command . Arguments . GetEnumerator ( ) ) ;
228- }
229- if ( arguments . MoveNext ( ) )
230- {
231- processed = true ;
232- arguments . Current . Values . Add ( arg ) ;
233- }
234- }
235- if ( ! processed )
236- {
237- HandleUnexpectedArg ( command , args , index , argTypeName : "command or argument" ) ;
238- break ;
239- }
240- }
241-
242- if ( option != null )
243- {
244- command . ShowHint ( ) ;
245- throw new CommandParsingException ( command , $ "Missing value for option '{ option . LongName } '") ;
246- }
14+ var processor = new CommandLineProcessor ( this , args ) ;
15+ var command = processor . Process ( ) ;
24716
24817 var result = command . GetValidationResult ( ) ;
24918
@@ -255,7 +24,7 @@ private int Execute(List<string> args)
25524 return command . Invoke ( ) ;
25625 }
25726
258- internal CommandLineApplication SelectedCommand { get ; private set ; }
27+ internal CommandLineApplication SelectedCommand { get ; set ; }
25928
26029 private bool _settingConsole ;
26130
@@ -279,49 +48,5 @@ internal void SetConsole(IConsole console)
27948
28049 _settingConsole = false ;
28150 }
282-
283- private void HandleUnexpectedArg ( CommandLineApplication command , IReadOnlyList < string > args , int index , string argTypeName )
284- {
285- if ( command . ThrowOnUnexpectedArgument )
286- {
287- command . ShowHint ( ) ;
288- throw new CommandParsingException ( command , $ "Unrecognized { argTypeName } '{ args [ index ] } '") ;
289- }
290- else
291- {
292- // All remaining arguments are stored for further use
293- command . RemainingArguments . AddRange ( new ArraySegment < string > ( args . ToArray ( ) , index , args . Count - index ) ) ;
294- }
295- }
296-
297- private class CommandArgumentEnumerator : IEnumerator < CommandArgument >
298- {
299- private readonly IEnumerator < CommandArgument > _enumerator ;
300-
301- public CommandArgumentEnumerator ( IEnumerator < CommandArgument > enumerator )
302- {
303- _enumerator = enumerator ;
304- }
305-
306- public CommandArgument Current => _enumerator . Current ;
307-
308- object IEnumerator . Current => Current ;
309-
310- public void Dispose ( ) => _enumerator . Dispose ( ) ;
311-
312- public bool MoveNext ( )
313- {
314- if ( Current == null || ! Current . MultipleValues )
315- {
316- return _enumerator . MoveNext ( ) ;
317- }
318-
319- // If current argument allows multiple values, we don't move forward and
320- // all later values will be added to current CommandArgument.Values
321- return true ;
322- }
323-
324- public void Reset ( ) => _enumerator . Reset ( ) ;
325- }
32651 }
32752}
0 commit comments