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
next prev 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).