Skip to content

Commit c0b9b3c

Browse files
authored
Cleanup deprecation issues (apache#272)
* updated documentation * Added tests to show errors * fixed default output for help, removed duplicate warning in parseOptionValue * removed unused import
1 parent a1f86c0 commit c0b9b3c

5 files changed

Lines changed: 215 additions & 30 deletions

File tree

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

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -499,9 +499,6 @@ public <T> T getParsedOptionValue(final Option option, final Supplier<T> default
499499
if (option == null) {
500500
return get(defaultValue);
501501
}
502-
if (option.isDeprecated()) {
503-
handleDeprecated(option);
504-
}
505502
final String res = getOptionValue(option);
506503
try {
507504
if (res == null) {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ public static final class Builder implements Supplier<HelpFormatter> {
8383
/**
8484
* Formatter for deprecated options.
8585
*/
86-
private BiFunction<String, Option, String> deprecatedFormatFunc;
86+
private BiFunction<String, Option, String> deprecatedFormatFunc = DEFAULT_DEPRECATED_FORMAT;
8787

8888
/**
8989
* The output PrintWriter, defaults to wrapping {@link System#out}.

src/site/xdoc/usage.xml

Lines changed: 156 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ Option buildFile = Option.builder("buildfile")
205205
.desc("use given buildfile")
206206
.build();
207207

208-
Option find = Option.builde("find")
208+
Option find = Option.builder("find")
209209
.argName("file")
210210
.hasArg()
211211
.desc("search for buildfile towards the "
@@ -214,7 +214,7 @@ Option find = Option.builde("find")
214214
</subsection>
215215
<subsection name="Defining Java Property Option">
216216
<p>
217-
The last option to create is the Java property and it is also created
217+
The last option to create is the Java property, and it is also created
218218
using the Option class' Builder.
219219
</p>
220220
<source>Option property = Option property = Option.builder("D")
@@ -252,7 +252,7 @@ options.addOption(buildfile);
252252
options.addOption(find);
253253
options.addOption(property);</source>
254254
<p>
255-
All the preperation is now complete and we are now ready to
255+
All the preparation is now complete, and we are now ready to
256256
parse the command line arguments.
257257
</p>
258258
</subsection>
@@ -317,7 +317,7 @@ formatter.printHelp("ant", options);</source>
317317
<p>
318318
If you also require to have a usage statement printed
319319
then calling <code>formatter.printHelp("ant", options, true)</code>
320-
will generate a usage statment as well as the help information.
320+
will generate a usage statement as well as the help information.
321321
</p>
322322
</subsection>
323323
</section>
@@ -389,7 +389,7 @@ catch (ParseException exp) {
389389
By in most cases the values on the command line are retrieved as Strings via the
390390
<code>commandLine.getOptionValue(key)</code> command. However, it is possible for
391391
the CLI library to convert the string into a different object. For example to specify
392-
that the "count" option should reutrn an Integer the following code could be used:
392+
that the "count" option should return an Integer the following code could be used:
393393
</p>
394394
<source>
395395
public static void main(String[] args) {
@@ -398,7 +398,7 @@ catch (ParseException exp) {
398398
.desc("the number of things")
399399
.type(Integer.class)
400400
.build();
401-
Options options = new Options().addOption(cound);
401+
Options options = new Options().addOption(count);
402402
// create the parser
403403
CommandLineParser parser = new DefaultParser();
404404
try {
@@ -440,7 +440,7 @@ catch (ParseException exp) {
440440
</ul>
441441
Additional types may be added to the automatic parsing system by calling <code>TypeHandler.register(Class&lt;T&gt; clazz, Converter&lt;T&gt; converter)</code>.
442442
The <code>Class&lt;T&gt;</code> can be any defined class. The converter is a function that takes a <code>String</code> argument and returns an instance of
443-
the class. Any expection thrown by the constructor will be caught and reported as a <code>ParseException</code>
443+
the class. Any exception thrown by the constructor will be caught and reported as a <code>ParseException</code>
444444
</p>
445445
<p>
446446
Conversions can be specified without using the <code>TypeHandler</code> class by specifying the converter
@@ -459,5 +459,154 @@ catch (ParseException exp) {
459459
before deserialization begins.
460460
</p>
461461
</section>
462+
<section name="Deprecating Options">
463+
<p>
464+
Options may be marked as deprecated using ghe <code>Option.builder.deprecated()</code> method.
465+
Additional information may be specified by passing a <code>DeprecatedAttributes</code> instance to the
466+
<code>deprecated</code> method.
467+
468+
Usage of the deprecated option is announced when the presence of the option is checked
469+
or the value of the option is retrieved. By default the announcement printed to Standard out.
470+
471+
The HelpFormatter output will be default show the description prefixed by "[Deprecated]"
472+
</p>
473+
<p>
474+
The examples below will implement <code>doSomething</code> in the following code block.
475+
<source>
476+
public static void main(String[] args) {
477+
Option n = Option.builder("n")
478+
.deprecated(DeprecatedAttributes.builder()
479+
.setDescription("Use '-count' instead")
480+
.setForRemoval(true)
481+
.setSince("now").get())
482+
.hasArg()
483+
.desc("the number of things")
484+
.type(Integer.class)
485+
.build();
486+
Option count = Option.builder("count")
487+
.hasArg()
488+
.desc("the number of things")
489+
.type(Integer.class)
490+
.build();
491+
Options options = new Options().addOption(n).addOption(count);
492+
493+
doSomething(options);
494+
}
495+
</source>
496+
</p>
497+
498+
<subsection name="Changing Usage Announcement">
499+
<p>
500+
The usage announcement may be changed by providing a <code>Consumer&gt;Option&lt;></code> to the
501+
<code>CommandLine.Builder.deprecatedHandler</code> method.
502+
</p>
503+
<p>
504+
for example if <code>doSomething</code> is implemented as:
505+
</p>
506+
<sorce>
507+
void doSomething(Options options) {
508+
CommandLineParser parser = new DefaultParser();
509+
CommandLine line;
510+
try {
511+
// parse the command line arguments
512+
line = parser.parse(options, new String[] {"-n", "5"});
513+
System.out.println( "n="+line.getParsedOptionValue("n"));
514+
} catch (ParseException exp) {
515+
// oops, something went wrong
516+
System.err.println("Parsing failed. Reason: " + exp.getMessage());
517+
}
518+
}
519+
</sorce>
520+
<p>
521+
The output of the run would be.
522+
</p>
523+
524+
<source>
525+
Option 'n': Deprecated for removal since now: Use '-count' instead
526+
n=5
527+
</source>
528+
529+
<p>
530+
for example if <code>doSomething</code> is implemented as:
531+
</p>
532+
533+
<source>
534+
void doSomething(Options options) {
535+
Consumer&gt;Option&lt; deprecatedUsageAnnouncement = o -> {
536+
final StringBuilder buf = new StringBuilder()
537+
.append("'")
538+
.append(o.getOpt())
539+
.append("'");
540+
if (o.getLongOpt() != null) {
541+
buf.append("'").append(o.getLongOpt()).append("'");
542+
}
543+
System.err.printf("ERROR: Option %s: %s%n", buf, o.getDeprecated());
544+
};
545+
DefaultParser parser = DefaultParser.builder().setDeprecatedHandler(deprecatedUsageAnnouncement).build();
546+
CommandLine line;
547+
try {
548+
// parse the command line arguments
549+
line = parser.parse(options, new String[] {"-n", "5"});
550+
System.out.println( "n="+line.getParsedOptionValue("n"));
551+
} catch (ParseException exp) {
552+
// oops, something went wrong
553+
System.err.println("Parsing failed. Reason: " + exp.getMessage());
554+
}
555+
}
556+
</source>
557+
<p>
558+
The output of the run would be.
559+
</p>
560+
<source>
561+
ERROR: Option 'n': Deprecated for removal since now: Use '-count' instead
562+
n=5
563+
</source>
564+
<p>
565+
However, the first line would be printed on system err instead of system out.
566+
</p>
567+
568+
</subsection>
569+
<subsection name="Changing help format">
570+
<p>
571+
If <code>doSomething</code> is implemented as:
572+
<source>
573+
void doSomething(Options options) {
574+
HelpFormatter formatter = HelpFormatter.builder().get();
575+
formatter.printHelp("Command line syntax:", options);
576+
}
577+
</source>
578+
To output is
579+
<source>
580+
usage: Command line syntax:
581+
-count &lt;arg> the number of things
582+
-n &lt;arg> [Deprecated] the number of things
583+
</source>
584+
</p>
585+
<p>
586+
The display of deprecated options may be changed through the use of the
587+
<code>HelpFormatter.Builder.setShowDeprecated()</code> method.
588+
<ul>
589+
<li>Calling <code>HelpFormatter.Builder.setShowDeprecated(false)</code> will disable the "[Deprecated]" tag.</li>
590+
<li>Calling <code>HelpFormatter.Builder.setShowDeprecated</code> with a <code>BiFunction&lt;String, Option, String></code>
591+
will use the output of the function as the description for the option.</li>
592+
</ul>
593+
As an example of the second case above, changing the implementation of <code>doSomething</code> to
594+
<source>
595+
void doSomething(Options options) {
596+
BiFunction&lt;String, Option, String> disp = (desc, option) -> String.format( "%s. %s", desc, option.getDeprecated().toString());
597+
HelpFormatter formatter = HelpFormatter.builder().setShowDeprecated(disp).get();
598+
formatter.printHelp("Command line syntax:", options);
599+
}
600+
</source>
601+
changes the output to
602+
<source>
603+
usage: Command line syntax:
604+
-count &lt;arg> the number of things
605+
-n &lt;arg> the number of things. Deprecated for removal since now:
606+
Use '-count' instead
607+
</source>
608+
</p>
609+
</subsection>
610+
</section>
462611
</body>
463612
</document>

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

Lines changed: 50 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ Licensed to the Apache Software Foundation (ASF) under one or more
2222
import static org.junit.jupiter.api.Assertions.assertNull;
2323
import static org.junit.jupiter.api.Assertions.assertSame;
2424

25+
import java.util.ArrayList;
26+
import java.util.List;
2527
import java.util.Properties;
2628
import java.util.concurrent.atomic.AtomicReference;
2729
import java.util.function.Supplier;
@@ -86,36 +88,66 @@ public void testDeprecatedDefaultOption() {
8688
public void testDeprecatedOption() {
8789
final CommandLine.Builder builder = new CommandLine.Builder();
8890
builder.addArg("foo").addArg("bar");
89-
final Option opt = Option.builder().option("T").deprecated().build();
91+
final Option opt = Option.builder().option("T").longOpt("tee").deprecated().build();
9092
builder.addOption(opt);
91-
final AtomicReference<Option> handler = new AtomicReference<>();
92-
final CommandLine cmd = builder.setDeprecatedHandler(handler::set).build();
93+
// verify one and only one call
94+
List<Option> handler = new ArrayList<>();
95+
final CommandLine cmd = builder.setDeprecatedHandler(handler::add).build();
96+
// test short option arg
9397
cmd.getOptionValue(opt.getOpt());
94-
assertSame(opt, handler.get());
95-
handler.set(null);
96-
cmd.getOptionValue("Nope");
97-
assertNull(handler.get());
98-
handler.set(null);
98+
assertEquals(1, handler.size());
99+
assertSame(opt, handler.get(0));
100+
handler.clear();
101+
102+
// test long option arg
103+
cmd.getOptionValue(opt.getLongOpt());
104+
assertEquals(1, handler.size());
105+
assertSame(opt, handler.get(0));
106+
handler.clear();
107+
108+
// test Option arg
99109
cmd.getOptionValue(opt);
100-
assertSame(opt, handler.get());
110+
assertEquals(1, handler.size());
111+
assertSame(opt, handler.get(0));
112+
handler.clear();
113+
114+
// test not an option
115+
cmd.getOptionValue("Nope");
116+
assertEquals(0, handler.size());
101117
}
102118

103119
@Test
104120
public void testDeprecatedParsedOptionValue() throws ParseException {
105121
final CommandLine.Builder builder = new CommandLine.Builder();
106122
builder.addArg("foo").addArg("bar");
107-
final Option opt = Option.builder().option("T").deprecated().build();
123+
final Option opt = Option.builder().option("T").longOpt("tee").deprecated().build();
108124
builder.addOption(opt);
109-
final AtomicReference<Option> handler = new AtomicReference<>();
110-
final CommandLine cmd = builder.setDeprecatedHandler(handler::set).build();
125+
// verify one and only one call
126+
List<Option> handler = new ArrayList<>();
127+
final CommandLine cmd = builder.setDeprecatedHandler(handler::add).build();
128+
129+
// test short option arg
111130
cmd.getParsedOptionValue(opt.getOpt());
112-
assertSame(opt, handler.get());
113-
handler.set(null);
114-
cmd.getParsedOptionValue("Nope");
115-
assertNull(handler.get());
116-
handler.set(null);
131+
assertEquals(1, handler.size());
132+
assertSame(opt, handler.get(0));
133+
handler.clear();
134+
135+
// test long option arg
136+
cmd.getParsedOptionValue(opt.getLongOpt());
137+
assertEquals(1, handler.size());
138+
assertSame(opt, handler.get(0));
139+
handler.clear();
140+
141+
// test option arg
117142
cmd.getParsedOptionValue(opt);
118-
assertSame(opt, handler.get());
143+
assertEquals(1, handler.size());
144+
assertSame(opt, handler.get(0));
145+
handler.clear();
146+
147+
148+
// test not an option
149+
cmd.getParsedOptionValue("Nope");
150+
assertEquals(0, handler.size());
119151
}
120152

121153
@Test

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,11 @@ static Stream<Arguments> deprecatedOptionsProvider() {
4747
.setDescription("Why why why").get())
4848
.build();
4949

50-
HelpFormatter hf = HelpFormatter.builder().setShowDeprecated(false).get();
50+
HelpFormatter hf = HelpFormatter.builder().get();
51+
lst.add(Arguments.of(hf, option, "[Deprecated] dddd dddd dddd"));
52+
53+
54+
hf = HelpFormatter.builder().setShowDeprecated(false).get();
5155
lst.add(Arguments.of(hf, option, "dddd dddd dddd"));
5256

5357
hf = HelpFormatter.builder().setShowDeprecated(true).get();
@@ -61,6 +65,9 @@ static Stream<Arguments> deprecatedOptionsProvider() {
6165
.setDescription("Why why why").get())
6266
.build();
6367

68+
hf = HelpFormatter.builder().get();
69+
lst.add(Arguments.of(hf, option, "[Deprecated]"));
70+
6471
hf = HelpFormatter.builder().setShowDeprecated(false).get();
6572
lst.add(Arguments.of(hf, option, ""));
6673

0 commit comments

Comments
 (0)