Merge pull request #52 from maginatics/make-commands-discoverable

List valid commands on CommandNotFoundException
diff --git a/assembly/src/main/filtered-resources/unix/bin/jclouds b/assembly/src/main/filtered-resources/unix/bin/jclouds
index 75cdfb0..e598ae6 100644
--- a/assembly/src/main/filtered-resources/unix/bin/jclouds
+++ b/assembly/src/main/filtered-resources/unix/bin/jclouds
@@ -34,23 +34,6 @@
         die "KARAF_HOME is not valid: $KARAF_HOME"
     fi
 }
-
-validateArguments() {
-    if [ "x$CATEGORY" == "x" -o "x$ACTION" == "x" ]; then
-        echo "Usage:jclouds {category} {action} {options/arguments}."
-        echo ""
-        echo "Categories: node, group, image, location, hardware"
-        echo "Actions: list, create, destroy, runscript"
-        echo ""
-        echo "Options:"
-        echo -e "--provider:\t\t The id of the provider."
-        echo -e "--api:\t\t\t The id of the api."
-        echo -e "--endpoint:\t\t The endpoint."
-        echo -e "--identity:\t\t The identity."
-        echo -e "--credential:\t\t The credential."
-        exit -1
-    fi
-}
 warn() {
     echo "${PROGNAME}: $*"
 }
@@ -66,7 +49,6 @@
 }
 
 main() {
-    validateArguments
     locateHome
     run "$@"
 }
diff --git a/assembly/src/main/filtered-resources/win/bin/jclouds.bat b/assembly/src/main/filtered-resources/win/bin/jclouds.bat
index 73e99ac..3c2fcc8 100644
--- a/assembly/src/main/filtered-resources/win/bin/jclouds.bat
+++ b/assembly/src/main/filtered-resources/win/bin/jclouds.bat
@@ -84,36 +84,6 @@
     set "KARAF_DATA=%KARAF_BASE%\data"
 )
 
-if [%1]==[] (
-        echo "Usage:jclouds {category} {action} {options/arguments}."
-        echo ""
-        echo "Categories: node, group, image, location hardware"
-        echo "Actions: list, create, destroy, runscript"
-        echo ""
-        echo "Options:"
-        echo "--provider:       The id of the provider."
-        echo "--api:            The id of the api."
-        echo "--endpoint:       The endpoint."
-        echo "--identity:       The identity."
-        echo "--credential:     The credential."
-        goto END
-)
-
-if [%2]==[] (
-        echo "Usage:jclouds {category} {action} {options/arguments}."
-        echo ""
-        echo "Categories: node, group, image, location hardware"
-        echo "Actions: list, create, destroy, runscript"
-        echo ""
-        echo "Options:"
-        echo "--provider:       The id of the provider."
-        echo "--api:            The id of the api."
-        echo "--endpoint:       The endpoint."
-        echo "--identity:       The identity."
-        echo "--credential:     The credential."
-        goto END
-)
-
 set CATEGORY=%1
 set ACTION=%2
 
diff --git a/runner/src/main/java/org/jclouds/cli/runner/Main.java b/runner/src/main/java/org/jclouds/cli/runner/Main.java
index 4dffaac..f5d092d 100644
--- a/runner/src/main/java/org/jclouds/cli/runner/Main.java
+++ b/runner/src/main/java/org/jclouds/cli/runner/Main.java
@@ -29,6 +29,7 @@
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Enumeration;
 import java.util.LinkedList;
 import java.util.List;
@@ -179,6 +180,45 @@
     private void run(final CommandProcessorImpl commandProcessor, String[] args, final InputStream in, final PrintStream out, final PrintStream err) throws Exception {
 
         if (args.length > 0) {
+            // Commands have the form: jclouds:category-action.
+            List<String> commands = new ArrayList<String>(
+                commandProcessor.getCommands());
+            Collections.sort(commands);
+            if (!commands.contains(args[0])) {
+                final String INDENT = "    ";
+                StringBuffer sb = new StringBuffer(
+                    "Usage: jclouds {category} {action} {options/arguments}");
+
+                // list commands
+                sb.append("\n\nValid commands:");
+                for (String command : commands) {
+                    if (command.startsWith("jclouds:")) {
+                        command = command.substring("jclouds:".length());
+                        int index = command.indexOf('-');
+                        String category = command.substring(0, index);
+                        String action = command.substring(index + 1);
+                        sb.append('\n').append(INDENT).append(category)
+                            .append(' ').append(action);
+                        // TODO: expose command descriptions
+                    }
+                }
+
+                // list options
+                sb.append("\n\nOptions:")
+                    .append('\n').append(INDENT)
+                    .append("--provider:   The id of the provider")
+                    .append('\n').append(INDENT)
+                    .append("--api:        The id of the api")
+                    .append('\n').append(INDENT)
+                    .append("--endpoint:   The endpoint")
+                    .append('\n').append(INDENT)
+                    .append("--identity:   The identity")
+                    .append('\n').append(INDENT)
+                    .append("--credential: The credential");
+
+                throw new CommandNotFoundException(sb.toString());
+            }
+
             StringBuilder sb = new StringBuilder();
             for (int i = 0; i < args.length; i++) {
                 if (i > 0) {