Skip to content

Commit 2ae3264

Browse files
authored
Merge branch 'release/3.0' into merge/release/3.0-preview9-to-release/3.0\n\nCommit migrated from dotnet/extensions@07c506d
2 parents d46d569 + 449a2ea commit 2ae3264

File tree

2 files changed

+549
-25
lines changed

2 files changed

+549
-25
lines changed

src/Shared/CommandLineUtils/CommandLine/CommandLineApplication.cs

Lines changed: 58 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,23 @@ namespace Microsoft.Extensions.CommandLineUtils
1313
{
1414
internal class CommandLineApplication
1515
{
16-
// Indicates whether the parser should throw an exception when it runs into an unexpected argument.
17-
// If this field is set to false, the parser will stop parsing when it sees an unexpected argument, and all
18-
// remaining arguments, including the first unexpected argument, will be stored in RemainingArguments property.
16+
// Indicates whether the parser should throw an exception when it runs into an unexpected argument. If this is
17+
// set to true (the default), the parser will throw on the first unexpected argument. Otherwise, all unexpected
18+
// arguments (including the first) are added to RemainingArguments.
1919
private readonly bool _throwOnUnexpectedArg;
2020

21-
public CommandLineApplication(bool throwOnUnexpectedArg = true)
21+
// Indicates whether the parser should check remaining arguments for command or option matches after
22+
// encountering an unexpected argument. Ignored if _throwOnUnexpectedArg is true (the default). If
23+
// _throwOnUnexpectedArg and this are both false, the first unexpected argument and all remaining arguments are
24+
// added to RemainingArguments. If _throwOnUnexpectedArg is false and this is true, only unexpected arguments
25+
// are added to RemainingArguments -- allowing a mix of expected and unexpected arguments, commands and
26+
// options.
27+
private readonly bool _continueAfterUnexpectedArg;
28+
29+
public CommandLineApplication(bool throwOnUnexpectedArg = true, bool continueAfterUnexpectedArg = false)
2230
{
2331
_throwOnUnexpectedArg = throwOnUnexpectedArg;
32+
_continueAfterUnexpectedArg = continueAfterUnexpectedArg;
2433
Options = new List<CommandOption>();
2534
Arguments = new List<CommandArgument>();
2635
Commands = new List<CommandLineApplication>();
@@ -145,6 +154,7 @@ public int Execute(params string[] args)
145154
{
146155
shortOption = arg.Substring(1).Split(new[] { ':', '=' }, 2);
147156
}
157+
148158
if (longOption != null)
149159
{
150160
processed = true;
@@ -153,13 +163,27 @@ public int Execute(params string[] args)
153163

154164
if (option == null)
155165
{
156-
if (string.IsNullOrEmpty(longOptionName) && !command._throwOnUnexpectedArg && AllowArgumentSeparator)
166+
var ignoreContinueAfterUnexpectedArg = false;
167+
if (string.IsNullOrEmpty(longOptionName) &&
168+
!command._throwOnUnexpectedArg &&
169+
AllowArgumentSeparator)
157170
{
158-
// skip over the '--' argument separator
171+
// Skip over the '--' argument separator then consume all remaining arguments. All
172+
// remaining arguments are unconditionally stored for further use.
159173
index++;
174+
ignoreContinueAfterUnexpectedArg = true;
175+
}
176+
177+
if (HandleUnexpectedArg(
178+
command,
179+
args,
180+
index,
181+
argTypeName: "option",
182+
ignoreContinueAfterUnexpectedArg))
183+
{
184+
continue;
160185
}
161186

162-
HandleUnexpectedArg(command, args, index, argTypeName: "option");
163187
break;
164188
}
165189

@@ -191,6 +215,7 @@ public int Execute(params string[] args)
191215
option = null;
192216
}
193217
}
218+
194219
if (shortOption != null)
195220
{
196221
processed = true;
@@ -204,7 +229,11 @@ public int Execute(params string[] args)
204229

205230
if (option == null)
206231
{
207-
HandleUnexpectedArg(command, args, index, argTypeName: "option");
232+
if (HandleUnexpectedArg(command, args, index, argTypeName: "option"))
233+
{
234+
continue;
235+
}
236+
208237
break;
209238
}
210239

@@ -268,6 +297,7 @@ public int Execute(params string[] args)
268297
processed = true;
269298
}
270299
}
300+
271301
if (!processed)
272302
{
273303
if (arguments == null)
@@ -280,9 +310,14 @@ public int Execute(params string[] args)
280310
arguments.Current.Values.Add(arg);
281311
}
282312
}
313+
283314
if (!processed)
284315
{
285-
HandleUnexpectedArg(command, args, index, argTypeName: "command or argument");
316+
if (HandleUnexpectedArg(command, args, index, argTypeName: "command or argument"))
317+
{
318+
continue;
319+
}
320+
286321
break;
287322
}
288323
}
@@ -490,17 +525,29 @@ public void ShowRootCommandFullNameAndVersion()
490525
Out.WriteLine();
491526
}
492527

493-
private void HandleUnexpectedArg(CommandLineApplication command, string[] args, int index, string argTypeName)
528+
private bool HandleUnexpectedArg(
529+
CommandLineApplication command,
530+
string[] args,
531+
int index,
532+
string argTypeName,
533+
bool ignoreContinueAfterUnexpectedArg = false)
494534
{
495535
if (command._throwOnUnexpectedArg)
496536
{
497537
command.ShowHint();
498538
throw new CommandParsingException(command, $"Unrecognized {argTypeName} '{args[index]}'");
499539
}
540+
else if (_continueAfterUnexpectedArg && !ignoreContinueAfterUnexpectedArg)
541+
{
542+
// Store argument for further use.
543+
command.RemainingArguments.Add(args[index]);
544+
return true;
545+
}
500546
else
501547
{
502-
// All remaining arguments are stored for further use
548+
// Store all remaining arguments for later use.
503549
command.RemainingArguments.AddRange(new ArraySegment<string>(args, index, args.Length - index));
550+
return false;
504551
}
505552
}
506553

0 commit comments

Comments
 (0)