git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [JGIT PATCH 0/9] List commonly used (or recognized) commands
@ 2008-07-25 19:45 Shawn O. Pearce
  2008-07-25 19:45 ` [JGIT PATCH 1/9] Switch jgit.pgm to J2SE-1.5 execution environment Shawn O. Pearce
  2008-07-25 19:52 ` [JGIT PATCH 0/9] List commonly used (or recognized) commands Shawn O. Pearce
  0 siblings, 2 replies; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:45 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

This series adds support to jgit to list commonly used subcommands
if the user just executes `jgit` with no subcommand requested:

  $ jgit
  jgit --git-dir GIT_DIR --help (-h) --show-stack-trace command [ARG ...]
  
  The most commonly used commands are:
   fetch  Update remote refs from another repository
   log    View commit history
   push   Update remote repository from local refs
   tag    Create a tag

Commands inside of the pgm.debug package are automatically given
the debug- prefix, allowing debug-show-commands to be used to show
the command table.

Commands must be listed in the META-INF/services/org...TextBuiltin
file in order to be considered for execution.  This means that we
must add (or remove) command class names from the listing each time
we introduce or remove a command line subcommand.

One advantage to this structure is additional commands can defined
in other packages, and are available so long as the classes are
reachable through the CLASSPATH.  Since jgit.sh hardcodes the
CLASSPATH to only itself this is not fully supported yet, but does
open the door for users to extend jgit's command line support.


Shawn O. Pearce (9):
  Switch jgit.pgm to J2SE-1.5 execution environment
  Remove unnecessary duplicate if (help) test inside TextBuiltin
  Create an optional documentation annotation for TextBuiltin
  Create a lightweight registration wrapper for TextBuiltin
  Create a catalog of CommandRefs for lookup and enumeration
  Document some common commands with the new Command annotation
  Include commonly used commands in main help output
  Refactor SubcommandHandler to use CommandCatalog instead of
    reflection
  Add debug-show-commands to display the command table

 org.spearce.jgit.pgm/.classpath                    |    2 +-
 .../services/org.spearce.jgit.pgm.TextBuiltin      |   14 ++
 .../src/org/spearce/jgit/pgm/Command.java          |   72 ++++++++
 .../src/org/spearce/jgit/pgm/CommandCatalog.java   |  188 ++++++++++++++++++++
 .../src/org/spearce/jgit/pgm/CommandRef.java       |  158 ++++++++++++++++
 .../src/org/spearce/jgit/pgm/Fetch.java            |    1 +
 .../src/org/spearce/jgit/pgm/Log.java              |    1 +
 .../src/org/spearce/jgit/pgm/Main.java             |   18 ++
 .../src/org/spearce/jgit/pgm/Push.java             |    1 +
 .../src/org/spearce/jgit/pgm/Tag.java              |    1 +
 .../src/org/spearce/jgit/pgm/TextBuiltin.java      |   17 +--
 .../org/spearce/jgit/pgm/debug/ShowCommands.java   |   78 ++++++++
 .../spearce/jgit/pgm/opt/SubcommandHandler.java    |   65 +------
 13 files changed, 543 insertions(+), 73 deletions(-)
 create mode 100644 org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Command.java
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/debug/ShowCommands.java

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [JGIT PATCH 1/9] Switch jgit.pgm to J2SE-1.5 execution environment
  2008-07-25 19:45 [JGIT PATCH 0/9] List commonly used (or recognized) commands Shawn O. Pearce
@ 2008-07-25 19:45 ` Shawn O. Pearce
  2008-07-25 19:46   ` [JGIT PATCH 2/9] Remove unnecessary duplicate if (help) test inside TextBuiltin Shawn O. Pearce
  2008-07-25 19:52 ` [JGIT PATCH 0/9] List commonly used (or recognized) commands Shawn O. Pearce
  1 sibling, 1 reply; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:45 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

We have been keeping the jgit library itself on Java 5, and the
jgit command line tools should also be on Java 5 and avoid using
any Java 6 APIs (for now).  Not all of our target platforms have
a Java 6 virtual machine available out of the box.

Since the pgm project broke out of the library project our code
already conforms to Java 5 APIs, so we just have to switch the
build path settings.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 org.spearce.jgit.pgm/.classpath |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/org.spearce.jgit.pgm/.classpath b/org.spearce.jgit.pgm/.classpath
index cc861d2..50dd6d3 100644
--- a/org.spearce.jgit.pgm/.classpath
+++ b/org.spearce.jgit.pgm/.classpath
@@ -2,7 +2,7 @@
 <classpath>
 	<classpathentry kind="src" path="src"/>
 	<classpathentry exported="true" kind="lib" path="lib/args4j-2.0.9.jar" sourcepath="lib/args4j-2.0.9.zip"/>
-	<classpathentry exported="true" kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
 	<classpathentry combineaccessrules="false" exported="true" kind="src" path="/org.spearce.jgit"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [JGIT PATCH 2/9] Remove unnecessary duplicate if (help) test inside TextBuiltin
  2008-07-25 19:45 ` [JGIT PATCH 1/9] Switch jgit.pgm to J2SE-1.5 execution environment Shawn O. Pearce
@ 2008-07-25 19:46   ` Shawn O. Pearce
  2008-07-25 19:46     ` [JGIT PATCH 3/9] Create an optional documentation annotation for TextBuiltin Shawn O. Pearce
  0 siblings, 1 reply; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:46 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

This was caused by a copy-and-paste error as I borrowed the
global argument handling code in Main to help start writing
the command specific argument handling in TextBuiltin.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../src/org/spearce/jgit/pgm/TextBuiltin.java      |    9 ++++-----
 1 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
index d02a0a2..e2eef84 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
@@ -145,11 +145,10 @@ public abstract class TextBuiltin {
 			clp.printSingleLineUsage(System.err);
 			System.err.println();
 
-			if (help) {
-				System.err.println();
-				clp.printUsage(System.err);
-				System.err.println();
-			}
+			System.err.println();
+			clp.printUsage(System.err);
+			System.err.println();
+
 			System.exit(1);
 		}
 
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [JGIT PATCH 3/9] Create an optional documentation annotation for TextBuiltin
  2008-07-25 19:46   ` [JGIT PATCH 2/9] Remove unnecessary duplicate if (help) test inside TextBuiltin Shawn O. Pearce
@ 2008-07-25 19:46     ` Shawn O. Pearce
  2008-07-25 19:46       ` [JGIT PATCH 4/9] Create a lightweight registration wrapper " Shawn O. Pearce
  0 siblings, 1 reply; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:46 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

This new annotation can be used for automatic command list creation,
or additional help generation by the default help generator.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../src/org/spearce/jgit/pgm/Command.java          |   72 ++++++++++++++++++++
 1 files changed, 72 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Command.java

diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Command.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Command.java
new file mode 100644
index 0000000..40be1f7
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Command.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.pgm;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to document a {@link TextBuiltin}.
+ * <p>
+ * This is an optional annotation for TextBuiltin subclasses and it carries
+ * documentation forward into the runtime system describing what the command is
+ * and why users may want to invoke it.
+ */
+@Retention(RUNTIME)
+@Target( { TYPE })
+public @interface Command {
+	/**
+	 * @return name the command is invoked as from the command line. If the
+	 *         (default) empty string is supplied the name will be generated
+	 *         from the class name.
+	 */
+	public String name() default "";
+
+	/**
+	 * @return one line description of the command's feature set.
+	 */
+	public String usage() default "";
+
+	/**
+	 * @return true if this command is considered to be commonly used.
+	 */
+	public boolean common() default false;
+}
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [JGIT PATCH 4/9] Create a lightweight registration wrapper for TextBuiltin
  2008-07-25 19:46     ` [JGIT PATCH 3/9] Create an optional documentation annotation for TextBuiltin Shawn O. Pearce
@ 2008-07-25 19:46       ` Shawn O. Pearce
  2008-07-25 19:46         ` [JGIT PATCH 5/9] Create a catalog of CommandRefs for lookup and enumeration Shawn O. Pearce
  0 siblings, 1 reply; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:46 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

Automatic command list generation requires knowing what commands
are available to this runtime, and what name those commands can be
called as by the end-user.  This lightweight wrappers carries the
data from the Command annotation, possibly filling in the name of
the command by generating it from the implementation class name.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../src/org/spearce/jgit/pgm/CommandRef.java       |  151 ++++++++++++++++++++
 1 files changed, 151 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java

diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java
new file mode 100644
index 0000000..40400a7
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.pgm;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+
+/**
+ * Description of a command (a {@link TextBuiltin} subclass.
+ * <p>
+ * These descriptions are lightweight compared to creating a command instance
+ * and are therefore suitable for catalogs of "known" commands without linking
+ * the command's implementation and creating a dummy instance of the command.
+ */
+public class CommandRef {
+	private final Class<? extends TextBuiltin> impl;
+
+	private final String name;
+
+	private String usage;
+
+	boolean common;
+
+	CommandRef(final Class<? extends TextBuiltin> clazz) {
+		this(clazz, guessName(clazz));
+	}
+
+	CommandRef(final Class<? extends TextBuiltin> clazz, final Command cmd) {
+		this(clazz, cmd.name().length() > 0 ? cmd.name() : guessName(clazz));
+		usage = cmd.usage();
+		common = cmd.common();
+	}
+
+	private CommandRef(final Class<? extends TextBuiltin> clazz, final String cn) {
+		impl = clazz;
+		name = cn;
+		usage = "";
+	}
+
+	private static String guessName(final Class<? extends TextBuiltin> clazz) {
+		final StringBuilder s = new StringBuilder();
+		if (clazz.getName().startsWith("org.spearce.jgit.pgm.debug."))
+			s.append("debug-");
+
+		boolean lastWasDash = true;
+		for (final char c : clazz.getSimpleName().toCharArray()) {
+			if (Character.isUpperCase(c)) {
+				if (!lastWasDash)
+					s.append('-');
+				lastWasDash = !lastWasDash;
+				s.append(Character.toLowerCase(c));
+			} else {
+				s.append(c);
+			}
+		}
+		return s.toString();
+	}
+
+	/**
+	 * @return name the command is invoked as from the command line.
+	 */
+	public String getName() {
+		return name;
+	}
+
+	/**
+	 * @return one line description of the command's feature set.
+	 */
+	public String getUsage() {
+		return usage;
+	}
+
+	/**
+	 * @return true if this command is considered to be commonly used.
+	 */
+	public boolean isCommon() {
+		return common;
+	}
+
+	/**
+	 * @return name of the Java class which implements this command.
+	 */
+	public String getImplementationClassName() {
+		return impl.getName();
+	}
+
+	/**
+	 * @return a new instance of the command implementation.
+	 */
+	public TextBuiltin create() {
+		final Constructor<? extends TextBuiltin> c;
+		try {
+			c = impl.getDeclaredConstructor();
+		} catch (SecurityException e) {
+			throw new RuntimeException("Cannot create command " + getName(), e);
+		} catch (NoSuchMethodException e) {
+			throw new RuntimeException("Cannot create command " + getName(), e);
+		}
+		c.setAccessible(true);
+
+		final TextBuiltin r;
+		try {
+			r = c.newInstance();
+		} catch (InstantiationException e) {
+			throw new RuntimeException("Cannot create command " + getName(), e);
+		} catch (IllegalAccessException e) {
+			throw new RuntimeException("Cannot create command " + getName(), e);
+		} catch (IllegalArgumentException e) {
+			throw new RuntimeException("Cannot create command " + getName(), e);
+		} catch (InvocationTargetException e) {
+			throw new RuntimeException("Cannot create command " + getName(), e);
+		}
+		r.setCommandName(getName());
+		return r;
+	}
+}
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [JGIT PATCH 5/9] Create a catalog of CommandRefs for lookup and enumeration
  2008-07-25 19:46       ` [JGIT PATCH 4/9] Create a lightweight registration wrapper " Shawn O. Pearce
@ 2008-07-25 19:46         ` Shawn O. Pearce
  2008-07-25 19:46           ` [JGIT PATCH 6/9] Document some common commands with the new Command annotation Shawn O. Pearce
  2008-07-25 20:02           ` [JGIT PATCH 5/9 v2] Create a catalog of CommandRefs for lookup and enumeration Shawn O. Pearce
  0 siblings, 2 replies; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:46 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

The command catalog supports enumerating commands registered through
a services list, converting each entry into a CommandRef and making
that available to callers on demand.  The CommandRef can be later used
to create a command instance or just to obtain documentation about it.

All current commands are listed in the service registration.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../services/org.spearce.jgit.pgm.TextBuiltin      |   12 ++
 .../src/org/spearce/jgit/pgm/CommandCatalog.java   |  188 ++++++++++++++++++++
 2 files changed, 200 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java

diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
new file mode 100644
index 0000000..69ef046
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -0,0 +1,12 @@
+org.spearce.jgit.pgm.DiffTree
+org.spearce.jgit.pgm.Fetch
+org.spearce.jgit.pgm.Glog
+org.spearce.jgit.pgm.IndexPack
+org.spearce.jgit.pgm.Log
+org.spearce.jgit.pgm.LsRemote
+org.spearce.jgit.pgm.LsTree
+org.spearce.jgit.pgm.MergeBase
+org.spearce.jgit.pgm.Push
+org.spearce.jgit.pgm.RevList
+org.spearce.jgit.pgm.ShowRev
+org.spearce.jgit.pgm.Tag
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java
new file mode 100644
index 0000000..13c585c
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.pgm;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * List of all commands known by jgit's command line tools.
+ * <p>
+ * Commands are implementations of {@link TextBuiltin}, with an optional
+ * {@link Command} class annotation to insert additional documentation or
+ * override the default command name (which is guessed from the class name).
+ * <p>
+ * Commands may be registered by adding them to a services file in the same JAR
+ * (or classes directory) as the command implementation. The service file name
+ * is <code>META-INF/services/org.spearce.jgit.pgm.TextBuiltin</code> and it
+ * contains one concrete implementation class name per line.
+ * <p>
+ * Command registration is identical to Java 6's services, however the catalog
+ * uses a lightweight wrapper to delay creating a command instance as much as
+ * possible. This avoids initializing the AWT or SWT GUI toolkits even if the
+ * command's constructor might require them.
+ */
+public class CommandCatalog {
+	private static final CommandCatalog INSTANCE = new CommandCatalog();
+
+	/**
+	 * Locate a single command by its user friendly name.
+	 *
+	 * @param name
+	 *            name of the command. Typically in dash-lower-case-form, which
+	 *            was derived from the DashLowerCaseForm class name.
+	 * @return the command instance; null if no command exists by that name.
+	 */
+	public static CommandRef get(final String name) {
+		return INSTANCE.commands.get(name);
+	}
+
+	/**
+	 * @return all known commands, sorted by command name.
+	 */
+	public static CommandRef[] all() {
+		return toSortedArray(INSTANCE.commands.values());
+	}
+
+	/**
+	 * @return all common commands, sorted by command name.
+	 */
+	public static CommandRef[] common() {
+		final ArrayList<CommandRef> common = new ArrayList<CommandRef>();
+		for (final CommandRef c : INSTANCE.commands.values())
+			if (c.isCommon())
+				common.add(c);
+		return toSortedArray(common);
+	}
+
+	private static CommandRef[] toSortedArray(final Collection<CommandRef> c) {
+		final CommandRef[] r = c.toArray(new CommandRef[c.size()]);
+		Arrays.sort(r, new Comparator<CommandRef>() {
+			public int compare(final CommandRef o1, final CommandRef o2) {
+				return o1.getName().compareTo(o2.getName());
+			}
+		});
+		return r;
+	}
+
+	private final ClassLoader ldr;
+
+	private final Map<String, CommandRef> commands;
+
+	private CommandCatalog() {
+		ldr = Thread.currentThread().getContextClassLoader();
+		commands = new HashMap<String, CommandRef>();
+
+		final Enumeration<URL> catalogs = catalogs();
+		while (catalogs.hasMoreElements())
+			scan(catalogs.nextElement());
+	}
+
+	private Enumeration<URL> catalogs() {
+		try {
+			final String pfx = "META-INF/services/";
+			return ldr.getResources(pfx + TextBuiltin.class.getName());
+		} catch (IOException err) {
+			return new Vector<URL>().elements();
+		}
+	}
+
+	private void scan(final URL cUrl) {
+		final BufferedReader cIn;
+		try {
+			final InputStream in = cUrl.openStream();
+			cIn = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+		} catch (IOException err) {
+			// If we cannot read from the service list, go to the next.
+			//
+			return;
+		}
+
+		try {
+			String line;
+			while ((line = cIn.readLine()) != null) {
+				if (line.length() > 0 && !line.startsWith("#"))
+					load(line);
+			}
+		} catch (IOException err) {
+			// If we failed during a read, ignore the error.
+			//
+		} finally {
+			try {
+				cIn.close();
+			} catch (IOException e) {
+				// Ignore the close error; we are only reading.
+			}
+		}
+	}
+
+	private void load(final String cn) {
+		final Class<? extends TextBuiltin> clazz;
+		try {
+			clazz = Class.forName(cn, false, ldr).asSubclass(TextBuiltin.class);
+		} catch (ClassNotFoundException notBuiltin) {
+			// Doesn't exist, even though the service entry is present.
+			//
+			return;
+		} catch (ClassCastException notBuiltin) {
+			// Isn't really a builtin, even though its listed as such.
+			//
+			return;
+		}
+
+		final CommandRef cr;
+		final Command a = clazz.getAnnotation(Command.class);
+		if (a != null)
+			cr = new CommandRef(clazz, a);
+		else
+			cr = new CommandRef(clazz);
+
+		commands.put(cr.getName(), cr);
+	}
+}
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [JGIT PATCH 6/9] Document some common commands with the new Command annotation
  2008-07-25 19:46         ` [JGIT PATCH 5/9] Create a catalog of CommandRefs for lookup and enumeration Shawn O. Pearce
@ 2008-07-25 19:46           ` Shawn O. Pearce
  2008-07-25 19:46             ` [JGIT PATCH 7/9] Include commonly used commands in main help output Shawn O. Pearce
  2008-07-25 20:02           ` [JGIT PATCH 5/9 v2] Create a catalog of CommandRefs for lookup and enumeration Shawn O. Pearce
  1 sibling, 1 reply; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:46 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

This way they are known to be common at runtime, by looking at
the annotation associated with the class instance.  Right now
we do not use these annotations but they will be useful soon.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../src/org/spearce/jgit/pgm/Fetch.java            |    1 +
 .../src/org/spearce/jgit/pgm/Log.java              |    1 +
 .../src/org/spearce/jgit/pgm/Push.java             |    1 +
 .../src/org/spearce/jgit/pgm/Tag.java              |    1 +
 4 files changed, 4 insertions(+), 0 deletions(-)

diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
index 194f669..dcad972 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java
@@ -47,6 +47,7 @@ import org.spearce.jgit.transport.RefSpec;
 import org.spearce.jgit.transport.TrackingRefUpdate;
 import org.spearce.jgit.transport.Transport;
 
+@Command(common = true, usage = "Update remote refs from another repository")
 class Fetch extends TextBuiltin {
 	@Argument(index = 0, metaVar = "uri-ish")
 	private String remote = "origin";
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Log.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Log.java
index 780a63b..e16387b 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Log.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Log.java
@@ -45,6 +45,7 @@ import java.util.TimeZone;
 import org.spearce.jgit.lib.PersonIdent;
 import org.spearce.jgit.revwalk.RevCommit;
 
+@Command(common = true, usage = "View commit history")
 class Log extends RevWalkTextBuiltin {
 	private final TimeZone myTZ = TimeZone.getDefault();
 
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
index df6c664..6b35ab8 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java
@@ -51,6 +51,7 @@ import org.spearce.jgit.transport.RemoteRefUpdate;
 import org.spearce.jgit.transport.Transport;
 import org.spearce.jgit.transport.RemoteRefUpdate.Status;
 
+@Command(common = true, usage = "Update remote repository from local refs")
 class Push extends TextBuiltin {
 	@Argument(index = 0, metaVar = "uri-ish")
 	private String remote = "origin";
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Tag.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Tag.java
index a7bd037..6c73552 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Tag.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Tag.java
@@ -45,6 +45,7 @@ import org.spearce.jgit.lib.ObjectId;
 import org.spearce.jgit.lib.ObjectLoader;
 import org.spearce.jgit.lib.PersonIdent;
 
+@Command(common = true, usage = "Create a tag")
 class Tag extends TextBuiltin {
 	@Option(name = "-f", usage = "force replacing an existing tag")
 	private boolean force;
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [JGIT PATCH 7/9] Include commonly used commands in main help output
  2008-07-25 19:46           ` [JGIT PATCH 6/9] Document some common commands with the new Command annotation Shawn O. Pearce
@ 2008-07-25 19:46             ` Shawn O. Pearce
  2008-07-25 19:46               ` [JGIT PATCH 8/9] Refactor SubcommandHandler to use CommandCatalog instead of reflection Shawn O. Pearce
  0 siblings, 1 reply; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:46 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

If the main loop did not get a subcommand during parsing of the
command line then we should offer up a list of commonly used
commands and their one-line usage summary, to help the user make
a decision about which command they should try to execute.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../src/org/spearce/jgit/pgm/Main.java             |   18 ++++++++++++++++++
 1 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Main.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Main.java
index c069989..c8bade8 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Main.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Main.java
@@ -121,6 +121,24 @@ public class Main {
 				System.err.println();
 				clp.printUsage(System.err);
 				System.err.println();
+			} else if (subcommand == null) {
+				System.err.println();
+				System.err.println("The most commonly used commands are:");
+				final CommandRef[] common = CommandCatalog.common();
+				int width = 0;
+				for (final CommandRef c : common)
+					width = Math.max(width, c.getName().length());
+				width += 2;
+
+				for (final CommandRef c : common) {
+					System.err.print(' ');
+					System.err.print(c.getName());
+					for (int i = c.getName().length(); i < width; i++)
+						System.err.print(' ');
+					System.err.print(c.getUsage());
+					System.err.println();
+				}
+				System.err.println();
 			}
 			System.exit(1);
 		}
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [JGIT PATCH 8/9] Refactor SubcommandHandler to use CommandCatalog instead of reflection
  2008-07-25 19:46             ` [JGIT PATCH 7/9] Include commonly used commands in main help output Shawn O. Pearce
@ 2008-07-25 19:46               ` Shawn O. Pearce
  2008-07-25 19:46                 ` [JGIT PATCH 9/9] Add debug-show-commands to display the command table Shawn O. Pearce
  0 siblings, 1 reply; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:46 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

Now that all commands are known to the CommandCatalog we do not need
to perform direct reflection inside of the SubcommandHandler.  Instead
we can reuse the lookup table already known to the CommandCatalog.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../src/org/spearce/jgit/pgm/TextBuiltin.java      |    8 +--
 .../spearce/jgit/pgm/opt/SubcommandHandler.java    |   65 ++------------------
 2 files changed, 6 insertions(+), 67 deletions(-)

diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
index e2eef84..5c066cb 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/TextBuiltin.java
@@ -83,13 +83,7 @@ public abstract class TextBuiltin {
 	/** RevWalk used during command line parsing, if it was required. */
 	protected RevWalk argWalk;
 
-	/**
-	 * Set the name this command can be invoked as on the command line.
-	 *
-	 * @param name
-	 *            the name of the command.
-	 */
-	public void setCommandName(final String name) {
+	final void setCommandName(final String name) {
 		commandName = name;
 	}
 
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/SubcommandHandler.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/SubcommandHandler.java
index c7e1bf6..86004bb 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/SubcommandHandler.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/opt/SubcommandHandler.java
@@ -37,8 +37,6 @@
 
 package org.spearce.jgit.pgm.opt;
 
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
 import java.text.MessageFormat;
 
 import org.kohsuke.args4j.CmdLineException;
@@ -47,7 +45,8 @@ import org.kohsuke.args4j.OptionDef;
 import org.kohsuke.args4j.spi.OptionHandler;
 import org.kohsuke.args4j.spi.Parameters;
 import org.kohsuke.args4j.spi.Setter;
-import org.spearce.jgit.pgm.Main;
+import org.spearce.jgit.pgm.CommandCatalog;
+import org.spearce.jgit.pgm.CommandRef;
 import org.spearce.jgit.pgm.TextBuiltin;
 
 /**
@@ -57,12 +56,6 @@ import org.spearce.jgit.pgm.TextBuiltin;
  * we can execute at runtime with the remaining arguments of the parser.
  */
 public class SubcommandHandler extends OptionHandler<TextBuiltin> {
-	private static String mypackage() {
-		final String p = Main.class.getName();
-		final int dot = p.lastIndexOf('.');
-		return p.substring(0, dot);
-	}
-
 	/**
 	 * Create a new handler for the command name.
 	 * <p>
@@ -80,65 +73,17 @@ public class SubcommandHandler extends OptionHandler<TextBuiltin> {
 	@Override
 	public int parseArguments(final Parameters params) throws CmdLineException {
 		final String name = params.getParameter(0);
-		final StringBuilder s = new StringBuilder();
-		s.append(mypackage());
-		s.append('.');
-		boolean upnext = true;
-		for (int i = 0; i < name.length(); i++) {
-			final char c = name.charAt(i);
-			if (c == '-') {
-				upnext = true;
-				continue;
-			}
-			if (upnext)
-				s.append(Character.toUpperCase(c));
-			else
-				s.append(c);
-			upnext = false;
-		}
-
-		final Class<?> clazz;
-		try {
-			clazz = Class.forName(s.toString());
-		} catch (ClassNotFoundException e) {
-			throw new CmdLineException(MessageFormat.format(
-					"{0} is not a jgit command", name));
-		}
-
-		if (!TextBuiltin.class.isAssignableFrom(clazz))
+		final CommandRef cr = CommandCatalog.get(name);
+		if (cr == null)
 			throw new CmdLineException(MessageFormat.format(
 					"{0} is not a jgit command", name));
 
-		final Constructor<?> cons;
-		try {
-			cons = clazz.getDeclaredConstructor();
-		} catch (SecurityException e) {
-			throw new CmdLineException("Cannot create " + name, e);
-		} catch (NoSuchMethodException e) {
-			throw new CmdLineException("Cannot create " + name, e);
-		}
-		cons.setAccessible(true);
-
-		final TextBuiltin cmd;
-		try {
-			cmd = (TextBuiltin) cons.newInstance();
-		} catch (InstantiationException e) {
-			throw new CmdLineException("Cannot create " + name, e);
-		} catch (IllegalAccessException e) {
-			throw new CmdLineException("Cannot create " + name, e);
-		} catch (InvocationTargetException e) {
-			throw new CmdLineException("Cannot create " + name, e);
-		}
-
-		cmd.setCommandName(name);
-		setter.addValue(cmd);
-
 		// Force option parsing to stop. Everything after us should
 		// be arguments known only to this command and must not be
 		// recognized by the current parser.
 		//
 		owner.stopOptionParsing();
-
+		setter.addValue(cr.create());
 		return 1;
 	}
 
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [JGIT PATCH 9/9] Add debug-show-commands to display the command table
  2008-07-25 19:46               ` [JGIT PATCH 8/9] Refactor SubcommandHandler to use CommandCatalog instead of reflection Shawn O. Pearce
@ 2008-07-25 19:46                 ` Shawn O. Pearce
  0 siblings, 0 replies; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:46 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

This can be useful to debug the command catalog.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---
 .../services/org.spearce.jgit.pgm.TextBuiltin      |    2 +
 .../src/org/spearce/jgit/pgm/CommandRef.java       |    7 ++
 .../org/spearce/jgit/pgm/debug/ShowCommands.java   |   78 ++++++++++++++++++++
 3 files changed, 87 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/debug/ShowCommands.java

diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
index 69ef046..1ff5a30 100644
--- a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -10,3 +10,5 @@ org.spearce.jgit.pgm.Push
 org.spearce.jgit.pgm.RevList
 org.spearce.jgit.pgm.ShowRev
 org.spearce.jgit.pgm.Tag
+
+org.spearce.jgit.pgm.debug.ShowCommands
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java
index 40400a7..8bf784b 100644
--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandRef.java
@@ -120,6 +120,13 @@ public class CommandRef {
 	}
 
 	/**
+	 * @return loader for {@link #getImplementationClassName()}.
+	 */
+	public ClassLoader getImplementationClassLoader() {
+		return impl.getClassLoader();
+	}
+
+	/**
 	 * @return a new instance of the command implementation.
 	 */
 	public TextBuiltin create() {
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/debug/ShowCommands.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/debug/ShowCommands.java
new file mode 100644
index 0000000..64ecf7f
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/debug/ShowCommands.java
@@ -0,0 +1,78 @@
+package org.spearce.jgit.pgm.debug;
+
+import java.net.URL;
+
+import org.kohsuke.args4j.Option;
+import org.spearce.jgit.pgm.Command;
+import org.spearce.jgit.pgm.CommandCatalog;
+import org.spearce.jgit.pgm.CommandRef;
+import org.spearce.jgit.pgm.TextBuiltin;
+
+@Command(usage = "Display a list of all registered jgit commands")
+class ShowCommands extends TextBuiltin {
+	@Option(name = "--pretty", usage = "alter the detail shown")
+	private Format pretty = Format.USAGE;
+
+	@Override
+	protected void run() throws Exception {
+		final CommandRef[] list = CommandCatalog.all();
+
+		int width = 0;
+		for (final CommandRef c : list)
+			width = Math.max(width, c.getName().length());
+		width += 2;
+
+		for (final CommandRef c : list) {
+			System.err.print(c.isCommon() ? '*' : ' ');
+			System.err.print(' ');
+
+			System.err.print(c.getName());
+			for (int i = c.getName().length(); i < width; i++)
+				System.err.print(' ');
+
+			pretty.print(c);
+			System.err.println();
+		}
+		System.err.println();
+	}
+
+	static enum Format {
+		/** */
+		USAGE {
+			void print(final CommandRef c) {
+				System.err.print(c.getUsage());
+			}
+		},
+
+		/** */
+		CLASSES {
+			void print(final CommandRef c) {
+				System.err.print(c.getImplementationClassName());
+			}
+		},
+
+		/** */
+		URLS {
+			void print(final CommandRef c) {
+				final ClassLoader ldr = c.getImplementationClassLoader();
+
+				String cn = c.getImplementationClassName();
+				cn = cn.replace('.', '/') + ".class";
+
+				final URL url = ldr.getResource(cn);
+				if (url == null) {
+					System.err.print("!! NOT FOUND !!");
+					return;
+				}
+
+				String rn = url.toExternalForm();
+				if (rn.endsWith(cn))
+					rn = rn.substring(0, rn.length() - cn.length());
+
+				System.err.print(rn);
+			}
+		};
+
+		abstract void print(CommandRef c);
+	}
+}
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

* Re: [JGIT PATCH 0/9] List commonly used (or recognized) commands
  2008-07-25 19:45 [JGIT PATCH 0/9] List commonly used (or recognized) commands Shawn O. Pearce
  2008-07-25 19:45 ` [JGIT PATCH 1/9] Switch jgit.pgm to J2SE-1.5 execution environment Shawn O. Pearce
@ 2008-07-25 19:52 ` Shawn O. Pearce
  1 sibling, 0 replies; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 19:52 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

"Shawn O. Pearce" <spearce@spearce.org> wrote:
> This series adds support to jgit to list commonly used subcommands
> if the user just executes `jgit` with no subcommand requested:
> 
>   $ jgit
>   jgit --git-dir GIT_DIR --help (-h) --show-stack-trace command [ARG ...]
>   
>   The most commonly used commands are:
>    fetch  Update remote refs from another repository
>    log    View commit history
>    push   Update remote repository from local refs
>    tag    Create a tag

Scratch that.  This series is busted if you install jgit and actually
try to use it.  No subcommands get registered.  I suspect it is due
to the shell script+ZIP file we have in the CLASSPATH confusing the
JRE and making it impossible to read correctly.

-- 
Shawn.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [JGIT PATCH 5/9 v2] Create a catalog of CommandRefs for lookup and enumeration
  2008-07-25 19:46         ` [JGIT PATCH 5/9] Create a catalog of CommandRefs for lookup and enumeration Shawn O. Pearce
  2008-07-25 19:46           ` [JGIT PATCH 6/9] Document some common commands with the new Command annotation Shawn O. Pearce
@ 2008-07-25 20:02           ` Shawn O. Pearce
  1 sibling, 0 replies; 12+ messages in thread
From: Shawn O. Pearce @ 2008-07-25 20:02 UTC (permalink / raw)
  To: Robin Rosenberg; +Cc: git

The command catalog supports enumerating commands registered through
a services list, converting each entry into a CommandRef and making
that available to callers on demand.  The CommandRef can be later used
to create a command instance or just to obtain documentation about it.

All current commands are listed in the service registration.

Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
---

 All that was missing was the services file entry in the built JAR.
 With this replacement for 5/9 the series should be fine.

 make_jgit.sh                                       |    1 +
 .../services/org.spearce.jgit.pgm.TextBuiltin      |   12 ++
 .../src/org/spearce/jgit/pgm/CommandCatalog.java   |  188 ++++++++++++++++++++
 3 files changed, 201 insertions(+), 0 deletions(-)
 create mode 100644 org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
 create mode 100644 org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java

diff --git a/make_jgit.sh b/make_jgit.sh
index bcb2df0..89df80c 100755
--- a/make_jgit.sh
+++ b/make_jgit.sh
@@ -71,6 +71,7 @@ sed s/@@use_self@@/1/ jgit.sh >$O+ &&
 java org.spearce.jgit.pgm.build.JarLinkUtil \
 	`for p in $JARS   ; do printf %s " -include $p"     ;done` \
 	`for p in $PLUGINS; do printf %s " -include $p/bin2";done` \
+	-file META-INF/services/org.spearce.jgit.pgm.TextBuiltin=org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin \
 	-file META-INF/MANIFEST.MF=$T_MF \
 	>>$O+ &&
 chmod 555 $O+ &&
diff --git a/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
new file mode 100644
index 0000000..69ef046
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/META-INF/services/org.spearce.jgit.pgm.TextBuiltin
@@ -0,0 +1,12 @@
+org.spearce.jgit.pgm.DiffTree
+org.spearce.jgit.pgm.Fetch
+org.spearce.jgit.pgm.Glog
+org.spearce.jgit.pgm.IndexPack
+org.spearce.jgit.pgm.Log
+org.spearce.jgit.pgm.LsRemote
+org.spearce.jgit.pgm.LsTree
+org.spearce.jgit.pgm.MergeBase
+org.spearce.jgit.pgm.Push
+org.spearce.jgit.pgm.RevList
+org.spearce.jgit.pgm.ShowRev
+org.spearce.jgit.pgm.Tag
diff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java
new file mode 100644
index 0000000..13c585c
--- /dev/null
+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/CommandCatalog.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Git Development Community nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.spearce.jgit.pgm;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+/**
+ * List of all commands known by jgit's command line tools.
+ * <p>
+ * Commands are implementations of {@link TextBuiltin}, with an optional
+ * {@link Command} class annotation to insert additional documentation or
+ * override the default command name (which is guessed from the class name).
+ * <p>
+ * Commands may be registered by adding them to a services file in the same JAR
+ * (or classes directory) as the command implementation. The service file name
+ * is <code>META-INF/services/org.spearce.jgit.pgm.TextBuiltin</code> and it
+ * contains one concrete implementation class name per line.
+ * <p>
+ * Command registration is identical to Java 6's services, however the catalog
+ * uses a lightweight wrapper to delay creating a command instance as much as
+ * possible. This avoids initializing the AWT or SWT GUI toolkits even if the
+ * command's constructor might require them.
+ */
+public class CommandCatalog {
+	private static final CommandCatalog INSTANCE = new CommandCatalog();
+
+	/**
+	 * Locate a single command by its user friendly name.
+	 *
+	 * @param name
+	 *            name of the command. Typically in dash-lower-case-form, which
+	 *            was derived from the DashLowerCaseForm class name.
+	 * @return the command instance; null if no command exists by that name.
+	 */
+	public static CommandRef get(final String name) {
+		return INSTANCE.commands.get(name);
+	}
+
+	/**
+	 * @return all known commands, sorted by command name.
+	 */
+	public static CommandRef[] all() {
+		return toSortedArray(INSTANCE.commands.values());
+	}
+
+	/**
+	 * @return all common commands, sorted by command name.
+	 */
+	public static CommandRef[] common() {
+		final ArrayList<CommandRef> common = new ArrayList<CommandRef>();
+		for (final CommandRef c : INSTANCE.commands.values())
+			if (c.isCommon())
+				common.add(c);
+		return toSortedArray(common);
+	}
+
+	private static CommandRef[] toSortedArray(final Collection<CommandRef> c) {
+		final CommandRef[] r = c.toArray(new CommandRef[c.size()]);
+		Arrays.sort(r, new Comparator<CommandRef>() {
+			public int compare(final CommandRef o1, final CommandRef o2) {
+				return o1.getName().compareTo(o2.getName());
+			}
+		});
+		return r;
+	}
+
+	private final ClassLoader ldr;
+
+	private final Map<String, CommandRef> commands;
+
+	private CommandCatalog() {
+		ldr = Thread.currentThread().getContextClassLoader();
+		commands = new HashMap<String, CommandRef>();
+
+		final Enumeration<URL> catalogs = catalogs();
+		while (catalogs.hasMoreElements())
+			scan(catalogs.nextElement());
+	}
+
+	private Enumeration<URL> catalogs() {
+		try {
+			final String pfx = "META-INF/services/";
+			return ldr.getResources(pfx + TextBuiltin.class.getName());
+		} catch (IOException err) {
+			return new Vector<URL>().elements();
+		}
+	}
+
+	private void scan(final URL cUrl) {
+		final BufferedReader cIn;
+		try {
+			final InputStream in = cUrl.openStream();
+			cIn = new BufferedReader(new InputStreamReader(in, "UTF-8"));
+		} catch (IOException err) {
+			// If we cannot read from the service list, go to the next.
+			//
+			return;
+		}
+
+		try {
+			String line;
+			while ((line = cIn.readLine()) != null) {
+				if (line.length() > 0 && !line.startsWith("#"))
+					load(line);
+			}
+		} catch (IOException err) {
+			// If we failed during a read, ignore the error.
+			//
+		} finally {
+			try {
+				cIn.close();
+			} catch (IOException e) {
+				// Ignore the close error; we are only reading.
+			}
+		}
+	}
+
+	private void load(final String cn) {
+		final Class<? extends TextBuiltin> clazz;
+		try {
+			clazz = Class.forName(cn, false, ldr).asSubclass(TextBuiltin.class);
+		} catch (ClassNotFoundException notBuiltin) {
+			// Doesn't exist, even though the service entry is present.
+			//
+			return;
+		} catch (ClassCastException notBuiltin) {
+			// Isn't really a builtin, even though its listed as such.
+			//
+			return;
+		}
+
+		final CommandRef cr;
+		final Command a = clazz.getAnnotation(Command.class);
+		if (a != null)
+			cr = new CommandRef(clazz, a);
+		else
+			cr = new CommandRef(clazz);
+
+		commands.put(cr.getName(), cr);
+	}
+}
-- 
1.6.0.rc0.182.gb96c7

^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2008-07-25 20:03 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-07-25 19:45 [JGIT PATCH 0/9] List commonly used (or recognized) commands Shawn O. Pearce
2008-07-25 19:45 ` [JGIT PATCH 1/9] Switch jgit.pgm to J2SE-1.5 execution environment Shawn O. Pearce
2008-07-25 19:46   ` [JGIT PATCH 2/9] Remove unnecessary duplicate if (help) test inside TextBuiltin Shawn O. Pearce
2008-07-25 19:46     ` [JGIT PATCH 3/9] Create an optional documentation annotation for TextBuiltin Shawn O. Pearce
2008-07-25 19:46       ` [JGIT PATCH 4/9] Create a lightweight registration wrapper " Shawn O. Pearce
2008-07-25 19:46         ` [JGIT PATCH 5/9] Create a catalog of CommandRefs for lookup and enumeration Shawn O. Pearce
2008-07-25 19:46           ` [JGIT PATCH 6/9] Document some common commands with the new Command annotation Shawn O. Pearce
2008-07-25 19:46             ` [JGIT PATCH 7/9] Include commonly used commands in main help output Shawn O. Pearce
2008-07-25 19:46               ` [JGIT PATCH 8/9] Refactor SubcommandHandler to use CommandCatalog instead of reflection Shawn O. Pearce
2008-07-25 19:46                 ` [JGIT PATCH 9/9] Add debug-show-commands to display the command table Shawn O. Pearce
2008-07-25 20:02           ` [JGIT PATCH 5/9 v2] Create a catalog of CommandRefs for lookup and enumeration Shawn O. Pearce
2008-07-25 19:52 ` [JGIT PATCH 0/9] List commonly used (or recognized) commands Shawn O. Pearce

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).