Skip to content

Commit 7c87307

Browse files
committed
don't mutate command on subsequent calls to Invoke extension
1 parent b38cb1a commit 7c87307

File tree

5 files changed

+32
-9
lines changed

5 files changed

+32
-9
lines changed

src/System.CommandLine.Tests/CommandTests.cs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,18 +336,31 @@ public void When_multiple_options_are_configured_then_they_must_differ_by_name()
336336
}
337337

338338
[Fact]
339-
public void When_global_options_are_added_then_they_must_differ_from_local_options_by_name()
339+
public void Global_options_may_be_added_with_aliases_that_conflict_with_local_options()
340340
{
341341
var command = new Command("the-command")
342342
{
343343
new Option("--same")
344344
};
345345

346+
command
347+
.Invoking(c => c.AddGlobalOption(new Option("--same")))
348+
.Should()
349+
.NotThrow<ArgumentException>();
350+
}
351+
352+
[Fact]
353+
public void Global_options_may_not_have_aliases_conflicting_with_other_global_option_aliases()
354+
{
355+
var command = new Command("the-command");
356+
357+
command.AddGlobalOption(new Option("--same"));
358+
346359
command
347360
.Invoking(c => c.AddGlobalOption(new Option("--same")))
348361
.Should()
349362
.Throw<ArgumentException>()
350-
.And
363+
.Which
351364
.Message
352365
.Should()
353366
.Be("Alias '--same' is already in use.");

src/System.CommandLine/Builder/CommandLineBuilder.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ public class CommandLineBuilder : CommandBuilder
1717
public CommandLineBuilder(Command rootCommand = null)
1818
: base(rootCommand ?? new RootCommand())
1919
{
20+
if (rootCommand?.ImplicitParser != null)
21+
{
22+
throw new ArgumentException($"Command \"{rootCommand.Name}\" has already been configured.");
23+
}
2024
}
2125

2226
public bool EnableDirectives { get; set; } = true;
@@ -33,7 +37,7 @@ public Parser Build()
3337
{
3438
var rootCommand = Command;
3539

36-
return new Parser(
40+
var parser = new Parser(
3741
new CommandLineConfiguration(
3842
new[] { rootCommand },
3943
enablePosixBundling: EnablePosixBundling,
@@ -44,6 +48,10 @@ public Parser Build()
4448
.Select(m => m.middleware)
4549
.ToArray(),
4650
helpBuilderFactory: HelpBuilderFactory));
51+
52+
Command.ImplicitParser = parser;
53+
54+
return parser;
4755
}
4856

4957
internal void AddMiddleware(

src/System.CommandLine/Builder/CommandLineBuilderExtensions.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,7 +401,6 @@ public static CommandLineBuilder UseSuggestDirective(
401401
return builder;
402402
}
403403

404-
405404
public static CommandLineBuilder UseTypoCorrections(
406405
this CommandLineBuilder builder, int maxLevenshteinDistance = 3)
407406
{

src/System.CommandLine/Command.cs

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

44
using System.Collections;
55
using System.Collections.Generic;
6+
using System.CommandLine.Builder;
67
using System.CommandLine.Collections;
78
using System.CommandLine.Invocation;
89
using System.CommandLine.Parsing;
@@ -32,7 +33,6 @@ public Command(string name, string description = null) : base(new[] { name }, de
3233

3334
public void AddGlobalOption(Option option)
3435
{
35-
Children.ThrowIfAnyAliasIsInUse(option);
3636
_globalOptions.Add(option);
3737
Children.AddWithoutAliasCollisionCheck(option);
3838
}
@@ -68,5 +68,7 @@ private protected override void AddSymbol(Symbol symbol)
6868
IEnumerable<IArgument> ICommand.Arguments => Arguments;
6969

7070
IEnumerable<IOption> ICommand.Options => Options;
71+
72+
internal Parser ImplicitParser { get; set; }
7173
}
7274
}

src/System.CommandLine/CommandExtensions.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,12 @@ public static Task<int> InvokeAsync(
4242

4343
private static InvocationPipeline GetInvocationPipeline(Command command, string[] args)
4444
{
45-
var parser = new CommandLineBuilder(command)
46-
.UseDefaults()
47-
.Build();
45+
var parser = command.ImplicitParser ??=
46+
new CommandLineBuilder(command)
47+
.UseDefaults()
48+
.Build();
4849

49-
ParseResult parseResult = parser.Parse(args);
50+
var parseResult = parser.Parse(args);
5051

5152
return new InvocationPipeline(parseResult);
5253
}

0 commit comments

Comments
 (0)