auto import from //branches/cupcake/...@130745

This commit is contained in:
The Android Open Source Project
2009-02-10 15:43:58 -08:00
parent 5a4d0fa291
commit e3c5766074
95 changed files with 6116 additions and 2460 deletions

View File

@@ -31,52 +31,67 @@ import java.util.Map.Entry;
* <li>define flags for your actions.
* </ul>
* <p/>
* To use, call {@link #parseArgs(String[])} and then call {@link #getValue(String, String)}.
* To use, call {@link #parseArgs(String[])} and then
* call {@link #getValue(String, String, String)}.
*/
public class CommandLineProcessor {
/** Internal action name for all global flags. */
public final static String GLOBAL_FLAG = "global";
/** Internal action name for internally hidden flags.
* This is currently used to store the requested action name. */
public final static String INTERNAL_FLAG = "internal";
/** Internal verb name for internally hidden flags. */
public final static String GLOBAL_FLAG_VERB = "@@internal@@";
/** String to use when the verb doesn't need any object. */
public final static String NO_VERB_OBJECT = "";
/** The global help flag. */
public static final String KEY_HELP = "help";
/** The global verbose flag. */
public static final String KEY_VERBOSE = "verbose";
/** The global silent flag. */
public static final String KEY_SILENT = "silent";
/** The internal action flag. */
public static final String KEY_ACTION = "action";
/** Verb requested by the user. Null if none specified, which will be an error. */
private String mVerbRequested;
/** Direct object requested by the user. Can be null. */
private String mDirectObjectRequested;
/** List of available actions.
/**
* Action definitions.
* <p/>
* Each entry must be a 2-string array with first the action name and then
* a description.
* Each entry is a string array with:
* <ul>
* <li> the verb.
* <li> a direct object (use #NO_VERB_OBJECT if there's no object).
* <li> a description.
* <li> an alternate form for the object (e.g. plural).
* </ul>
*/
private final String[][] mActions;
/** The hash of all defined arguments.
private static final int ACTION_VERB_INDEX = 0;
private static final int ACTION_OBJECT_INDEX = 1;
private static final int ACTION_DESC_INDEX = 2;
private static final int ACTION_ALT_OBJECT_INDEX = 3;
/**
* The map of all defined arguments.
* <p/>
* The key is a string "action/longName".
* The key is a string "verb/directObject/longName".
*/
private final HashMap<String, Arg> mArguments = new HashMap<String, Arg>();
/** Logger */
private final ISdkLog mLog;
public CommandLineProcessor(ISdkLog logger, String[][] actions) {
mLog = logger;
mActions = actions;
define(MODE.STRING, false, INTERNAL_FLAG, null, KEY_ACTION,
"Selected Action", null);
define(MODE.BOOLEAN, false, GLOBAL_FLAG, "v", KEY_VERBOSE,
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, "s", KEY_SILENT,
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, "h", KEY_HELP,
define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "h", KEY_HELP,
"This help.",
false);
}
@@ -86,47 +101,54 @@ public class CommandLineProcessor {
/** Helper that returns true if --verbose was requested. */
public boolean isVerbose() {
return ((Boolean) getValue(GLOBAL_FLAG, KEY_VERBOSE)).booleanValue();
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_VERBOSE)).booleanValue();
}
/** Helper that returns true if --silent was requested. */
public boolean isSilent() {
return ((Boolean) getValue(GLOBAL_FLAG, KEY_SILENT)).booleanValue();
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_SILENT)).booleanValue();
}
/** Helper that returns true if --help was requested. */
public boolean isHelpRequested() {
return ((Boolean) getValue(GLOBAL_FLAG, KEY_HELP)).booleanValue();
return ((Boolean) getValue(GLOBAL_FLAG_VERB, NO_VERB_OBJECT, KEY_HELP)).booleanValue();
}
/** Returns the verb name from the command-line. Can be null. */
public String getVerb() {
return mVerbRequested;
}
/** Helper that returns the requested action name. */
public String getActionRequested() {
return (String) getValue(INTERNAL_FLAG, KEY_ACTION);
/** Returns the direct object name from the command-line. Can be null. */
public String getDirectObject() {
return mDirectObjectRequested;
}
//------------------
/**
* Raw access to parsed parameter values.
* @param action The action name, including {@link #GLOBAL_FLAG} and {@link #INTERNAL_FLAG}
* @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.
* @return The current value object stored in the parameter, which depends on the argument mode.
*/
public Object getValue(String action, String longFlagName) {
String key = action + "/" + longFlagName;
public Object getValue(String verb, String directObject, String longFlagName) {
String key = verb + "/" + directObject + "/" + longFlagName;
Arg arg = mArguments.get(key);
return arg.getCurrentValue();
}
/**
* Internal setter for raw parameter value.
* @param action The action name, including {@link #GLOBAL_FLAG} and {@link #INTERNAL_FLAG}
* @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.
*/
protected void setValue(String action, String longFlagName, Object value) {
String key = action + "/" + longFlagName;
protected void setValue(String verb, String directObject, String longFlagName, Object value) {
String key = verb + "/" + directObject + "/" + longFlagName;
Arg arg = mArguments.get(key);
arg.setCurrentValue(value);
}
@@ -140,114 +162,172 @@ public class CommandLineProcessor {
*/
public void parseArgs(String[] args) {
String needsHelp = null;
String action = null;
int n = args.length;
for (int i = 0; i < n; i++) {
Arg arg = null;
String a = args[i];
if (a.startsWith("--")) {
arg = findLongArg(action, a.substring(2));
} else if (a.startsWith("-")) {
arg = findShortArg(action, a.substring(1));
}
// Not a keyword and we don't have an action yet, this should be an action
if (arg == null && action == null) {
String verb = null;
String directObject = null;
if (a.startsWith("-")) {
// Got a keyword but not valid for global flags
needsHelp = String.format(
"Flag '%1$s' is not a valid global flag. Did you mean to specify it after the action name?",
a, action);
break;
}
for (String[] actionDesc : mActions) {
if (actionDesc[0].equals(a)) {
action = a;
break;
}
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));
}
if (action == null) {
needsHelp = String.format(
"Expected action name after global parameters but found %1$s instead.",
a);
break;
}
} else if (arg == null && action != null) {
// Got a keyword but not valid for the current action
needsHelp = String.format(
"Flag '%1$s' is not valid for action '%2$s'.",
a, action);
break;
} else if (arg != null) {
// Process keyword
String error = null;
if (arg.getMode().needsExtra()) {
if (++i >= n) {
needsHelp = String.format("Missing argument for flag %1$s.", a);
break;
// 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;
}
}
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.
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) {
// 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 (error != null) {
needsHelp = String.format("Invalid usage for flag %1$s: %2$s.", a, error);
break;
}
}
}
if (needsHelp == null) {
if (action == null) {
needsHelp = "Missing action name.";
} else {
// 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.getAction().equals(action)) {
if (arg.isMandatory() && arg.getCurrentValue() == null) {
if (missing == null) {
missing = "--" + arg.getLongArg();
} else {
missing += ", --" + arg.getLongArg();
plural = true;
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);
}
if (missing != null) {
needsHelp = String.format("The %1$s %2$s must be defined for action '%3$s'",
plural ? "parameters" : "parameter",
missing,
action);
mVerbRequested = verb;
mDirectObjectRequested = directObject;
}
setValue(INTERNAL_FLAG, KEY_ACTION, action);
}
}
if (needsHelp != null) {
printHelpAndExitForAction(action, needsHelp);
} finally {
if (needsHelp != null) {
printHelpAndExitForAction(verb, directObject, needsHelp);
}
}
}
@@ -255,11 +335,14 @@ public class CommandLineProcessor {
* Finds an {@link Arg} given an action name and a long flag name.
* @return The {@link Arg} found or null.
*/
protected Arg findLongArg(String action, String longName) {
if (action == null) {
action = GLOBAL_FLAG;
protected Arg findLongArg(String verb, String directObject, String longName) {
if (verb == null) {
verb = GLOBAL_FLAG_VERB;
}
String key = action + "/" + longName;
if (directObject == null) {
directObject = NO_VERB_OBJECT;
}
String key = verb + "/" + directObject + "/" + longName;
return mArguments.get(key);
}
@@ -267,14 +350,17 @@ public class CommandLineProcessor {
* Finds an {@link Arg} given an action name and a short flag name.
* @return The {@link Arg} found or null.
*/
protected Arg findShortArg(String action, String shortName) {
if (action == null) {
action = GLOBAL_FLAG;
protected Arg findShortArg(String verb, String directObject, String shortName) {
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.getAction().equals(action)) {
if (arg.getVerb().equals(verb) && arg.getDirectObject().equals(directObject)) {
if (shortName.equals(arg.getShortArg())) {
return arg;
}
@@ -291,18 +377,22 @@ public class CommandLineProcessor {
* @param args Arguments for String.format
*/
public void printHelpAndExit(String errorFormat, Object... args) {
printHelpAndExitForAction(null /*actionFilter*/, errorFormat, args);
printHelpAndExitForAction(null /*verb*/, null /*directObject*/, errorFormat, args);
}
/**
* Prints the help/usage and exits.
*
* @param actionFilter If null, displays help for all actions. If not null, display help only
* for that specific action. In all cases also display general usage and action list.
* @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
*/
public void printHelpAndExitForAction(String actionFilter, String errorFormat, Object... args) {
public void printHelpAndExitForAction(String verb, String directObject,
String errorFormat, Object... args) {
if (errorFormat != null) {
stderr(errorFormat, args);
}
@@ -316,25 +406,27 @@ public class CommandLineProcessor {
" android [global options] action [action options]\n" +
"\n" +
"Global options:");
listOptions(GLOBAL_FLAG);
listOptions(GLOBAL_FLAG_VERB, NO_VERB_OBJECT);
stdout("\nValid actions:");
stdout("\nValid actions are composed of a verb and an optional direct object:");
for (String[] action : mActions) {
String filler = "";
int len = action[0].length();
if (len < 10) {
filler = " ".substring(len);
}
stdout("- %1$s:%2$s %3$s", action[0], filler, action[1]);
stdout("- %1$6s %2$-7s: %3$s",
action[ACTION_VERB_INDEX],
action[ACTION_OBJECT_INDEX],
action[ACTION_DESC_INDEX]);
}
for (String[] action : mActions) {
if (actionFilter == null || actionFilter.equals(action[0])) {
stdout("\nAction \"%1$s\":", action[0]);
stdout(" %1$s", action[1]);
stdout("Options:");
listOptions(action[0]);
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]);
}
}
}
@@ -344,11 +436,11 @@ public class CommandLineProcessor {
/**
* Internal helper to print all the option flags for a given action name.
*/
protected void listOptions(String action) {
protected void listOptions(String verb, String directObject) {
int numOptions = 0;
for (Entry<String, Arg> entry : mArguments.entrySet()) {
Arg arg = entry.getValue();
if (arg.getAction().equals(action)) {
if (arg.getVerb().equals(verb) && arg.getDirectObject().equals(directObject)) {
String value = "";
if (arg.getDefaultValue() instanceof String[]) {
@@ -483,21 +575,22 @@ public class CommandLineProcessor {
* or a String array (in which case the first item is the current by default.)
*/
static class Arg {
private final String mAction;
private final String mVerb;
private final String mDirectObject;
private final String mShortName;
private final String mLongName;
private final String mDescription;
private final Object mDefaultValue;
private Object mCurrentValue;
private final MODE mMode;
private final boolean mMandatory;
private Object mCurrentValue;
/**
* Creates a new argument flag description.
*
* @param mode The {@link MODE} for the argument.
* @param mandatory True if this argument is mandatory for this action.
* @param action The action name. Can be #GLOBAL_FLAG or #INTERNAL_FLAG.
* @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.
@@ -505,14 +598,16 @@ public class CommandLineProcessor {
*/
public Arg(MODE mode,
boolean mandatory,
String action,
String verb,
String directObject,
String shortName,
String longName,
String description,
Object defaultValue) {
mMode = mode;
mMandatory = mandatory;
mAction = action;
mVerb = verb;
mDirectObject = directObject;
mShortName = shortName;
mLongName = longName;
mDescription = description;
@@ -540,8 +635,12 @@ public class CommandLineProcessor {
return mDescription;
}
public String getAction() {
return mAction;
public String getVerb() {
return mVerb;
}
public String getDirectObject() {
return mDirectObject;
}
public Object getDefaultValue() {
@@ -565,7 +664,8 @@ public class CommandLineProcessor {
* Internal helper to define a new argument for a give action.
*
* @param mode The {@link MODE} for the argument.
* @param action The action name. Can be #GLOBAL_FLAG or #INTERNAL_FLAG.
* @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.
@@ -573,14 +673,19 @@ public class CommandLineProcessor {
*/
protected void define(MODE mode,
boolean mandatory,
String action,
String verb,
String directObject,
String shortName, String longName,
String description, Object defaultValue) {
assert(mandatory || mode == MODE.BOOLEAN); // a boolean mode cannot be mandatory
String key = action + "/" + longName;
if (directObject == null) {
directObject = NO_VERB_OBJECT;
}
String key = verb + "/" + directObject + "/" + longName;
mArguments.put(key, new Arg(mode, mandatory,
action, shortName, longName, description, defaultValue));
verb, directObject, shortName, longName, description, defaultValue));
}
/**

View File

@@ -23,12 +23,12 @@ import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
import com.android.sdklib.avd.AvdManager;
import com.android.sdklib.avd.HardwareProperties;
import com.android.sdklib.avd.AvdManager.AvdInfo;
import com.android.sdklib.avd.HardwareProperties.HardwareProperty;
import com.android.sdklib.project.ProjectCreator;
import com.android.sdklib.project.ProjectCreator.OutputLevel;
import com.android.sdklib.vm.HardwareProperties;
import com.android.sdklib.vm.VmManager;
import com.android.sdklib.vm.HardwareProperties.HardwareProperty;
import com.android.sdklib.vm.VmManager.VmInfo;
import java.io.File;
import java.io.IOException;
@@ -56,8 +56,8 @@ class Main {
private ISdkLog mSdkLog;
/** The SDK manager parses the SDK folder and gives access to the content. */
private SdkManager mSdkManager;
/** Virtual Machine manager to access the list of VMs or create new ones. */
private VmManager mVmManager;
/** Virtual Machine manager to access the list of AVDs or create new ones. */
private AvdManager mAvdManager;
/** Command-line processor with options specific to SdkManager. */
private SdkCommandLine mSdkCommandLine;
/** The working directory, either null or set to an existing absolute canonical directory. */
@@ -183,26 +183,31 @@ class Main {
* Actually do an action...
*/
private void doAction() {
String action = mSdkCommandLine.getActionRequested();
String verb = mSdkCommandLine.getVerb();
String directObject = mSdkCommandLine.getDirectObject();
if (SdkCommandLine.ACTION_LIST.equals(action)) {
if (SdkCommandLine.VERB_LIST.equals(verb)) {
// list action.
if (SdkCommandLine.ARG_TARGET.equals(mSdkCommandLine.getListFilter())) {
if (SdkCommandLine.OBJECT_TARGET.equals(directObject)) {
displayTargetList();
} else if (SdkCommandLine.ARG_VM.equals(mSdkCommandLine.getListFilter())) {
displayVmList();
} else if (SdkCommandLine.OBJECT_AVD.equals(directObject)) {
displayAvdList();
} else {
displayTargetList();
displayVmList();
displayAvdList();
}
} else if (SdkCommandLine.ACTION_NEW_VM.equals(action)) {
createVm();
} else if (SdkCommandLine.ACTION_NEW_PROJECT.equals(action)) {
} else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
createAvd();
} else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
// get the target and try to resolve it.
int targetId = mSdkCommandLine.getNewProjectTargetId();
int targetId = mSdkCommandLine.getCreateProjectTargetId();
IAndroidTarget[] targets = mSdkManager.getTargets();
if (targetId < 1 || targetId > targets.length) {
errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.",
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
SdkConstants.androidCmdName());
}
IAndroidTarget target = targets[targetId - 1];
@@ -213,22 +218,24 @@ class Main {
OutputLevel.NORMAL,
mSdkLog);
String projectDir = getProjectLocation(mSdkCommandLine.getNewProjectLocation());
String projectDir = getProjectLocation(mSdkCommandLine.getCreateProjectLocation());
creator.createProject(projectDir,
mSdkCommandLine.getNewProjectName(),
mSdkCommandLine.getNewProjectPackage(),
mSdkCommandLine.getNewProjectActivity(),
mSdkCommandLine.getCreateProjectName(),
mSdkCommandLine.getCreateProjectPackage(),
mSdkCommandLine.getCreateProjectActivity(),
target,
false /* isTestProject*/);
} else if (SdkCommandLine.ACTION_UPDATE_PROJECT.equals(action)) {
} else if (SdkCommandLine.VERB_UPDATE.equals(verb) &&
SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
// get the target and try to resolve it.
IAndroidTarget target = null;
int targetId = mSdkCommandLine.getUpdateProjectTargetId();
if (targetId >= 0) {
IAndroidTarget[] targets = mSdkManager.getTargets();
if (targetId < 1 || targetId > targets.length) {
errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.",
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
SdkConstants.androidCmdName());
}
target = targets[targetId - 1];
@@ -340,20 +347,20 @@ class Main {
}
/**
* Displays the list of available VMs.
* Displays the list of available AVDs.
*/
private void displayVmList() {
private void displayAvdList() {
try {
mVmManager = new VmManager(mSdkManager, null /* sdklog */);
mAvdManager = new AvdManager(mSdkManager, null /* sdklog */);
mSdkLog.printf("Available Android VMs:\n");
mSdkLog.printf("Available Android Virtual Devices:\n");
int index = 1;
for (VmInfo info : mVmManager.getVms()) {
for (AvdInfo info : mAvdManager.getAvds()) {
mSdkLog.printf("[%d] %s\n", index, info.getName());
mSdkLog.printf(" Path: %s\n", info.getPath());
// get the target of the Vm
// get the target of the AVD
IAndroidTarget target = info.getTarget();
if (target.isPlatform()) {
mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(),
@@ -373,57 +380,85 @@ class Main {
}
/**
* Creates a new VM. This is a text based creation with command line prompt.
* Creates a new AVD. This is a text based creation with command line prompt.
*/
private void createVm() {
private void createAvd() {
// find a matching target
int targetId = mSdkCommandLine.getNewVmTargetId();
int targetId = mSdkCommandLine.getCreateAvdTargetId();
IAndroidTarget target = null;
if (targetId >= 1 && targetId <= mSdkManager.getTargets().length) {
target = mSdkManager.getTargets()[targetId-1]; // target it is 1-based
} else {
errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.",
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
SdkConstants.androidCmdName());
}
try {
mVmManager = new VmManager(mSdkManager, mSdkLog);
boolean removePrevious = false;
mAvdManager = new AvdManager(mSdkManager, mSdkLog);
String vmName = mSdkCommandLine.getNewVmName();
VmInfo info = mVmManager.getVm(vmName);
String avdName = mSdkCommandLine.getCreateAvdName();
AvdInfo info = mAvdManager.getAvd(avdName);
if (info != null) {
errorAndExit("VM %s already exists.", vmName);
} else {
String vmParentFolder = mSdkCommandLine.getNewVmLocation();
if (vmParentFolder == null) {
vmParentFolder = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
if (mSdkCommandLine.getCreateAvdForce()) {
removePrevious = true;
mSdkLog.warning(
"Android Virtual Device '%s' already exists and will be replaced.",
avdName);
} else {
errorAndExit("Android Virtual Device '%s' already exists.", avdName);
return;
}
Map<String, String> hardwareConfig = null;
if (target.isPlatform()) {
try {
hardwareConfig = promptForHardware(target);
} catch (IOException e) {
errorAndExit(e.getMessage());
}
}
mVmManager.createVm(vmParentFolder,
mSdkCommandLine.getNewVmName(),
target,
mSdkCommandLine.getNewVmSkin(),
mSdkCommandLine.getNewVmSdCard(),
hardwareConfig,
mSdkLog);
}
String avdParentFolder = mSdkCommandLine.getCreateAvdLocation();
if (avdParentFolder == null) {
avdParentFolder = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
}
Map<String, String> hardwareConfig = null;
if (target.isPlatform()) {
try {
hardwareConfig = promptForHardware(target);
} catch (IOException e) {
errorAndExit(e.getMessage());
}
}
AvdInfo oldAvdInfo = null;
if (removePrevious) {
oldAvdInfo = mAvdManager.getAvd(avdName);
}
AvdInfo newAvdInfo = mAvdManager.createAvd(avdParentFolder,
avdName,
target,
mSdkCommandLine.getCreateAvdSkin(),
mSdkCommandLine.getCreateAvdSdCard(),
hardwareConfig,
removePrevious,
mSdkLog);
if (newAvdInfo != null &&
oldAvdInfo != null &&
!oldAvdInfo.getPath().equals(newAvdInfo.getPath())) {
mSdkLog.warning("Removing previous AVD directory at %s", oldAvdInfo.getPath());
// Remove the old data directory
File dir = new File(oldAvdInfo.getPath());
mAvdManager.recursiveDelete(dir);
dir.delete();
// Remove old avd info from manager
mAvdManager.removeAvd(oldAvdInfo);
}
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
}
}
/**
* Prompts the user to setup a hardware config for a Platform-based VM.
* Prompts the user to setup a hardware config for a Platform-based AVD.
* @throws IOException
*/
private Map<String, String> promptForHardware(IAndroidTarget createTarget) throws IOException {

View File

@@ -25,152 +25,218 @@ import com.android.sdklib.SdkManager;
*/
public class SdkCommandLine extends CommandLineProcessor {
public static final String ARG_ALIAS = "alias";
public static final String ARG_ACTIVITY = "activity";
public static final String ARG_VM = "vm";
public static final String ARG_TARGET = "target";
public static final String ARG_ALL = "all";
public static final String KEY_ACTIVITY = ARG_ACTIVITY;
public static final String KEY_PACKAGE = "package";
public static final String KEY_MODE = "mode";
public static final String KEY_TARGET_ID = ARG_TARGET;
public static final String KEY_NAME = "name";
public static final String KEY_OUT = "out";
public static final String KEY_FILTER = "filter";
public static final String KEY_SKIN = "skin";
public static final String KEY_SDCARD = "sdcard";
public final static String VERB_LIST = "list";
public final static String VERB_CREATE = "create";
public final static String VERB_RENAME = "rename";
public final static String VERB_MOVE = "move";
public final static String VERB_DELETE = "delete";
public final static String VERB_UPDATE = "update";
public final static String ACTION_LIST = "list";
public final static String ACTION_NEW_VM = ARG_VM;
public final static String ACTION_NEW_PROJECT = "project";
public final static String ACTION_UPDATE_PROJECT = "update";
public static final String OBJECT_AVD = "avd";
public static final String OBJECT_AVDS = "avds";
public static final String OBJECT_TARGET = "target";
public static final String OBJECT_TARGETS = "targets";
public static final String OBJECT_PROJECT = "project";
public static final String ARG_ALIAS = "alias";
public static final String ARG_ACTIVITY = "activity";
public static final String KEY_ACTIVITY = ARG_ACTIVITY;
public static final String KEY_PACKAGE = "package";
public static final String KEY_MODE = "mode";
public static final String KEY_TARGET_ID = OBJECT_TARGET;
public static final String KEY_NAME = "name";
public static final String KEY_PATH = "path";
public static final String KEY_FILTER = "filter";
public static final String KEY_SKIN = "skin";
public static final String KEY_SDCARD = "sdcard";
public static final String KEY_FORCE = "force";
/**
* Action definitions for SdkManager command line.
* <p/>
* Each entry is a string array with:
* <ul>
* <li> the verb.
* <li> an object (use #NO_VERB_OBJECT if there's no object).
* <li> a description.
* <li> an alternate form for the object (e.g. plural).
* </ul>
*/
private final static String[][] ACTIONS = {
{ ACTION_LIST,
"Lists existing targets or VMs." },
{ ACTION_NEW_VM,
"Creates a new VM." },
{ ACTION_NEW_PROJECT,
"Creates a new project using a template." },
{ ACTION_UPDATE_PROJECT,
"Updates a project from existing source (must have an AndroidManifest.xml)." },
{ VERB_LIST,
NO_VERB_OBJECT,
"Lists existing targets or virtual devices." },
{ VERB_LIST,
OBJECT_AVD,
"Lists existing Android Virtual Devices.",
OBJECT_AVDS },
{ VERB_LIST,
OBJECT_TARGET,
"Lists existing targets.",
OBJECT_TARGETS },
{ VERB_CREATE,
OBJECT_AVD,
"Creates a new Android Virtual Device." },
{ VERB_RENAME,
OBJECT_AVD,
"Renames a new Android Virtual Device." },
{ VERB_MOVE,
OBJECT_AVD,
"Moves a new Android Virtual Device." },
{ VERB_DELETE,
OBJECT_AVD,
"Deletes a new Android Virtual Device." },
{ VERB_CREATE,
OBJECT_PROJECT,
"Creates a new Android Project." },
{ VERB_UPDATE,
OBJECT_PROJECT,
"Updates an Android Project (must have an AndroidManifest.xml)." },
};
public SdkCommandLine(ISdkLog logger) {
super(logger, ACTIONS);
define(MODE.ENUM, false, ACTION_LIST, "f", KEY_FILTER,
"List filter", new String[] { ARG_ALL, ARG_TARGET, ARG_VM });
define(MODE.STRING, false,
VERB_CREATE, OBJECT_AVD,
"p", KEY_PATH,
"Location path of the parent directory where the new AVD will be created", null);
define(MODE.STRING, true,
VERB_CREATE, OBJECT_AVD,
"n", KEY_NAME,
"Name of the new AVD", null);
define(MODE.INTEGER, true,
VERB_CREATE, OBJECT_AVD,
"t", KEY_TARGET_ID,
"Target id of the new AVD", null);
define(MODE.STRING, true,
VERB_CREATE, OBJECT_AVD,
"s", KEY_SKIN,
"Skin of the new AVD", null);
define(MODE.STRING, false,
VERB_CREATE, OBJECT_AVD,
"c", KEY_SDCARD,
"Path to a shared SD card image, or size of a new sdcard for the new AVD", null);
define(MODE.BOOLEAN, false,
VERB_CREATE, OBJECT_AVD,
"f", KEY_FORCE,
"Force creation (override an existing AVD)", false);
define(MODE.STRING, false, ACTION_NEW_VM, "o", KEY_OUT,
"Location path of new VM", null);
define(MODE.STRING, true, ACTION_NEW_VM, "n", KEY_NAME,
"Name of the new VM", null);
define(MODE.INTEGER, true, ACTION_NEW_VM, "t", KEY_TARGET_ID,
"Target id of the new VM", null);
define(MODE.STRING, true, ACTION_NEW_VM, "s", KEY_SKIN,
"Skin of the new VM", null);
define(MODE.STRING, false, ACTION_NEW_VM, "c", KEY_SDCARD,
"Path to a shared SD card image, or size of a new sdcard for the new VM", null);
define(MODE.ENUM, true, ACTION_NEW_PROJECT, "m", KEY_MODE,
define(MODE.ENUM, true,
VERB_CREATE, OBJECT_PROJECT,
"m", KEY_MODE,
"Project mode", new String[] { ARG_ACTIVITY, ARG_ALIAS });
define(MODE.STRING, true, ACTION_NEW_PROJECT, "o", KEY_OUT,
define(MODE.STRING, true,
VERB_CREATE, OBJECT_PROJECT,
"p", KEY_PATH,
"Location path of new project", null);
define(MODE.INTEGER, true, ACTION_NEW_PROJECT, "t", KEY_TARGET_ID,
define(MODE.INTEGER, true,
VERB_CREATE, OBJECT_PROJECT,
"t", KEY_TARGET_ID,
"Target id of the new project", null);
define(MODE.STRING, true, ACTION_NEW_PROJECT, "p", KEY_PACKAGE,
define(MODE.STRING, true,
VERB_CREATE, OBJECT_PROJECT,
"k", KEY_PACKAGE,
"Package name", null);
define(MODE.STRING, true, ACTION_NEW_PROJECT, "a", KEY_ACTIVITY,
define(MODE.STRING, true,
VERB_CREATE, OBJECT_PROJECT,
"a", KEY_ACTIVITY,
"Activity name", null);
define(MODE.STRING, false, ACTION_NEW_PROJECT, "n", KEY_NAME,
define(MODE.STRING, false,
VERB_CREATE, OBJECT_PROJECT,
"n", KEY_NAME,
"Project name", null);
define(MODE.STRING, true, ACTION_UPDATE_PROJECT, "o", KEY_OUT,
define(MODE.STRING, true,
VERB_UPDATE, OBJECT_PROJECT,
"p", KEY_PATH,
"Location path of the project", null);
define(MODE.INTEGER, true, ACTION_UPDATE_PROJECT, "t", KEY_TARGET_ID,
define(MODE.INTEGER, true,
VERB_UPDATE, OBJECT_PROJECT,
"t", KEY_TARGET_ID,
"Target id to set for the project", -1);
define(MODE.STRING, false, ACTION_UPDATE_PROJECT, "n", KEY_NAME,
define(MODE.STRING, false,
VERB_UPDATE, OBJECT_PROJECT,
"n", KEY_NAME,
"Project name", null);
}
// -- some helpers for list action flags
// -- some helpers for AVD action flags
/** Helper to retrieve the --filter for the list action. */
public String getListFilter() {
return ((String) getValue(ACTION_LIST, KEY_FILTER));
/** Helper to retrieve the --out location for the new AVD action. */
public String getCreateAvdLocation() {
return ((String) getValue(VERB_CREATE, OBJECT_AVD, KEY_PATH));
}
/** Helper to retrieve the --target id for the new AVD action. */
public int getCreateAvdTargetId() {
return ((Integer) getValue(VERB_CREATE, OBJECT_AVD, KEY_TARGET_ID)).intValue();
}
// -- some helpers for vm action flags
/** Helper to retrieve the --out location for the new vm action. */
public String getNewVmLocation() {
return ((String) getValue(ACTION_NEW_VM, KEY_OUT));
/** Helper to retrieve the --name for the new AVD action. */
public String getCreateAvdName() {
return ((String) getValue(VERB_CREATE, OBJECT_AVD, KEY_NAME));
}
/** Helper to retrieve the --target id for the new vm action. */
public int getNewVmTargetId() {
return ((Integer) getValue(ACTION_NEW_VM, KEY_TARGET_ID)).intValue();
/** Helper to retrieve the --skin name for the new AVD action. */
public String getCreateAvdSkin() {
return ((String) getValue(VERB_CREATE, OBJECT_AVD, KEY_SKIN));
}
/** Helper to retrieve the --name for the new vm action. */
public String getNewVmName() {
return ((String) getValue(ACTION_NEW_VM, KEY_NAME));
/** Helper to retrieve the --sdcard data for the new AVD action. */
public String getCreateAvdSdCard() {
return ((String) getValue(VERB_CREATE, OBJECT_AVD, KEY_SDCARD));
}
/** Helper to retrieve the --skin name for the new vm action. */
public String getNewVmSkin() {
return ((String) getValue(ACTION_NEW_VM, KEY_SKIN));
}
/** Helper to retrieve the --sdcard data for the new vm action. */
public String getNewVmSdCard() {
return ((String) getValue(ACTION_NEW_VM, KEY_SDCARD));
public boolean getCreateAvdForce() {
return ((Boolean) getValue(VERB_CREATE, OBJECT_AVD, KEY_FORCE)).booleanValue();
}
// -- some helpers for project action flags
/** Helper to retrieve the --out location for the new project action. */
public String getNewProjectLocation() {
return ((String) getValue(ACTION_NEW_PROJECT, KEY_OUT));
public String getCreateProjectLocation() {
return ((String) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_PATH));
}
/** Helper to retrieve the --target id for the new project action. */
public int getNewProjectTargetId() {
return ((Integer) getValue(ACTION_NEW_PROJECT, KEY_TARGET_ID)).intValue();
public int getCreateProjectTargetId() {
return ((Integer) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_TARGET_ID)).intValue();
}
/** Helper to retrieve the --name for the new project action. */
public String getNewProjectName() {
return ((String) getValue(ACTION_NEW_PROJECT, KEY_NAME));
public String getCreateProjectName() {
return ((String) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_NAME));
}
/** Helper to retrieve the --package for the new project action. */
public String getNewProjectPackage() {
return ((String) getValue(ACTION_NEW_PROJECT, KEY_PACKAGE));
public String getCreateProjectPackage() {
return ((String) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_PACKAGE));
}
/** Helper to retrieve the --activity for the new project action. */
public String getNewProjectActivity() {
return ((String) getValue(ACTION_NEW_PROJECT, KEY_ACTIVITY));
public String getCreateProjectActivity() {
return ((String) getValue(VERB_CREATE, OBJECT_PROJECT, KEY_ACTIVITY));
}
// -- some helpers for update action flags
/** Helper to retrieve the --out location for the update project action. */
public String getUpdateProjectLocation() {
return ((String) getValue(ACTION_UPDATE_PROJECT, KEY_OUT));
return ((String) getValue(VERB_UPDATE, OBJECT_PROJECT, KEY_PATH));
}
/** Helper to retrieve the --target id for the update project action. */
public int getUpdateProjectTargetId() {
return ((Integer) getValue(ACTION_UPDATE_PROJECT, KEY_TARGET_ID)).intValue();
return ((Integer) getValue(VERB_UPDATE, OBJECT_PROJECT, KEY_TARGET_ID)).intValue();
}
/** Helper to retrieve the --name for the update project action. */
public String getUpdateProjectName() {
return ((String) getValue(ACTION_UPDATE_PROJECT, KEY_NAME));
return ((String) getValue(VERB_UPDATE, OBJECT_PROJECT, KEY_NAME));
}
}

View File

@@ -38,20 +38,20 @@ public class CommandLineProcessorTest extends TestCase {
public MockCommandLineProcessor(ISdkLog logger) {
super(logger,
new String[][] {
{ "action1", "Some action" },
{ "action2", "Another action" },
{ "verb1", "action1", "Some action" },
{ "verb1", "action2", "Another action" },
});
define(MODE.STRING, false /*mandatory*/,
"action1", "1", "first", "non-mandatory flag", null);
"verb1", "action1", "1", "first", "non-mandatory flag", null);
define(MODE.STRING, true /*mandatory*/,
"action1", "2", "second", "mandatory flag", null);
"verb1", "action1", "2", "second", "mandatory flag", null);
}
@Override
public void printHelpAndExitForAction(String actionFilter,
public void printHelpAndExitForAction(String verb, String directObject,
String errorFormat, Object... args) {
mHelpCalled = true;
super.printHelpAndExitForAction(actionFilter, errorFormat, args);
super.printHelpAndExitForAction(verb, directObject, errorFormat, args);
}
@Override
@@ -132,14 +132,14 @@ public class CommandLineProcessorTest extends TestCase {
assertTrue(c.isVerbose());
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
assertTrue(c.getStdErr().indexOf("Missing action name.") != -1);
assertTrue(c.getStdErr().indexOf("Missing verb name.") != -1);
c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "--verbose" });
assertTrue(c.isVerbose());
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
assertTrue(c.getStdErr().indexOf("Missing action name.") != -1);
assertTrue(c.getStdErr().indexOf("Missing verb name.") != -1);
}
public final void testHelp() {
@@ -148,39 +148,39 @@ public class CommandLineProcessorTest extends TestCase {
c.parseArgs(new String[] { "-h" });
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
assertTrue(c.getStdErr().indexOf("Missing action name.") == -1);
assertTrue(c.getStdErr().indexOf("Missing verb name.") == -1);
c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "--help" });
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
assertTrue(c.getStdErr().indexOf("Missing action name.") == -1);
assertTrue(c.getStdErr().indexOf("Missing verb name.") == -1);
}
public final void testMandatory() {
MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "action1", "-1", "value1", "-2", "value2" });
c.parseArgs(new String[] { "verb1", "action1", "-1", "value1", "-2", "value2" });
assertFalse(c.wasExitCalled());
assertFalse(c.wasHelpCalled());
assertEquals("", c.getStdErr());
assertEquals("value1", c.getValue("action1", "first"));
assertEquals("value2", c.getValue("action1", "second"));
assertEquals("value1", c.getValue("verb1", "action1", "first"));
assertEquals("value2", c.getValue("verb1", "action1", "second"));
c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "action1", "-2", "value2" });
c.parseArgs(new String[] { "verb1", "action1", "-2", "value2" });
assertFalse(c.wasExitCalled());
assertFalse(c.wasHelpCalled());
assertEquals("", c.getStdErr());
assertEquals(null, c.getValue("action1", "first"));
assertEquals("value2", c.getValue("action1", "second"));
assertEquals(null, c.getValue("verb1", "action1", "first"));
assertEquals("value2", c.getValue("verb1", "action1", "second"));
c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "action1" });
c.parseArgs(new String[] { "verb1", "action1" });
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
assertTrue(c.getStdErr().indexOf("must be defined") != -1);
assertEquals(null, c.getValue("action1", "first"));
assertEquals(null, c.getValue("action1", "second"));
assertEquals(null, c.getValue("verb1", "action1", "first"));
assertEquals(null, c.getValue("verb1", "action1", "second"));
}
}

View File

@@ -37,10 +37,10 @@ public class SdkCommandLineTest extends TestCase {
}
@Override
public void printHelpAndExitForAction(String actionFilter,
public void printHelpAndExitForAction(String verb, String directObject,
String errorFormat, Object... args) {
mHelpCalled = true;
super.printHelpAndExitForAction(actionFilter, errorFormat, args);
super.printHelpAndExitForAction(verb, directObject, errorFormat, args);
}
@Override
@@ -78,34 +78,64 @@ public class SdkCommandLineTest extends TestCase {
super.tearDown();
}
/** Test list with long name and verbose */
public final void testList_Long_Verbose() {
/** Test list */
public final void testList_Avd_Verbose() {
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
assertEquals("all", c.getListFilter());
c.parseArgs(new String[] { "-v", "list", "--filter", "vm" });
c.parseArgs(new String[] { "-v", "list", "avd" });
assertFalse(c.wasHelpCalled());
assertFalse(c.wasExitCalled());
assertEquals("vm", c.getListFilter());
assertEquals("list", c.getVerb());
assertEquals("avd", c.getDirectObject());
assertTrue(c.isVerbose());
}
/** Test list with short name and no verbose */
public final void testList_Short() {
public final void testList_Target() {
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
assertEquals("all", c.getListFilter());
c.parseArgs(new String[] { "list", "-f", "vm" });
c.parseArgs(new String[] { "list", "target" });
assertFalse(c.wasHelpCalled());
assertFalse(c.wasExitCalled());
assertEquals("vm", c.getListFilter());
assertEquals("list", c.getVerb());
assertEquals("target", c.getDirectObject());
assertFalse(c.isVerbose());
}
/** Test list with long name and missing parameter */
public final void testList_Long_MissingParam() {
public final void testList_None() {
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
assertEquals("all", c.getListFilter());
c.parseArgs(new String[] { "list", "--filter" });
c.parseArgs(new String[] { "list" });
assertFalse(c.wasHelpCalled());
assertFalse(c.wasExitCalled());
assertEquals("list", c.getVerb());
assertEquals("", c.getDirectObject());
assertFalse(c.isVerbose());
}
public final void testList_Invalid() {
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
c.parseArgs(new String[] { "list", "unknown" });
assertTrue(c.wasHelpCalled());
assertTrue(c.wasExitCalled());
assertEquals("all", c.getListFilter());
assertEquals(null, c.getVerb());
assertEquals(null, c.getDirectObject());
assertFalse(c.isVerbose());
}
public final void testList_Plural() {
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
c.parseArgs(new String[] { "list", "avds" });
assertFalse(c.wasHelpCalled());
assertFalse(c.wasExitCalled());
assertEquals("list", c.getVerb());
// we get the non-plural form
assertEquals("avd", c.getDirectObject());
assertFalse(c.isVerbose());
c = new MockSdkCommandLine(mLog);
c.parseArgs(new String[] { "list", "targets" });
assertFalse(c.wasHelpCalled());
assertFalse(c.wasExitCalled());
assertEquals("list", c.getVerb());
// we get the non-plural form
assertEquals("target", c.getDirectObject());
assertFalse(c.isVerbose());
}
}

View File

@@ -16,11 +16,48 @@
package com.android.sdklib;
import java.util.Formatter;
/**
* Interface used to display warnings/errors while parsing the SDK content.
*/
public interface ISdkLog {
/**
* Prints a warning message on stdout.
* <p/>
* Implementations should only display warnings in verbose mode.
* The message should be prefixed with "Warning:".
*
* @param warningFormat is an optional error format. If non-null, it will be printed
* using a {@link Formatter} with the provided arguments.
* @param args provides the arguments for warningFormat.
*/
void warning(String warningFormat, Object... args);
/**
* Prints an error message on stderr.
* <p/>
* Implementation should always display errors, independent of verbose mode.
* The message should be prefixed with "Error:".
*
* @param t is an optional {@link Throwable} or {@link Exception}. If non-null, it's
* message will be printed out.
* @param errorFormat is an optional error format. If non-null, it will be printed
* using a {@link Formatter} with the provided arguments.
* @param args provides the arguments for errorFormat.
*/
void error(Throwable t, String errorFormat, Object... args);
/**
* Prints a message as-is on stdout.
* <p/>
* Implementation should always display errors, independent of verbose mode.
* No prefix is used, the message is printed as-is after formatting.
*
* @param msgFormat is an optional error format. If non-null, it will be printed
* using a {@link Formatter} with the provided arguments.
* @param args provides the arguments for msgFormat.
*/
void printf(String msgFormat, Object... args);
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.sdklib.vm;
package com.android.sdklib.avd;
import com.android.prefs.AndroidLocation;
import com.android.prefs.AndroidLocation.AndroidLocationException;
@@ -39,12 +39,13 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Virtual Machine manager to access the list of VMs or create new ones.
* Virtual Device Manager to access the list of AVDs or create new ones.
*/
public final class VmManager {
public final class AvdManager {
private final static String VM_INFO_PATH = "path";
private final static String VM_INFO_TARGET = "target";
private static final String AVD_FOLDER_EXTENSION = ".avd";
private final static String AVD_INFO_PATH = "path";
private final static String AVD_INFO_TARGET = "target";
private final static String IMAGE_USERDATA = "userdata.img";
private final static String CONFIG_INI = "config.ini";
@@ -54,7 +55,7 @@ public final class VmManager {
private final static Pattern SDCARD_SIZE_PATTERN = Pattern.compile("\\d+[MK]?");
public static final class VmInfo {
public static final class AvdInfo {
String name;
String path;
IAndroidTarget target;
@@ -72,30 +73,30 @@ public final class VmManager {
}
}
private final ArrayList<VmInfo> mVmList = new ArrayList<VmInfo>();
private final ArrayList<AvdInfo> mAvdList = new ArrayList<AvdInfo>();
private ISdkLog mSdkLog;
private final SdkManager mSdk;
public VmManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException {
public AvdManager(SdkManager sdk, ISdkLog sdkLog) throws AndroidLocationException {
mSdk = sdk;
mSdkLog = sdkLog;
buildVmList();
buildAvdList();
}
/**
* Returns the existing VMs.
* @return a newly allocated arrays containing all the VMs.
* Returns the existing AVDs.
* @return a newly allocated array containing all the AVDs.
*/
public VmInfo[] getVms() {
return mVmList.toArray(new VmInfo[mVmList.size()]);
public AvdInfo[] getAvds() {
return mAvdList.toArray(new AvdInfo[mAvdList.size()]);
}
/**
* Returns the {@link VmInfo} matching the given <var>name</var>.
* @return the matching VmInfo or <code>null</code> if none were found.
* Returns the {@link AvdInfo} matching the given <var>name</var>.
* @return the matching AvdInfo or <code>null</code> if none were found.
*/
public VmInfo getVm(String name) {
for (VmInfo info : mVmList) {
public AvdInfo getAvd(String name) {
for (AvdInfo info : mAvdList) {
if (info.name.equals(name)) {
return info;
}
@@ -105,19 +106,20 @@ public final class VmManager {
}
/**
* Creates a new VM. It is expected that there is no existing VM with this name already.
* @param parentFolder the folder to contain the VM. A new folder will be created in this
* folder with the name of the VM
* @param name the name of the VM
* @param target the target of the VM
* Creates a new AVD. It is expected that there is no existing AVD with this name already.
* @param parentFolder the folder to contain the AVD. A new folder will be created in this
* folder with the name of the AVD
* @param name the name of the AVD
* @param target the target of the AVD
* @param skinName the name of the skin. Can be null.
* @param sdcard the parameter value for the sdCard. Can be null. This is either a path to
* an existing sdcard image or a sdcard size (\d+, \d+K, \dM).
* @param hardwareConfig the hardware setup for the VM
* @param hardwareConfig the hardware setup for the AVD
* @param removePrevious If true remove any previous files.
*/
public VmInfo createVm(String parentFolder, String name, IAndroidTarget target,
public AvdInfo createAvd(String parentFolder, String name, IAndroidTarget target,
String skinName, String sdcard, Map<String,String> hardwareConfig,
ISdkLog log) {
boolean removePrevious, ISdkLog log) {
try {
File rootDirectory = new File(parentFolder);
@@ -128,24 +130,31 @@ public final class VmManager {
return null;
}
File vmFolder = new File(parentFolder, name + ".avm");
if (vmFolder.exists()) {
if (log != null) {
log.error(null, "Folder %s is in the way.", vmFolder.getAbsolutePath());
File avdFolder = new File(parentFolder, name + AVD_FOLDER_EXTENSION);
if (avdFolder.exists()) {
if (removePrevious) {
// AVD already exists and removePrevious is set, try to remove the
// directory's content first (but not the directory itself).
recursiveDelete(avdFolder);
} else {
// AVD shouldn't already exist if removePrevious is false.
if (log != null) {
log.error(null, "Folder %s is in the way.", avdFolder.getAbsolutePath());
}
return null;
}
return null;
}
// create the vm folder.
vmFolder.mkdir();
// create the AVD folder.
avdFolder.mkdir();
HashMap<String, String> values = new HashMap<String, String>();
// prepare the ini file.
String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
File iniFile = new File(vmRoot, name + ".ini");
values.put(VM_INFO_PATH, vmFolder.getAbsolutePath());
values.put(VM_INFO_TARGET, target.hashString());
String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
File iniFile = new File(avdRoot, name + ".ini");
values.put(AVD_INFO_PATH, avdFolder.getAbsolutePath());
values.put(AVD_INFO_TARGET, target.hashString());
createConfigIni(iniFile, values);
// writes the userdata.img in it.
@@ -153,7 +162,7 @@ public final class VmManager {
File userdataSrc = new File(imagePath, IMAGE_USERDATA);
FileInputStream fis = new FileInputStream(userdataSrc);
File userdataDest = new File(vmFolder, IMAGE_USERDATA);
File userdataDest = new File(avdFolder, IMAGE_USERDATA);
FileOutputStream fos = new FileOutputStream(userdataDest);
byte[] buffer = new byte[4096];
@@ -193,7 +202,7 @@ public final class VmManager {
Matcher m = SDCARD_SIZE_PATTERN.matcher(sdcard);
if (m.matches()) {
// create the sdcard.
sdcardFile = new File(vmFolder, "sdcard.img");
sdcardFile = new File(avdFolder, "sdcard.img");
String path = sdcardFile.getAbsolutePath();
// execute mksdcard with the proper parameters.
@@ -224,28 +233,27 @@ public final class VmManager {
values.putAll(hardwareConfig);
}
File configIniFile = new File(vmFolder, CONFIG_INI);
File configIniFile = new File(avdFolder, CONFIG_INI);
createConfigIni(configIniFile, values);
if (log != null) {
if (target.isPlatform()) {
log.printf("Created VM '%s' based on %s\n", name, target.getName());
log.printf("Created AVD '%s' based on %s\n", name, target.getName());
} else {
log.printf(
"Created VM '%s' based on %s (%s)\n", name, target.getName(),
target.getVendor());
log.printf("Created AVD '%s' based on %s (%s)\n", name, target.getName(),
target.getVendor());
}
}
// create the VmInfo object, and add it to the list
VmInfo vmInfo = new VmInfo();
vmInfo.name = name;
vmInfo.path = vmFolder.getAbsolutePath();
vmInfo.target = target;
// create the AvdInfo object, and add it to the list
AvdInfo avdInfo = new AvdInfo();
avdInfo.name = name;
avdInfo.path = avdFolder.getAbsolutePath();
avdInfo.target = target;
mVmList.add(vmInfo);
mAvdList.add(avdInfo);
return vmInfo;
return avdInfo;
} catch (AndroidLocationException e) {
if (log != null) {
log.error(e, null);
@@ -259,21 +267,35 @@ public final class VmManager {
return null;
}
private void buildVmList() throws AndroidLocationException {
/**
* Helper method to recursively delete a folder's content (but not the folder itself).
*
* @throws SecurityException like {@link File#delete()} does if file/folder is not writable.
*/
public void recursiveDelete(File folder) {
for (File f : folder.listFiles()) {
if (f.isDirectory()) {
recursiveDelete(folder);
}
f.delete();
}
}
private void buildAvdList() throws AndroidLocationException {
// get the Android prefs location.
String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD;
// ensure folder validity.
File folder = new File(vmRoot);
File folder = new File(avdRoot);
if (folder.isFile()) {
throw new AndroidLocationException(String.format("%s is not a valid folder.", vmRoot));
throw new AndroidLocationException(String.format("%s is not a valid folder.", avdRoot));
} else if (folder.exists() == false) {
// folder is not there, we create it and return
folder.mkdirs();
return;
}
File[] vms = folder.listFiles(new FilenameFilter() {
File[] avds = folder.listFiles(new FilenameFilter() {
public boolean accept(File parent, String name) {
if (INI_NAME_PATTERN.matcher(name).matches()) {
// check it's a file and not a folder
@@ -284,23 +306,23 @@ public final class VmManager {
}
});
for (File vm : vms) {
VmInfo info = parseVmInfo(vm);
for (File avd : avds) {
AvdInfo info = parseAvdInfo(avd);
if (info != null) {
mVmList.add(info);
mAvdList.add(info);
}
}
}
private VmInfo parseVmInfo(File path) {
private AvdInfo parseAvdInfo(File path) {
Map<String, String> map = SdkManager.parsePropertyFile(path, mSdkLog);
String vmPath = map.get(VM_INFO_PATH);
if (vmPath == null) {
String avdPath = map.get(AVD_INFO_PATH);
if (avdPath == null) {
return null;
}
String targetHash = map.get(VM_INFO_TARGET);
String targetHash = map.get(AVD_INFO_TARGET);
if (targetHash == null) {
return null;
}
@@ -310,14 +332,14 @@ public final class VmManager {
return null;
}
VmInfo info = new VmInfo();
AvdInfo info = new AvdInfo();
Matcher matcher = INI_NAME_PATTERN.matcher(path.getName());
if (matcher.matches()) {
info.name = matcher.group(1);
} else {
info.name = path.getName(); // really this should not happen.
}
info.path = vmPath;
info.path = avdPath;
info.target = target;
return info;
@@ -447,4 +469,14 @@ public final class VmManager {
return process.waitFor();
}
/**
* Removes an {@link AvdInfo} from the internal list.
*
* @param avdInfo The {@link AvdInfo} to remove.
* @return true if this {@link AvdInfo} was present and has been removed.
*/
public boolean removeAvd(AvdInfo avdInfo) {
return mAvdList.remove(avdInfo);
}
}

View File

@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.android.sdklib.vm;
package com.android.sdklib.avd;
import com.android.sdklib.ISdkLog;

View File

@@ -17,7 +17,7 @@
package com.android.sdkuilib;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.vm.VmManager.VmInfo;
import com.android.sdklib.avd.AvdManager.AvdInfo;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ControlAdapter;
@@ -40,16 +40,16 @@ import java.util.ArrayList;
/**
* The VM selector is a table that is added to the given parent composite.
* The AVD selector is a table that is added to the given parent composite.
* <p/>
* To use, create it using {@link #VmSelector(Composite, VmInfo[], boolean)} then
* call {@link #setSelection(VmInfo)}, {@link #setSelectionListener(SelectionListener)}
* To use, create it using {@link #AvdSelector(Composite, AvdInfo[], boolean)} then
* call {@link #setSelection(AvdInfo)}, {@link #setSelectionListener(SelectionListener)}
* and finally use {@link #getFirstSelected()} or {@link #getAllSelected()} to retrieve the
* selection.
*/
public final class VmSelector {
public final class AvdSelector {
private VmInfo[] mVms;
private AvdInfo[] mAvds;
private final boolean mAllowMultipleSelection;
private SelectionListener mSelectionListener;
private Table mTable;
@@ -59,12 +59,12 @@ public final class VmSelector {
* Creates a new SDK Target Selector.
*
* @param parent The parent composite where the selector will be added.
* @param vms The list of vms. This is <em>not</em> copied, the caller must not modify.
* @param avds The list of AVDs. This is <em>not</em> copied, the caller must not modify.
* @param allowMultipleSelection True if more than one SDK target can be selected at the same
* time.
*/
public VmSelector(Composite parent, VmInfo[] vms, boolean allowMultipleSelection) {
mVms = vms;
public AvdSelector(Composite parent, AvdInfo[] avds, boolean allowMultipleSelection) {
mAvds = avds;
// Layout has 1 column
Composite group = new Composite(parent, SWT.NONE);
@@ -89,7 +89,7 @@ public final class VmSelector {
// create the table columns
final TableColumn column0 = new TableColumn(mTable, SWT.NONE);
column0.setText("VM Name");
column0.setText("AVD Name");
final TableColumn column1 = new TableColumn(mTable, SWT.NONE);
column1.setText("Target Name");
final TableColumn column2 = new TableColumn(mTable, SWT.NONE);
@@ -104,25 +104,25 @@ public final class VmSelector {
}
/**
* Sets a new set of VM, with an optional filter.
* Sets a new set of AVD, with an optional filter.
* <p/>This must be called from the UI thread.
*
* @param vms The list of vms. This is <em>not</em> copied, the caller must not modify.
* @param filter An IAndroidTarget. If non-null, only VM whose target are compatible with the
* @param avds The list of AVDs. This is <em>not</em> copied, the caller must not modify.
* @param filter An IAndroidTarget. If non-null, only AVD whose target are compatible with the
* filter target will displayed an available for selection.
*/
public void setVms(VmInfo[] vms, IAndroidTarget filter) {
mVms = vms;
public void setAvds(AvdInfo[] avds, IAndroidTarget filter) {
mAvds = avds;
fillTable(mTable, filter);
}
/**
* Returns the list of known Vms.
* Returns the list of known AVDs.
* <p/>
* This is not a copy. Callers must <em>not</em> modify this array.
*/
public VmInfo[] getVms() {
return mVms;
public AvdInfo[] getAvds() {
return mAvds;
}
/**
@@ -151,11 +151,11 @@ public final class VmSelector {
* @param target the target to be selection
* @return true if the target could be selected, false otherwise.
*/
public boolean setSelection(VmInfo target) {
public boolean setSelection(AvdInfo target) {
boolean found = false;
boolean modified = false;
for (TableItem i : mTable.getItems()) {
if ((VmInfo) i.getData() == target) {
if ((AvdInfo) i.getData() == target) {
found = true;
if (!i.getChecked()) {
modified = true;
@@ -181,14 +181,14 @@ public final class VmSelector {
* @see #getFirstSelected()
* @return An array of selected items. The list can be empty but not null.
*/
public VmInfo[] getAllSelected() {
public AvdInfo[] getAllSelected() {
ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
for (TableItem i : mTable.getItems()) {
if (i.getChecked()) {
list.add((IAndroidTarget) i.getData());
}
}
return list.toArray(new VmInfo[list.size()]);
return list.toArray(new AvdInfo[list.size()]);
}
/**
@@ -198,10 +198,10 @@ public final class VmSelector {
* @see #getAllSelected()
* @return The first selected item or null.
*/
public VmInfo getFirstSelected() {
public AvdInfo getFirstSelected() {
for (TableItem i : mTable.getItems()) {
if (i.getChecked()) {
return (VmInfo) i.getData();
return (AvdInfo) i.getData();
}
}
return null;
@@ -283,7 +283,7 @@ public final class VmSelector {
}
/**
* Fills the table with all VM.
* Fills the table with all AVD.
* The table columns are:
* <ul>
* <li>column 0: sdk name
@@ -294,14 +294,14 @@ public final class VmSelector {
*/
private void fillTable(final Table table, IAndroidTarget filter) {
table.removeAll();
if (mVms != null && mVms.length > 0) {
if (mAvds != null && mAvds.length > 0) {
table.setEnabled(true);
for (VmInfo vm : mVms) {
if (filter == null || filter.isCompatibleBaseFor(vm.getTarget())) {
for (AvdInfo avd : mAvds) {
if (filter == null || filter.isCompatibleBaseFor(avd.getTarget())) {
TableItem item = new TableItem(table, SWT.NONE);
item.setData(vm);
item.setText(0, vm.getName());
IAndroidTarget target = vm.getTarget();
item.setData(avd);
item.setText(0, avd.getName());
IAndroidTarget target = avd.getTarget();
item.setText(1, target.getFullName());
item.setText(2, target.getApiVersionName());
item.setText(3, Integer.toString(target.getApiVersionNumber()));
@@ -314,7 +314,7 @@ public final class VmSelector {
TableItem item = new TableItem(table, SWT.NONE);
item.setData(null);
item.setText(0, "--");
item.setText(1, "No VM available");
item.setText(1, "No AVD available");
item.setText(2, "--");
item.setText(3, "--");
}
@@ -365,13 +365,13 @@ public final class VmSelector {
}
/**
* Updates the description label with the path of the item's VM, if any.
* Updates the description label with the path of the item's AVD, if any.
*/
private void updateDescription(TableItem item) {
if (item != null) {
Object data = item.getData();
if (data instanceof VmInfo) {
String newTooltip = ((VmInfo) data).getPath();
if (data instanceof AvdInfo) {
String newTooltip = ((AvdInfo) data).getPath();
mDescription.setText(newTooltip == null ? "" : newTooltip); //$NON-NLS-1$
}
}