From a24bfd8e6439a14568046dd646f427f1cf095fec Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Tue, 31 Mar 2015 14:18:17 +0000
Subject: [PATCH] CR-6519 OPENDJ-1899 Generate multiple man pages for dsconfig
---
opendj-cli/src/main/resources/templates/dscfgReference.ftl | 46 ++++++
opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/GenerateRefEntriesMojo.java | 92 ++++++++++++
opendj-cli/src/main/resources/templates/refSect1.ftl | 4
opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl | 4
opendj-cli/src/main/resources/templates/dscfgListItem.ftl | 36 +++++
opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties | 2
opendj-cli/src/main/resources/templates/dscfgSubcommand.ftl | 106 +++++++++++++++
opendj-server-legacy/src/main/docbkx/reference/index.xml | 4
opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java | 115 +++++++++++++++-
9 files changed, 397 insertions(+), 12 deletions(-)
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
index 8134ec6..99f6e03 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java
@@ -396,7 +396,7 @@
@Override
public void setUsageArgument(Argument argument, OutputStream outputStream) {
super.setUsageArgument(argument, outputStream);
- usageGroupArguments.put(argument, Collections.<SubCommand> emptySet());
+ usageGroupArguments.put(argument, Collections.<SubCommand>emptySet());
}
/**
@@ -1127,7 +1127,11 @@
}
/**
- * Appends a generated DocBook XML RefEntry (man page) to the StringBuilder.
+ * Appends one or more generated DocBook XML RefEntry elements (man pages) to the StringBuilder.
+ * <br>
+ * If the result contains more than one RefEntry,
+ * then the RefEntry elements are separated with a marker:
+ * {@code @@@scriptName + "-" + subCommand.getName() + @@@}.
*
* @param builder Append the RefEntry element to this.
* @param subCommands Collection of subcommands for this tool.
@@ -1155,6 +1159,11 @@
map.put("subcommands", toRefSect1(scriptName, subCommands));
map.put("trailingSectionString", System.getProperty("org.forgerock.opendj.gendoc.trailing"));
applyTemplate(builder, "refEntry.ftl", map);
+
+ // For dsconfig, generate one page per subcommand.
+ if (scriptName.equals("dsconfig")) {
+ appendSubCommandPages(builder, scriptName, subCommands);
+ }
}
/**
@@ -1171,10 +1180,17 @@
Map<String, Object> map = new HashMap<String, Object>();
map.put("name", scriptName);
map.put("info", getDocSubcommandsDescriptionSupplement());
-
+ if (scriptName.equals("dsconfig")) {
+ // Break dsconfig into multiple pages, so use only the list here.
+ map.put("isItemizedList", true);
+ }
List<String> scUsageList = new ArrayList<String>();
for (SubCommand subCommand : subCommands) {
- scUsageList.add(toRefSect2(scriptName, subCommand));
+ if (scriptName.equals("dsconfig")) {
+ scUsageList.add(getSubCommandListItem(scriptName, subCommand));
+ } else {
+ scUsageList.add(toRefSect2(scriptName, subCommand));
+ }
}
map.put("subcommands", scUsageList);
@@ -1184,6 +1200,22 @@
}
/**
+ * Returns a DocBook XML ListItem element linking to the subcommand page.
+ * @param scriptName The name of this script.
+ * @param subCommand The SubCommand to reference.
+ * @return A DocBook XML ListItem element linking to the subcommand page.
+ */
+ private String getSubCommandListItem(String scriptName, SubCommand subCommand) {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("id", scriptName + "-" + subCommand.getName());
+ map.put("name", scriptName + " " + subCommand.getName());
+ map.put("description", subCommand.getDescription());
+ StringBuilder sb = new StringBuilder();
+ applyTemplate(sb, "dscfgListItem.ftl", map);
+ return sb.toString();
+ }
+
+ /**
* Returns a generated DocBook XML RefSect2 element for a single subcommand to the StringBuilder.
*
* @param scriptName The name of this script.
@@ -1203,6 +1235,22 @@
// If there is a supplement to the description for this subcommand,
// then it is already DocBook XML, so use it as is.
map.put("info", subCommand.getDocDescriptionSupplement());
+ setSubCommandOptionsInfo(map, subCommand);
+
+ StringBuilder sb = new StringBuilder();
+ applyTemplate(sb, "refSect2.ftl", map);
+ return sb.toString();
+ }
+
+ /**
+ * Sets information for the subcommand options in the map.
+ * <br>
+ * The map is expected to be used in a FreeMarker template to generate docs.
+ *
+ * @param map The map in which to set the information.
+ * @param subCommand The subcommand containing the information.
+ */
+ private void setSubCommandOptionsInfo(Map<String, Object> map, SubCommand subCommand) {
if (!subCommand.getArguments().isEmpty()) {
List<Map<String, Object>> options = new LinkedList<Map<String, Object>>();
String nameOption = null;
@@ -1236,9 +1284,62 @@
if (subCommandUsageHandler != null) {
map.put("propertiesInfo", subCommandUsageHandler.getProperties(subCommand));
}
+ }
- StringBuilder sb = new StringBuilder();
- applyTemplate(sb, "refSect2.ftl", map);
- return sb.toString();
+ /**
+ * Appends a generated DocBook XML RefEntry element for each subcommand to the StringBuilder.
+ * <br>
+ * The RefEntry elements are separated with a marker:
+ * {@code @@@scriptName + "-" + subCommand.getName() + @@@}.
+ *
+ * @param builder Append the RefEntry elements to this.
+ * @param scriptName The name of the tool with subcommands.
+ * @param subCommands SubCommands containing reference information.
+ */
+ private void appendSubCommandPages(StringBuilder builder, String scriptName, Collection<SubCommand> subCommands) {
+ for (SubCommand subCommand : subCommands) {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("marker", "@@@" + scriptName + "-" + subCommand.getName() + "@@@");
+ map.put("locale", Locale.getDefault().getLanguage());
+ map.put("year", new SimpleDateFormat("yyyy").format(new Date()));
+ map.put("id", scriptName + "-" + subCommand.getName());
+ map.put("name", scriptName + " " + subCommand.getName());
+ map.put("purpose", subCommand.getDescription());
+ map.put("args", INFO_SUBCMDPARSER_OPTIONS.get());
+ map.put("descTitle", REF_TITLE_DESCRIPTION.get());
+ map.put("description", subCommand.getDescription());
+ map.put("info", subCommand.getDocDescriptionSupplement());
+ map.put("optionsTitle", REF_TITLE_OPTIONS.get());
+ map.put("optionsIntro", REF_INTRO_OPTIONS.get(scriptName + " " + subCommand.getName()));
+ setSubCommandOptionsInfo(map, subCommand);
+ applyTemplate(builder, "dscfgSubcommand.ftl", map);
+ }
+ appendSubCommandReference(builder, scriptName, subCommands);
+ }
+
+ /**
+ * Appends a generated DocBook XML Reference element XIncluding subcommands.
+ *
+ * @param builder Append the Reference element to this.
+ * @param scriptName The name of the tool with subcommands.
+ * @param subCommands SubCommands containing reference information.
+ */
+ private void appendSubCommandReference(StringBuilder builder,
+ String scriptName,
+ Collection<SubCommand> subCommands) {
+ Map<String, Object> map = new HashMap<String, Object>();
+ map.put("marker", "@@@" + scriptName + "-subcommands-ref" + "@@@");
+ map.put("name", scriptName);
+ map.put("locale", Locale.getDefault().getLanguage());
+ map.put("title", REF_PART_TITLE_SUBCOMMANDS.get(scriptName));
+ map.put("partintro", REF_PART_INTRO_SUBCOMMANDS.get(scriptName));
+ List<Map<String, Object>> commands = new LinkedList<Map<String, Object>>();
+ for (SubCommand subCommand : subCommands) {
+ Map<String, Object> scMap = new HashMap<String, Object>();
+ scMap.put("id", scriptName + "-" + subCommand.getName());
+ commands.add(scMap);
+ }
+ map.put("subcommands", commands);
+ applyTemplate(builder, "dscfgReference.ftl", map);
}
}
diff --git a/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties b/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties
index 444d981..404a5f4 100755
--- a/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties
+++ b/opendj-cli/src/main/resources/com/forgerock/opendj/cli/cli.properties
@@ -976,6 +976,8 @@
REF_INTRO_OPTIONS=The <command>%s</command> command takes the following options:
REF_DEFAULT=Default: %s
REF_TITLE_SUBCOMMANDS=Subcommands
+REF_PART_TITLE_SUBCOMMANDS=%s Subcommands Reference
+REF_PART_INTRO_SUBCOMMANDS=This section covers <command>%s</command> subcommands.
REF_SHORT_DESC_UNINSTALL=remove OpenDJ directory server software
# Supplements to descriptions for generated reference documentation.
diff --git a/opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl b/opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl
index 790d19a..da914fa 100644
--- a/opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl
+++ b/opendj-cli/src/main/resources/templates/dscfgAppendProps.ftl
@@ -24,7 +24,7 @@
# Copyright 2015 ForgeRock AS.
#
#-->
-<refsect3 xml:id="${id}">
+<refsect1 xml:id="${id}">
<title>${title}</title>
<para>
@@ -32,4 +32,4 @@
</para>
${list}
-</refsect3>
+</refsect1>
diff --git a/opendj-cli/src/main/resources/templates/dscfgListItem.ftl b/opendj-cli/src/main/resources/templates/dscfgListItem.ftl
new file mode 100644
index 0000000..9b49a1c
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/dscfgListItem.ftl
@@ -0,0 +1,36 @@
+<#--
+ # CDDL HEADER START
+ #
+ # The contents of this file are subject to the terms of the
+ # Common Development and Distribution License, Version 1.0 only
+ # (the "License"). You may not use this file except in compliance
+ # with the License.
+ #
+ # You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ # or http://forgerock.org/license/CDDLv1.0.html.
+ # See the License for the specific language governing permissions
+ # and limitations under the License.
+ #
+ # When distributing Covered Code, include this CDDL HEADER in each
+ # file and include the License file at legal-notices/CDDLv1_0.txt.
+ # If applicable, add the following below this CDDL HEADER,
+ # with the fields enclosed by brackets "[]" replaced
+ # with your own identifying information:
+ #
+ # Portions Copyright [yyyy] [name of copyright owner]
+ #
+ # CDDL HEADER END
+ #
+ # Copyright 2015 ForgeRock AS.
+ #
+ #-->
+<listitem>
+ <para>
+ <link
+ <#-- Link to the Reference. Change this if the pages move to another document. -->
+ xlink:href="reference#${id}"
+ xlink:role="http://docbook.org/xlink/role/olink"
+ xlink:show="new"
+ ><command>${name}</command></link>: ${description}
+ </para>
+</listitem>
diff --git a/opendj-cli/src/main/resources/templates/dscfgReference.ftl b/opendj-cli/src/main/resources/templates/dscfgReference.ftl
new file mode 100644
index 0000000..1e3bcad
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/dscfgReference.ftl
@@ -0,0 +1,46 @@
+<#--
+ # CDDL HEADER START
+ #
+ # The contents of this file are subject to the terms of the
+ # Common Development and Distribution License, Version 1.0 only
+ # (the "License"). You may not use this file except in compliance
+ # with the License.
+ #
+ # You can obtain a copy of the license at legal-notices/CDDLv1_0.txt
+ # or http://forgerock.org/license/CDDLv1.0.html.
+ # See the License for the specific language governing permissions
+ # and limitations under the License.
+ #
+ # When distributing Covered Code, include this CDDL HEADER in each
+ # file and include the License file at legal-notices/CDDLv1_0.txt.
+ # If applicable, add the following below this CDDL HEADER,
+ # with the fields enclosed by brackets "[]" replaced
+ # with your own identifying information:
+ #
+ # Portions Copyright [yyyy] [name of copyright owner]
+ #
+ # CDDL HEADER END
+ #
+ # Copyright 2015 ForgeRock AS.
+ #
+ #-->
+${marker}
+<reference xml:id="${name}-subcommands-ref"
+ xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="${locale}"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook
+ http://docbook.org/xml/5.0/xsd/docbook.xsd"
+ xmlns:xinclude="http://www.w3.org/2001/XInclude">
+
+ <title>${title}</title>
+
+ <partintro>
+ <para>
+ ${partintro}
+ </para>
+ </partintro>
+
+ <#list subcommands as subcommand>
+ <xinclude:include href="../man-pages/man-${subcommand.id}.xml" />
+ </#list>
+</reference>
diff --git a/opendj-cli/src/main/resources/templates/dscfgSubcommand.ftl b/opendj-cli/src/main/resources/templates/dscfgSubcommand.ftl
new file mode 100644
index 0000000..ad7f243
--- /dev/null
+++ b/opendj-cli/src/main/resources/templates/dscfgSubcommand.ftl
@@ -0,0 +1,106 @@
+${marker}
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ! CCPL HEADER START
+ !
+ ! This work is licensed under the Creative Commons
+ ! Attribution-NonCommercial-NoDerivs 3.0 Unported License.
+ ! To view a copy of this license, visit
+ ! http://creativecommons.org/licenses/by-nc-nd/3.0/
+ ! or send a letter to Creative Commons, 444 Castro Street,
+ ! Suite 900, Mountain View, California, 94041, USA.
+ !
+ ! You can also obtain a copy of the license at
+ ! trunk/opendj/legal-notices/CC-BY-NC-ND.txt.
+ ! See the License for the specific language governing permissions
+ ! and limitations under the License.
+ !
+ ! If applicable, add the following below this CCPL HEADER, with the fields
+ ! enclosed by brackets "[]" replaced with your own identifying information:
+ ! Portions Copyright [yyyy] [name of copyright owner]
+ !
+ ! CCPL HEADER END
+ !
+ ! Copyright 2011-${year} ForgeRock AS.
+ !
+-->
+<refentry xml:id="${id}"
+ xmlns="http://docbook.org/ns/docbook" version="5.0" xml:lang="${locale}"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://docbook.org/ns/docbook
+ http://docbook.org/xml/5.0/xsd/docbook.xsd"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:xinclude="http://www.w3.org/2001/XInclude">
+
+ <info>
+ <copyright>
+ <year>2011-${year}</year>
+ <holder>ForgeRock AS.</holder>
+ </copyright>
+ </info>
+
+ <refmeta>
+ <refentrytitle>${name}</refentrytitle><manvolnum>1</manvolnum>
+ <refmiscinfo class="software">OpenDJ</refmiscinfo>
+ <refmiscinfo class="version">${r"${project.version}"}</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>${name}</refname>
+ <refpurpose>${purpose}</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <cmdsynopsis>
+ <command>${name}</command>
+ <arg choice="plain">${args}</arg>
+ </cmdsynopsis>
+ </refsynopsisdiv>
+
+ <refsect1 xml:id="${id}-description">
+ <title>${descTitle}</title>
+
+ <para>
+ ${description}
+ </para>
+
+ <#if info??>${info}</#if>
+ </refsect1>
+
+ <#if options??>
+ <refsect1 xml:id="${id}-options">
+ <title>${optionsTitle}</title>
+
+ <variablelist>
+ <para>
+ ${optionsIntro}
+ </para>
+
+ <#list options as option>
+ <varlistentry>
+ <term><option>${option.synopsis?xml}</option></term>
+ <listitem>
+ <para>
+ ${option.description}
+ </para>
+
+ <#if option.info??>
+ <#if option.info.usage??>${option.info.usage}</#if>
+
+ <#if option.info.default??>
+ <para>
+ ${option.info.default}
+ </para>
+ </#if>
+
+ <#if option.info.doc??>${option.info.doc}</#if>
+ </#if>
+ </listitem>
+ </varlistentry>
+ </#list>
+ </variablelist>
+ </refsect1>
+ </#if>
+
+ <#if propertiesInfo??>${propertiesInfo}</#if>
+</refentry>
diff --git a/opendj-cli/src/main/resources/templates/refSect1.ftl b/opendj-cli/src/main/resources/templates/refSect1.ftl
index c4e71fe..1302f58 100644
--- a/opendj-cli/src/main/resources/templates/refSect1.ftl
+++ b/opendj-cli/src/main/resources/templates/refSect1.ftl
@@ -35,7 +35,9 @@
The <command>${name}</command> utility supports the following subcommands.
</para>
+ <#if isItemizedList??><itemizedlist></#if>
<#list subcommands as subcommand>
- ${subcommand}
+ ${subcommand}
</#list>
+ <#if isItemizedList??></itemizedlist></#if>
</refsect1>
diff --git a/opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/GenerateRefEntriesMojo.java b/opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/GenerateRefEntriesMojo.java
index 580521c..5901008 100644
--- a/opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/GenerateRefEntriesMojo.java
+++ b/opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/GenerateRefEntriesMojo.java
@@ -34,9 +34,14 @@
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
+import org.forgerock.util.Utils;
import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
@@ -45,10 +50,14 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.channels.FileChannel;
+import java.nio.charset.Charset;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Generate DocBook RefEntry source documents for command-line tools man pages.
@@ -165,6 +174,14 @@
} catch (IOException e) {
throw new MojoExecutionException(toolClass + " not found", e);
}
+
+ if (tool.getName().equals("dsconfig")) {
+ try {
+ splitPage(manPage);
+ } catch (IOException e) {
+ throw new MojoExecutionException("Failed to split " + manPage.getName(), e);
+ }
+ }
}
/**
@@ -287,9 +304,80 @@
writer.write(EOL);
}
} finally {
- if (writer != null) {
- writer.close();
+ Utils.closeSilently(writer);
+ }
+ }
+
+ /**
+ * Splits the content of a single man page into multiple pages.
+ * <br>
+ * RefEntry elements must be separated with a marker:
+ * {@code @@@scriptName + "-" + subCommand.getName() + @@@}.
+ *
+ * @param page The page to split.
+ * @throws IOException Failed to split the page.
+ */
+ private void splitPage(final File page) throws IOException {
+ // Read from a copy of the page.
+ final File pageCopy = new File(page.getPath() + ".tmp");
+ copyFile(page, pageCopy);
+ final BufferedReader reader = new BufferedReader(new FileReader(pageCopy));
+ try {
+ // Write first to the page, then to pages named according to marker values.
+ File output = page;
+ getLog().info("Rewriting man page: " + page.getPath());
+ final Pattern marker = Pattern.compile("@@@(.+?)@@@");
+ final StringBuilder builder = new StringBuilder();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ final Matcher matcher = marker.matcher(line);
+ if (matcher.find()) {
+ writeToFile(builder.toString(), output);
+ builder.setLength(0);
+ output = new File(page.getParentFile(), "man-" + matcher.group(1) + ".xml");
+ getLog().info("Writing man page: " + output.getPath());
+ } else {
+ builder.append(line).append(System.getProperty("line.separator"));
+ }
}
+ writeToFile(builder.toString(), output);
+ if (!pageCopy.delete()) {
+ throw new IOException("Failed to delete " + pageCopy.getName());
+ }
+ } finally {
+ Utils.closeSilently(reader);
+ }
+ }
+
+ /**
+ * Writes the content of the input to the output file.
+ * @param input The UTF-8 input to write.
+ * @param output The file to write it to.
+ * @throws IOException Failed to write the content of the input.
+ */
+ private void writeToFile(final String input, final File output) throws IOException {
+ InputStream is = new ByteArrayInputStream(input.getBytes(Charset.forName("UTF-8")));
+ writeToFile(is, output);
+ }
+
+ /**
+ * Copies the content of the original file to the copy.
+ * @param original The original file.
+ * @param copy The copy.
+ * @throws IOException Failed to make the copy.
+ */
+ private void copyFile(File original, File copy) throws IOException {
+ if (!copy.exists() && !copy.createNewFile()) {
+ throw new IOException("Failed to create " + copy);
+ }
+ FileChannel in = null;
+ FileChannel out = null;
+ try {
+ in = new FileInputStream(original).getChannel();
+ out = new FileOutputStream(copy).getChannel();
+ out.transferFrom(in, 0, in.size());
+ } finally {
+ Utils.closeSilently(in, out);
}
}
}
diff --git a/opendj-server-legacy/src/main/docbkx/reference/index.xml b/opendj-server-legacy/src/main/docbkx/reference/index.xml
index e2fcc1b..97e733c 100644
--- a/opendj-server-legacy/src/main/docbkx/reference/index.xml
+++ b/opendj-server-legacy/src/main/docbkx/reference/index.xml
@@ -187,6 +187,10 @@
<xinclude:include href='../man-pages/man-windows-service.xml' />
</reference>
+ <xinclude:include href="../man-pages/man-dsconfig-subcommands-ref.xml">
+ <xinclude:fallback><!-- Failed to include page --></xinclude:fallback>
+ </xinclude:include>
+
<xinclude:include href="../shared/glossary.xml" />
<xinclude:include href="appendix-rest2ldap.xml" />
--
Gitblit v1.10.0