From 463b1954572662a98bdfa11c872f96838697a99a Mon Sep 17 00:00:00 2001
From: matthew_swift <matthew_swift@localhost>
Date: Thu, 14 Jun 2007 09:04:02 +0000
Subject: [PATCH] Add support for grouping sub-commands in the sub-command parser.
---
opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java | 656 ++++++++++++++++++++++++++++++-----------------------------
1 files changed, 336 insertions(+), 320 deletions(-)
diff --git a/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java b/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
index 5a64f79..7b9451f 100644
--- a/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
+++ b/opends/src/server/org/opends/server/util/args/SubCommandArgumentParser.java
@@ -28,25 +28,28 @@
+import static org.opends.server.messages.MessageHandler.*;
+import static org.opends.server.messages.ToolMessages.*;
+import static org.opends.server.messages.UtilityMessages.*;
+import static org.opends.server.tools.ToolConstants.*;
+import static org.opends.server.util.ServerConstants.*;
+import static org.opends.server.util.StaticUtils.*;
+
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
+import java.util.Map;
import java.util.Properties;
import java.util.SortedMap;
import java.util.TreeMap;
import org.opends.server.core.DirectoryServer;
-import static org.opends.server.messages.MessageHandler.*;
-import static org.opends.server.messages.ToolMessages.*;
-import static org.opends.server.messages.UtilityMessages.*;
-import static org.opends.server.util.ServerConstants.*;
-import static org.opends.server.util.StaticUtils.*;
-import static org.opends.server.tools.ToolConstants.*;
-
/**
@@ -65,6 +68,10 @@
// The argument that will be used to trigger the display of usage information.
private Argument usageArgument;
+ // The arguments that will be used to trigger the display of usage
+ // information for groups of sub-commands.
+ private Map<Argument, Collection<SubCommand>> usageGroupArguments;
+
// The set of unnamed trailing arguments that were provided for this parser.
private ArrayList<String> trailingArguments;
@@ -135,17 +142,18 @@
this.toolDescription = toolDescription;
this.longArgumentsCaseSensitive = longArgumentsCaseSensitive;
- trailingArguments = new ArrayList<String>();
- globalArgumentList = new LinkedList<Argument>();
- globalArgumentMap = new HashMap<String,Argument>();
- globalShortIDMap = new HashMap<Character,Argument>();
- globalLongIDMap = new HashMap<String,Argument>();
- subCommands = new TreeMap<String,SubCommand>();
- usageOrVersionDisplayed = false;
- rawArguments = null;
- subCommand = null;
- usageArgument = null;
- usageOutputStream = null;
+ trailingArguments = new ArrayList<String>();
+ globalArgumentList = new LinkedList<Argument>();
+ globalArgumentMap = new HashMap<String,Argument>();
+ globalShortIDMap = new HashMap<Character,Argument>();
+ globalLongIDMap = new HashMap<String,Argument>();
+ usageGroupArguments = new HashMap<Argument, Collection<SubCommand>>();
+ subCommands = new TreeMap<String,SubCommand>();
+ usageOrVersionDisplayed = false;
+ rawArguments = null;
+ subCommand = null;
+ usageArgument = null;
+ usageOutputStream = null;
}
@@ -513,62 +521,67 @@
/**
- * Sets the provided argument as one which will automatically trigger the
- * output of usage information if it is provided on the command line and no
- * further argument validation will be performed. Note that the caller will
- * still need to add this argument to the parser with the
- * <CODE>addArgument</CODE> method, and the argument should not be required
- * and should not take a value. Also, the caller will still need to check
- * for the presence of the usage argument after calling
- * <CODE>parseArguments</CODE> to know that no further processing will be
- * required.
+ * Sets the provided argument as one which will automatically
+ * trigger the output of full usage information if it is provided on
+ * the command line and no further argument validation will be
+ * performed.
+ * <p>
+ * If sub-command groups are defined using the
+ * {@link #setUsageGroupArgument(Argument, Collection)} method, then
+ * this usage argument, when specified, will result in usage
+ * information being displayed which does not include information on
+ * sub-commands.
+ * <p>
+ * Note that the caller will still need to add this argument to the
+ * parser with the {@link #addGlobalArgument(Argument)} method, and
+ * the argument should not be required and should not take a value.
+ * Also, the caller will still need to check for the presence of the
+ * usage argument after calling {@link #parseArguments(String[])} to
+ * know that no further processing will be required.
*
- * @param argument The argument whose presence should automatically
- * trigger the display of usage information.
+ * @param argument
+ * The argument whose presence should automatically trigger
+ * the display of full usage information.
+ * @param outputStream
+ * The output stream to which the usage information should
+ * be written.
*/
- public void setUsageArgument(Argument argument)
- {
- usageArgument = argument;
- usageOutputStream = System.out;
- }
-
-
-
- /**
- * Sets the provided argument as one which will automatically trigger the
- * output of usage information if it is provided on the command line and no
- * further argument validation will be performed. Note that the caller will
- * still need to add this argument to the parser with the
- * <CODE>addArgument</CODE> method, and the argument should not be required
- * and should not take a value. Also, the caller will still need to check
- * for the presence of the usage argument after calling
- * <CODE>parseArguments</CODE> to know that no further processing will be
- * required.
- *
- * @param argument The argument whose presence should automatically
- * trigger the display of usage information.
- * @param outputStream The output stream to which the usage information
- * should be written.
- */
- public void setUsageArgument(Argument argument, OutputStream outputStream)
- {
- usageArgument = argument;
+ public void setUsageArgument(Argument argument, OutputStream outputStream) {
+ usageArgument = argument;
usageOutputStream = outputStream;
+
+ usageGroupArguments.put(argument, Collections.<SubCommand>emptySet());
}
/**
- * Adds the provided subcommand to this argument parser. This is only
- * intended for use by the <CODE>SubCommand</CODE> constructor and does not
- * do any validation of its own to ensure that there are no conflicts with the
- * subcommand or any of its arguments.
+ * Sets the provided argument as one which will automatically
+ * trigger the output of partial usage information if it is provided
+ * on the command line and no further argument validation will be
+ * performed.
+ * <p>
+ * Partial usage information will include a usage synopsis, a
+ * summary of each of the sub-commands listed in the provided
+ * sub-commands collection, and a summary of the global options.
+ * <p>
+ * Note that the caller will still need to add this argument to the
+ * parser with the {@link #addGlobalArgument(Argument)} method, and
+ * the argument should not be required and should not take a value.
+ * Also, the caller will still need to check for the presence of the
+ * usage argument after calling {@link #parseArguments(String[])} to
+ * know that no further processing will be required.
*
- * @param subCommand The subcommand to add to this argument parser.
+ * @param argument
+ * The argument whose presence should automatically trigger
+ * the display of partial usage information.
+ * @param subCommands
+ * The list of sub-commands which should have their usage
+ * displayed.
*/
- void addSubCommand(SubCommand subCommand)
- {
- subCommands.put(toLowerCase(subCommand.getName()), subCommand);
+ public void setUsageGroupArgument(Argument argument,
+ Collection<SubCommand> subCommands) {
+ usageGroupArguments.put(argument, subCommands);
}
@@ -803,14 +816,13 @@
a.setPresent(true);
- // If this is the usage argument, then immediately stop and print
+ // If this is a usage argument, then immediately stop and print
// usage information.
- if ((usageArgument != null) &&
- usageArgument.getName().equals(a.getName()))
+ if (usageGroupArguments.containsKey(a))
{
try
{
- getUsage(usageOutputStream);
+ getUsage(a, usageOutputStream);
} catch (Exception e) {}
return;
@@ -1021,12 +1033,11 @@
// If this is the usage argument, then immediately stop and print
// usage information.
- if ((usageArgument != null) &&
- usageArgument.getName().equals(a.getName()))
+ if (usageGroupArguments.containsKey(a))
{
try
{
- getUsage(usageOutputStream);
+ getUsage(a, usageOutputStream);
} catch (Exception e) {}
return;
@@ -1122,12 +1133,11 @@
// If this is the usage argument, then immediately stop and
// print usage information.
- if ((usageArgument != null) &&
- usageArgument.getName().equals(b.getName()))
+ if (usageGroupArguments.containsKey(b))
{
try
{
- getUsage(usageOutputStream);
+ getUsage(b, usageOutputStream);
} catch (Exception e) {}
return;
@@ -1276,199 +1286,6 @@
/**
- * Appends complete usage information to the provided buffer. It will include
- * information about global options as well as all subcommand-specific
- * options. The output will be somewhat compressed in that it will not
- * include any of the descriptions for any of the arguments.
- *
- * @param buffer The buffer to which the usage information should be
- * appended.
- */
- public void getFullUsage(StringBuilder buffer)
- {
- usageOrVersionDisplayed = true;
- if ((toolDescription != null) && (toolDescription.length() > 0))
- {
- buffer.append(wrapText(toolDescription, 79));
- buffer.append(EOL);
- }
-
- String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
- if ((scriptName == null) || (scriptName.length() == 0))
- {
- buffer.append("Usage: java ");
- buffer.append(mainClassName);
- }
- else
- {
- buffer.append("Usage: ");
- buffer.append(scriptName);
- }
-
- buffer.append(" {subcommand} {options}");
- buffer.append(EOL);
- buffer.append(EOL);
-
- buffer.append("Available subcommands:");
- buffer.append(EOL);
- int indentNb = 0;
- for (SubCommand sc : subCommands.values())
- {
- if (sc.isHidden())
- {
- continue;
- }
- if (sc.getName().length() > indentNb )
- {
- indentNb = sc.getName().length();
- }
- }
- indentNb++;
- for (SubCommand sc : subCommands.values())
- {
- if (sc.isHidden())
- {
- continue;
- }
- buffer.append(" " + sc.getName());
- for (int i=0; i < indentNb - sc.getName().length() ; i++)
- {
- buffer.append(" ");
- }
- buffer.append(sc.getDescription());
- buffer.append(EOL);
- }
- buffer.append(EOL);
-
- buffer.append("The accepted value for global options are:");
- buffer.append(EOL);
-
- // --version is a builtin option
- boolean dashVAccepted = true;
- if (globalShortIDMap.containsKey(OPTION_SHORT_PRODUCT_VERSION))
- {
- dashVAccepted = false;
- }
- else
- {
- for (SubCommand subCmd : subCommands.values())
- {
- if (subCmd.getArgument(OPTION_SHORT_PRODUCT_VERSION) != null)
- {
- dashVAccepted = false;
- break;
- }
- }
- }
- if (dashVAccepted)
- {
- buffer.append("-" + OPTION_SHORT_PRODUCT_VERSION + ", ");
- }
- buffer.append("--" + OPTION_LONG_PRODUCT_VERSION);
- buffer.append(EOL);
- buffer.append(" ");
- buffer.append( getMessage(MSGID_DESCRIPTION_PRODUCT_VERSION));
- buffer.append(EOL);
- Argument helpArgument = null ;
- for (Argument a : globalArgumentList)
- {
- if (a.isHidden())
- {
- continue;
- }
-
- // Help argument should be printed at the end
- if ((usageArgument != null) ? usageArgument.getName().equals(a.getName())
- : false)
- {
- helpArgument = a ;
- continue ;
- }
-
- printArgumentUsage(a, buffer);
- }
- if (helpArgument != null)
- {
- printArgumentUsage(helpArgument, buffer);
- }
- else
- {
- buffer.append("-?");
- }
- buffer.append(EOL);
- }
-
-
-/**
- * Appends argument usage information to the provided buffer.
- *
- * @param a The argument to handle.
- * @param buffer
- * The buffer to which the usage information should be
- * appended.
- */
- private void printArgumentUsage(Argument a, StringBuilder buffer)
- {
- String value;
- if (a.needsValue())
- {
- String valuePlaceholder = a.getValuePlaceholder();
- if (valuePlaceholder == null)
- {
- value = " {value}";
- }
- else
- {
- value = " " + valuePlaceholder;
- }
- }
- else
- {
- value = "";
- }
-
- Character shortIDChar = a.getShortIdentifier();
- boolean isHelpArg = (usageArgument != null) ? usageArgument.getName()
- .equals(a.getName()) : false;
- if (shortIDChar != null)
- {
- if (isHelpArg)
- {
- buffer.append("-?, ");
- }
- buffer.append("-");
- buffer.append(shortIDChar);
-
- String longIDString = a.getLongIdentifier();
- if (longIDString != null)
- {
- buffer.append(", --");
- buffer.append(longIDString);
- }
- buffer.append(value);
- }
- else
- {
- String longIDString = a.getLongIdentifier();
- if (longIDString != null)
- {
- if (isHelpArg)
- {
- buffer.append("-?, ");
- }
- buffer.append("--");
- buffer.append(longIDString);
- buffer.append(value);
- }
- }
-
- buffer.append(EOL);
- indentAndWrap(" ", a.getDescription(), buffer);
- }
-
-
-
- /**
* Appends usage information for the specified subcommand to the provided
* buffer.
*
@@ -1481,19 +1298,13 @@
{
usageOrVersionDisplayed = true;
String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
- String printName;
if ((scriptName == null) || (scriptName.length() == 0))
{
- buffer.append("Usage: java ");
- buffer.append(mainClassName);
- printName = "java " + mainClassName;
+ scriptName = "java " + mainClassName;
}
- else
- {
- buffer.append("Usage: ");
- buffer.append(scriptName);
- printName = scriptName;
- }
+ buffer.append(getMessage(MSGID_ARGPARSER_USAGE));
+ buffer.append(" ");
+ buffer.append(scriptName);
buffer.append(" ");
buffer.append(subCommand.getName());
@@ -1512,7 +1323,7 @@
buffer.append(getMessage(MSGID_GLOBAL_OPTIONS));
buffer.append(EOL);
buffer.append(" ");
- buffer.append(getMessage(MSGID_GLOBAL_OPTIONS_REFERENCE, printName));
+ buffer.append(getMessage(MSGID_GLOBAL_OPTIONS_REFERENCE, scriptName));
buffer.append(EOL);
}
@@ -1539,7 +1350,7 @@
{
int currentLength = buffer.length();
- if (usageArgument.getName().equals(a.getName()))
+ if (a.equals(usageArgument))
{
buffer.append("-?, ");
}
@@ -1584,7 +1395,7 @@
{
if (longID != null)
{
- if (usageArgument.getName().equals(a.getName()))
+ if (a.equals(usageArgument))
{
buffer.append("-?, ");
}
@@ -1671,12 +1482,16 @@
{
StringBuilder buffer = new StringBuilder();
- if (subCommand == null)
- {
- getFullUsage(buffer);
- }
- else
- {
+ if (subCommand == null) {
+ if (usageGroupArguments.size() > 1) {
+ // We have sub-command groups, so don't display any
+ // sub-commands by default.
+ getFullUsage(Collections.<SubCommand> emptySet(), buffer);
+ } else {
+ // No grouping, so display all sub-commands.
+ getFullUsage(subCommands.values(), buffer);
+ }
+ } else {
getSubCommandUsage(buffer, subCommand);
}
@@ -1686,40 +1501,11 @@
/**
- * Writes usage information based on the defined arguments to the provided
- * output stream.
+ * Retrieves the set of unnamed trailing arguments that were
+ * provided on the command line.
*
- * @param outputStream The output stream to which the usage information
- * should be written.
- *
- * @throws IOException If a problem occurs while attempting to write the
- * usage information to the provided output stream.
- */
- public void getUsage(OutputStream outputStream)
- throws IOException
- {
- StringBuilder buffer = new StringBuilder();
-
- if (subCommand == null)
- {
- getFullUsage(buffer);
- }
- else
- {
- getSubCommandUsage(buffer, subCommand);
- }
-
- outputStream.write(getBytes(buffer.toString()));
- }
-
-
-
- /**
- * Retrieves the set of unnamed trailing arguments that were provided on the
- * command line.
- *
- * @return The set of unnamed trailing arguments that were provided on the
- * command line.
+ * @return The set of unnamed trailing arguments that were provided
+ * on the command line.
*/
public ArrayList<String> getTrailingArguments()
{
@@ -1742,12 +1528,242 @@
}
+
+ /**
+ * Adds the provided subcommand to this argument parser. This is only
+ * intended for use by the <CODE>SubCommand</CODE> constructor and does not
+ * do any validation of its own to ensure that there are no conflicts with the
+ * subcommand or any of its arguments.
+ *
+ * @param subCommand The subcommand to add to this argument parser.
+ */
+ void addSubCommand(SubCommand subCommand)
+ {
+ subCommands.put(toLowerCase(subCommand.getName()), subCommand);
+ }
+
+
+
+ // Get usage for a specific usage argument.
+ private void getUsage(Argument a, OutputStream outputStream)
+ throws IOException {
+ StringBuilder buffer = new StringBuilder();
+
+ if (a.equals(usageArgument) && subCommand != null) {
+ getSubCommandUsage(buffer, subCommand);
+ } else if (a.equals(usageArgument) && usageGroupArguments.size() <= 1) {
+ getFullUsage(subCommands.values(), buffer);
+ } else {
+ getFullUsage(usageGroupArguments.get(a), buffer);
+ }
+
+ outputStream.write(getBytes(buffer.toString()));
+ }
+
+
+
+ // Get default usage.
+ private void getUsage(OutputStream outputStream)
+ throws IOException {
+ outputStream.write(getBytes(getUsage()));
+ }
+
+
+
+ // Appends complete usage information for the specified set of
+ // sub-commands.
+ private void getFullUsage(Collection<SubCommand> c, StringBuilder buffer) {
+ usageOrVersionDisplayed = true;
+ if ((toolDescription != null) && (toolDescription.length() > 0))
+ {
+ buffer.append(wrapText(toolDescription, 79));
+ buffer.append(EOL);
+ }
+
+ String scriptName = System.getProperty(PROPERTY_SCRIPT_NAME);
+ if ((scriptName == null) || (scriptName.length() == 0))
+ {
+ scriptName = "java " + mainClassName;
+ }
+ buffer.append(getMessage(MSGID_ARGPARSER_USAGE));
+ buffer.append(" ");
+ buffer.append(scriptName);
+
+ buffer.append(" {subcommand} {options}");
+
+ buffer.append(EOL);
+ buffer.append(EOL);
+
+ buffer.append(getMessage(MSGID_SUBCMDPARSER_SUBCMD_HEADING));
+ buffer.append(EOL);
+
+ if (c.isEmpty()) {
+ buffer.append(" ");
+ buffer.append(getMessage(MSGID_SUBCMDPARSER_SUBCMD_REFERENCE,
+ scriptName));
+ buffer.append(EOL);
+ } else {
+ int indentNb = 0;
+ for (SubCommand sc : c) {
+ if (sc.isHidden()) {
+ continue;
+ }
+ if (sc.getName().length() > indentNb) {
+ indentNb = sc.getName().length();
+ }
+ }
+ indentNb++;
+ for (SubCommand sc : c) {
+ if (sc.isHidden()) {
+ continue;
+ }
+ buffer.append(" " + sc.getName());
+ for (int i = 0; i < indentNb - sc.getName().length(); i++) {
+ buffer.append(" ");
+ }
+ buffer.append(sc.getDescription());
+ buffer.append(EOL);
+ }
+ }
+
+ buffer.append(EOL);
+ buffer.append(getMessage(MSGID_SUBCMDPARSER_GLOBAL_HEADING));
+ buffer.append(EOL);
+
+ // --version is a builtin option
+ boolean dashVAccepted = true;
+ if (globalShortIDMap.containsKey(OPTION_SHORT_PRODUCT_VERSION))
+ {
+ dashVAccepted = false;
+ }
+ else
+ {
+ for (SubCommand subCmd : subCommands.values())
+ {
+ if (subCmd.getArgument(OPTION_SHORT_PRODUCT_VERSION) != null)
+ {
+ dashVAccepted = false;
+ break;
+ }
+ }
+ }
+ if (dashVAccepted)
+ {
+ buffer.append("-" + OPTION_SHORT_PRODUCT_VERSION + ", ");
+ }
+ buffer.append("--" + OPTION_LONG_PRODUCT_VERSION);
+ buffer.append(EOL);
+ buffer.append(" ");
+ buffer.append( getMessage(MSGID_DESCRIPTION_PRODUCT_VERSION));
+ buffer.append(EOL);
+
+ // Display non-usage arguments.
+ for (Argument a : globalArgumentList) {
+ if (a.isHidden()) {
+ continue;
+ }
+
+ if (!usageGroupArguments.containsKey(a)) {
+ printArgumentUsage(a, buffer);
+ }
+ }
+
+ // Display usage arguments (except the default one).
+ for (Argument a : globalArgumentList) {
+ if (a.isHidden()) {
+ continue;
+ }
+
+ if (usageGroupArguments.containsKey(a)) {
+ if (!a.equals(usageArgument)) {
+ printArgumentUsage(a, buffer);
+ }
+ }
+ }
+
+ // Finally print default usage argument.
+ if (usageArgument != null) {
+ printArgumentUsage(usageArgument, buffer);
+ } else {
+ buffer.append("-?");
+ }
+ buffer.append(EOL);
+ }
+
+
+
+ /**
+ * Appends argument usage information to the provided buffer.
+ *
+ * @param a
+ * The argument to handle.
+ * @param buffer
+ * The buffer to which the usage information should be
+ * appended.
+ */
+ private void printArgumentUsage(Argument a, StringBuilder buffer) {
+ String value;
+ if (a.needsValue())
+ {
+ String valuePlaceholder = a.getValuePlaceholder();
+ if (valuePlaceholder == null)
+ {
+ value = " {value}";
+ }
+ else
+ {
+ value = " " + valuePlaceholder;
+ }
+ }
+ else
+ {
+ value = "";
+ }
+
+ Character shortIDChar = a.getShortIdentifier();
+ if (shortIDChar != null)
+ {
+ if (a.equals(usageArgument))
+ {
+ buffer.append("-?, ");
+ }
+ buffer.append("-");
+ buffer.append(shortIDChar);
+
+ String longIDString = a.getLongIdentifier();
+ if (longIDString != null)
+ {
+ buffer.append(", --");
+ buffer.append(longIDString);
+ }
+ buffer.append(value);
+ }
+ else
+ {
+ String longIDString = a.getLongIdentifier();
+ if (longIDString != null)
+ {
+ if (a.equals(usageArgument))
+ {
+ buffer.append("-?, ");
+ }
+ buffer.append("--");
+ buffer.append(longIDString);
+ buffer.append(value);
+ }
+ }
+
+ buffer.append(EOL);
+ indentAndWrap(" ", a.getDescription(), buffer);
+ }
+
+
+
/**
* Write one or more lines with the description of the argument. We will
* indent the description five characters and try our best to wrap at or
* before column 79 so it will be friendly to 80-column displays.
*/
-
private void indentAndWrap(String indent, String text, StringBuilder buffer)
{
int actualSize = 80 - indent.length();
--
Gitblit v1.10.0