FileDocCategorySizeDatePackage
CommandLineProcessor.javaAPI DocAndroid 1.5 API31541Wed May 06 22:41:10 BST 2009com.android.sdkmanager

CommandLineProcessor

public 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_VERB
Internal verb name for internally hidden flags.
public static final String
NO_VERB_OBJECT
String to use when the verb doesn't need any object.
public static final String
KEY_HELP
The global help flag.
public static final String
KEY_VERBOSE
The global verbose flag.
public static final String
KEY_SILENT
The global silent flag.
private String
mVerbRequested
Verb requested by the user. Null if none specified, which will be an error.
private String
mDirectObjectRequested
Direct object requested by the user. Can be null.
private final String[]
mActions
Action 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
mArguments
The map of all defined arguments.

The key is a string "verb/directObject/longName".

private final com.android.sdklib.ISdkLog
mLog
Logger
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 voiddefine(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.

param
mode The {@link MODE} for the argument.
param
verb The verb name. Can be #INTERNAL_VERB.
param
directObject The action name. Can be #NO_VERB_OBJECT or #INTERNAL_FLAG.
param
shortName The one-letter short argument name. Cannot be empty nor null.
param
longName The long argument name. Cannot be empty nor null.
param
description The description. Cannot be null.
param
defaultValue The default value (or values), which depends on the selected {@link MODE}.

        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 voidexit()
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$ArgfindLongArg(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.

return
The {@link Arg} found or null.

        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$ArgfindShortArg(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.

return
The {@link Arg} found or null.

        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.StringgetDirectObject()
Returns the direct object name from the command-line. Can be null.

        return mDirectObjectRequested;
    
public java.lang.ObjectgetValue(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.

param
verb The verb name, including {@link #GLOBAL_FLAG_VERB}. If null, all possible verbs that match the direct object condition will be examined and the first value set will be used.
param
directObject The direct object name, including {@link #NO_VERB_OBJECT}. If null, all possible direct objects that match the verb condition will be examined and the first value set will be used.
param
longFlagName The long flag name for the given action. Mandatory. Cannot be null.
return
The current value object stored in the parameter, which depends on the argument mode.


        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.StringgetVerb()
Returns the verb name from the command-line. Can be null.

        return mVerbRequested;
    
public booleanisHelpRequested()
Helper that returns true if --help was requested.

        return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_HELP)).booleanValue();
    
public booleanisSilent()
Helper that returns true if --silent was requested.

        return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_SILENT)).booleanValue();
    
public booleanisVerbose()
Helper that returns true if --verbose was requested.

        return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_VERBOSE)).booleanValue();
    
protected voidlistOptions(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 voidparseArgs(java.lang.String[] args)
Parses the command-line arguments.

This method will exit and not return if a parsing error arise.

param
args The arguments typically received by a main method.

        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 voidprintHelpAndExit(java.lang.String errorFormat, java.lang.Object args)
Prints the help/usage and exits.

param
errorFormat Optional error message to print prior to usage using String.format
param
args Arguments for String.format

        printHelpAndExitForAction(null /*verb*/, null /*directObject*/, errorFormat, args);
    
public voidprintHelpAndExitForAction(java.lang.String verb, java.lang.String directObject, java.lang.String errorFormat, java.lang.Object args)
Prints the help/usage and exits.

param
verb If null, displays help for all verbs. If not null, display help only for that specific verb. In all cases also displays general usage and action list.
param
directObject If null, displays help for all verb objects. If not null, displays help only for that specific action In all cases also display general usage and action list.
param
errorFormat Optional error message to print prior to usage using String.format
param
args Arguments for String.format

        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 voidsetValue(java.lang.String verb, java.lang.String directObject, java.lang.String longFlagName, java.lang.Object value)
Internal setter for raw parameter value.

param
verb The verb name, including {@link #GLOBAL_FLAG_VERB}.
param
directObject The direct object name, including {@link #NO_VERB_OBJECT}.
param
longFlagName The long flag name for the given action.
param
value The new current value object stored in the parameter, which depends on the argument mode.

        String key = verb + "/" + directObject + "/" + longFlagName;
        Arg arg = mArguments.get(key);
        arg.setCurrentValue(value);
    
protected voidstderr(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.

param
format The string to be formatted. Cannot be null.
param
args Format arguments.

        mLog.error(null, format, args);
    
protected voidstdout(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.

param
format The string to be formatted. Cannot be null.
param
args Format arguments.

        mLog.printf(format + "\n", args);