Move parsing of --help/-h to CmdLineParser

Make the handling of --help common across all uses of CmdLineParser.
This will eventually make it easier to support more complex parsing
cases that need to span objects.

Change-Id: I38b153035cfc5cce80ca631be66c8b4d4683590d
This commit is contained in:
Shawn O. Pearce
2012-04-04 15:11:42 -07:00
parent 7b825b3871
commit 2a9ced1f9e
3 changed files with 95 additions and 14 deletions

View File

@@ -34,9 +34,6 @@ public abstract class AbstractProgram {
@Option(name = "--show-stack-trace", usage = "display stack trace on failure") @Option(name = "--show-stack-trace", usage = "display stack trace on failure")
protected boolean showStackTrace; protected boolean showStackTrace;
@Option(name = "--help", usage = "display this help text", aliases = {"-h"})
private boolean help;
private String getName() { private String getName() {
String n = getClass().getName(); String n = getClass().getName();
int dot = n.lastIndexOf('.'); int dot = n.lastIndexOf('.');
@@ -52,13 +49,13 @@ public abstract class AbstractProgram {
try { try {
clp.parseArgument(argv); clp.parseArgument(argv);
} catch (CmdLineException err) { } catch (CmdLineException err) {
if (!help) { if (!clp.wasHelpRequestedByOption()) {
System.err.println("fatal: " + err.getMessage()); System.err.println("fatal: " + err.getMessage());
return 1; return 1;
} }
} }
if (help) { if (clp.wasHelpRequestedByOption()) {
final StringWriter msg = new StringWriter(); final StringWriter msg = new StringWriter();
msg.write(getName()); msg.write(getName());
clp.printSingleLineUsage(msg, null); clp.printSingleLineUsage(msg, null);

View File

@@ -60,9 +60,6 @@ public abstract class BaseCommand implements Command {
static final int STATUS_NOT_FOUND = PRIVATE_STATUS | 2; static final int STATUS_NOT_FOUND = PRIVATE_STATUS | 2;
public static final int STATUS_NOT_ADMIN = PRIVATE_STATUS | 3; public static final int STATUS_NOT_ADMIN = PRIVATE_STATUS | 3;
@Option(name = "--help", usage = "display this help text", aliases = {"-h"})
private boolean help;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@Option(name = "--", usage = "end of options", handler = EndOfOptionsHandler.class) @Option(name = "--", usage = "end of options", handler = EndOfOptionsHandler.class)
private boolean endOfOptions; private boolean endOfOptions;
@@ -159,16 +156,16 @@ public abstract class BaseCommand implements Command {
try { try {
clp.parseArgument(argv); clp.parseArgument(argv);
} catch (IllegalArgumentException err) { } catch (IllegalArgumentException err) {
if (!help) { if (!clp.wasHelpRequestedByOption()) {
throw new UnloggedFailure(1, "fatal: " + err.getMessage()); throw new UnloggedFailure(1, "fatal: " + err.getMessage());
} }
} catch (CmdLineException err) { } catch (CmdLineException err) {
if (!help) { if (!clp.wasHelpRequestedByOption()) {
throw new UnloggedFailure(1, "fatal: " + err.getMessage()); throw new UnloggedFailure(1, "fatal: " + err.getMessage());
} }
} }
if (help) { if (clp.wasHelpRequestedByOption()) {
final StringWriter msg = new StringWriter(); final StringWriter msg = new StringWriter();
msg.write(commandName); msg.write(commandName);
clp.printSingleLineUsage(msg, null); clp.printSingleLineUsage(msg, null);

View File

@@ -44,11 +44,14 @@ import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.IllegalAnnotationError; import org.kohsuke.args4j.IllegalAnnotationError;
import org.kohsuke.args4j.Option; import org.kohsuke.args4j.Option;
import org.kohsuke.args4j.OptionDef; import org.kohsuke.args4j.OptionDef;
import org.kohsuke.args4j.spi.BooleanOptionHandler;
import org.kohsuke.args4j.spi.OptionHandler; import org.kohsuke.args4j.spi.OptionHandler;
import org.kohsuke.args4j.spi.Setter; import org.kohsuke.args4j.spi.Setter;
import java.io.Writer; import java.io.Writer;
import java.lang.annotation.Annotation;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle; import java.util.ResourceBundle;
/** /**
@@ -102,6 +105,10 @@ public class CmdLineParser {
parser.printUsage(out, rb); parser.printUsage(out, rb);
} }
public boolean wasHelpRequestedByOption() {
return parser.help.value;
}
public void parseArgument(final String... args) throws CmdLineException { public void parseArgument(final String... args) throws CmdLineException {
final ArrayList<String> tmp = new ArrayList<String>(args.length); final ArrayList<String> tmp = new ArrayList<String>(args.length);
for (int argi = 0; argi < args.length; argi++) { for (int argi = 0; argi < args.length; argi++) {
@@ -128,8 +135,13 @@ public class CmdLineParser {
} }
private class MyParser extends org.kohsuke.args4j.CmdLineParser { private class MyParser extends org.kohsuke.args4j.CmdLineParser {
@SuppressWarnings("rawtypes")
private List<OptionHandler> options;
private HelpOption help;
MyParser(final Object bean) { MyParser(final Object bean) {
super(bean); super(bean);
ensureOptionsInitialized();
} }
@SuppressWarnings({"unchecked", "rawtypes"}) @SuppressWarnings({"unchecked", "rawtypes"})
@@ -137,7 +149,7 @@ public class CmdLineParser {
protected OptionHandler createOptionHandler(final OptionDef option, protected OptionHandler createOptionHandler(final OptionDef option,
final Setter setter) { final Setter setter) {
if (isHandlerSpecified(option) || isEnum(setter) || isPrimitive(setter)) { if (isHandlerSpecified(option) || isEnum(setter) || isPrimitive(setter)) {
return super.createOptionHandler(option, setter); return add(super.createOptionHandler(option, setter));
} }
final Key<OptionHandlerFactory<?>> key = final Key<OptionHandlerFactory<?>> key =
@@ -145,12 +157,28 @@ public class CmdLineParser {
Injector i = injector; Injector i = injector;
while (i != null) { while (i != null) {
if (i.getBindings().containsKey(key)) { if (i.getBindings().containsKey(key)) {
return i.getInstance(key).create(this, option, setter); return add(i.getInstance(key).create(this, option, setter));
} }
i = i.getParent(); i = i.getParent();
} }
return super.createOptionHandler(option, setter); return add(super.createOptionHandler(option, setter));
}
@SuppressWarnings("rawtypes")
private OptionHandler add(OptionHandler handler) {
ensureOptionsInitialized();
options.add(handler);
return handler;
}
@SuppressWarnings("rawtypes")
private void ensureOptionsInitialized() {
if (options == null) {
help = new HelpOption();
options = new ArrayList<OptionHandler>();
addOption(help, help);
}
} }
private boolean isHandlerSpecified(final OptionDef option) { private boolean isHandlerSpecified(final OptionDef option) {
@@ -165,4 +193,63 @@ public class CmdLineParser {
return setter.getType().isPrimitive(); return setter.getType().isPrimitive();
} }
} }
private static class HelpOption implements Option, Setter<Boolean> {
private boolean value;
@Override
public String name() {
return "--help";
}
@Override
public String[] aliases() {
return new String[] {"-h"};
}
@Override
public String usage() {
return "display this help text";
}
@Override
public void addValue(Boolean val) {
value = val;
}
@Override
public Class<? extends OptionHandler<Boolean>> handler() {
return BooleanOptionHandler.class;
}
@Override
public String metaVar() {
return "";
}
@Override
public boolean multiValued() {
return false;
}
@Override
public boolean required() {
return false;
}
@Override
public Class<? extends Annotation> annotationType() {
return Option.class;
}
@Override
public Class<Boolean> getType() {
return Boolean.class;
}
@Override
public boolean isMultiValued() {
return multiValued();
}
}
} }