mirror of
https://github.com/jlengrand/vert.x.git
synced 2026-03-10 08:51:19 +00:00
Merge pull request #3067 from MitchAman/master
Make CLI options case sensitive for short names (#2844).
This commit is contained in:
@@ -41,8 +41,10 @@ contain more details. Each option and argument are also added on the `CLI` objec
|
||||
|
||||
An {@link io.vertx.core.cli.Option} is a command line parameter identified by a _key_ present in the user command
|
||||
line. Options must have at least a long name or a short name. Long name are generally used using a `--` prefix,
|
||||
while short names are used with a single `-`. Options can get a description displayed in the usage (see below).
|
||||
Options can receive 0, 1 or several values. An option receiving 0 values is a `flag`, and must be declared using
|
||||
while short names are used with a single `-`. Names are case-sensitive; however, case-insensitive name matching
|
||||
will be used during the <<query_interrogation_stage, Query / Interrogation Stage>> if no exact match is found.
|
||||
Options can get a description displayed in the usage (see below). Options can receive 0, 1 or several values. An
|
||||
option receiving 0 values is a `flag`, and must be declared using
|
||||
{@link io.vertx.core.cli.Option#setFlag(boolean)}. By default, options receive a single value, however, you can
|
||||
configure the option to receive several values using {@link io.vertx.core.cli.Option#setMultiValued(boolean)}:
|
||||
|
||||
@@ -152,6 +154,7 @@ This is useful if you want to check an argument or option is present even if the
|
||||
You can check whether or not the
|
||||
{@link io.vertx.core.cli.CommandLine} is valid using {@link io.vertx.core.cli.CommandLine#isValid()}.
|
||||
|
||||
[[query_interrogation_stage]]
|
||||
=== Query / Interrogation Stage
|
||||
|
||||
Once parsed, you can retrieve the values of the options and arguments from the
|
||||
@@ -163,8 +166,8 @@ method:
|
||||
{@link examples.cli.CLIExamples#example8}
|
||||
----
|
||||
|
||||
One of your option can have been marked as "help". If a user command line enabled a "help" option, the validation
|
||||
won't failed, but give you the opportunity to check if the user asks for help:
|
||||
One of your options can be marked as "help". If a user command line enabled a "help" option, the validation
|
||||
won't fail, but you have the opportunity to check if the user asks for help:
|
||||
|
||||
[source,$lang]
|
||||
----
|
||||
|
||||
@@ -14,6 +14,7 @@ package io.vertx.core.cli.impl;
|
||||
import io.vertx.core.cli.*;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -160,25 +161,25 @@ public class DefaultCLI implements CLI {
|
||||
@Override
|
||||
public Option getOption(String name) {
|
||||
Objects.requireNonNull(name);
|
||||
// The option by name look up is a three steps lookup:
|
||||
// first check by long name
|
||||
// then by short name
|
||||
// finally by arg name
|
||||
for (Option option : options) {
|
||||
if (name.equalsIgnoreCase(option.getLongName())) {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
List<Predicate<Option>> equalityChecks = Arrays.asList(
|
||||
// The option by name look up is a three steps lookup:
|
||||
// first check by long name
|
||||
// then by short name
|
||||
// finally by arg name
|
||||
option -> name.equals(option.getLongName()),
|
||||
option -> name.equals(option.getShortName()),
|
||||
option -> name.equals(option.getArgName()),
|
||||
// If there's no exact match, check again in the same order, this time ignoring case-sensitivity
|
||||
option -> name.equalsIgnoreCase(option.getLongName()),
|
||||
option -> name.equalsIgnoreCase(option.getShortName()),
|
||||
option -> name.equalsIgnoreCase(option.getArgName())
|
||||
);
|
||||
|
||||
for (Option option : options) {
|
||||
if (name.equalsIgnoreCase(option.getShortName())) {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
|
||||
for (Option option : options) {
|
||||
if (name.equalsIgnoreCase(option.getArgName())) {
|
||||
return option;
|
||||
for (Predicate<Option> equalityCheck : equalityChecks) {
|
||||
for (Option option : options) {
|
||||
if (equalityCheck.test(option)) {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -479,7 +480,7 @@ public class DefaultParser {
|
||||
|
||||
private boolean hasOptionWithLongName(String name) {
|
||||
for (Option option : cli.getOptions()) {
|
||||
if (name.equalsIgnoreCase(option.getLongName())) {
|
||||
if (name.equals(option.getLongName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -488,7 +489,7 @@ public class DefaultParser {
|
||||
|
||||
private boolean hasOptionWithShortName(String name) {
|
||||
for (Option option : cli.getOptions()) {
|
||||
if (name.equalsIgnoreCase(option.getShortName())) {
|
||||
if (name.equals(option.getShortName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -529,7 +530,7 @@ public class DefaultParser {
|
||||
public Option getOption(String opt) {
|
||||
opt = stripLeadingHyphens(opt);
|
||||
for (Option option : cli.getOptions()) {
|
||||
if (opt.equalsIgnoreCase(option.getShortName()) || opt.equalsIgnoreCase(option.getLongName())) {
|
||||
if (opt.equals(option.getShortName()) || opt.equalsIgnoreCase(option.getLongName())) {
|
||||
return option;
|
||||
}
|
||||
}
|
||||
@@ -549,6 +550,7 @@ public class DefaultParser {
|
||||
* @return the options matching the partial name specified, or an empty list if none matches
|
||||
*/
|
||||
public List<Option> getMatchingOptions(String opt) {
|
||||
Objects.requireNonNull(opt);
|
||||
opt = stripLeadingHyphens(opt);
|
||||
|
||||
List<Option> matching = new ArrayList<>();
|
||||
@@ -558,11 +560,18 @@ public class DefaultParser {
|
||||
|
||||
// Exact match first
|
||||
for (Option option : options) {
|
||||
if (opt.equalsIgnoreCase(option.getLongName())) {
|
||||
if (opt.equals(option.getLongName())) {
|
||||
return Collections.singletonList(option);
|
||||
}
|
||||
}
|
||||
|
||||
// Case-insensitive match second
|
||||
for (Option option : options) {
|
||||
if (opt.equalsIgnoreCase(option.getLongName())) {
|
||||
matching.add(option);
|
||||
}
|
||||
}
|
||||
|
||||
for (Option option : options) {
|
||||
if (option.getLongName() != null && option.getLongName().startsWith(opt)) {
|
||||
matching.add(option);
|
||||
|
||||
@@ -802,4 +802,48 @@ public class DefaultParserTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOptionValueWithCaseSensitivityConflict() {
|
||||
final CLI cli = CLI.create("test")
|
||||
.addOption(new Option().setShortName("a").setLongName("longname"))
|
||||
.addOption(new Option().setShortName("A").setLongName("LONGNAME"));
|
||||
|
||||
String lowercaseValue = "someValue";
|
||||
String uppercaseValue = "someOtherValue";
|
||||
|
||||
CommandLine commandLine = cli.parse(Arrays.asList("-a", lowercaseValue, "-A", uppercaseValue));
|
||||
assertThat((String) commandLine.getOptionValue("a")).isEqualTo(lowercaseValue);
|
||||
assertThat((String) commandLine.getOptionValue("A")).isEqualTo(uppercaseValue);
|
||||
assertThat((String) commandLine.getOptionValue("longname")).isEqualTo(lowercaseValue);
|
||||
assertThat((String) commandLine.getOptionValue("LONGNAME")).isEqualTo(uppercaseValue);
|
||||
|
||||
commandLine = cli.parse(Arrays.asList("--longname", lowercaseValue, "--LONGNAME", uppercaseValue));
|
||||
assertThat((String) commandLine.getOptionValue("a")).isEqualTo(lowercaseValue);
|
||||
assertThat((String) commandLine.getOptionValue("A")).isEqualTo(uppercaseValue);
|
||||
assertThat((String) commandLine.getOptionValue("longname")).isEqualTo(lowercaseValue);
|
||||
assertThat((String) commandLine.getOptionValue("LONGNAME")).isEqualTo(uppercaseValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetOptionValueWithoutCaseSensitivityConflict() {
|
||||
// If there's no case-sensitivity conflict for a given short name, then using the opposite case when getting that
|
||||
// option value should still work.
|
||||
final CLI cli = CLI.create("test")
|
||||
.addOption(new Option().setShortName("a").setLongName("lowercase"));
|
||||
|
||||
String value = "foo";
|
||||
|
||||
CommandLine commandLine = cli.parse(Arrays.asList("-a", value));
|
||||
assertThat((String) commandLine.getOptionValue("a")).isEqualTo(value);
|
||||
assertThat((String) commandLine.getOptionValue("A")).isEqualTo(value);
|
||||
assertThat((String) commandLine.getOptionValue("lowercase")).isEqualTo(value);
|
||||
assertThat((String) commandLine.getOptionValue("LOWERCASE")).isEqualTo(value);
|
||||
|
||||
commandLine = cli.parse(Arrays.asList("--lowercase", value));
|
||||
assertThat((String) commandLine.getOptionValue("a")).isEqualTo(value);
|
||||
assertThat((String) commandLine.getOptionValue("A")).isEqualTo(value);
|
||||
assertThat((String) commandLine.getOptionValue("lowercase")).isEqualTo(value);
|
||||
assertThat((String) commandLine.getOptionValue("LOWERCASE")).isEqualTo(value);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user