Modified the OBR shell command to hide multiple versions of available
artifacts to cut down on noise. It is still possible to list all versions
by using a new "-v" switch.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@707467 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrCommandImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrCommandImpl.java
index 84f02cd..7822d0c 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrCommandImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrCommandImpl.java
@@ -41,6 +41,7 @@
private static final String JAVADOC_CMD = "javadoc";
private static final String EXTRACT_SWITCH = "-x";
+ private static final String VERBOSE_SWITCH = "-v";
private BundleContext m_context = null;
private RepositoryAdmin m_repoAdmin = null;
@@ -186,77 +187,83 @@
private void list(
String commandLine, String command, PrintStream out, PrintStream err)
- throws IOException
+ throws IOException, InvalidSyntaxException
{
- // Create a stream tokenizer for the command line string,
- // since the syntax for install/start is more sophisticated.
- StringReader sr = new StringReader(commandLine);
- StreamTokenizer tokenizer = new StreamTokenizer(sr);
- tokenizer.resetSyntax();
- tokenizer.quoteChar('\'');
- tokenizer.quoteChar('\"');
- tokenizer.whitespaceChars('\u0000', '\u0020');
- tokenizer.wordChars('A', 'Z');
- tokenizer.wordChars('a', 'z');
- tokenizer.wordChars('0', '9');
- tokenizer.wordChars('\u00A0', '\u00FF');
- tokenizer.wordChars('.', '.');
- tokenizer.wordChars('-', '-');
- tokenizer.wordChars('_', '_');
+ // Parse the command for an option switch and tokens.
+ ParsedCommand pc = parseList(commandLine);
- // Ignore the invoking command name and the OBR command.
- int type = tokenizer.nextToken();
- type = tokenizer.nextToken();
-
- String substr = null;
-
- for (type = tokenizer.nextToken();
- type != StreamTokenizer.TT_EOF;
- type = tokenizer.nextToken())
- {
- // Add a space in between tokens.
- if (substr == null)
- {
- substr = "";
- }
- else
- {
- substr += " ";
- }
-
- if ((type == StreamTokenizer.TT_WORD) ||
- (type == '\'') || (type == '"'))
- {
- substr += tokenizer.sval;
- }
- }
-
+ // Create a filter that will match presentation name or symbolic name.
StringBuffer sb = new StringBuffer();
- if ((substr == null) || (substr.length() == 0))
+ if ((pc.getTokens() == null) || (pc.getTokens().length() == 0))
{
sb.append("(|(presentationname=*)(symbolicname=*))");
}
else
{
sb.append("(|(presentationname=*");
- sb.append(substr);
+ sb.append(pc.getTokens());
sb.append("*)(symbolicname=*");
- sb.append(substr);
+ sb.append(pc.getTokens());
sb.append("*))");
}
+ // Use filter to get matching resources.
Resource[] resources = m_repoAdmin.discoverResources(sb.toString());
+
+ // Group the resources by symbolic name in descending version order,
+ // but keep them in overall sorted order by presentation name.
+ Map revisionMap = new TreeMap(new Comparator() {
+ public int compare(Object o1, Object o2)
+ {
+ Resource r1 = (Resource) o1;
+ Resource r2 = (Resource) o2;
+ // Assume if the symbolic name is equal, then the two are equal,
+ // since we are trying to aggregate by symbolic name.
+ int symCompare = r1.getSymbolicName().compareTo(r2.getSymbolicName());
+ if (symCompare == 0)
+ {
+ return 0;
+ }
+ // Otherwise, compare the presentation name to keep them sorted
+ // by presentation name. If the presentation names are equal, then
+ // use the symbolic name to differentiate.
+ int compare = r1.getPresentationName().compareToIgnoreCase(r2.getPresentationName());
+ if (compare == 0)
+ {
+ return symCompare;
+ }
+ return compare;
+ }
+ });
for (int resIdx = 0; (resources != null) && (resIdx < resources.length); resIdx++)
{
- String name = resources[resIdx].getPresentationName();
- Version version = resources[resIdx].getVersion();
- if (version != null)
+ Resource[] revisions = (Resource[]) revisionMap.get(resources[resIdx]);
+ revisionMap.put(resources[resIdx], addResourceByVersion(revisions, resources[resIdx]));
+ }
+
+ // Print any matching resources.
+ for (Iterator i = revisionMap.entrySet().iterator(); i.hasNext(); )
+ {
+ Map.Entry entry = (Map.Entry) i.next();
+ Resource[] revisions = (Resource[]) entry.getValue();
+ String name = revisions[0].getPresentationName();
+ name = (name == null) ? revisions[0].getSymbolicName() : name;
+ out.print(name + " (");
+ int revIdx = 0;
+ do
{
- out.println(name + " (" + version + ")");
+ if (revIdx > 0)
+ {
+ out.print(", ");
+ }
+ out.print(revisions[revIdx].getVersion());
+ revIdx++;
}
- else
+ while (pc.isVerbose() && (revIdx < revisions.length));
+ if (!pc.isVerbose() && (revisions.length > 1))
{
- out.println(name);
+ out.print(", ...");
}
+ out.println(")");
}
if (resources == null)
@@ -564,6 +571,101 @@
out.println("");
}
+ private ParsedCommand parseList(String commandLine)
+ throws IOException, InvalidSyntaxException
+ {
+ // The command line for list will be something like:
+ // obr list -v token token
+
+ // Create a stream tokenizer for the command line string,
+ StringReader sr = new StringReader(commandLine);
+ StreamTokenizer tokenizer = new StreamTokenizer(sr);
+ tokenizer.resetSyntax();
+ tokenizer.quoteChar('\'');
+ tokenizer.quoteChar('\"');
+ tokenizer.whitespaceChars('\u0000', '\u0020');
+ tokenizer.wordChars('A', 'Z');
+ tokenizer.wordChars('a', 'z');
+ tokenizer.wordChars('0', '9');
+ tokenizer.wordChars('\u00A0', '\u00FF');
+ tokenizer.wordChars('.', '.');
+ tokenizer.wordChars('-', '-');
+ tokenizer.wordChars('_', '_');
+
+ // Ignore the invoking command name and the OBR command.
+ int type = tokenizer.nextToken();
+ type = tokenizer.nextToken();
+
+ int EOF = 1;
+ int SWITCH = 2;
+ int TOKEN = 4;
+
+ // Construct an install record.
+ ParsedCommand pc = new ParsedCommand();
+ String tokens = null;
+
+ // The state machine starts by expecting either a
+ // SWITCH or a DIRECTORY.
+ int expecting = (SWITCH | TOKEN | EOF);
+ while (true)
+ {
+ // Get the next token type.
+ type = tokenizer.nextToken();
+ switch (type)
+ {
+ // EOF received.
+ case StreamTokenizer.TT_EOF:
+ // Error if we weren't expecting EOF.
+ if ((expecting & EOF) == 0)
+ {
+ throw new InvalidSyntaxException(
+ "Expecting more arguments.", null);
+ }
+ // Add current target if there is one.
+ if (tokens != null)
+ {
+ pc.setTokens(tokens);
+ }
+ // Return cleanly.
+ return pc;
+
+ // WORD or quoted WORD received.
+ case StreamTokenizer.TT_WORD:
+ case '\'':
+ case '\"':
+ // If we are expecting a command SWITCH and the token
+ // equals a command SWITCH, then record it.
+ if (((expecting & SWITCH) > 0) && tokenizer.sval.equals(VERBOSE_SWITCH))
+ {
+ pc.setVerbose(true);
+ expecting = (TOKEN | EOF);
+ }
+ // If we are expecting a target, the record it.
+ else if ((expecting & TOKEN) > 0)
+ {
+ // Add a space in between tokens.
+ if (tokens == null)
+ {
+ tokens = "";
+ }
+ else
+ {
+ tokens += " ";
+ }
+ // Append to the current token.
+ tokens += tokenizer.sval;
+ expecting = (EOF | TOKEN);
+ }
+ else
+ {
+ throw new InvalidSyntaxException(
+ "Not expecting '" + tokenizer.sval + "'.", null);
+ }
+ break;
+ }
+ }
+ }
+
private ParsedCommand parseInfo(String commandLine)
throws IOException, InvalidSyntaxException
{
@@ -928,13 +1030,16 @@
else if (command.equals(LIST_CMD))
{
out.println("");
- out.println("obr " + LIST_CMD + " [<string> ...]");
+ out.println("obr " + LIST_CMD
+ + " [" + VERBOSE_SWITCH + "] [<string> ...]");
out.println("");
out.println(
"This command lists bundles available in the bundle repository.\n" +
"If no arguments are specified, then all available bundles are\n" +
"listed, otherwise any arguments are concatenated with spaces\n" +
- "and used as a substring filter on the bundle names.");
+ "and used as a substring filter on the bundle names. By default,\n" +
+ "only the most recent version of each artifact is shown. To list\n" +
+ "all available versions use the \"" + VERBOSE_SWITCH + "\" switch.");
out.println("");
}
else if (command.equals(INFO_CMD))
@@ -1048,7 +1153,7 @@
out.println("obr " + ADDURL_CMD + " [<repository-file-url> ...]");
out.println("obr " + REMOVEURL_CMD + " [<repository-file-url> ...]");
out.println("obr " + LISTURL_CMD);
- out.println("obr " + LIST_CMD + " [<string> ...]");
+ out.println("obr " + LIST_CMD + " [" + VERBOSE_SWITCH + "] [<string> ...]");
out.println("obr " + INFO_CMD
+ " <bundle-name>|<bundle-symbolic-name>|<bundle-id>[;<version>] ...");
out.println("obr " + DEPLOY_CMD
@@ -1064,6 +1169,48 @@
}
}
+ private static Resource[] addResourceByVersion(Resource[] revisions, Resource resource)
+ {
+ // We want to add the resource into the array of revisions
+ // in descending version sorted order (i.e., newest first)
+ Resource[] sorted = null;
+ if (revisions == null)
+ {
+ sorted = new Resource[] { resource };
+ }
+ else
+ {
+ Version version = resource.getVersion();
+ Version middleVersion = null;
+ int top = 0, bottom = revisions.length - 1, middle = 0;
+ while (top <= bottom)
+ {
+ middle = (bottom - top) / 2 + top;
+ middleVersion = revisions[middle].getVersion();
+ // Sort in reverse version order.
+ int cmp = middleVersion.compareTo(version);
+ if (cmp < 0)
+ {
+ bottom = middle - 1;
+ }
+ else
+ {
+ top = middle + 1;
+ }
+ }
+
+ // Ignore duplicates.
+ if ((top >= revisions.length) || (revisions[top] != resource))
+ {
+ sorted = new Resource[revisions.length + 1];
+ System.arraycopy(revisions, 0, sorted, 0, top);
+ System.arraycopy(revisions, top, sorted, top + 1, revisions.length - top);
+ sorted[top] = resource;
+ }
+ }
+ return sorted;
+ }
+
private static class ParsedCommand
{
private static final int NAME_IDX = 0;
@@ -1072,6 +1219,8 @@
private boolean m_isResolve = true;
private boolean m_isCheck = false;
private boolean m_isExtract = false;
+ private boolean m_isVerbose = false;
+ private String m_tokens = null;
private String m_dir = null;
private String[][] m_targets = new String[0][];
@@ -1099,12 +1248,32 @@
{
return m_isExtract;
}
-
+
public void setExtract(boolean b)
{
m_isExtract = b;
}
+ public boolean isVerbose()
+ {
+ return m_isVerbose;
+ }
+
+ public void setVerbose(boolean b)
+ {
+ m_isVerbose = b;
+ }
+
+ public String getTokens()
+ {
+ return m_tokens;
+ }
+
+ public void setTokens(String s)
+ {
+ m_tokens = s;
+ }
+
public String getDirectory()
{
return m_dir;
@@ -1146,4 +1315,4 @@
m_targets = newTargets;
}
}
-}
+}
\ No newline at end of file
diff --git a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
index 607696b..614105b 100644
--- a/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
+++ b/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ResourceImpl.java
@@ -114,7 +114,9 @@
public Version getVersion()
{
- return (Version) m_map.get(VERSION);
+ Version v = (Version) m_map.get(VERSION);
+ v = (v == null) ? Version.emptyVersion : v;
+ return v;
}
public URL getURL()