CommandLineProcessorpublic class CommandLineProcessor extends Object Parses the command-line and stores flags needed or requested.
This is a base class. To be useful you want to:
- override it.
- pass an action array to the constructor.
- define flags for your actions.
To use, call {@link #parseArgs(String[])} and then
call {@link #getValue(String, String, String)}. |
Fields Summary |
---|
public static final String | GLOBAL_FLAG_VERBInternal verb name for internally hidden flags. | public static final String | NO_VERB_OBJECTString to use when the verb doesn't need any object. | public static final String | KEY_HELPThe global help flag. | public static final String | KEY_VERBOSEThe global verbose flag. | public static final String | KEY_SILENTThe global silent flag. | private String | mVerbRequestedVerb requested by the user. Null if none specified, which will be an error. | private String | mDirectObjectRequestedDirect object requested by the user. Can be null. | private final String[] | mActionsAction definitions.
Each entry is a string array with:
- the verb.
- a direct object (use #NO_VERB_OBJECT if there's no object).
- a description.
- an alternate form for the object (e.g. plural).
| private static final int | ACTION_VERB_INDEX | private static final int | ACTION_OBJECT_INDEX | private static final int | ACTION_DESC_INDEX | private static final int | ACTION_ALT_OBJECT_INDEX | private final HashMap | mArgumentsThe map of all defined arguments.
The key is a string "verb/directObject/longName". | private final com.android.sdklib.ISdkLog | mLogLogger |
Constructors Summary |
---|
public CommandLineProcessor(com.android.sdklib.ISdkLog logger, String[] actions)
mLog = logger;
mActions = actions;
define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "v", KEY_VERBOSE,
"Verbose mode: errors, warnings and informational messages are printed.",
false);
define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "s", KEY_SILENT,
"Silent mode: only errors are printed out.",
false);
define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "h", KEY_HELP,
"This help.",
false);
|
Methods Summary |
---|
protected void | define(com.android.sdkmanager.CommandLineProcessor$MODE mode, boolean mandatory, java.lang.String verb, java.lang.String directObject, java.lang.String shortName, java.lang.String longName, java.lang.String description, java.lang.Object defaultValue)Internal helper to define a new argument for a give action.
assert(mandatory || mode == MODE.BOOLEAN); // a boolean mode cannot be mandatory
if (directObject == null) {
directObject = NO_VERB_OBJECT;
}
String key = verb + "/" + directObject + "/" + longName;
mArguments.put(key, new Arg(mode, mandatory,
verb, directObject, shortName, longName, description, defaultValue));
| protected void | exit()Exits in case of error.
This is protected so that it can be overridden in unit tests.
System.exit(1);
| protected com.android.sdkmanager.CommandLineProcessor$Arg | findLongArg(java.lang.String verb, java.lang.String directObject, java.lang.String longName)Finds an {@link Arg} given an action name and a long flag name.
if (verb == null) {
verb = GLOBAL_FLAG_VERB;
}
if (directObject == null) {
directObject = NO_VERB_OBJECT;
}
String key = verb + "/" + directObject + "/" + longName;
return mArguments.get(key);
| protected com.android.sdkmanager.CommandLineProcessor$Arg | findShortArg(java.lang.String verb, java.lang.String directObject, java.lang.String shortName)Finds an {@link Arg} given an action name and a short flag name.
if (verb == null) {
verb = GLOBAL_FLAG_VERB;
}
if (directObject == null) {
directObject = NO_VERB_OBJECT;
}
for (Entry<String, Arg> entry : mArguments.entrySet()) {
Arg arg = entry.getValue();
if (arg.getVerb().equals(verb) && arg.getDirectObject().equals(directObject)) {
if (shortName.equals(arg.getShortArg())) {
return arg;
}
}
}
return null;
| public java.lang.String | getDirectObject()Returns the direct object name from the command-line. Can be null.
return mDirectObjectRequested;
| public java.lang.Object | getValue(java.lang.String verb, java.lang.String directObject, java.lang.String longFlagName)Raw access to parsed parameter values.
The default is to scan all parameters. Parameters that have been explicitly set on the
command line are returned first. Otherwise one with a non-null value is returned.
Both a verb and a direct object filter can be specified. When they are non-null they limit
the scope of the search.
If nothing has been found, return the last default value seen matching the filter.
if (verb != null && directObject != null) {
String key = verb + "/" + directObject + "/" + longFlagName;
Arg arg = mArguments.get(key);
return arg.getCurrentValue();
}
Object lastDefault = null;
for (Arg arg : mArguments.values()) {
if (arg.getLongArg().equals(longFlagName)) {
if (verb == null || arg.getVerb().equals(verb)) {
if (directObject == null || arg.getDirectObject().equals(directObject)) {
if (arg.isInCommandLine()) {
return arg.getCurrentValue();
}
if (arg.getCurrentValue() != null) {
lastDefault = arg.getCurrentValue();
}
}
}
}
}
return lastDefault;
| public java.lang.String | getVerb()Returns the verb name from the command-line. Can be null.
return mVerbRequested;
| public boolean | isHelpRequested()Helper that returns true if --help was requested.
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_HELP)).booleanValue();
| public boolean | isSilent()Helper that returns true if --silent was requested.
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_SILENT)).booleanValue();
| public boolean | isVerbose()Helper that returns true if --verbose was requested.
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_VERBOSE)).booleanValue();
| protected void | listOptions(java.lang.String verb, java.lang.String directObject)Internal helper to print all the option flags for a given action name.
int numOptions = 0;
for (Entry<String, Arg> entry : mArguments.entrySet()) {
Arg arg = entry.getValue();
if (arg.getVerb().equals(verb) && arg.getDirectObject().equals(directObject)) {
String value = "";
String required = "";
if (arg.isMandatory()) {
required = " [required]";
} else {
if (arg.getDefaultValue() instanceof String[]) {
for (String v : (String[]) arg.getDefaultValue()) {
if (value.length() > 0) {
value += ", ";
}
value += v;
}
} else if (arg.getDefaultValue() != null) {
Object v = arg.getDefaultValue();
if (arg.getMode() != MODE.BOOLEAN || v.equals(Boolean.TRUE)) {
value = v.toString();
}
}
if (value.length() > 0) {
value = " [Default: " + value + "]";
}
}
stdout(" -%1$s %2$-10s %3$s%4$s%5$s",
arg.getShortArg(),
"--" + arg.getLongArg(),
arg.getDescription(),
value,
required);
numOptions++;
}
}
if (numOptions == 0) {
stdout(" No options");
}
| public void | parseArgs(java.lang.String[] args)Parses the command-line arguments.
This method will exit and not return if a parsing error arise.
String needsHelp = null;
String verb = null;
String directObject = null;
try {
int n = args.length;
for (int i = 0; i < n; i++) {
Arg arg = null;
String a = args[i];
if (a.startsWith("--")) {
arg = findLongArg(verb, directObject, a.substring(2));
} else if (a.startsWith("-")) {
arg = findShortArg(verb, directObject, a.substring(1));
}
// No matching argument name found
if (arg == null) {
// Does it looks like a dashed parameter?
if (a.startsWith("-")) {
if (verb == null || directObject == null) {
// It looks like a dashed parameter and we don't have a a verb/object
// set yet, the parameter was just given too early.
needsHelp = String.format(
"Flag '%1$s' is not a valid global flag. Did you mean to specify it after the verb/object name?",
a);
return;
} else {
// It looks like a dashed parameter and but it is unknown by this
// verb-object combination
needsHelp = String.format(
"Flag '%1$s' is not valid for '%2$s %3$s'.",
a, verb, directObject);
return;
}
}
if (verb == null) {
// Fill verb first. Find it.
for (String[] actionDesc : mActions) {
if (actionDesc[ACTION_VERB_INDEX].equals(a)) {
verb = a;
break;
}
}
// Error if it was not a valid verb
if (verb == null) {
needsHelp = String.format(
"Expected verb after global parameters but found '%1$s' instead.",
a);
return;
}
} else if (directObject == null) {
// Then fill the direct object. Find it.
for (String[] actionDesc : mActions) {
if (actionDesc[ACTION_VERB_INDEX].equals(verb)) {
if (actionDesc[ACTION_OBJECT_INDEX].equals(a)) {
directObject = a;
break;
} else if (actionDesc.length > ACTION_ALT_OBJECT_INDEX &&
actionDesc[ACTION_ALT_OBJECT_INDEX].equals(a)) {
// if the alternate form exist and is used, we internally
// only memorize the default direct object form.
directObject = actionDesc[ACTION_OBJECT_INDEX];
break;
}
}
}
// Error if it was not a valid object for that verb
if (directObject == null) {
needsHelp = String.format(
"Expected verb after global parameters but found '%1$s' instead.",
a);
return;
}
}
} else if (arg != null) {
// This argument was present on the command line
arg.setInCommandLine(true);
// Process keyword
String error = null;
if (arg.getMode().needsExtra()) {
if (++i >= n) {
needsHelp = String.format("Missing argument for flag %1$s.", a);
return;
}
error = arg.getMode().process(arg, args[i]);
} else {
error = arg.getMode().process(arg, null);
// If we just toggled help, we want to exit now without printing any error.
// We do this test here only when a Boolean flag is toggled since booleans
// are the only flags that don't take parameters and help is a boolean.
if (isHelpRequested()) {
printHelpAndExit(null);
// The call above should terminate however in unit tests we override
// it so we still need to return here.
return;
}
}
if (error != null) {
needsHelp = String.format("Invalid usage for flag %1$s: %2$s.", a, error);
return;
}
}
}
if (needsHelp == null) {
if (verb == null) {
needsHelp = "Missing verb name.";
} else {
if (directObject == null) {
// Make sure this verb has an optional direct object
for (String[] actionDesc : mActions) {
if (actionDesc[ACTION_VERB_INDEX].equals(verb) &&
actionDesc[ACTION_OBJECT_INDEX].equals(NO_VERB_OBJECT)) {
directObject = NO_VERB_OBJECT;
break;
}
}
if (directObject == null) {
needsHelp = String.format("Missing object name for verb '%1$s'.", verb);
return;
}
}
// Validate that all mandatory arguments are non-null for this action
String missing = null;
boolean plural = false;
for (Entry<String, Arg> entry : mArguments.entrySet()) {
Arg arg = entry.getValue();
if (arg.getVerb().equals(verb) &&
arg.getDirectObject().equals(directObject)) {
if (arg.isMandatory() && arg.getCurrentValue() == null) {
if (missing == null) {
missing = "--" + arg.getLongArg();
} else {
missing += ", --" + arg.getLongArg();
plural = true;
}
}
}
}
if (missing != null) {
needsHelp = String.format(
"The %1$s %2$s must be defined for action '%3$s %4$s'",
plural ? "parameters" : "parameter",
missing,
verb,
directObject);
}
mVerbRequested = verb;
mDirectObjectRequested = directObject;
}
}
} finally {
if (needsHelp != null) {
printHelpAndExitForAction(verb, directObject, needsHelp);
}
}
| public void | printHelpAndExit(java.lang.String errorFormat, java.lang.Object args)Prints the help/usage and exits.
printHelpAndExitForAction(null /*verb*/, null /*directObject*/, errorFormat, args);
| public void | printHelpAndExitForAction(java.lang.String verb, java.lang.String directObject, java.lang.String errorFormat, java.lang.Object args)Prints the help/usage and exits.
if (errorFormat != null) {
stderr(errorFormat, args);
}
/*
* usage should fit in 80 columns
* 12345678901234567890123456789012345678901234567890123456789012345678901234567890
*/
stdout("\n" +
"Usage:\n" +
" android [global options] action [action options]\n" +
"\n" +
"Global options:");
listOptions(GLOBAL_FLAG_VERB, NO_VERB_OBJECT);
if (verb == null || directObject == null) {
stdout("\nValid actions are composed of a verb and an optional direct object:");
for (String[] action : mActions) {
stdout("- %1$6s %2$-7s: %3$s",
action[ACTION_VERB_INDEX],
action[ACTION_OBJECT_INDEX],
action[ACTION_DESC_INDEX]);
}
}
for (String[] action : mActions) {
if (verb == null || verb.equals(action[ACTION_VERB_INDEX])) {
if (directObject == null || directObject.equals(action[ACTION_OBJECT_INDEX])) {
stdout("\nAction \"%1$s %2$s\":",
action[ACTION_VERB_INDEX],
action[ACTION_OBJECT_INDEX]);
stdout(" %1$s", action[ACTION_DESC_INDEX]);
stdout("Options:");
listOptions(action[ACTION_VERB_INDEX], action[ACTION_OBJECT_INDEX]);
}
}
}
exit();
| protected void | setValue(java.lang.String verb, java.lang.String directObject, java.lang.String longFlagName, java.lang.Object value)Internal setter for raw parameter value.
String key = verb + "/" + directObject + "/" + longFlagName;
Arg arg = mArguments.get(key);
arg.setCurrentValue(value);
| protected void | stderr(java.lang.String format, java.lang.Object args)Prints a line to stderr.
This is protected so that it can be overridden in unit tests.
mLog.error(null, format, args);
| protected void | stdout(java.lang.String format, java.lang.Object args)Prints a line to stdout.
This is protected so that it can be overridden in unit tests.
mLog.printf(format + "\n", args);
|
|