git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Shawn O. Pearce" <spearce@spearce.org>
To: Robin Rosenberg <robin.rosenberg@dewire.com>
Cc: git@vger.kernel.org
Subject: [JGIT PATCH 5/9 v2] Create a catalog of CommandRefs for lookup and enumeration
Date: Fri, 25 Jul 2008 15:02:46 -0500	[thread overview]
Message-ID: <20080725200246.GA23117@spearce.org> (raw)
In-Reply-To: <1217015167-4680-6-git-send-email-spearce@spearce.org>

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

  parent reply	other threads:[~2008-07-25 20:03 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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           ` Shawn O. Pearce [this message]
2008-07-25 19:52 ` [JGIT PATCH 0/9] List commonly used (or recognized) commands Shawn O. Pearce

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20080725200246.GA23117@spearce.org \
    --to=spearce@spearce.org \
    --cc=git@vger.kernel.org \
    --cc=robin.rosenberg@dewire.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).