Skip to content

Commit f8c42e1

Browse files
committed
[CLI-329] Support "Deprecated" CLI Options
Deprecated string looks like: "Option 'c': Deprecated for removal since 2.0: Use X."
1 parent a37841b commit f8c42e1

5 files changed

Lines changed: 67 additions & 61 deletions

File tree

src/main/java/org/apache/commons/cli/CommandLine.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public static final class Builder {
5151
/**
5252
* Prints an Option to {@link System#out}.
5353
*/
54-
static final Consumer<Option> DEPRECATED_HANDLER = o -> System.out.println(o);
54+
static final Consumer<Option> DEPRECATED_HANDLER = o -> System.out.println(o.toDeprecatedString());
5555

5656
/** The unrecognized options/arguments */
5757
private final List<String> args = new LinkedList<>();
@@ -570,7 +570,6 @@ private void handleDeprecated(final Option option) {
570570
if (deprecatedHandler != null) {
571571
deprecatedHandler.accept(option);
572572
}
573-
574573
}
575574

576575
/**

src/main/java/org/apache/commons/cli/DeprecatedAttributes.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -167,23 +167,16 @@ private String toEmpty(final String since) {
167167
return since != null ? since : EMPTY_STRING;
168168
}
169169

170-
public String toShortString() {
171-
final StringBuilder builder = new StringBuilder();
172-
builder.append("Deprecated");
170+
@Override
171+
public String toString() {
172+
final StringBuilder builder = new StringBuilder("Deprecated");
173173
if (forRemoval) {
174174
builder.append(" for removal");
175175
}
176176
if (!since.isEmpty()) {
177177
builder.append(" since ");
178178
builder.append(since);
179179
}
180-
return builder.toString();
181-
}
182-
183-
@Override
184-
public String toString() {
185-
final StringBuilder builder = new StringBuilder();
186-
builder.append(toShortString());
187180
if (!description.isEmpty()) {
188181
builder.append(": ");
189182
builder.append(description);

src/main/java/org/apache/commons/cli/Option.java

Lines changed: 49 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,13 @@ Licensed to the Apache Software Foundation (ASF) under one or more
2525
import java.util.Objects;
2626

2727
/**
28-
* Describes a single command-line option. It maintains information regarding the short-name of the option, the
29-
* long-name, if any exists, a flag indicating if an argument is required for this option, and a self-documenting
30-
* description of the option.
28+
* Describes a single command-line option. It maintains information regarding the short-name of the option, the long-name, if any exists, a flag indicating if
29+
* an argument is required for this option, and a self-documenting description of the option.
3130
* <p>
32-
* An Option is not created independently, but is created through an instance of {@link Options}. An Option is required
33-
* to have at least a short or a long-name.
31+
* An Option is not created independently, but is created through an instance of {@link Options}. An Option is required to have at least a short or a long-name.
3432
* </p>
3533
* <p>
36-
* <b>Note:</b> once an {@link Option} has been added to an instance of {@link Options}, its required flag cannot be
37-
* changed.
34+
* <b>Note:</b> once an {@link Option} has been added to an instance of {@link Options}, its required flag cannot be changed.
3835
* </p>
3936
*
4037
* @see org.apache.commons.cli.Options
@@ -126,7 +123,9 @@ public Option build() {
126123
/**
127124
* Sets the converter for the option.
128125
*
129-
* <p>Note: see {@link TypeHandler} for serialization discussion.</p>
126+
* <p>
127+
* Note: see {@link TypeHandler} for serialization discussion.
128+
* </p>
130129
*
131130
* @param converter the Converter to use.
132131
* @return this builder, to allow method chaining.
@@ -300,7 +299,7 @@ public Builder valueSeparator() {
300299
* Option opt = Option.builder("D").hasArgs().valueSeparator('=').build();
301300
* Options options = new Options();
302301
* options.addOption(opt);
303-
* String[] args = {"-Dkey=value"};
302+
* String[] args = { "-Dkey=value" };
304303
* CommandLineParser parser = new DefaultParser();
305304
* CommandLine line = parser.parse(options, args);
306305
* String propertyName = line.getOptionValues("D")[0]; // will be "key"
@@ -389,7 +388,7 @@ public static Builder builder(final String option) {
389388
/** The character that is the value separator. */
390389
private char valuesep;
391390

392-
/** The explicit converter for this option. May be null. */
391+
/** The explicit converter for this option. May be null. */
393392
private transient Converter<?, ?> converter;
394393

395394
/**
@@ -414,8 +413,8 @@ private Option(final Builder builder) {
414413
/**
415414
* Creates an Option using the specified parameters.
416415
*
417-
* @param option short representation of the option.
418-
* @param hasArg specifies whether the Option takes an argument or not.
416+
* @param option short representation of the option.
417+
* @param hasArg specifies whether the Option takes an argument or not.
419418
* @param description describes the function of the option.
420419
*
421420
* @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
@@ -427,7 +426,7 @@ public Option(final String option, final boolean hasArg, final String descriptio
427426
/**
428427
* Creates an Option using the specified parameters. The option does not take an argument.
429428
*
430-
* @param option short representation of the option.
429+
* @param option short representation of the option.
431430
* @param description describes the function of the option.
432431
*
433432
* @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
@@ -439,9 +438,9 @@ public Option(final String option, final String description) throws IllegalArgum
439438
/**
440439
* Creates an Option using the specified parameters.
441440
*
442-
* @param option short representation of the option.
443-
* @param longOption the long representation of the option.
444-
* @param hasArg specifies whether the Option takes an argument or not.
441+
* @param option short representation of the option.
442+
* @param longOption the long representation of the option.
443+
* @param hasArg specifies whether the Option takes an argument or not.
445444
* @param description describes the function of the option.
446445
*
447446
* @throws IllegalArgumentException if there are any non valid Option characters in {@code opt}.
@@ -469,8 +468,8 @@ boolean acceptsArg() {
469468
}
470469

471470
/**
472-
* Adds the value to this Option. If the number of arguments is greater than zero and there is enough space in the list
473-
* then add the value. Otherwise, throw a runtime exception.
471+
* Adds the value to this Option. If the number of arguments is greater than zero and there is enough space in the list then add the value. Otherwise, throw
472+
* a runtime exception.
474473
*
475474
* @param value The value to be added to this Option.
476475
*
@@ -485,8 +484,7 @@ private void add(final String value) {
485484
}
486485

487486
/**
488-
* This method is not intended to be used. It was a piece of internal API that was made public in 1.0. It currently
489-
* throws an UnsupportedOperationException.
487+
* This method is not intended to be used. It was a piece of internal API that was made public in 1.0. It currently throws an UnsupportedOperationException.
490488
*
491489
* @param value the value to add.
492490
* @return always throws an {@link UnsupportedOperationException}.
@@ -496,7 +494,7 @@ private void add(final String value) {
496494
@Deprecated
497495
public boolean addValue(final String value) {
498496
throw new UnsupportedOperationException(
499-
"The addValue method is not intended for client use. " + "Subclasses should use the addValueForProcessing method instead. ");
497+
"The addValue method is not intended for client use. " + "Subclasses should use the addValueForProcessing method instead. ");
500498
}
501499

502500
/**
@@ -512,8 +510,7 @@ void addValueForProcessing(final String value) {
512510
}
513511

514512
/**
515-
* Clears the Option values. After a parse is complete, these are left with data in them and they need clearing if
516-
* another parse is done.
513+
* Clears the Option values. After a parse is complete, these are left with data in them and they need clearing if another parse is done.
517514
*
518515
* See: <a href="https://issues.apache.org/jira/browse/CLI-71">CLI-71</a>
519516
*/
@@ -566,9 +563,8 @@ public String getArgName() {
566563
* Gets the number of argument values this Option can take.
567564
*
568565
* <p>
569-
* A value equal to the constant {@link #UNINITIALIZED} (= -1) indicates the number of arguments has not been specified.
570-
* A value equal to the constant {@link #UNLIMITED_VALUES} (= -2) indicates that this options takes an unlimited amount
571-
* of values.
566+
* A value equal to the constant {@link #UNINITIALIZED} (= -1) indicates the number of arguments has not been specified. A value equal to the constant
567+
* {@link #UNLIMITED_VALUES} (= -2) indicates that this options takes an unlimited amount of values.
572568
* </p>
573569
*
574570
* @return num the number of argument values.
@@ -609,8 +605,7 @@ public String getDescription() {
609605
}
610606

611607
/**
612-
* Gets the id of this Option. This is only set when the Option shortOpt is a single character. This is used for
613-
* switch statements.
608+
* Gets the id of this Option. This is only set when the Option shortOpt is a single character. This is used for switch statements.
614609
*
615610
* @return the id of this Option.
616611
*/
@@ -619,8 +614,7 @@ public int getId() {
619614
}
620615

621616
/**
622-
* Gets the 'unique' Option identifier. This is the option value if set or the long value
623-
* if the options value is not set.
617+
* Gets the 'unique' Option identifier. This is the option value if set or the long value if the options value is not set.
624618
*
625619
* @return the 'unique' Option identifier.
626620
* @since 1.7.0
@@ -642,8 +636,8 @@ public String getLongOpt() {
642636
/**
643637
* Gets the name of this Option.
644638
*
645-
* It is this String which can be used with {@link CommandLine#hasOption(String opt)} and
646-
* {@link CommandLine#getOptionValue(String opt)} to check for existence and argument.
639+
* It is this String which can be used with {@link CommandLine#hasOption(String opt)} and {@link CommandLine#getOptionValue(String opt)} to check for
640+
* existence and argument.
647641
*
648642
* @return The name of this option.
649643
*/
@@ -811,9 +805,8 @@ public boolean isRequired() {
811805
}
812806

813807
/**
814-
* Processes the value. If this Option has a value separator the value will have to be parsed into individual tokens.
815-
* When n-1 tokens have been processed and there are more value separators in the value, parsing is ceased and the
816-
* remaining characters are added as a single token.
808+
* Processes the value. If this Option has a value separator the value will have to be parsed into individual tokens. When n-1 tokens have been processed
809+
* and there are more value separators in the value, parsing is ceased and the remaining characters are added as a single token.
817810
*
818811
* @param value The String to be processed.
819812
*
@@ -945,8 +938,7 @@ public void setType(final Class<?> type) {
945938
/**
946939
* Sets the type of this Option.
947940
* <p>
948-
* <b>Note:</b> this method is kept for binary compatibility and the input type is supposed to be a {@link Class}
949-
* object.
941+
* <b>Note:</b> this method is kept for binary compatibility and the input type is supposed to be a {@link Class} object.
950942
* </p>
951943
*
952944
* @param type the type of this Option.
@@ -966,6 +958,21 @@ public void setValueSeparator(final char sep) {
966958
this.valuesep = sep;
967959
}
968960

961+
String toDeprecatedString() {
962+
if (!isDeprecated()) {
963+
return "";
964+
}
965+
final StringBuilder buf = new StringBuilder().append("Option '");
966+
buf.append(option).append('\'');
967+
if (longOption != null) {
968+
buf.append('\'').append(longOption).append('\'');
969+
}
970+
if (isDeprecated()) {
971+
buf.append(": ").append(deprecated);
972+
}
973+
return buf.toString();
974+
}
975+
969976
/**
970977
* Creates a String suitable for debugging.
971978
*
@@ -974,16 +981,15 @@ public void setValueSeparator(final char sep) {
974981
@Override
975982
public String toString() {
976983
final StringBuilder buf = new StringBuilder().append("[ ");
977-
if (isDeprecated()) {
978-
buf.append(deprecated.toShortString());
979-
buf.append(' ');
980-
}
981-
buf.append("option: ");
984+
buf.append("Option ");
982985
buf.append(option);
983986
if (longOption != null) {
984987
buf.append(' ').append(longOption);
985988
}
986-
buf.append(' ');
989+
if (isDeprecated()) {
990+
buf.append(' ');
991+
buf.append(deprecated.toString());
992+
}
987993
if (hasArgs()) {
988994
buf.append("[ARG...]");
989995
} else if (hasArg()) {

src/test/java/org/apache/commons/cli/OptionTest.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,6 @@ public void testHashCode() {
266266

267267
@Test
268268
public void testSerialization() throws IOException, ClassNotFoundException {
269-
270269
final Option o = Option.builder("o").type(TypeHandlerTest.Instantiable.class).build();
271270
assertEquals(Converter.DEFAULT, o.getConverter());
272271
Option o2 = roundTrip(o);

src/test/java/org/apache/commons/cli/OptionsTest.java

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,10 @@ Licensed to the Apache Software Foundation (ASF) under one or more
1717

1818
package org.apache.commons.cli;
1919

20+
2021
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
2122
import static org.junit.jupiter.api.Assertions.assertEquals;
23+
import static org.junit.jupiter.api.Assertions.assertFalse;
2224
import static org.junit.jupiter.api.Assertions.assertNotNull;
2325
import static org.junit.jupiter.api.Assertions.assertThrows;
2426
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -132,18 +134,25 @@ public void testDuplicateLong() {
132134
@Test
133135
public void testDeprecated() {
134136
final Options opts = new Options();
135-
opts.addOption(Option.builder().option("a").deprecated().build());
136-
opts.addOption(Option.builder().option("b").build());
137-
assertTrue(opts.getOption("a").toString().startsWith("[ Deprecated option:"));
138-
assertTrue(opts.getOption("b").toString().startsWith("[ option:"));
137+
opts.addOption(Option.builder().option("a").build());
138+
opts.addOption(Option.builder().option("b").deprecated().build());
139+
opts.addOption(Option.builder().option("c")
140+
.deprecated(DeprecatedAttributes.builder().setForRemoval(true).setSince("2.0").setDescription("Use X.").get()).build());
141+
// toString()
142+
assertTrue(opts.getOption("a").toString().startsWith("[ Option a"));
143+
assertTrue(opts.getOption("b").toString().startsWith("[ Option b"));
144+
assertTrue(opts.getOption("c").toString().startsWith("[ Option c"));
145+
// toDeprecatedString()
146+
assertFalse(opts.getOption("a").toDeprecatedString().startsWith("Option a"));
147+
assertEquals("Option 'b': Deprecated", opts.getOption("b").toDeprecatedString());
148+
assertEquals("Option 'c': Deprecated for removal since 2.0: Use X.", opts.getOption("c").toDeprecatedString());
139149
}
140150

141151
@Test
142152
public void testDuplicateSimple() {
143153
final Options opts = new Options();
144154
opts.addOption("a", false, "toggle -a");
145155
opts.addOption("a", true, "toggle -a*");
146-
147156
assertEquals("toggle -a*", opts.getOption("a").getDescription(), "last one in wins");
148157
}
149158

0 commit comments

Comments
 (0)