Skip to content

Commit b4131ce

Browse files
bclozelsnicoll
authored andcommitted
Support "--" end of options in SimpleCommandLineArgsParser
Prior to this commit, the `SimpleCommandLineArgsParser` would reject "--" arguments as invalid. As reported by the community, the POSIX utility conventions (Guideline 10) state that > The first -- argument that is not an option-argument should be > accepted as a delimiter indicating the end of options. > Any following arguments should be treated as operands, even if they > begin with the '-' character. This commit updates `SimpleCommandLineArgsParser` to not reject "--" arguments and instead to consider remaining arguments as non-optional. See gh-31513
1 parent 0f70770 commit b4131ce

File tree

2 files changed

+32
-16
lines changed

2 files changed

+32
-16
lines changed

spring-core/src/main/java/org/springframework/core/env/SimpleCommandLineArgsParser.java

+22-11
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -30,6 +30,13 @@
3030
* <em>without spaces</em> by an equals sign ("="). The value may optionally be
3131
* an empty string.
3232
*
33+
* <p>This parser supports the POSIX "end of options" delimiter, meaning that
34+
* any {@code "--"} (empty option name) in the command signals that all remaining
35+
* arguments will non-optional. For example, here {@code "--opt=ignored"} is considered
36+
* as a non-optional argument.
37+
* <pre class="code">
38+
* --foo=bar -- --opt=ignored</pre>
39+
*
3340
* <h4>Valid examples of option arguments</h4>
3441
* <pre class="code">
3542
* --foo
@@ -53,6 +60,7 @@
5360
*
5461
* @author Chris Beams
5562
* @author Sam Brannen
63+
* @author Brian Clozel
5664
* @since 3.1
5765
*/
5866
class SimpleCommandLineArgsParser {
@@ -65,23 +73,26 @@ class SimpleCommandLineArgsParser {
6573
*/
6674
public CommandLineArgs parse(String... args) {
6775
CommandLineArgs commandLineArgs = new CommandLineArgs();
76+
boolean endOfOptions = false;
6877
for (String arg : args) {
69-
if (arg.startsWith("--")) {
78+
if (!endOfOptions && arg.startsWith("--")) {
7079
String optionText = arg.substring(2);
71-
String optionName;
72-
String optionValue = null;
7380
int indexOfEqualsSign = optionText.indexOf('=');
7481
if (indexOfEqualsSign > -1) {
75-
optionName = optionText.substring(0, indexOfEqualsSign);
76-
optionValue = optionText.substring(indexOfEqualsSign + 1);
82+
String optionName = optionText.substring(0, indexOfEqualsSign);
83+
String optionValue = optionText.substring(indexOfEqualsSign + 1);
84+
if (optionName.isEmpty()) {
85+
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
86+
}
87+
commandLineArgs.addOptionArg(optionName, optionValue);
7788
}
78-
else {
79-
optionName = optionText;
89+
else if (!optionText.isEmpty()){
90+
commandLineArgs.addOptionArg(optionText, null);
8091
}
81-
if (optionName.isEmpty()) {
82-
throw new IllegalArgumentException("Invalid argument syntax: " + arg);
92+
else {
93+
// '--' End of options delimiter, all remaining args must be non-optional
94+
endOfOptions = true;
8395
}
84-
commandLineArgs.addOptionArg(optionName, optionValue);
8596
}
8697
else {
8798
commandLineArgs.addNonOptionArg(arg);

spring-core/src/test/java/org/springframework/core/env/SimpleCommandLineArgsParserTests.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
*
3131
* @author Chris Beams
3232
* @author Sam Brannen
33+
* @author Brian Clozel
3334
*/
3435
class SimpleCommandLineArgsParserTests {
3536

@@ -66,11 +67,6 @@ void withMixOfOptionsHavingValueAndOptionsHavingNoValue() {
6667
assertThat(args.getOptionValues("o3")).isNull();
6768
}
6869

69-
@Test
70-
void withEmptyOptionText() {
71-
assertThatIllegalArgumentException().isThrownBy(() -> parser.parse("--"));
72-
}
73-
7470
@Test
7571
void withEmptyOptionName() {
7672
assertThatIllegalArgumentException().isThrownBy(() -> parser.parse("--=v1"));
@@ -112,4 +108,13 @@ void assertNonOptionArgsIsUnmodifiable() {
112108
args.getNonOptionArgs().add("foo"));
113109
}
114110

111+
@Test
112+
void supportsEndOfOptionsDelimiter() {
113+
CommandLineArgs args = parser.parse("--o1=v1", "--", "--o2=v2");
114+
assertThat(args.containsOption("o1")).isTrue();
115+
assertThat(args.containsOption("o2")).isFalse();
116+
assertThat(args.getOptionValues("o1")).containsExactly("v1");
117+
assertThat(args.getNonOptionArgs()).contains("--o2=v2");
118+
}
119+
115120
}

0 commit comments

Comments
 (0)