Merge pull request #31513 from bclozel

* pr/31513:
  Support "--" end of options in SimpleCommandLineArgsParser

Closes gh-31513
This commit is contained in:
Stéphane Nicoll
2024-02-15 15:09:39 +01:00
2 changed files with 32 additions and 16 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2020 the original author or authors. * Copyright 2002-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -30,6 +30,13 @@ package org.springframework.core.env;
* <em>without spaces</em> by an equals sign ("="). The value may optionally be * <em>without spaces</em> by an equals sign ("="). The value may optionally be
* an empty string. * an empty string.
* *
* <p>This parser supports the POSIX "end of options" delimiter, meaning that
* any {@code "--"} (empty option name) in the command signals that all remaining
* arguments will non-optional. For example, here {@code "--opt=ignored"} is considered
* as a non-optional argument.
* <pre class="code">
* --foo=bar -- --opt=ignored</pre>
*
* <h4>Valid examples of option arguments</h4> * <h4>Valid examples of option arguments</h4>
* <pre class="code"> * <pre class="code">
* --foo * --foo
@@ -53,6 +60,7 @@ package org.springframework.core.env;
* *
* @author Chris Beams * @author Chris Beams
* @author Sam Brannen * @author Sam Brannen
* @author Brian Clozel
* @since 3.1 * @since 3.1
*/ */
class SimpleCommandLineArgsParser { class SimpleCommandLineArgsParser {
@@ -65,23 +73,26 @@ class SimpleCommandLineArgsParser {
*/ */
public CommandLineArgs parse(String... args) { public CommandLineArgs parse(String... args) {
CommandLineArgs commandLineArgs = new CommandLineArgs(); CommandLineArgs commandLineArgs = new CommandLineArgs();
boolean endOfOptions = false;
for (String arg : args) { for (String arg : args) {
if (arg.startsWith("--")) { if (!endOfOptions && arg.startsWith("--")) {
String optionText = arg.substring(2); String optionText = arg.substring(2);
String optionName;
String optionValue = null;
int indexOfEqualsSign = optionText.indexOf('='); int indexOfEqualsSign = optionText.indexOf('=');
if (indexOfEqualsSign > -1) { if (indexOfEqualsSign > -1) {
optionName = optionText.substring(0, indexOfEqualsSign); String optionName = optionText.substring(0, indexOfEqualsSign);
optionValue = optionText.substring(indexOfEqualsSign + 1); String optionValue = optionText.substring(indexOfEqualsSign + 1);
if (optionName.isEmpty()) {
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
}
commandLineArgs.addOptionArg(optionName, optionValue);
}
else if (!optionText.isEmpty()){
commandLineArgs.addOptionArg(optionText, null);
} }
else { else {
optionName = optionText; // '--' End of options delimiter, all remaining args must be non-optional
endOfOptions = true;
} }
if (optionName.isEmpty()) {
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
}
commandLineArgs.addOptionArg(optionName, optionValue);
} }
else { else {
commandLineArgs.addNonOptionArg(arg); commandLineArgs.addNonOptionArg(arg);

View File

@@ -30,6 +30,7 @@ import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException
* *
* @author Chris Beams * @author Chris Beams
* @author Sam Brannen * @author Sam Brannen
* @author Brian Clozel
*/ */
class SimpleCommandLineArgsParserTests { class SimpleCommandLineArgsParserTests {
@@ -66,11 +67,6 @@ class SimpleCommandLineArgsParserTests {
assertThat(args.getOptionValues("o3")).isNull(); assertThat(args.getOptionValues("o3")).isNull();
} }
@Test
void withEmptyOptionText() {
assertThatIllegalArgumentException().isThrownBy(() -> parser.parse("--"));
}
@Test @Test
void withEmptyOptionName() { void withEmptyOptionName() {
assertThatIllegalArgumentException().isThrownBy(() -> parser.parse("--=v1")); assertThatIllegalArgumentException().isThrownBy(() -> parser.parse("--=v1"));
@@ -112,4 +108,13 @@ class SimpleCommandLineArgsParserTests {
args.getNonOptionArgs().add("foo")); args.getNonOptionArgs().add("foo"));
} }
@Test
void supportsEndOfOptionsDelimiter() {
CommandLineArgs args = parser.parse("--o1=v1", "--", "--o2=v2");
assertThat(args.containsOption("o1")).isTrue();
assertThat(args.containsOption("o2")).isFalse();
assertThat(args.getOptionValues("o1")).containsExactly("v1");
assertThat(args.getNonOptionArgs()).contains("--o2=v2");
}
} }