auto import from //depot/cupcake/@135843

This commit is contained in:
The Android Open Source Project
2009-03-03 19:29:09 -08:00
parent d4aee0c0ca
commit 52d4c30ca5
2386 changed files with 299112 additions and 0 deletions

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="tests"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry combineaccessrules="false" kind="src" path="/SdkLib"/>
<classpathentry combineaccessrules="false" kind="src" path="/AndroidPrefs"/>
<classpathentry combineaccessrules="false" kind="src" path="/SdkUiLib"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
<classpathentry kind="output" path="bin"/>
</classpath>

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>SdkManager</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View File

@@ -0,0 +1,5 @@
# Copyright 2007 The Android Open Source Project
#
SDKMANAGERAPP_LOCAL_DIR := $(call my-dir)
include $(SDKMANAGERAPP_LOCAL_DIR)/etc/Android.mk
include $(SDKMANAGERAPP_LOCAL_DIR)/src/Android.mk

View File

@@ -0,0 +1,8 @@
# Copyright 2008 The Android Open Source Project
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_PREBUILT_EXECUTABLES := android
include $(BUILD_HOST_PREBUILT)

View File

@@ -0,0 +1,84 @@
#!/bin/sh
# Copyright 2005-2007, The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Set up prog to be the path of this script, including following symlinks,
# and set up progdir to be the fully-qualified pathname of its directory.
prog="$0"
while [ -h "${prog}" ]; do
newProg=`/bin/ls -ld "${prog}"`
newProg=`expr "${newProg}" : ".* -> \(.*\)$"`
if expr "x${newProg}" : 'x/' >/dev/null; then
prog="${newProg}"
else
progdir=`dirname "${prog}"`
prog="${progdir}/${newProg}"
fi
done
oldwd=`pwd`
progdir=`dirname "${prog}"`
cd "${progdir}"
progdir=`pwd`
prog="${progdir}"/`basename "${prog}"`
cd "${oldwd}"
jarfile=sdkmanager.jar
frameworkdir="$progdir"
libdir="$progdir"
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/tools/lib
libdir=`dirname "$progdir"`/tools/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
frameworkdir=`dirname "$progdir"`/framework
libdir=`dirname "$progdir"`/lib
fi
if [ ! -r "$frameworkdir/$jarfile" ]
then
echo `basename "$prog"`": can't find $jarfile"
exit 1
fi
# Check args.
if [ debug = "$1" ]; then
# add this in for debugging
java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y
shift 1
else
java_debug=
fi
# Mac OS X needs an additional arg, or you get an "illegal thread" complaint.
if [ `uname` = "Darwin" ]; then
os_opts="-XstartOnFirstThread"
#because Java 1.6 is 64 bits only and SWT doesn't support this, we force the usage of java 1.5
java_cmd="/System/Library/Frameworks/JavaVM.framework/Versions/1.5/Commands/java"
else
os_opts=
java_cmd="java"
fi
if [ "$OSTYPE" = "cygwin" ] ; then
jarpath=`cygpath -w "$frameworkdir/$jarfile"`
progdir=`cygpath -w "$progdir"`
else
jarpath="$frameworkdir/$jarfile"
fi
# need to use "java.ext.dirs" because "-jar" causes classpath to be ignored
# might need more memory, e.g. -Xmx128M
exec "$java_cmd" -Xmx256M $os_opts $java_debug -Djava.ext.dirs="$frameworkdir" -Djava.library.path="$libdir" -Dcom.android.sdkmanager.toolsdir="$progdir" -jar "$jarpath" "$@"

View File

@@ -0,0 +1,51 @@
@echo off
rem Copyright (C) 2007 The Android Open Source Project
rem
rem Licensed under the Apache License, Version 2.0 (the "License");
rem you may not use this file except in compliance with the License.
rem You may obtain a copy of the License at
rem
rem http://www.apache.org/licenses/LICENSE-2.0
rem
rem Unless required by applicable law or agreed to in writing, software
rem distributed under the License is distributed on an "AS IS" BASIS,
rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
rem See the License for the specific language governing permissions and
rem limitations under the License.
rem don't modify the caller's environment
setlocal
rem Set up prog to be the path of this script, including following symlinks,
rem and set up progdir to be the fully-qualified pathname of its directory.
set prog=%~f0
rem Grab current directory before we change it
set workdir=%cd%
rem Change current directory and drive to where the script is, to avoid
rem issues with directories containing whitespaces.
cd /d %~dp0
set jarfile=sdkmanager.jar
set frameworkdir=
set libdir=
if exist %frameworkdir%%jarfile% goto JarFileOk
set frameworkdir=lib\
set libdir=lib\
if exist %frameworkdir%%jarfile% goto JarFileOk
set frameworkdir=..\framework\
set libdir=..\lib\
:JarFileOk
if debug NEQ "%1" goto NoDebug
set java_debug=-agentlib:jdwp=transport=dt_socket,server=y,address=8050,suspend=y
shift 1
:NoDebug
set jarpath=%frameworkdir%%jarfile%
call java %java_debug% -Djava.ext.dirs=%frameworkdir% -Djava.library.path=%libdir% -Dcom.android.sdkmanager.toolsdir= -Dcom.android.sdkmanager.workdir="%workdir%" -jar %jarpath% %*

View File

@@ -0,0 +1 @@
Main-Class: com.android.sdkmanager.Main

View File

@@ -0,0 +1,16 @@
# Copyright 2007 The Android Open Source Project
#
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_JAR_MANIFEST := ../etc/manifest.txt
LOCAL_JAVA_LIBRARIES := \
androidprefs \
sdklib \
sdkuilib
LOCAL_MODULE := sdkmanager
include $(BUILD_HOST_JAVA_LIBRARY)

View File

@@ -0,0 +1,791 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdkmanager;
import com.android.sdklib.ISdkLog;
import java.util.HashMap;
import java.util.Map.Entry;
/**
* Parses the command-line and stores flags needed or requested.
* <p/>
* This is a base class. To be useful you want to:
* <ul>
* <li>override it.
* <li>pass an action array to the constructor.
* <li>define flags for your actions.
* </ul>
* <p/>
* To use, call {@link #parseArgs(String[])} and then
* call {@link #getValue(String, String, String)}.
*/
public class CommandLineProcessor {
/** 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";
/** 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;
/**
* Action definitions.
* <p/>
* 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;
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 "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.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);
}
//------------------
// Helpers to get flags values
/** Helper that returns true if --verbose was requested. */
public boolean isVerbose() {
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_VERB, NO_VERB_OBJECT, KEY_SILENT)).booleanValue();
}
/** Helper that returns true if --help was requested. */
public boolean isHelpRequested() {
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;
}
/** Returns the direct object name from the command-line. Can be null. */
public String getDirectObject() {
return mDirectObjectRequested;
}
//------------------
/**
* Raw access to parsed parameter values.
* <p/>
* 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.
* <p/>
* Both a verb and a direct object filter can be specified. When they are non-null they limit
* the scope of the search.
* <p/>
* 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.
*/
public Object getValue(String verb, String directObject, String longFlagName) {
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;
}
/**
* 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.
*/
protected void setValue(String verb, String directObject, String longFlagName, Object value) {
String key = verb + "/" + directObject + "/" + longFlagName;
Arg arg = mArguments.get(key);
arg.setCurrentValue(value);
}
/**
* Parses the command-line arguments.
* <p/>
* This method will exit and not return if a parsing error arise.
*
* @param args The arguments typically received by a main method.
*/
public void parseArgs(String[] args) {
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);
}
}
}
/**
* Finds an {@link Arg} given an action name and a long flag name.
* @return The {@link Arg} found or null.
*/
protected Arg findLongArg(String verb, String directObject, String longName) {
if (verb == null) {
verb = GLOBAL_FLAG_VERB;
}
if (directObject == null) {
directObject = NO_VERB_OBJECT;
}
String key = verb + "/" + directObject + "/" + longName;
return mArguments.get(key);
}
/**
* Finds an {@link Arg} given an action name and a short flag name.
* @return The {@link Arg} found or null.
*/
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.getVerb().equals(verb) && arg.getDirectObject().equals(directObject)) {
if (shortName.equals(arg.getShortArg())) {
return arg;
}
}
}
return null;
}
/**
* 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
*/
public void printHelpAndExit(String errorFormat, Object... args) {
printHelpAndExitForAction(null /*verb*/, null /*directObject*/, errorFormat, 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
*/
public void printHelpAndExitForAction(String verb, String directObject,
String errorFormat, Object... args) {
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();
}
/**
* Internal helper to print all the option flags for a given action name.
*/
protected void listOptions(String verb, String directObject) {
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 = "";
if (arg.getDefaultValue() instanceof String[]) {
for (String v : (String[]) arg.getDefaultValue()) {
if (value.length() > 0) {
value += ", ";
}
value += v;
}
} else if (arg.getDefaultValue() != null) {
value = arg.getDefaultValue().toString();
}
if (value.length() > 0) {
value = " (" + value + ")";
}
String required = arg.isMandatory() ? " [required]" : "";
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");
}
}
//----
/**
* The mode of an argument specifies the type of variable it represents,
* whether an extra parameter is required after the flag and how to parse it.
*/
static enum MODE {
/** Argument value is a Boolean. Default value is a Boolean. */
BOOLEAN {
@Override
public boolean needsExtra() {
return false;
}
@Override
public String process(Arg arg, String extra) {
// Toggle the current value
arg.setCurrentValue(! ((Boolean) arg.getCurrentValue()).booleanValue());
return null;
}
},
/** Argument value is an Integer. Default value is an Integer. */
INTEGER {
@Override
public boolean needsExtra() {
return true;
}
@Override
public String process(Arg arg, String extra) {
try {
arg.setCurrentValue(Integer.parseInt(extra));
return null;
} catch (NumberFormatException e) {
return String.format("Failed to parse '%1$s' as an integer: %2%s",
extra, e.getMessage());
}
}
},
/** Argument value is a String. Default value is a String[]. */
ENUM {
@Override
public boolean needsExtra() {
return true;
}
@Override
public String process(Arg arg, String extra) {
StringBuilder desc = new StringBuilder();
String[] values = (String[]) arg.getDefaultValue();
for (String value : values) {
if (value.equals(extra)) {
arg.setCurrentValue(extra);
return null;
}
if (desc.length() != 0) {
desc.append(", ");
}
desc.append(value);
}
return String.format("'%1$s' is not one of %2$s", extra, desc.toString());
}
},
/** Argument value is a String. Default value is a null. */
STRING {
@Override
public boolean needsExtra() {
return true;
}
@Override
public String process(Arg arg, String extra) {
arg.setCurrentValue(extra);
return null;
}
};
/**
* Returns true if this mode requires an extra parameter.
*/
public abstract boolean needsExtra();
/**
* Processes the flag for this argument.
*
* @param arg The argument being processed.
* @param extra The extra parameter. Null if {@link #needsExtra()} returned false.
* @return An error string or null if there's no error.
*/
public abstract String process(Arg arg, String extra);
}
/**
* An argument accepted by the command-line, also called "a flag".
* Arguments must have a short version (one letter), a long version name and a description.
* They can have a default value, or it can be null.
* Depending on the {@link MODE}, the default value can be a Boolean, an Integer, a String
* or a String array (in which case the first item is the current by default.)
*/
static class Arg {
/** Verb for that argument. Never null. */
private final String mVerb;
/** Direct Object for that argument. Never null, but can be empty string. */
private final String mDirectObject;
/** The 1-letter short name of the argument, e.g. -v. */
private final String mShortName;
/** The long name of the argument, e.g. --verbose. */
private final String mLongName;
/** A description. Never null. */
private final String mDescription;
/** A default value. Can be null. */
private final Object mDefaultValue;
/** The argument mode (type + process method). Never null. */
private final MODE mMode;
/** True if this argument is mandatory for this verb/directobject. */
private final boolean mMandatory;
/** Current value. Initially set to the default value. */
private Object mCurrentValue;
/** True if the argument has been used on the command line. */
private boolean mInCommandLine;
/**
* 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 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}.
*/
public Arg(MODE mode,
boolean mandatory,
String verb,
String directObject,
String shortName,
String longName,
String description,
Object defaultValue) {
mMode = mode;
mMandatory = mandatory;
mVerb = verb;
mDirectObject = directObject;
mShortName = shortName;
mLongName = longName;
mDescription = description;
mDefaultValue = defaultValue;
mInCommandLine = false;
if (defaultValue instanceof String[]) {
mCurrentValue = ((String[])defaultValue)[0];
} else {
mCurrentValue = mDefaultValue;
}
}
/** Return true if this argument is mandatory for this verb/directobject. */
public boolean isMandatory() {
return mMandatory;
}
/** Returns the 1-letter short name of the argument, e.g. -v. */
public String getShortArg() {
return mShortName;
}
/** Returns the long name of the argument, e.g. --verbose. */
public String getLongArg() {
return mLongName;
}
/** Returns the description. Never null. */
public String getDescription() {
return mDescription;
}
/** Returns the verb for that argument. Never null. */
public String getVerb() {
return mVerb;
}
/** Returns the direct Object for that argument. Never null, but can be empty string. */
public String getDirectObject() {
return mDirectObject;
}
/** Returns the default value. Can be null. */
public Object getDefaultValue() {
return mDefaultValue;
}
/** Returns the current value. Initially set to the default value. Can be null. */
public Object getCurrentValue() {
return mCurrentValue;
}
/** Sets the current value. Can be null. */
public void setCurrentValue(Object currentValue) {
mCurrentValue = currentValue;
}
/** Returns the argument mode (type + process method). Never null. */
public MODE getMode() {
return mMode;
}
/** Returns true if the argument has been used on the command line. */
public boolean isInCommandLine() {
return mInCommandLine;
}
/** Sets if the argument has been used on the command line. */
public void setInCommandLine(boolean inCommandLine) {
mInCommandLine = inCommandLine;
}
}
/**
* 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}.
*/
protected void define(MODE mode,
boolean mandatory,
String verb,
String directObject,
String shortName, String longName,
String description, Object defaultValue) {
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));
}
/**
* Exits in case of error.
* This is protected so that it can be overridden in unit tests.
*/
protected void exit() {
System.exit(1);
}
/**
* 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.
*/
protected void stdout(String format, Object...args) {
mLog.printf(format + "\n", 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.
*/
protected void stderr(String format, Object...args) {
mLog.error(null, format, args);
}
}

View File

@@ -0,0 +1,813 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdkmanager;
import com.android.prefs.AndroidLocation;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
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 java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* Main class for the 'android' application.
*/
class Main {
/** Java property that defines the location of the sdk/tools directory. */
private final static String TOOLSDIR = "com.android.sdkmanager.toolsdir";
/** Java property that defines the working directory. On Windows the current working directory
* is actually the tools dir, in which case this is used to get the original CWD. */
private final static String WORKDIR = "com.android.sdkmanager.workdir";
private final static String[] BOOLEAN_YES_REPLIES = new String[] { "yes", "y" };
private final static String[] BOOLEAN_NO_REPLIES = new String[] { "no", "n" };
/** Path to the SDK folder. This is the parent of {@link #TOOLSDIR}. */
private String mSdkFolder;
/** Logger object. Use this to print normal output, warnings or errors. */
private ISdkLog mSdkLog;
/** The SDK manager parses the SDK folder and gives access to the content. */
private SdkManager mSdkManager;
/** Command-line processor with options specific to SdkManager. */
private SdkCommandLine mSdkCommandLine;
/** The working directory, either null or set to an existing absolute canonical directory. */
private File mWorkDir;
public static void main(String[] args) {
new Main().run(args);
}
/**
* Runs the sdk manager app
*/
private void run(String[] args) {
createLogger();
init();
mSdkCommandLine.parseArgs(args);
parseSdk();
doAction();
}
/**
* Creates the {@link #mSdkLog} object.
* <p/>
* This must be done before {@link #init()} as it will be used to report errors.
*/
private void createLogger() {
mSdkLog = new ISdkLog() {
public void error(Throwable t, String errorFormat, Object... args) {
if (errorFormat != null) {
System.err.printf("Error: " + errorFormat, args);
if (!errorFormat.endsWith("\n")) {
System.err.printf("\n");
}
}
if (t != null) {
System.err.printf("Error: %s\n", t.getMessage());
}
}
public void warning(String warningFormat, Object... args) {
if (mSdkCommandLine.isVerbose()) {
System.out.printf("Warning: " + warningFormat, args);
if (!warningFormat.endsWith("\n")) {
System.out.printf("\n");
}
}
}
public void printf(String msgFormat, Object... args) {
System.out.printf(msgFormat, args);
}
};
}
/**
* Init the application by making sure the SDK path is available and
* doing basic parsing of the SDK.
*/
private void init() {
mSdkCommandLine = new SdkCommandLine(mSdkLog);
// We get passed a property for the tools dir
String toolsDirProp = System.getProperty(TOOLSDIR);
if (toolsDirProp == null) {
// for debugging, it's easier to override using the process environment
toolsDirProp = System.getenv(TOOLSDIR);
}
if (toolsDirProp != null) {
// got back a level for the SDK folder
File tools;
if (toolsDirProp.length() > 0) {
tools = new File(toolsDirProp);
mSdkFolder = tools.getParent();
} else {
try {
tools = new File(".").getCanonicalFile();
mSdkFolder = tools.getParent();
} catch (IOException e) {
// Will print an error below since mSdkFolder is not defined
}
}
}
if (mSdkFolder == null) {
errorAndExit("The tools directory property is not set, please make sure you are executing %1$s",
SdkConstants.androidCmdName());
}
// We might get passed a property for the working directory
// Either it is a valid directory and mWorkDir is set to it's absolute canonical value
// or mWorkDir remains null.
String workDirProp = System.getProperty(WORKDIR);
if (workDirProp == null) {
workDirProp = System.getenv(WORKDIR);
}
if (workDirProp != null) {
// This should be a valid directory
mWorkDir = new File(workDirProp);
try {
mWorkDir = mWorkDir.getCanonicalFile().getAbsoluteFile();
} catch (IOException e) {
mWorkDir = null;
}
if (mWorkDir == null || !mWorkDir.isDirectory()) {
errorAndExit("The working directory does not seem to be valid: '%1$s", workDirProp);
}
}
}
/**
* Does the basic SDK parsing required for all actions
*/
private void parseSdk() {
mSdkManager = SdkManager.createManager(mSdkFolder, mSdkLog);
if (mSdkManager == null) {
errorAndExit("Unable to parse SDK content.");
}
}
/**
* Actually do an action...
*/
private void doAction() {
String verb = mSdkCommandLine.getVerb();
String directObject = mSdkCommandLine.getDirectObject();
if (SdkCommandLine.VERB_LIST.equals(verb)) {
// list action.
if (SdkCommandLine.OBJECT_TARGET.equals(directObject)) {
displayTargetList();
} else if (SdkCommandLine.OBJECT_AVD.equals(directObject)) {
displayAvdList();
} else {
displayTargetList();
displayAvdList();
}
} else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
createAvd();
} else if (SdkCommandLine.VERB_DELETE.equals(verb) &&
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
deleteAvd();
} else if (SdkCommandLine.VERB_MOVE.equals(verb) &&
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
moveAvd();
} else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
createProject();
} else if (SdkCommandLine.VERB_UPDATE.equals(verb) &&
SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
updateProject();
} else {
mSdkCommandLine.printHelpAndExit(null);
}
}
/**
* Creates a new Android project based on command-line parameters
*/
private void createProject() {
// get the target and try to resolve it.
int targetId = mSdkCommandLine.getParamTargetId();
IAndroidTarget[] targets = mSdkManager.getTargets();
if (targetId < 1 || targetId > targets.length) {
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
SdkConstants.androidCmdName());
}
IAndroidTarget target = targets[targetId - 1];
ProjectCreator creator = new ProjectCreator(mSdkFolder,
mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE :
mSdkCommandLine.isSilent() ? OutputLevel.SILENT :
OutputLevel.NORMAL,
mSdkLog);
String projectDir = getProjectLocation(mSdkCommandLine.getParamLocationPath());
creator.createProject(projectDir,
mSdkCommandLine.getParamName(),
mSdkCommandLine.getParamProjectPackage(),
mSdkCommandLine.getParamProjectActivity(),
target,
false /* isTestProject*/);
}
/**
* Updates an existing Android project based on command-line parameters
*/
private void updateProject() {
// get the target and try to resolve it.
IAndroidTarget target = null;
int targetId = mSdkCommandLine.getParamTargetId();
if (targetId >= 0) {
IAndroidTarget[] targets = mSdkManager.getTargets();
if (targetId < 1 || targetId > targets.length) {
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
SdkConstants.androidCmdName());
}
target = targets[targetId - 1];
}
ProjectCreator creator = new ProjectCreator(mSdkFolder,
mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE :
mSdkCommandLine.isSilent() ? OutputLevel.SILENT :
OutputLevel.NORMAL,
mSdkLog);
String projectDir = getProjectLocation(mSdkCommandLine.getParamLocationPath());
creator.updateProject(projectDir,
target,
mSdkCommandLine.getParamName());
}
/**
* Adjusts the project location to make it absolute & canonical relative to the
* working directory, if any.
*
* @return The project absolute path relative to {@link #mWorkDir} or the original
* newProjectLocation otherwise.
*/
private String getProjectLocation(String newProjectLocation) {
// If the new project location is absolute, use it as-is
File projectDir = new File(newProjectLocation);
if (projectDir.isAbsolute()) {
return newProjectLocation;
}
// if there's no working directory, just use the project location as-is.
if (mWorkDir == null) {
return newProjectLocation;
}
// Combine then and get an absolute canonical directory
try {
projectDir = new File(mWorkDir, newProjectLocation).getCanonicalFile();
return projectDir.getPath();
} catch (IOException e) {
errorAndExit("Failed to combine working directory '%1$s' with project location '%2$s': %3$s",
mWorkDir.getPath(),
newProjectLocation,
e.getMessage());
return null;
}
}
/**
* Displays the list of available Targets (Platforms and Add-ons)
*/
private void displayTargetList() {
mSdkLog.printf("Available Android targets:\n");
int index = 1;
for (IAndroidTarget target : mSdkManager.getTargets()) {
if (target.isPlatform()) {
mSdkLog.printf("[%d] %s\n", index, target.getName());
mSdkLog.printf(" API level: %d\n", target.getApiVersionNumber());
} else {
mSdkLog.printf("[%d] Add-on: %s\n", index, target.getName());
mSdkLog.printf(" Vendor: %s\n", target.getVendor());
if (target.getDescription() != null) {
mSdkLog.printf(" Description: %s\n", target.getDescription());
}
mSdkLog.printf(" Based on Android %s (API level %d)\n",
target.getApiVersionName(), target.getApiVersionNumber());
// display the optional libraries.
IOptionalLibrary[] libraries = target.getOptionalLibraries();
if (libraries != null) {
mSdkLog.printf(" Libraries:\n");
for (IOptionalLibrary library : libraries) {
mSdkLog.printf(" * %1$s (%2$s)\n",
library.getName(), library.getJarName());
mSdkLog.printf(String.format(
" %1$s\n", library.getDescription()));
}
}
}
// get the target skins
displaySkinList(target, " Skins: ");
index++;
}
}
/**
* Displays the skins valid for the given target.
*/
private void displaySkinList(IAndroidTarget target, String message) {
String[] skins = target.getSkins();
String defaultSkin = target.getDefaultSkin();
mSdkLog.printf(message);
if (skins != null) {
boolean first = true;
for (String skin : skins) {
if (first == false) {
mSdkLog.printf(", ");
} else {
first = false;
}
mSdkLog.printf(skin);
if (skin.equals(defaultSkin)) {
mSdkLog.printf(" (default)");
}
}
mSdkLog.printf("\n");
} else {
mSdkLog.printf("no skins.\n");
}
}
/**
* Displays the list of available AVDs.
*/
private void displayAvdList() {
try {
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
mSdkLog.printf("Available Android Virtual Devices:\n");
AvdInfo[] avds = avdManager.getAvds();
for (int index = 0 ; index < avds.length ; index++) {
AvdInfo info = avds[index];
if (index > 0) {
mSdkLog.printf("---------\n");
}
mSdkLog.printf(" Name: %s\n", info.getName());
mSdkLog.printf(" Path: %s\n", info.getPath());
// get the target of the AVD
IAndroidTarget target = info.getTarget();
if (target.isPlatform()) {
mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(),
target.getApiVersionNumber());
} else {
mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target
.getVendor());
mSdkLog.printf(" Based on Android %s (API level %d)\n", target
.getApiVersionName(), target.getApiVersionNumber());
}
// display some extra values.
Map<String, String> properties = info.getProperties();
String skin = properties.get(AvdManager.AVD_INI_SKIN_NAME);
if (skin != null) {
mSdkLog.printf(" Skin: %s\n", skin);
}
String sdcard = properties.get(AvdManager.AVD_INI_SDCARD_SIZE);
if (sdcard == null) {
sdcard = properties.get(AvdManager.AVD_INI_SDCARD_PATH);
}
if (sdcard != null) {
mSdkLog.printf(" Sdcard: %s\n", sdcard);
}
}
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
}
}
/**
* Creates a new AVD. This is a text based creation with command line prompt.
*/
private void createAvd() {
// find a matching target
int targetId = mSdkCommandLine.getParamTargetId();
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 targets' to get the target ids.",
SdkConstants.androidCmdName());
}
try {
boolean removePrevious = false;
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
String avdName = mSdkCommandLine.getParamName();
AvdInfo info = avdManager.getAvd(avdName);
if (info != null) {
if (mSdkCommandLine.getFlagForce()) {
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;
}
}
String paramFolderPath = mSdkCommandLine.getParamLocationPath();
File avdFolder = null;
if (paramFolderPath != null) {
avdFolder = new File(paramFolderPath);
} else {
avdFolder = new File(AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD,
avdName + AvdManager.AVD_FOLDER_EXTENSION);
}
Map<String, String> hardwareConfig = null;
if (target.isPlatform()) {
try {
hardwareConfig = promptForHardware(target);
} catch (IOException e) {
errorAndExit(e.getMessage());
}
}
AvdInfo oldAvdInfo = null;
if (removePrevious) {
oldAvdInfo = avdManager.getAvd(avdName);
}
// Validate skin is either default (empty) or NNNxMMM or a valid skin name.
String skin = mSdkCommandLine.getParamSkin();
if (skin != null && skin.length() == 0) {
skin = null;
}
if (skin != null) {
boolean valid = false;
// Is it a know skin name for this target?
for (String s : target.getSkins()) {
if (skin.equalsIgnoreCase(s)) {
skin = s; // Make skin names case-insensitive.
valid = true;
break;
}
}
// Is it NNNxMMM?
if (!valid) {
valid = AvdManager.NUMERIC_SKIN_SIZE.matcher(skin).matches();
}
if (!valid) {
displaySkinList(target, "Valid skins: ");
errorAndExit("'%s' is not a valid skin name or size (NNNxMMM)", skin);
return;
}
}
AvdInfo newAvdInfo = avdManager.createAvd(avdFolder,
avdName,
target,
skin,
mSdkCommandLine.getParamSdCard(),
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());
avdManager.recursiveDelete(dir);
dir.delete();
// Remove old avd info from manager
avdManager.removeAvd(oldAvdInfo);
}
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
}
}
/**
* Delete an AVD.
*/
private void deleteAvd() {
try {
String avdName = mSdkCommandLine.getParamName();
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
AvdInfo info = avdManager.getAvd(avdName);
if (info == null) {
errorAndExit("There is no Android Virtual Device named '%s'.", avdName);
return;
}
avdManager.deleteAvd(info, mSdkLog);
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
}
}
/**
* Move an AVD.
*/
private void moveAvd() {
try {
String avdName = mSdkCommandLine.getParamName();
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
AvdInfo info = avdManager.getAvd(avdName);
if (info == null) {
errorAndExit("There is no Android Virtual Device named '%s'.", avdName);
return;
}
// This is a rename if there's a new name for the AVD
String newName = mSdkCommandLine.getParamMoveNewName();
if (newName != null && newName.equals(info.getName())) {
// same name, not actually a rename operation
newName = null;
}
// This is a move (of the data files) if there's a new location path
String paramFolderPath = mSdkCommandLine.getParamLocationPath();
if (paramFolderPath != null) {
// check if paths are the same. Use File methods to account for OS idiosyncrasies.
try {
File f1 = new File(paramFolderPath).getCanonicalFile();
File f2 = new File(info.getPath()).getCanonicalFile();
if (f1.equals(f2)) {
// same canonical path, so not actually a move
paramFolderPath = null;
}
} catch (IOException e) {
// Fail to resolve canonical path. Fail now since a move operation might fail
// later and be harder to recover from.
errorAndExit(e.getMessage());
return;
}
}
if (newName == null && paramFolderPath == null) {
mSdkLog.warning("Move operation aborted: same AVD name, same canonical data path");
return;
}
// If a rename was requested and no data move was requested, check if the original
// data path is our default constructed from the AVD name. In this case we still want
// to rename that folder too.
if (newName != null && paramFolderPath == null) {
// Compute the original data path
File originalFolder = new File(
AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD,
info.getName() + AvdManager.AVD_FOLDER_EXTENSION);
if (originalFolder.equals(info.getPath())) {
try {
// The AVD is using the default data folder path based on the AVD name.
// That folder needs to be adjusted to use the new name.
File f = new File(AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD,
newName + AvdManager.AVD_FOLDER_EXTENSION);
paramFolderPath = f.getCanonicalPath();
} catch (IOException e) {
// Fail to resolve canonical path. Fail now rather than later.
errorAndExit(e.getMessage());
}
}
}
// Check for conflicts
if (newName != null && avdManager.getAvd(newName) != null) {
errorAndExit("There is already an AVD named '%s'.", newName);
return;
}
if (newName != null) {
if (avdManager.getAvd(newName) != null) {
errorAndExit("There is already an AVD named '%s'.", newName);
return;
}
File ini = info.getIniFile();
if (ini.equals(AvdInfo.getIniFile(newName))) {
errorAndExit("The AVD file '%s' is in the way.", ini.getCanonicalPath());
return;
}
}
if (paramFolderPath != null && new File(paramFolderPath).exists()) {
errorAndExit(
"There is already a file or directory at '%s'.\nUse --path to specify a different data folder.",
paramFolderPath);
}
avdManager.moveAvd(info, newName, paramFolderPath, mSdkLog);
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
} catch (IOException e) {
errorAndExit(e.getMessage());
}
}
/**
* Prompts the user to setup a hardware config for a Platform-based AVD.
* @throws IOException
*/
private Map<String, String> promptForHardware(IAndroidTarget createTarget) throws IOException {
byte[] readLineBuffer = new byte[256];
String result;
String defaultAnswer = "no";
mSdkLog.printf("%s is a basic Android platform.\n", createTarget.getName());
mSdkLog.printf("Do you wish to create a custom hardware profile [%s]",
defaultAnswer);
result = readLine(readLineBuffer).trim();
// handle default:
if (result.length() == 0) {
result = defaultAnswer;
}
if (getBooleanReply(result) == false) {
// no custom config.
return null;
}
mSdkLog.printf("\n"); // empty line
// get the list of possible hardware properties
File hardwareDefs = new File (mSdkFolder + File.separator +
SdkConstants.OS_SDK_TOOLS_LIB_FOLDER, SdkConstants.FN_HARDWARE_INI);
List<HardwareProperty> list = HardwareProperties.parseHardwareDefinitions(hardwareDefs,
null /*sdkLog*/);
HashMap<String, String> map = new HashMap<String, String>();
for (int i = 0 ; i < list.size() ;) {
HardwareProperty property = list.get(i);
String description = property.getDescription();
if (description != null) {
mSdkLog.printf("%s: %s\n", property.getAbstract(), description);
} else {
mSdkLog.printf("%s\n", property.getAbstract());
}
String defaultValue = property.getDefault();
if (defaultValue != null) {
mSdkLog.printf("%s [%s]:", property.getName(), defaultValue);
} else {
mSdkLog.printf("%s (%s):", property.getName(), property.getType());
}
result = readLine(readLineBuffer);
if (result.length() == 0) {
if (defaultValue != null) {
mSdkLog.printf("\n"); // empty line
i++; // go to the next property if we have a valid default value.
// if there's no default, we'll redo this property
}
continue;
}
switch (property.getType()) {
case BOOLEAN:
try {
if (getBooleanReply(result)) {
map.put(property.getName(), "yes");
i++; // valid reply, move to next property
} else {
map.put(property.getName(), "no");
i++; // valid reply, move to next property
}
} catch (IOException e) {
// display error, and do not increment i to redo this property
mSdkLog.printf("\n%s\n", e.getMessage());
}
break;
case INTEGER:
try {
Integer.parseInt(result);
map.put(property.getName(), result);
i++; // valid reply, move to next property
} catch (NumberFormatException e) {
// display error, and do not increment i to redo this property
mSdkLog.printf("\n%s\n", e.getMessage());
}
break;
case DISKSIZE:
// TODO check validity
map.put(property.getName(), result);
i++; // valid reply, move to next property
break;
}
mSdkLog.printf("\n"); // empty line
}
return map;
}
/**
* Reads the line from the input stream.
* @param buffer
* @throws IOException
*/
private String readLine(byte[] buffer) throws IOException {
int count = System.in.read(buffer);
// is the input longer than the buffer?
if (count == buffer.length && buffer[count-1] != 10) {
// create a new temp buffer
byte[] tempBuffer = new byte[256];
// and read the rest
String secondHalf = readLine(tempBuffer);
// return a concat of both
return new String(buffer, 0, count) + secondHalf;
}
// ignore end whitespace
while (count > 0 && (buffer[count-1] == '\r' || buffer[count-1] == '\n')) {
count--;
}
return new String(buffer, 0, count);
}
/**
* Returns the boolean value represented by the string.
* @throws IOException If the value is not a boolean string.
*/
private boolean getBooleanReply(String reply) throws IOException {
for (String valid : BOOLEAN_YES_REPLIES) {
if (valid.equalsIgnoreCase(reply)) {
return true;
}
}
for (String valid : BOOLEAN_NO_REPLIES) {
if (valid.equalsIgnoreCase(reply)) {
return false;
}
}
throw new IOException(String.format("%s is not a valid reply", reply));
}
private void errorAndExit(String format, Object...args) {
mSdkLog.error(null, format, args);
System.exit(1);
}
}

View File

@@ -0,0 +1,220 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdkmanager;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkManager;
/**
* Specific command-line flags for the {@link SdkManager}.
*/
public class SdkCommandLine extends CommandLineProcessor {
public final static String VERB_LIST = "list";
public final static String VERB_CREATE = "create";
public final static String VERB_MOVE = "move";
public final static String VERB_DELETE = "delete";
public final static String VERB_UPDATE = "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";
public static final String KEY_RENAME = "rename";
/**
* 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 = {
{ 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_MOVE, OBJECT_AVD,
"Moves or renames an Android Virtual Device." },
{ VERB_DELETE, OBJECT_AVD,
"Deletes an 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);
// --- create avd ---
define(MODE.STRING, false,
VERB_CREATE, OBJECT_AVD, "p", KEY_PATH,
"Location path of the 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, false,
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);
// --- delete avd ---
define(MODE.STRING, true,
VERB_DELETE, OBJECT_AVD, "n", KEY_NAME,
"Name of the AVD to delete", null);
// --- move avd ---
define(MODE.STRING, true,
VERB_MOVE, OBJECT_AVD, "n", KEY_NAME,
"Name of the AVD to move or rename", null);
define(MODE.STRING, false,
VERB_MOVE, OBJECT_AVD, "r", KEY_RENAME,
"New name of the AVD to rename", null);
define(MODE.STRING, false,
VERB_MOVE, OBJECT_AVD, "p", KEY_PATH,
"New location path of the directory where to move the AVD", null);
// --- create project ---
define(MODE.ENUM, true,
VERB_CREATE, OBJECT_PROJECT, "m", KEY_MODE,
"Project mode", new String[] { ARG_ACTIVITY, ARG_ALIAS });
define(MODE.STRING, true,
VERB_CREATE, OBJECT_PROJECT,
"p", KEY_PATH,
"Location path of new project", null);
define(MODE.INTEGER, true,
VERB_CREATE, OBJECT_PROJECT, "t", KEY_TARGET_ID,
"Target id of the new project", null);
define(MODE.STRING, true,
VERB_CREATE, OBJECT_PROJECT, "k", KEY_PACKAGE,
"Package name", null);
define(MODE.STRING, true,
VERB_CREATE, OBJECT_PROJECT, "a", KEY_ACTIVITY,
"Activity name", null);
define(MODE.STRING, false,
VERB_CREATE, OBJECT_PROJECT, "n", KEY_NAME,
"Project name", null);
// --- update project ---
define(MODE.STRING, true,
VERB_UPDATE, OBJECT_PROJECT,
"p", KEY_PATH,
"Location path of the project", null);
define(MODE.INTEGER, true,
VERB_UPDATE, OBJECT_PROJECT,
"t", KEY_TARGET_ID,
"Target id to set for the project", -1);
define(MODE.STRING, false,
VERB_UPDATE, OBJECT_PROJECT,
"n", KEY_NAME,
"Project name", null);
}
// -- some helpers for generic action flags
/** Helper to retrieve the --path value. */
public String getParamLocationPath() {
return ((String) getValue(null, null, KEY_PATH));
}
/** Helper to retrieve the --target id value. */
public int getParamTargetId() {
return ((Integer) getValue(null, null, KEY_TARGET_ID)).intValue();
}
/** Helper to retrieve the --name value. */
public String getParamName() {
return ((String) getValue(null, null, KEY_NAME));
}
/** Helper to retrieve the --skin value. */
public String getParamSkin() {
return ((String) getValue(null, null, KEY_SKIN));
}
/** Helper to retrieve the --sdcard value. */
public String getParamSdCard() {
return ((String) getValue(null, null, KEY_SDCARD));
}
/** Helper to retrieve the --force flag. */
public boolean getFlagForce() {
return ((Boolean) getValue(null, null, KEY_FORCE)).booleanValue();
}
// -- some helpers for avd action flags
/** Helper to retrieve the --rename value for a move verb. */
public String getParamMoveNewName() {
return ((String) getValue(VERB_MOVE, null, KEY_RENAME));
}
// -- some helpers for project action flags
/** Helper to retrieve the --package value. */
public String getParamProjectPackage() {
return ((String) getValue(null, OBJECT_PROJECT, KEY_PACKAGE));
}
/** Helper to retrieve the --activity for the new project action. */
public String getParamProjectActivity() {
return ((String) getValue(null, OBJECT_PROJECT, KEY_ACTIVITY));
}
}

View File

@@ -0,0 +1,186 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdkmanager;
import com.android.sdklib.ISdkLog;
import junit.framework.TestCase;
public class CommandLineProcessorTest extends TestCase {
private MockStdLogger mLog;
/**
* A mock version of the {@link CommandLineProcessor} class that does not
* exits and captures its stdout/stderr output.
*/
public static class MockCommandLineProcessor extends CommandLineProcessor {
private boolean mExitCalled;
private boolean mHelpCalled;
private String mStdOut = "";
private String mStdErr = "";
public MockCommandLineProcessor(ISdkLog logger) {
super(logger,
new String[][] {
{ "verb1", "action1", "Some action" },
{ "verb1", "action2", "Another action" },
});
define(MODE.STRING, false /*mandatory*/,
"verb1", "action1", "1", "first", "non-mandatory flag", null);
define(MODE.STRING, true /*mandatory*/,
"verb1", "action1", "2", "second", "mandatory flag", null);
}
@Override
public void printHelpAndExitForAction(String verb, String directObject,
String errorFormat, Object... args) {
mHelpCalled = true;
super.printHelpAndExitForAction(verb, directObject, errorFormat, args);
}
@Override
protected void exit() {
mExitCalled = true;
}
@Override
protected void stdout(String format, Object... args) {
String s = String.format(format, args);
mStdOut += s + "\n";
// don't call super to avoid printing stuff
}
@Override
protected void stderr(String format, Object... args) {
String s = String.format(format, args);
mStdErr += s + "\n";
// don't call super to avoid printing stuff
}
public boolean wasHelpCalled() {
return mHelpCalled;
}
public boolean wasExitCalled() {
return mExitCalled;
}
public String getStdOut() {
return mStdOut;
}
public String getStdErr() {
return mStdErr;
}
}
@Override
protected void setUp() throws Exception {
mLog = new MockStdLogger();
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
public final void testPrintHelpAndExit() {
MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
assertFalse(c.wasExitCalled());
assertFalse(c.wasHelpCalled());
assertTrue(c.getStdOut().equals(""));
assertTrue(c.getStdErr().equals(""));
c.printHelpAndExit(null);
assertTrue(c.getStdOut().indexOf("-v") != -1);
assertTrue(c.getStdOut().indexOf("--verbose") != -1);
assertTrue(c.getStdErr().equals(""));
assertTrue(c.wasExitCalled());
c = new MockCommandLineProcessor(mLog);
assertFalse(c.wasExitCalled());
assertTrue(c.getStdOut().equals(""));
assertTrue(c.getStdErr().indexOf("Missing parameter") == -1);
c.printHelpAndExit("Missing %s", "parameter");
assertTrue(c.wasExitCalled());
assertFalse(c.getStdOut().equals(""));
assertTrue(c.getStdErr().indexOf("Missing parameter") != -1);
}
public final void testVerbose() {
MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
assertFalse(c.isVerbose());
c.parseArgs(new String[] { "-v" });
assertTrue(c.isVerbose());
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
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 verb name.") != -1);
}
public final void testHelp() {
MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "-h" });
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
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 verb name.") == -1);
}
public final void testMandatory() {
MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "verb1", "action1", "-1", "value1", "-2", "value2" });
assertFalse(c.wasExitCalled());
assertFalse(c.wasHelpCalled());
assertEquals("", c.getStdErr());
assertEquals("value1", c.getValue("verb1", "action1", "first"));
assertEquals("value2", c.getValue("verb1", "action1", "second"));
c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "verb1", "action1", "-2", "value2" });
assertFalse(c.wasExitCalled());
assertFalse(c.wasHelpCalled());
assertEquals("", c.getStdErr());
assertEquals(null, c.getValue("verb1", "action1", "first"));
assertEquals("value2", c.getValue("verb1", "action1", "second"));
c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "verb1", "action1" });
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
assertTrue(c.getStdErr().indexOf("must be defined") != -1);
assertEquals(null, c.getValue("verb1", "action1", "first"));
assertEquals(null, c.getValue("verb1", "action1", "second"));
}
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Eclipse Public License, Version 1.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.eclipse.org/org/documents/epl-v10.php
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdkmanager;
import com.android.sdklib.ISdkLog;
/**
*
*/
public class MockStdLogger implements ISdkLog {
public void error(Throwable t, String errorFormat, Object... args) {
if (errorFormat != null) {
System.err.printf("Error: " + errorFormat, args);
if (!errorFormat.endsWith("\n")) {
System.err.printf("\n");
}
}
if (t != null) {
System.err.printf("Error: %s\n", t.getMessage());
}
}
public void warning(String warningFormat, Object... args) {
System.out.printf("Warning: " + warningFormat, args);
if (!warningFormat.endsWith("\n")) {
System.out.printf("\n");
}
}
public void printf(String msgFormat, Object... args) {
System.out.printf(msgFormat, args);
}
}

View File

@@ -0,0 +1,141 @@
/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.sdkmanager;
import com.android.sdklib.ISdkLog;
import junit.framework.TestCase;
public class SdkCommandLineTest extends TestCase {
private MockStdLogger mLog;
/**
* A mock version of the {@link SdkCommandLine} class that does not
* exits and discards its stdout/stderr output.
*/
public static class MockSdkCommandLine extends SdkCommandLine {
private boolean mExitCalled;
private boolean mHelpCalled;
public MockSdkCommandLine(ISdkLog logger) {
super(logger);
}
@Override
public void printHelpAndExitForAction(String verb, String directObject,
String errorFormat, Object... args) {
mHelpCalled = true;
super.printHelpAndExitForAction(verb, directObject, errorFormat, args);
}
@Override
protected void exit() {
mExitCalled = true;
}
@Override
protected void stdout(String format, Object... args) {
// discard
}
@Override
protected void stderr(String format, Object... args) {
// discard
}
public boolean wasExitCalled() {
return mExitCalled;
}
public boolean wasHelpCalled() {
return mHelpCalled;
}
}
@Override
protected void setUp() throws Exception {
mLog = new MockStdLogger();
super.setUp();
}
@Override
protected void tearDown() throws Exception {
super.tearDown();
}
/** Test list */
public final void testList_Avd_Verbose() {
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
c.parseArgs(new String[] { "-v", "list", "avd" });
assertFalse(c.wasHelpCalled());
assertFalse(c.wasExitCalled());
assertEquals("list", c.getVerb());
assertEquals("avd", c.getDirectObject());
assertTrue(c.isVerbose());
}
public final void testList_Target() {
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
c.parseArgs(new String[] { "list", "target" });
assertFalse(c.wasHelpCalled());
assertFalse(c.wasExitCalled());
assertEquals("list", c.getVerb());
assertEquals("target", c.getDirectObject());
assertFalse(c.isVerbose());
}
public final void testList_None() {
MockSdkCommandLine c = new MockSdkCommandLine(mLog);
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(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());
}
}