aboutsummaryrefslogtreecommitdiffstats
path: root/sdkmanager/libs
diff options
context:
space:
mode:
authorRaphael <raphael@google.com>2011-12-20 22:41:55 -0800
committerRaphael <raphael@google.com>2012-01-05 11:54:38 -0800
commit5843f30f42b11cc6a6b4ca25a57bfe04bfe7d517 (patch)
tree50026d1f4970148990d1d218657353423ffed46c /sdkmanager/libs
parent09c6e56052a136ce9f82876d3199a527d9cba678 (diff)
downloadsdk-5843f30f42b11cc6a6b4ca25a57bfe04bfe7d517.zip
sdk-5843f30f42b11cc6a6b4ca25a57bfe04bfe7d517.tar.gz
sdk-5843f30f42b11cc6a6b4ca25a57bfe04bfe7d517.tar.bz2
SDK: Extend CommandLineParser to support string arrays.
This allows the parser to process an input such as: $ cmd verb --arg1 value1 --arg2 value2 value3 value4 or $ cmd verb --arg1 value1 --arg2 value2 -- -value3 --value4 Change-Id: I7ea6c019c2bb4ee5003bdba1f0774f3c062322c2
Diffstat (limited to 'sdkmanager/libs')
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/util/CommandLineParser.java117
-rw-r--r--sdkmanager/libs/sdklib/tests/src/com/android/sdklib/util/CommandLineParserTest.java60
2 files changed, 150 insertions, 27 deletions
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/util/CommandLineParser.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/util/CommandLineParser.java
index ae17813..1fa69b2 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/util/CommandLineParser.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/util/CommandLineParser.java
@@ -18,7 +18,9 @@ package com.android.sdklib.util;
import com.android.sdklib.ISdkLog;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map.Entry;
/**
@@ -326,28 +328,46 @@ public class CommandLineParser {
arg.setInCommandLine(true);
// Process keyword
- String error = null;
+ Object error = null;
if (arg.getMode().needsExtra()) {
- if (++i >= n) {
+ if (i+1 >= n) {
errorMsg = String.format("Missing argument for flag %1$s.", a);
return;
}
- String b = args[i];
- Arg dummyArg = null;
- if (b.startsWith("--")) { //$NON-NLS-1$
- dummyArg = findLongArg(verb, directObject, b.substring(2));
- } else if (b.startsWith("-")) { //$NON-NLS-1$
- dummyArg = findShortArg(verb, directObject, b.substring(1));
- }
- if (dummyArg != null) {
- errorMsg = String.format(
- "Oops, it looks like you didn't provide an argument for '%1$s'.\n'%2$s' was found instead.",
- a, b);
- return;
- }
+ while (i+1 < n) {
+ String b = args[i+1];
+
+ if (arg.getMode() != Mode.STRING_ARRAY) {
+ // We never accept something that looks like a valid argument
+ // unless we see -- first
+ Arg dummyArg = null;
+ if (b.startsWith("--")) { //$NON-NLS-1$
+ dummyArg = findLongArg(verb, directObject, b.substring(2));
+ } else if (b.startsWith("-")) { //$NON-NLS-1$
+ dummyArg = findShortArg(verb, directObject, b.substring(1));
+ }
+ if (dummyArg != null) {
+ errorMsg = String.format(
+ "Oops, it looks like you didn't provide an argument for '%1$s'.\n'%2$s' was found instead.",
+ a, b);
+ return;
+ }
+ }
- error = arg.getMode().process(arg, b);
+ error = arg.getMode().process(arg, b);
+ if (error == Accept.CONTINUE) {
+ i++;
+ } else if (error == Accept.ACCEPT_AND_STOP) {
+ i++;
+ break;
+ } else if (error == Accept.REJECT_AND_STOP) {
+ break;
+ } else if (error instanceof String) {
+ // We stop because of an error
+ break;
+ }
+ }
} else {
error = arg.getMode().process(arg, null);
@@ -361,7 +381,7 @@ public class CommandLineParser {
}
}
- if (error != null) {
+ if (error instanceof String) {
errorMsg = String.format("Invalid usage for flag %1$s: %2$s.", a, error);
return;
}
@@ -610,6 +630,11 @@ public class CommandLineParser {
//----
+ private static enum Accept {
+ CONTINUE,
+ ACCEPT_AND_STOP,
+ REJECT_AND_STOP,
+ }
/**
* The mode of an argument specifies the type of variable it represents,
@@ -623,10 +648,10 @@ public class CommandLineParser {
return false;
}
@Override
- public String process(Arg arg, String extra) {
+ public Object process(Arg arg, String extra) {
// Toggle the current value
arg.setCurrentValue(! ((Boolean) arg.getCurrentValue()).booleanValue());
- return null;
+ return Accept.ACCEPT_AND_STOP;
}
},
@@ -637,7 +662,7 @@ public class CommandLineParser {
return true;
}
@Override
- public String process(Arg arg, String extra) {
+ public Object process(Arg arg, String extra) {
try {
arg.setCurrentValue(Integer.parseInt(extra));
return null;
@@ -655,13 +680,13 @@ public class CommandLineParser {
return true;
}
@Override
- public String process(Arg arg, String extra) {
+ public Object 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;
+ return Accept.ACCEPT_AND_STOP;
}
if (desc.length() != 0) {
@@ -681,9 +706,43 @@ public class CommandLineParser {
return true;
}
@Override
- public String process(Arg arg, String extra) {
+ public Object process(Arg arg, String extra) {
arg.setCurrentValue(extra);
- return null;
+ return Accept.ACCEPT_AND_STOP;
+ }
+ },
+
+ /** Argument value is a String Array. Default value is a null. */
+ STRING_ARRAY {
+ @Override
+ public boolean needsExtra() {
+ return true;
+ }
+ @Override
+ public Object process(Arg arg, String extra) {
+ // For simplification, a string array doesn't accept something that
+ // starts with a dash unless a pure -- was seen before.
+ if (extra != null) {
+ Object v = arg.getCurrentValue();
+ if (v == null) {
+ ArrayList<String> a = new ArrayList<String>();
+ arg.setCurrentValue(a);
+ v = a;
+ }
+ if (v instanceof List<?>) {
+ @SuppressWarnings("unchecked") List<String> a = (List<String>) v;
+
+ if (extra.equals("--") ||
+ !extra.startsWith("-") ||
+ (extra.startsWith("-") && a.contains("--"))) {
+ a.add(extra);
+ return Accept.CONTINUE;
+ } else if (a.isEmpty()) {
+ return "No values provided";
+ }
+ }
+ }
+ return Accept.REJECT_AND_STOP;
}
};
@@ -697,9 +756,15 @@ public class CommandLineParser {
*
* @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.
+ * @return {@link Accept#CONTINUE} if this argument can use multiple values and
+ * wishes to receive more.
+ * Or {@link Accept#ACCEPT_AND_STOP} if this was the last value accepted by the argument.
+ * Or {@link Accept#REJECT_AND_STOP} if this was value was reject and the argument
+ * stops accepting new values with no error.
+ * Or a string in case of error.
+ * Never returns null.
*/
- public abstract String process(Arg arg, String extra);
+ public abstract Object process(Arg arg, String extra);
}
/**
diff --git a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/util/CommandLineParserTest.java b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/util/CommandLineParserTest.java
index 6f0af81..99e0ba4 100644
--- a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/util/CommandLineParserTest.java
+++ b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/util/CommandLineParserTest.java
@@ -18,7 +18,9 @@ package com.android.sdklib.util;
import com.android.sdklib.ISdkLog;
import com.android.sdklib.StdSdkLog;
-import com.android.sdklib.util.CommandLineParser;
+
+import java.util.Arrays;
+import java.util.List;
import junit.framework.TestCase;
@@ -42,11 +44,19 @@ public class CommandLineParserTest extends TestCase {
new String[][] {
{ "verb1", "action1", "Some action" },
{ "verb1", "action2", "Another action" },
+ { "verb2", NO_VERB_OBJECT, "Action with string array" },
});
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);
+
+ define(Mode.STRING, true /*mandatory*/,
+ "verb2", NO_VERB_OBJECT, "1", "first", "1st mandatory flag", null);
+ define(Mode.STRING_ARRAY, true /*mandatory*/,
+ "verb2", NO_VERB_OBJECT, "2", "second", "2nd mandatory flag", null);
+ define(Mode.STRING, true /*mandatory*/,
+ "verb2", NO_VERB_OBJECT, "3", "third", "3rd mandatory flag", null);
}
@Override
@@ -185,4 +195,52 @@ public class CommandLineParserTest extends TestCase {
assertEquals(null, c.getValue("verb1", "action1", "first"));
assertEquals(null, c.getValue("verb1", "action1", "second"));
}
+
+ public void testStringArray() {
+ MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
+
+ c.parseArgs(new String[] { "verb2",
+ "-1", "value1",
+ "-2", "value2_a", "value2_b", "value2_c", "value2_d",
+ "-3", "value3" });
+ assertFalse(c.wasExitCalled());
+ assertFalse(c.wasHelpCalled());
+ assertEquals("", c.getStdErr());
+ assertEquals("value1", c.getValue("verb2", null, "first"));
+ assertTrue(c.getValue("verb2", null, "second") instanceof List<?>);
+ assertEquals("[value2_a, value2_b, value2_c, value2_d]",
+ Arrays.toString(((List<?>) c.getValue("verb2", null, "second")).toArray()));
+ assertEquals("value3", c.getValue("verb2", null, "third"));
+ }
+
+ public void testStringArray_DashDash() {
+ MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
+
+ // Use -- to tell argument -2 it can absorb any argument, including dashed ones.
+ // Logically -2 must be the last argument and -1/-3 must be placed before it.
+ c.parseArgs(new String[] { "verb2",
+ "-1", "value1",
+ "-3", "value3",
+ "-2", "value2_a", "--", "-value2_b", "--value2_c", "value2_d" });
+ assertFalse(c.wasExitCalled());
+ assertFalse(c.wasHelpCalled());
+ assertEquals("", c.getStdErr());
+ assertEquals("value1", c.getValue("verb2", null, "first"));
+ assertTrue(c.getValue("verb2", null, "second") instanceof List<?>);
+ assertEquals("[value2_a, --, -value2_b, --value2_c, value2_d]",
+ Arrays.toString(((List<?>) c.getValue("verb2", null, "second")).toArray()));
+ assertEquals("value3", c.getValue("verb2", null, "third"));
+ }
+
+ public void testStringArray_EmptyStringArray() {
+ MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
+
+ c.parseArgs(new String[] { "verb2",
+ "-1", "value1",
+ "-2",
+ "-3", "value3" });
+ assertTrue(c.wasExitCalled());
+ assertTrue(c.wasHelpCalled());
+ assertEquals("Invalid usage for flag -2: No values provided.", c.getStdErr().trim());
+ }
}