diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java b/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java index 4a3c16c97..d4da21bee 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java @@ -85,13 +85,13 @@ public class CommandLineProcessor { mLog = logger; mActions = actions; - define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "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_VERB, NO_VERB_OBJECT, "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_VERB, NO_VERB_OBJECT, "h", KEY_HELP, + define(Mode.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "h", KEY_HELP, "This help.", false); } @@ -507,7 +507,7 @@ public class CommandLineProcessor { } } else if (arg.getDefaultValue() != null) { Object v = arg.getDefaultValue(); - if (arg.getMode() != MODE.BOOLEAN || v.equals(Boolean.TRUE)) { + if (arg.getMode() != Mode.BOOLEAN || v.equals(Boolean.TRUE)) { value = v.toString(); } } @@ -537,7 +537,7 @@ public class CommandLineProcessor { * 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 { + static enum Mode { /** Argument value is a Boolean. Default value is a Boolean. */ BOOLEAN { @Override @@ -628,7 +628,7 @@ public class CommandLineProcessor { * 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 + * 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 { @@ -645,7 +645,7 @@ public class CommandLineProcessor { /** A default value. Can be null. */ private final Object mDefaultValue; /** The argument mode (type + process method). Never null. */ - private final MODE mMode; + 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. */ @@ -656,15 +656,15 @@ public class CommandLineProcessor { /** * Creates a new argument flag description. * - * @param mode The {@link MODE} for the argument. + * @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}. + * @param defaultValue The default value (or values), which depends on the selected {@link Mode}. */ - public Arg(MODE mode, + public Arg(Mode mode, boolean mandatory, String verb, String directObject, @@ -734,7 +734,7 @@ public class CommandLineProcessor { } /** Returns the argument mode (type + process method). Never null. */ - public MODE getMode() { + public Mode getMode() { return mMode; } @@ -752,21 +752,21 @@ public class CommandLineProcessor { /** * Internal helper to define a new argument for a give action. * - * @param mode The {@link MODE} for the argument. + * @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}. + * @param defaultValue The default value (or values), which depends on the selected {@link Mode}. */ - protected void define(MODE 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 + assert(mandatory || mode == Mode.BOOLEAN); // a boolean mode cannot be mandatory if (directObject == null) { directObject = NO_VERB_OBJECT; diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java index 1836d330b..b5988ffc3 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -337,6 +337,33 @@ class Main { creator.updateProject(projectDir, target, mSdkCommandLine.getParamName()); + + boolean doSubProjects = mSdkCommandLine.getParamSubProject(); + boolean couldHaveDone = false; + + // If there are any sub-folders with a manifest, try to update them as projects + // too. This will take care of updating any underlying test project even if the + // user changed the folder name. + File[] files = new File(projectDir).listFiles(); + if (files != null) { + for (File dir : files) { + if (dir.isDirectory() && + new File(dir, SdkConstants.FN_ANDROID_MANIFEST_XML).isFile()) { + if (doSubProjects) { + creator.updateProject(dir.getPath(), + target, + mSdkCommandLine.getParamName()); + } else { + couldHaveDone = true; + } + } + } + } + + if (couldHaveDone) { + mSdkLog.printf("It seems that there are sub-projects. If you want to update them\nplease use the --%1$s parameter.", + SdkCommandLine.KEY_SUBPROJECTS); + } } /** diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java b/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java index 2ff0c5326..c48a3860b 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java @@ -38,20 +38,21 @@ public class SdkCommandLine extends CommandLineProcessor { public static final String OBJECT_PROJECT = "project"; public static final String OBJECT_ADB = "adb"; - public static final String ARG_ALIAS = "alias"; - public static final String ARG_ACTIVITY = "activity"; + 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"; + 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"; + public static final String KEY_SUBPROJECTS = "subprojects"; /** * Action definitions for SdkManager command line. @@ -97,46 +98,46 @@ public class SdkCommandLine extends CommandLineProcessor { // --- create avd --- - define(MODE.STRING, false, + 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, + define(Mode.STRING, true, VERB_CREATE, OBJECT_AVD, "n", KEY_NAME, "Name of the new AVD", null); - define(MODE.INTEGER, true, + define(Mode.INTEGER, true, VERB_CREATE, OBJECT_AVD, "t", KEY_TARGET_ID, "Target id of the new AVD", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_CREATE, OBJECT_AVD, "s", KEY_SKIN, "Skin of the new AVD", null); - define(MODE.STRING, false, + 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, + define(Mode.BOOLEAN, false, VERB_CREATE, OBJECT_AVD, "f", KEY_FORCE, "Force creation (override an existing AVD)", false); // --- delete avd --- - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_DELETE, OBJECT_AVD, "n", KEY_NAME, "Name of the AVD to delete", null); // --- move avd --- - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_MOVE, OBJECT_AVD, "n", KEY_NAME, "Name of the AVD to move or rename", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_MOVE, OBJECT_AVD, "r", KEY_RENAME, "New name of the AVD to rename", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_MOVE, OBJECT_AVD, "p", KEY_PATH, "New location path of the directory where to move the AVD", null); // --- update avd --- - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_UPDATE, OBJECT_AVD, "n", KEY_NAME, "Name of the AVD to update", null); @@ -145,41 +146,45 @@ public class SdkCommandLine extends CommandLineProcessor { /* Disabled for ADT 0.9 / Cupcake SDK 1.5_r1 release. [bug #1795718]. This currently does not work, the alias build rules need to be fixed. - define(MODE.ENUM, true, + define(Mode.ENUM, true, VERB_CREATE, OBJECT_PROJECT, "m", KEY_MODE, "Project mode", new String[] { ARG_ACTIVITY, ARG_ALIAS }); */ - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_CREATE, OBJECT_PROJECT, "p", KEY_PATH, "Location path of new project", null); - define(MODE.INTEGER, true, + define(Mode.INTEGER, true, VERB_CREATE, OBJECT_PROJECT, "t", KEY_TARGET_ID, "Target id of the new project", null); - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_CREATE, OBJECT_PROJECT, "k", KEY_PACKAGE, "Package name", null); - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_CREATE, OBJECT_PROJECT, "a", KEY_ACTIVITY, "Activity name", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_CREATE, OBJECT_PROJECT, "n", KEY_NAME, "Project name", null); // --- update project --- - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_UPDATE, OBJECT_PROJECT, "p", KEY_PATH, "Location path of the project", null); - define(MODE.INTEGER, true, + define(Mode.INTEGER, true, VERB_UPDATE, OBJECT_PROJECT, "t", KEY_TARGET_ID, "Target id to set for the project", -1); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_UPDATE, OBJECT_PROJECT, "n", KEY_NAME, "Project name", null); + define(Mode.BOOLEAN, false, + VERB_UPDATE, OBJECT_PROJECT, + "s", KEY_SUBPROJECTS, + "Also update any projects in sub-folders, such as test projects.", false); } @Override @@ -234,8 +239,13 @@ public class SdkCommandLine extends CommandLineProcessor { return ((String) getValue(null, OBJECT_PROJECT, KEY_PACKAGE)); } - /** Helper to retrieve the --activity for the new project action. */ + /** Helper to retrieve the --activity for any project action. */ public String getParamProjectActivity() { return ((String) getValue(null, OBJECT_PROJECT, KEY_ACTIVITY)); } + + /** Helper to retrieve the --subprojects for any project action. */ + public boolean getParamSubProject() { + return ((Boolean) getValue(null, OBJECT_PROJECT, KEY_SUBPROJECTS)).booleanValue(); + } } diff --git a/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java b/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java index 918591b53..a213652d7 100644 --- a/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java +++ b/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java @@ -41,9 +41,9 @@ public class CommandLineProcessorTest extends TestCase { { "verb1", "action1", "Some action" }, { "verb1", "action2", "Another action" }, }); - define(MODE.STRING, false /*mandatory*/, + define(Mode.STRING, false /*mandatory*/, "verb1", "action1", "1", "first", "non-mandatory flag", null); - define(MODE.STRING, true /*mandatory*/, + define(Mode.STRING, true /*mandatory*/, "verb1", "action1", "2", "second", "mandatory flag", null); } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java index a33eaaa18..29dac833c 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java @@ -50,7 +50,7 @@ import javax.xml.xpath.XPathFactory; * @hide */ public class ProjectCreator { - + /** Package path substitution string used in template files, i.e. "PACKAGE_PATH" */ private final static String PH_JAVA_FOLDER = "PACKAGE_PATH"; /** Package name substitution string used in template files, i.e. "PACKAGE" */ @@ -59,9 +59,9 @@ public class ProjectCreator { private final static String PH_ACTIVITY_NAME = "ACTIVITY_NAME"; /** Project name substitution string used in template files, i.e. "PROJECT_NAME". */ private final static String PH_PROJECT_NAME = "PROJECT_NAME"; - + private final static String FOLDER_TESTS = "tests"; - + /** Pattern for characters accepted in a project name. Since this will be used as a * directory name, we're being a bit conservative on purpose: dot and space cannot be used. */ public static final Pattern RE_PROJECT_NAME = Pattern.compile("[a-zA-Z0-9_]+"); @@ -69,7 +69,7 @@ public class ProjectCreator { public final static String CHARS_PROJECT_NAME = "a-z A-Z 0-9 _"; /** Pattern for characters accepted in a package name. A package is list of Java identifier - * separated by a dot. We need to have at least one dot (e.g. a two-level package name). + * separated by a dot. We need to have at least one dot (e.g. a two-level package name). * A Java identifier cannot start by a digit. */ public static final Pattern RE_PACKAGE_NAME = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)+"); @@ -82,7 +82,7 @@ public class ProjectCreator { /** List of valid characters for a project name. Used for display purposes. */ public final static String CHARS_ACTIVITY_NAME = "a-z A-Z 0-9 _"; - + public enum OutputLevel { /** Silent mode. Project creation will only display errors. */ SILENT, @@ -100,11 +100,11 @@ public class ProjectCreator { private static class ProjectCreateException extends Exception { /** default UID. This will not be serialized anyway. */ private static final long serialVersionUID = 1L; - + ProjectCreateException(String message) { super(message); } - + ProjectCreateException(Throwable t, String format, Object... args) { super(format != null ? String.format(format, args) : format, t); } @@ -113,23 +113,23 @@ public class ProjectCreator { super(String.format(format, args)); } } - + private final OutputLevel mLevel; private final ISdkLog mLog; private final String mSdkFolder; - + public ProjectCreator(String sdkFolder, OutputLevel level, ISdkLog log) { mSdkFolder = sdkFolder; mLevel = level; mLog = log; } - + /** * Creates a new project. *
* The caller should have already checked and sanitized the parameters. - * + * * @param folderPath the folder of the project to create. * @param projectName the name of the project. The name must match the * {@link #RE_PROJECT_NAME} regex. @@ -137,14 +137,16 @@ public class ProjectCreator { * {@link #RE_PACKAGE_NAME} regex. * @param activityName the activity of the project as it will appear in the manifest. Can be * null if no activity should be created. The name must match the - * {@link #RE_ACTIVITY_NAME} regex. + * {@link #RE_ACTIVITY_NAME} regex. * @param target the project target. - * @param isTestProject whether the project to create is a test project. + * @param isTestProject whether the project to create is a test project. Caller should + * initially call this will false. The method will call itself back to create + * a test project as needed. */ public void createProject(String folderPath, String projectName, String packageName, String activityName, IAndroidTarget target, boolean isTestProject) { - + // create project folder if it does not exist File projectFolder = new File(folderPath); if (!projectFolder.exists()) { @@ -156,7 +158,7 @@ public class ProjectCreator { } catch (Exception e) { t = e; } - + if (created) { println("Created project directory: %1$s", projectFolder); } else { @@ -176,7 +178,7 @@ public class ProjectCreator { } catch (Exception e1) { e = e1; } - + if (e != null || error != null) { mLog.error(e, error, projectFolder, SdkConstants.androidCmdName()); } @@ -196,7 +198,7 @@ public class ProjectCreator { PropertyType.DEFAULT); defaultProperties.setAndroidTarget(target); defaultProperties.save(); - + // create an empty build.properties ProjectProperties buildProperties = ProjectProperties.create(folderPath, PropertyType.BUILD); @@ -225,16 +227,16 @@ public class ProjectCreator { keywords.put(PH_PROJECT_NAME, projectName); } else { if (activityName != null) { - // Use the activity as project name + // Use the activity as project name keywords.put(PH_PROJECT_NAME, activityName); } else { // We need a project name. Just pick up the basename of the project // directory. projectName = projectFolder.getName(); - keywords.put(PH_PROJECT_NAME, projectName); + keywords.put(PH_PROJECT_NAME, projectName); } } - + // create the source folder and the java package folders. String srcFolderPath = SdkConstants.FD_SOURCES + File.separator + packagePath; File sourceFolder = createDirs(projectFolder, srcFolderPath); @@ -270,13 +272,13 @@ public class ProjectCreator { /* Make AndroidManifest.xml and build.xml files */ String manifestTemplate = "AndroidManifest.template"; if (isTestProject) { - manifestTemplate = "AndroidManifest.tests.template"; + manifestTemplate = "AndroidManifest.tests.template"; } installTemplate(manifestTemplate, new File(projectFolder, SdkConstants.FN_ANDROID_MANIFEST_XML), keywords, target); - + installTemplate("build.template", new File(projectFolder, SdkConstants.FN_BUILD_XML), keywords); @@ -286,7 +288,7 @@ public class ProjectCreator { // create the test project folder. createDirs(projectFolder, FOLDER_TESTS); File testProjectFolder = new File(folderPath, FOLDER_TESTS); - + createProject(testProjectFolder.getAbsolutePath(), projectName, packageName, activityName, target, true /*isTestProject*/); } @@ -296,7 +298,7 @@ public class ProjectCreator { mLog.error(e, null); } } - + /** * Updates an existing project. * @@ -308,12 +310,12 @@ public class ProjectCreator { *