From 314e6e2709c4b0ebfe509e262ca366874f9069da Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Wed, 11 Mar 2015 11:59:20 +0000
Subject: [PATCH] CR-6316 OPENDJ-1786 Automate integration of generated content
---
opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java | 311 ++++++++++++++++++++++++++++++++++++---------------
1 files changed, 220 insertions(+), 91 deletions(-)
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
index a55aa2e..2dee2ad 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java
@@ -65,7 +65,7 @@
* file to obtain default values for arguments there if they are not specified
* on the command-line.
*/
-public class ArgumentParser {
+public class ArgumentParser implements ToolRefDocContainer {
private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass();
/**
@@ -617,23 +617,14 @@
*/
private LocalizableMessage shortToolDescription;
- /**
- * Gets a short description for this tool, suitable in a man page summary line.
- *
- * @return A short description for this tool,
- * suitable in a man page summary line,
- * or LocalizableMessage.EMPTY if there is no short description.
- */
- LocalizableMessage getShortToolDescription() {
+ /** {@inheritDoc} */
+ @Override
+ public LocalizableMessage getShortToolDescription() {
return shortToolDescription != null ? shortToolDescription : LocalizableMessage.EMPTY;
}
- /**
- * Sets a short description for this tool, suitable in a man page summary line.
- *
- * @param shortDescription The short description for this tool,
- * suitable in a man page summary line.
- */
+ /** {@inheritDoc} */
+ @Override
public void setShortToolDescription(final LocalizableMessage shortDescription) {
this.shortToolDescription = shortDescription;
}
@@ -642,29 +633,86 @@
* A supplement to the description for this tool
* intended for use in generated reference documentation.
*/
- private LocalizableMessage docToolDescriptionSupplement;
+ private DocDescriptionSupplement docToolDescriptionSupplement;
- /**
- * Retrieves a supplement to the description for this tool,
- * intended for use in generated reference documentation.
- *
- * @return A supplement to the description for this tool
- * intended for use in generated reference documentation,
- * or LocalizableMessage.EMPTY if there is no supplement.
- */
- LocalizableMessage getDocToolDescriptionSupplement() {
- return docToolDescriptionSupplement != null ? docToolDescriptionSupplement : LocalizableMessage.EMPTY;
+ /** {@inheritDoc} */
+ @Override
+ public LocalizableMessage getDocToolDescriptionSupplement() {
+ this.docToolDescriptionSupplement =
+ constructIfNull(this.docToolDescriptionSupplement);
+ return this.docToolDescriptionSupplement.getDocDescriptionSupplement();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setDocToolDescriptionSupplement(final LocalizableMessage supplement) {
+ this.docToolDescriptionSupplement =
+ constructIfNull(this.docToolDescriptionSupplement);
+ this.docToolDescriptionSupplement.setDocDescriptionSupplement(supplement);
}
/**
- * Sets a supplement to the description for this tool,
+ * A supplement to the description for all subcommands of this tool,
* intended for use in generated reference documentation.
- *
- * @param docToolDescriptionSupplement The supplement to the description for this tool
- * intended for use in generated reference documentation.
*/
- public void setDocToolDescriptionSupplement(final LocalizableMessage docToolDescriptionSupplement) {
- this.docToolDescriptionSupplement = docToolDescriptionSupplement;
+ private class DocSubcommandsDescriptionSupplement implements DocDescriptionSupplement {
+ /**
+ * A supplement to the description intended for use in generated reference documentation.
+ */
+ private LocalizableMessage docDescriptionSupplement;
+
+ /** {@inheritDoc} */
+ public LocalizableMessage getDocDescriptionSupplement() {
+ return docDescriptionSupplement != null ? docDescriptionSupplement : LocalizableMessage.EMPTY;
+ }
+
+ /** {@inheritDoc} */
+ public void setDocDescriptionSupplement(final LocalizableMessage docDescriptionSupplement) {
+ this.docDescriptionSupplement = docDescriptionSupplement;
+ }
+ }
+
+ private DocDescriptionSupplement docSubcommandsDescriptionSupplement;
+
+ /** {@inheritDoc} */
+ @Override
+ public LocalizableMessage getDocSubcommandsDescriptionSupplement() {
+ this.docSubcommandsDescriptionSupplement =
+ constructIfNull(this.docSubcommandsDescriptionSupplement);
+ return this.docSubcommandsDescriptionSupplement.getDocDescriptionSupplement();
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setDocSubcommandsDescriptionSupplement(final LocalizableMessage supplement) {
+ this.docSubcommandsDescriptionSupplement =
+ constructIfNull(this.docSubcommandsDescriptionSupplement);
+ this.docSubcommandsDescriptionSupplement.setDocDescriptionSupplement(supplement);
+ }
+
+ private DocDescriptionSupplement constructIfNull(DocDescriptionSupplement supplement) {
+ if (supplement != null) {
+ return supplement;
+ }
+ return new DocSubcommandsDescriptionSupplement();
+ }
+
+ /**
+ * Additional paths to DocBook XML {@code RefSect1} documents
+ * to be appended after generated content in reference documentation.
+ */
+ private String[] pathsToTrailingRefSect1s;
+
+ /** {@inheritDoc} */
+ @Override
+ public String[] getPathsToTrailingRefSect1s() {
+ return pathsToTrailingRefSect1s != null ? pathsToTrailingRefSect1s : new String[0];
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ public void setPathsToTrailingRefSect1s(final String... paths) {
+ this.pathsToTrailingRefSect1s = paths;
}
/**
@@ -689,7 +737,7 @@
final StringBuilder buffer = new StringBuilder();
usageOrVersionDisplayed = true;
if (System.getProperty("org.forgerock.opendj.gendoc") != null) {
- toRefEntry(buffer);
+ toRefEntry(buffer, getSynopsisArgs(), argumentList);
} else {
getUsage(buffer);
}
@@ -697,56 +745,128 @@
}
/**
+ * Return the list of arguments for the generated reference documentation.
+ *
+ * @return The list of arguments for the generated reference documentation.
+ */
+ String getSynopsisArgs() {
+ if (allowsTrailingArguments()) {
+ if (trailingArgsDisplayName != null) {
+ return trailingArgsDisplayName;
+ } else {
+ return INFO_ARGPARSER_USAGE_TRAILINGARGS.get().toString();
+ }
+ }
+ return null;
+ }
+
+ /**
* Appends a generated DocBook XML RefEntry (man page) to the StringBuilder.
*
- * @param sb Append the RefEntry element to this.
+ * @param builder Append the RefEntry element to this.
+ * @param synopsisArgs List of arguments for the command synopsis.
+ * @param argList List of (global) arguments for this tool.
*/
- private void toRefEntry(StringBuilder sb) {
+ void toRefEntry(StringBuilder builder, String synopsisArgs, List<Argument> argList) {
final String scriptName = getScriptName();
if (scriptName == null) {
throw new RuntimeException("The script name should have been set via the environment property '"
+ PROPERTY_SCRIPT_NAME + "'.");
}
- // Model for a FreeMarker template.
Map<String, Object> map = new HashMap<String, Object>();
map.put("locale", Locale.getDefault().getLanguage());
map.put("year", new SimpleDateFormat("yyyy").format(new Date()));
map.put("name", scriptName);
map.put("shortDesc", getShortToolDescription());
map.put("descTitle", REF_TITLE_DESCRIPTION.get());
- map.put("optsTitle", REF_TITLE_OPTIONS.get());
- map.put("optsIntro", REF_INTRO_OPTIONS.get(scriptName));
- String args = null;
- if (allowsTrailingArguments) {
- if (trailingArgsDisplayName != null) {
- args = trailingArgsDisplayName;
- } else {
- args = INFO_ARGPARSER_USAGE_TRAILINGARGS.get().toString();
- }
- }
- map.put("args", args);
+ map.put("args", synopsisArgs);
map.put("description", getToolDescription());
-
- // If there is a supplement to the description for this utility,
- // then it is already DocBook XML, so use it as is.
map.put("info", getDocToolDescriptionSupplement());
- if (!argumentList.isEmpty()) {
- List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
- for (Argument a : argumentList) {
- Map<String, Object> option = new HashMap<String, Object>();
- option.put("synopsis", getOptionSynopsis(a));
- option.put("description", a.getDescription());
- option.put("default", REF_DEFAULT.get(a.getDefaultValue()));
-
- // If there is a supplement to the description for this argument,
- // then it is already DocBook XML, so use it as is.
- option.put("info", a.getDocDescriptionSupplement());
- options.add(option);
- }
- map.put("options", options);
+ if (!argList.isEmpty()) {
+ map.put("optionSection", getOptionsRefSect1(scriptName));
}
- applyTemplate(sb, "refEntry.ftl", map);
+ map.put("subcommands", null);
+ map.put("trailingSections", pathsToXIncludes(getPathsToTrailingRefSect1s()));
+ applyTemplate(builder, "refEntry.ftl", map);
+ }
+
+
+ /**
+ * Returns a generated DocBook XML RefSect1 element for all command options.
+ * @param scriptName The name of this script.
+ * @return The RefSect1 element as a String.
+ */
+ protected String getOptionsRefSect1(String scriptName) {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("name", scriptName);
+ map.put("title", REF_TITLE_OPTIONS.get());
+ map.put("intro", REF_INTRO_OPTIONS.get(scriptName));
+
+ Argument helpArgument = null;
+ final boolean printHeaders = printUsageGroupHeaders();
+ List<Map<String, Object>> groups = new LinkedList<Map<String, Object>>();
+ for (final ArgumentGroup argGroup : argumentGroups) {
+ Map<String, Object> group = new HashMap<String, Object>();
+
+ // Add the group's description if any
+ if (argGroup.containsArguments() && printHeaders) {
+ LocalizableMessage description = argGroup.getDescription();
+ if (description != LocalizableMessage.EMPTY) {
+ group.put("description", argGroup.getDescription());
+ } else {
+ group.put("description", INFO_SUBCMDPARSER_WHERE_OPTIONS_INCLUDE.get());
+ }
+ }
+
+ List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
+ final SortedSet<Argument> args = sortArguments(argGroup.getArguments());
+ for (final Argument a : args) {
+ if (a.isHidden()) {
+ continue;
+ }
+
+ // The help argument should be added at the end.
+ if (isUsageArgument(a)) {
+ helpArgument = a;
+ continue;
+ }
+
+ options.add(getArgumentMap(a));
+ }
+ group.put("options", options);
+ if (!options.isEmpty()) {
+ groups.add(group);
+ }
+ }
+ if (helpArgument != null) {
+ Map<String, Object> helpGroup = new HashMap<String, Object>();
+ helpGroup.put("description", null);
+ List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
+ options.add(getArgumentMap(helpArgument));
+ helpGroup.put("options", options);
+ groups.add(helpGroup);
+ }
+ map.put("groups", groups);
+
+ StringBuilder sb = new StringBuilder();
+ applyTemplate(sb, "optionsRefSect1.ftl", map);
+ return sb.toString();
+ }
+
+ /**
+ * Returns a map containing information about an argument option.
+ * @param a The argument
+ * @return A map containing information about an argument option
+ */
+ private Map<String, Object> getArgumentMap(final Argument a) {
+ Map<String, Object> option = new HashMap<String, Object>();
+ option.put("synopsis", getOptionSynopsis(a));
+ option.put("description", a.getDescription());
+ String dv = a.getDefaultValue();
+ option.put("default", dv != null ? REF_DEFAULT.get(dv) : null);
+ option.put("info", a.getDocDescriptionSupplement());
+ return option;
}
/**
@@ -805,33 +925,8 @@
}
}
- final SortedSet<Argument> args = new TreeSet<Argument>(new Comparator<Argument>() {
-
- /** {@inheritDoc} */
- @Override
- public int compare(final Argument o1, final Argument o2) {
- final String s1 = getIdentifier(o1);
- final String s2 = getIdentifier(o2);
- final int res = s1.compareToIgnoreCase(s2);
- if (res != 0) {
- return res;
- }
- // Lowercase options first then uppercase.
- return -s1.compareTo(s2);
- }
-
- private String getIdentifier(final Argument o1) {
- if (o1.getShortIdentifier() != null) {
- return o1.getShortIdentifier().toString();
- }
- return o1.getLongIdentifier();
- }
-
- });
- args.addAll(argGroup.getArguments());
-
+ final SortedSet<Argument> args = sortArguments(argGroup.getArguments());
for (final Argument a : args) {
- // If this argument is hidden, then skip it.
if (a.isHidden()) {
continue;
}
@@ -854,6 +949,40 @@
}
/**
+ * Sorts arguments by identifier, lowercase options first then uppercase.
+ *
+ * @param arguments The arguments to sort.
+ * @return The set of arguments in sorted order.
+ */
+ SortedSet<Argument> sortArguments(final List<Argument> arguments) {
+ final SortedSet<Argument> result = new TreeSet<Argument>(new Comparator<Argument>() {
+
+ /** {@inheritDoc} */
+ @Override
+ public int compare(final Argument o1, final Argument o2) {
+ final String s1 = getIdentifier(o1);
+ final String s2 = getIdentifier(o2);
+ final int res = s1.compareToIgnoreCase(s2);
+ if (res != 0) {
+ return res;
+ }
+ // Lowercase options first then uppercase.
+ return -s1.compareTo(s2);
+ }
+
+ private String getIdentifier(final Argument o1) {
+ if (o1.getShortIdentifier() != null) {
+ return o1.getShortIdentifier().toString();
+ }
+ return o1.getLongIdentifier();
+ }
+
+ });
+ result.addAll(arguments);
+ return result;
+ }
+
+ /**
* Returns the script name or a Java equivalent command-line string.
*
* @return the script name or a Java equivalent command-line string
--
Gitblit v1.10.0