Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make options, arguments, and commands *read-only* collections on CommandLineApplication #407

Merged
merged 1 commit into from
Nov 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/CommandLineUtils/Attributes/OptionAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ internal CommandOption Configure(CommandLineApplication app, PropertyInfo prop)

option.Description ??= prop.Name;

app.Options.Add(option);
app.AddOption(option);
return option;
}

Expand Down
41 changes: 27 additions & 14 deletions src/CommandLineUtils/CommandLineApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ static CommandLineApplication()
private readonly Lazy<IServiceProvider> _services;
private readonly ConventionContext _conventionContext;
private readonly List<IConvention> _conventions = new List<IConvention>();
private readonly List<CommandArgument> _arguments = new List<CommandArgument>();
private readonly List<CommandOption> _options = new List<CommandOption>();
private readonly List<CommandLineApplication> _subcommands = new List<CommandLineApplication>();
internal readonly List<string> _remainingArguments = new List<string>();

/// <summary>
/// Initializes a new instance of <see cref="CommandLineApplication"/>.
Expand Down Expand Up @@ -109,10 +113,6 @@ internal CommandLineApplication(CommandLineApplication parent, string name)
{
_context = context ?? throw new ArgumentNullException(nameof(context));
Parent = parent;
Options = new List<CommandOption>();
Arguments = new List<CommandArgument>();
Commands = new List<CommandLineApplication>();
RemainingArguments = new List<string>();
_helpTextGenerator = helpTextGenerator ?? throw new ArgumentNullException(nameof(helpTextGenerator));
_handler = DefaultAction;
_validationErrorHandler = DefaultValidationErrorHandler;
Expand Down Expand Up @@ -186,7 +186,7 @@ public IHelpTextGenerator HelpTextGenerator
/// <summary>
/// Available command-line options on this command. Use <see cref="GetOptions"/> to get all available options, which may include inherited options.
/// </summary>
public List<CommandOption> Options { get; private set; }
public IReadOnlyCollection<CommandOption> Options => _options;

/// <summary>
/// Whether a Pager should be used to display help text.
Expand Down Expand Up @@ -239,13 +239,13 @@ public IEnumerable<string> Names
/// <summary>
/// Required command-line arguments.
/// </summary>
public List<CommandArgument> Arguments { get; private set; }
public IReadOnlyList<CommandArgument> Arguments => _arguments;

/// <summary>
/// When initialized when <see cref="UnrecognizedArgumentHandling"/> is <see cref="McMaster.Extensions.CommandLineUtils.UnrecognizedArgumentHandling.StopParsingAndCollect" />,
/// this will contain any unrecognized arguments.
/// </summary>
public List<string> RemainingArguments { get; private set; }
public IReadOnlyList<string> RemainingArguments => _remainingArguments;

/// <summary>
/// Configures what the parser should do when it runs into an unexpected argument.
Expand Down Expand Up @@ -274,7 +274,7 @@ public UnrecognizedArgumentHandling UnrecognizedArgumentHandling
/// <summary>
/// Subcommands.
/// </summary>
public List<CommandLineApplication> Commands { get; private set; }
public IReadOnlyCollection<CommandLineApplication> Commands => _subcommands;

/// <summary>
/// Determines if '--' can be used to separate known arguments and options from additional content passed to <see cref="RemainingArguments"/>.
Expand Down Expand Up @@ -454,7 +454,7 @@ public void AddSubcommand(CommandLineApplication subcommand)

subcommand.Parent = this;

Commands.Add(subcommand);
_subcommands.Add(subcommand);
}

private void AssertCommandNameIsUnique(string? name, CommandLineApplication? commandToIgnore)
Expand Down Expand Up @@ -562,11 +562,20 @@ public CommandOption Option(string template, string description, CommandOptionTy
Description = description,
Inherited = inherited
};
Options.Add(option);
AddOption(option);
configuration(option);
return option;
}

/// <summary>
/// Add an option to the definition of this command
/// </summary>
/// <param name="option"></param>
public void AddOption(CommandOption option)
{
_options.Add(option);
}

/// <summary>
/// Adds a command line option with values that should be parsable into <typeparamref name="T" />.
/// </summary>
Expand All @@ -591,7 +600,7 @@ public CommandOption<T> Option<T>(string template, string description, CommandOp
Description = description,
Inherited = inherited
};
Options.Add(option);
AddOption(option);
configuration(option);
return option;
}
Expand Down Expand Up @@ -662,14 +671,18 @@ public CommandArgument<T> Argument<T>(string name, string description, Action<Co
return argument;
}

private void AddArgument(CommandArgument argument)
/// <summary>
/// Add an argument to the definition of this command.
/// </summary>
/// <param name="argument"></param>
public void AddArgument(CommandArgument argument)
{
var lastArg = Arguments.LastOrDefault();
if (lastArg != null && lastArg.MultipleValues)
{
throw new InvalidOperationException(Strings.OnlyLastArgumentCanAllowMultipleValues(lastArg.Name));
}
Arguments.Add(argument);
_arguments.Add(argument);
}

/// <summary>
Expand Down Expand Up @@ -708,7 +721,7 @@ private void Reset()
}

IsShowingInformation = default;
RemainingArguments.Clear();
_remainingArguments.Clear();
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ public virtual void Apply(ConventionContext context)
}
}

context.Application.Arguments.Add(arg.Value);
context.Application.AddArgument(arg.Value);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public void Apply(ConventionContext context)
if (help.LongName != null || help.ShortName != null || help.SymbolName != null)
{
context.Application.OptionHelp = help;
context.Application.Options.Add(help);
context.Application.AddOption(help);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace McMaster.Extensions.CommandLineUtils.Conventions
Expand Down
4 changes: 2 additions & 2 deletions src/CommandLineUtils/Internal/CommandLineProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ private bool ProcessUnexpectedArg(string argTypeName, string? argValue = null)

case UnrecognizedArgumentHandling.CollectAndContinue:
var arg = _enumerator.Current;
_currentCommand.RemainingArguments.Add(arg.Raw);
_currentCommand._remainingArguments.Add(arg.Raw);
return true;

case UnrecognizedArgumentHandling.StopParsingAndCollect:
Expand All @@ -354,7 +354,7 @@ private void AddRemainingArgumentValues()
var arg = _enumerator.Current;
if (arg != null)
{
_currentCommand.RemainingArguments.Add(arg.Raw);
_currentCommand._remainingArguments.Add(arg.Raw);
}
} while (_enumerator.MoveNext());
}
Expand Down
8 changes: 4 additions & 4 deletions src/CommandLineUtils/PublicAPI.Shipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ McMaster.Extensions.CommandLineUtils.CommandLineApplication.AllowArgumentSeparat
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Argument(string! name, string! description, bool multipleValues = false) -> McMaster.Extensions.CommandLineUtils.CommandArgument!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Argument(string! name, string! description, System.Action<McMaster.Extensions.CommandLineUtils.CommandArgument!>! configuration, bool multipleValues = false) -> McMaster.Extensions.CommandLineUtils.CommandArgument!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Argument<T>(string! name, string! description, System.Action<McMaster.Extensions.CommandLineUtils.CommandArgument<T>!>! configuration, bool multipleValues = false) -> McMaster.Extensions.CommandLineUtils.CommandArgument<T>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Arguments.get -> System.Collections.Generic.List<McMaster.Extensions.CommandLineUtils.CommandArgument!>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Arguments.get -> System.Collections.Generic.IReadOnlyList<McMaster.Extensions.CommandLineUtils.CommandArgument!>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.ClusterOptions.get -> bool
McMaster.Extensions.CommandLineUtils.CommandLineApplication.ClusterOptions.set -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Command(string! name, System.Action<McMaster.Extensions.CommandLineUtils.CommandLineApplication!>! configuration) -> McMaster.Extensions.CommandLineUtils.CommandLineApplication!
Expand All @@ -114,7 +114,7 @@ McMaster.Extensions.CommandLineUtils.CommandLineApplication.CommandLineApplicati
McMaster.Extensions.CommandLineUtils.CommandLineApplication.CommandLineApplication(McMaster.Extensions.CommandLineUtils.HelpText.IHelpTextGenerator! helpTextGenerator, McMaster.Extensions.CommandLineUtils.IConsole! console, string! workingDirectory) -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.CommandLineApplication(McMaster.Extensions.CommandLineUtils.IConsole! console, string! workingDirectory) -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.CommandLineApplication(McMaster.Extensions.CommandLineUtils.IConsole! console) -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Commands.get -> System.Collections.Generic.List<McMaster.Extensions.CommandLineUtils.CommandLineApplication!>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Commands.get -> System.Collections.Generic.IReadOnlyCollection<McMaster.Extensions.CommandLineUtils.CommandLineApplication!>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Conventions.get -> McMaster.Extensions.CommandLineUtils.Conventions.IConventionBuilder!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Description.get -> string?
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Description.set -> void
Expand Down Expand Up @@ -152,7 +152,7 @@ McMaster.Extensions.CommandLineUtils.CommandLineApplication.Option<T>(string! te
McMaster.Extensions.CommandLineUtils.CommandLineApplication.OptionHelp.get -> McMaster.Extensions.CommandLineUtils.CommandOption?
McMaster.Extensions.CommandLineUtils.CommandLineApplication.OptionNameValueSeparators.get -> char[]!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.OptionNameValueSeparators.set -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Options.get -> System.Collections.Generic.List<McMaster.Extensions.CommandLineUtils.CommandOption!>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Options.get -> System.Collections.Generic.IReadOnlyCollection<McMaster.Extensions.CommandLineUtils.CommandOption!>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.OptionsComparison.get -> System.StringComparison
McMaster.Extensions.CommandLineUtils.CommandLineApplication.OptionsComparison.set -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.OptionVersion.get -> McMaster.Extensions.CommandLineUtils.CommandOption?
Expand All @@ -161,7 +161,7 @@ McMaster.Extensions.CommandLineUtils.CommandLineApplication.Out.set -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Parent.get -> McMaster.Extensions.CommandLineUtils.CommandLineApplication?
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Parent.set -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.Parse(params string![]! args) -> McMaster.Extensions.CommandLineUtils.Abstractions.ParseResult!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.RemainingArguments.get -> System.Collections.Generic.List<string!>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.RemainingArguments.get -> System.Collections.Generic.IReadOnlyList<string!>!
McMaster.Extensions.CommandLineUtils.CommandLineApplication.ResponseFileHandling.get -> McMaster.Extensions.CommandLineUtils.ResponseFileHandling
McMaster.Extensions.CommandLineUtils.CommandLineApplication.ResponseFileHandling.set -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.ShortVersionGetter.get -> System.Func<string?>?
Expand Down
2 changes: 2 additions & 0 deletions src/CommandLineUtils/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ McMaster.Extensions.CommandLineUtils.CommandArgument.HasValue.get -> bool
McMaster.Extensions.CommandLineUtils.CommandArgument.TryParse(string? value) -> bool
virtual McMaster.Extensions.CommandLineUtils.CommandArgument.Reset() -> void
virtual McMaster.Extensions.CommandLineUtils.CommandOption.Reset() -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.AddArgument(McMaster.Extensions.CommandLineUtils.CommandArgument! argument) -> void
McMaster.Extensions.CommandLineUtils.CommandLineApplication.AddOption(McMaster.Extensions.CommandLineUtils.CommandOption! option) -> void
4 changes: 2 additions & 2 deletions test/CommandLineUtils.Tests/CommandLineApplicationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -745,7 +745,7 @@ public void OptionNameCanHaveSemicolon()
{
LongName = "debug:hive"
};
app.Options.Add(option);
app.AddOption(option);
app.Parse("--debug:hive", "abc");
Assert.Equal("abc", option.Value());
}
Expand All @@ -759,7 +759,7 @@ public void OptionSeparatorMustNotUseSpace()
{
LongName = "debug:hive"
};
app.Options.Add(option);
app.AddOption(option);

var ex = Assert.ThrowsAny<CommandParsingException>(() =>
app.Parse("--debug:hive", "abc"));
Expand Down
10 changes: 8 additions & 2 deletions test/CommandLineUtils.Tests/HelpOptionAttributeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,10 @@ public void HelpOptionIsInherited()
var outWriter = new StringWriter(sb);
var app = new CommandLineApplication<Parent> { Out = outWriter };
app.Conventions.UseDefaultConventions();
app.Commands.ForEach(f => f.Out = outWriter);
foreach (var subcmd in app.Commands)
{
subcmd.Out = outWriter;
}
app.Execute("lvl2", "--help");
var outData = sb.ToString();

Expand Down Expand Up @@ -210,7 +213,10 @@ public void NestedHelpOptionsChoosesHelpOptionNearestSelectedCommand(string[] ar
return 1;
});

app.Commands.ForEach(f => f.Out = outWriter);
foreach (var subcmd in app.Commands)
{
subcmd.Out = outWriter;
}

app.Execute(args);
var outData = sb.ToString();
Expand Down
3 changes: 2 additions & 1 deletion test/CommandLineUtils.Tests/OptionAttributeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using McMaster.Extensions.CommandLineUtils.Conventions;
Expand Down Expand Up @@ -314,7 +315,7 @@ private CommandOption CreateOption(Type propType, string propName)
var appBuilder = typeof(CommandLineApplication<>).MakeGenericType(program);
var app = (CommandLineApplication)Activator.CreateInstance(appBuilder, Util.EmptyArray<object>());
app.Conventions.UseOptionAttributes();
return app.Options[0];
return app.Options.First();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils.Abstractions;
using Xunit;
Expand Down Expand Up @@ -227,7 +228,7 @@ public void CustomParsersAreAvailableToSubCommands()

Assert.Equal(1, result);
Assert.Equal(expectedDate, app.Model.MainDate);
Assert.Equal(expectedDate.AddSeconds(123456), ((CommandLineApplication<CustomParserProgramAttributesSubCommand>)app.Commands[0]).Model.SubDate);
Assert.Equal(expectedDate.AddSeconds(123456), app.Commands.OfType<CommandLineApplication<CustomParserProgramAttributesSubCommand>>().Single().Model.SubDate);
}

[Fact]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using McMaster.Extensions.CommandLineUtils;
using McMaster.Extensions.CommandLineUtils.Abstractions;
Expand Down