From e1bd1505ae1dd09a564b6dd2c0021020d74c8422 Mon Sep 17 00:00:00 2001
From: Mark Craig <mark.craig@forgerock.com>
Date: Tue, 17 Mar 2015 13:09:01 +0000
Subject: [PATCH] CR-6372 OPENDJ-1786 Automate integration of generated content
---
opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/GenerateRefEntriesMojo.java | 215 +++++++++++++++++++++++
opendj-cli/src/main/resources/templates/refEntry.ftl | 6
opendj-server-legacy/pom.xml | 23 ++
opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java | 23 --
opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java | 72 --------
opendj-cli/src/main/java/com/forgerock/opendj/cli/SubCommandArgumentParser.java | 2
opendj-cli/src/main/java/com/forgerock/opendj/cli/ArgumentParser.java | 20 --
opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/CommandLineTool.java | 158 +++++++++++++++++
8 files changed, 399 insertions(+), 120 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 2dee2ad..3168041 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
@@ -698,24 +698,6 @@
}
/**
- * 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;
- }
-
- /**
* Retrieves the set of unnamed trailing arguments that were provided on the
* command line.
*
@@ -787,7 +769,7 @@
map.put("optionSection", getOptionsRefSect1(scriptName));
}
map.put("subcommands", null);
- map.put("trailingSections", pathsToXIncludes(getPathsToTrailingRefSect1s()));
+ map.put("trailingSectionString", System.getProperty("org.forgerock.opendj.gendoc.trailing"));
applyTemplate(builder, "refEntry.ftl", map);
}
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java
index 828029f..a60d99a 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/DocGenerationHelper.java
@@ -32,8 +32,6 @@
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
-import java.util.LinkedList;
-import java.util.List;
import java.util.Map;
/**
@@ -136,25 +134,4 @@
final String id = argument.getLongIdentifier();
return ("add".equals(id) || "remove".equals(id) || "reset".equals(id) || "set".equals(id));
}
-
- /**
- * Translate paths to XML files to XInclude elements.
- *
- * @return XInclude elements corresponding to the paths.
- */
- static List<String> pathsToXIncludes(final String[] paths) {
- if (paths == null) {
- return new LinkedList<String>();
- }
-
- // Assume xmlns:xinclude="http://www.w3.org/2001/XInclude",
- // as in the declaration of resources/templates/refEntry.ftl.
- final String nameSpace = "xinclude";
- List<String> xIncludes = new LinkedList<String>();
- for (int i = 0; i < paths.length; ++i) {
- xIncludes.add("<" + nameSpace + ":include href=\"" + paths[i] + "\" />");
- }
-
- return xIncludes;
- }
}
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 262c3b0..8134ec6 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
@@ -1153,7 +1153,7 @@
map.put("optionSection", getOptionsRefSect1(scriptName));
}
map.put("subcommands", toRefSect1(scriptName, subCommands));
- map.put("trailingSections", pathsToXIncludes(getPathsToTrailingRefSect1s()));
+ map.put("trailingSectionString", System.getProperty("org.forgerock.opendj.gendoc.trailing"));
applyTemplate(builder, "refEntry.ftl", map);
}
diff --git a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java
index 36aa9d2..08676d8 100644
--- a/opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java
+++ b/opendj-cli/src/main/java/com/forgerock/opendj/cli/ToolRefDocContainer.java
@@ -87,76 +87,4 @@
* intended for use in generated reference documentation.
*/
void setDocSubcommandsDescriptionSupplement(final LocalizableMessage docSubcommandsDescriptionSupplement);
-
- /**
- * Get additional paths to DocBook XML {@code RefSect1} documents
- * to be appended after generated content in reference documentation.
- *
- * <br>
- *
- * DocBook represents a reference manual page with the {@code RefEntry}.
- * See <a href="http://www.docbook.org/tdg51/en/html/refentry.html">refentry</a>.
- *
- * <br>
- *
- * A {@code RefEntry} describing an OpenDJ tool contains
- * block elements in the following order:
- *
- * <pre>
- * RefMeta
- * RefNameDiv
- * RefSynopsisDiv
- * RefSect1 - Description (generated, potentially with a hand-written supplement)
- * RefSect1 - Options (generated)
- * RefSect1 - Subcommands (optional, hand-written intro + generated RefSect2s)
- * RefSect1 - Filter (optional, hand-written)
- * RefSect1 - Attribute (optional, hand-written)
- * RefSect1 - Exit Codes (hand-written)
- * RefSect1 - Files (optional, hand-written)
- * RefSect1 - Examples (hand-written)
- * RefSect1 - See Also (hand-written)
- * </pre>
- *
- * As the trailing RefSect1s following Subcommands are hand-written,
- * they are included in the generated content as XIncludes elements.
- *
- * @return The paths to trailing {@code RefSect1} documents.
- */
- String[] getPathsToTrailingRefSect1s();
-
- /**
- * Set additional paths to DocBook XML {@code RefSect1} documents
- * to be appended after generated content in reference documentation.
- *
- * <br>
- *
- * DocBook represents a reference manual page with the {@code RefEntry}.
- * See <a href="http://www.docbook.org/tdg51/en/html/refentry.html">refentry</a>.
- *
- * <br>
- *
- * A {@code RefEntry} describing an OpenDJ tool contains
- * block elements in the following order:
- *
- * <pre>
- * RefMeta
- * RefNameDiv
- * RefSynopsisDiv
- * RefSect1 - Description (generated, potentially with a hand-written supplement)
- * RefSect1 - Options (generated)
- * RefSect1 - Subcommands (optional, hand-written intro + generated RefSect2s)
- * RefSect1 - Filter (optional, hand-written)
- * RefSect1 - Attribute (optional, hand-written)
- * RefSect1 - Exit Codes (hand-written)
- * RefSect1 - Files (optional, hand-written)
- * RefSect1 - Examples (hand-written)
- * RefSect1 - See Also (hand-written)
- * </pre>
- *
- * As the trailing RefSect1s following Subcommands are hand-written,
- * they are included in the generated content as XIncludes elements.
- *
- * @param paths The paths to trailing {@code RefSect1} documents.
- */
- public void setPathsToTrailingRefSect1s(final String... paths);
}
diff --git a/opendj-cli/src/main/resources/templates/refEntry.ftl b/opendj-cli/src/main/resources/templates/refEntry.ftl
index db23699..5cb3275 100644
--- a/opendj-cli/src/main/resources/templates/refEntry.ftl
+++ b/opendj-cli/src/main/resources/templates/refEntry.ftl
@@ -100,9 +100,7 @@
${subcommands}
</#if>
- <#if trailingSections??>
- <#list trailingSections as section>
- ${section}
- </#list>
+ <#if trailingSectionString??>
+ ${trailingSectionString}
</#if>
</refentry>
diff --git a/opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/CommandLineTool.java b/opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/CommandLineTool.java
new file mode 100644
index 0000000..3545f6e
--- /dev/null
+++ b/opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/CommandLineTool.java
@@ -0,0 +1,158 @@
+/*
+ * 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.
+ */
+package org.forgerock.opendj.maven;
+
+import java.util.List;
+
+/**
+ * Represents a command-line tool as used in the configuration for {@see GenerateRefEntriesMojo}.
+ * <br>
+ * Command-line tools are associated with a script name, the Java class of the tool,
+ * and a list of relative paths to hand-written files for trailing sections.
+ * <br>
+ * Trailing section paths are relative to the RefEntry file to write.
+ */
+public class CommandLineTool {
+ /** The script name. */
+ private String name;
+
+ /** The tool class. */
+ private String application;
+
+ /**
+ * Additional paths to DocBook XML {@code RefSect1} documents
+ * to be appended after generated content in reference documentation.
+ *
+ * <br>
+ *
+ * DocBook represents a reference manual page with the {@code RefEntry}.
+ * See <a href="http://www.docbook.org/tdg51/en/html/refentry.html">refentry</a>.
+ *
+ * <br>
+ *
+ * A {@code RefEntry} describing an OpenDJ tool contains
+ * block elements in the following order:
+ *
+ * <pre>
+ * RefMeta
+ * RefNameDiv
+ * RefSynopsisDiv
+ * RefSect1 - Description (generated, potentially with a hand-written supplement)
+ * RefSect1 - Options (generated)
+ * RefSect1 - Subcommands (optional, hand-written intro + generated RefSect2s)
+ * RefSect1 - Filter (optional, hand-written)
+ * RefSect1 - Attribute (optional, hand-written)
+ * RefSect1 - Exit Codes (hand-written)
+ * RefSect1 - Files (optional, hand-written)
+ * RefSect1 - Examples (hand-written)
+ * RefSect1 - See Also (hand-written)
+ * </pre>
+ *
+ * As the trailing RefSect1s following Subcommands are hand-written,
+ * they are included in the generated content as XIncludes elements.
+ * The paths in this case are therefore relative to the current RefEntry.
+ */
+ private List<String> trailingSectionPaths;
+
+ /**
+ * Returns the script name.
+ * @return The script name.
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * Set the script name.
+ * @param name The script name.
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * Returns the tool class.
+ * @return The tool class.
+ */
+ public String getApplication() {
+ return application;
+ }
+
+ /**
+ * Set the tool class.
+ * @param application The tool class.
+ */
+ public void setApplication(final String application) {
+ this.application = application;
+ }
+
+ /**
+ * Returns additional paths to DocBook XML {@code RefSect1} documents
+ * to be appended after generated content in reference documentation.
+ *
+ * <br>
+ *
+ * DocBook represents a reference manual page with the {@code RefEntry}.
+ * See <a href="http://www.docbook.org/tdg51/en/html/refentry.html">refentry</a>.
+ *
+ * <br>
+ *
+ * A {@code RefEntry} describing an OpenDJ tool contains
+ * block elements in the following order:
+ *
+ * <pre>
+ * RefMeta
+ * RefNameDiv
+ * RefSynopsisDiv
+ * RefSect1 - Description (generated, potentially with a hand-written supplement)
+ * RefSect1 - Options (generated)
+ * RefSect1 - Subcommands (optional, hand-written intro + generated RefSect2s)
+ * RefSect1 - Filter (optional, hand-written)
+ * RefSect1 - Attribute (optional, hand-written)
+ * RefSect1 - Exit Codes (hand-written)
+ * RefSect1 - Files (optional, hand-written)
+ * RefSect1 - Examples (hand-written)
+ * RefSect1 - See Also (hand-written)
+ * </pre>
+ *
+ * As the trailing RefSect1s following Subcommands are hand-written,
+ * they are included in the generated content as XIncludes elements.
+ * The paths in this case are therefore relative to the current RefEntry.
+ *
+ * @return The relative paths to trailing section files.
+ */
+ public List<String> getTrailingSectionPaths() {
+ return trailingSectionPaths;
+ }
+
+ /**
+ * Set additional paths to DocBook XML {@code RefSect1} documents.
+ * @param paths The paths relative to the current RefEntry.
+ */
+ public void setTrailingSectionPaths(final List<String> paths) {
+ this.trailingSectionPaths = paths;
+ }
+}
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
new file mode 100644
index 0000000..1b5be78
--- /dev/null
+++ b/opendj-maven-plugin/src/main/java/org/forgerock/opendj/maven/GenerateRefEntriesMojo.java
@@ -0,0 +1,215 @@
+/*
+ * 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.
+ */
+package org.forgerock.opendj.maven;
+
+import org.apache.maven.artifact.DependencyResolutionRequiredException;
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugins.annotations.LifecyclePhase;
+import org.apache.maven.plugins.annotations.Mojo;
+import org.apache.maven.plugins.annotations.Parameter;
+import org.apache.maven.plugins.annotations.ResolutionScope;
+import org.apache.maven.project.MavenProject;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Generate DocBook RefEntry source documents for command-line tools man pages.
+ */
+@Mojo(name = "generate-refentry", defaultPhase = LifecyclePhase.PREPARE_PACKAGE,
+ requiresDependencyResolution = ResolutionScope.COMPILE_PLUS_RUNTIME)
+public final class GenerateRefEntriesMojo extends AbstractMojo {
+
+ /** The Maven Project. */
+ @Parameter(property = "project", required = true, readonly = true)
+ private MavenProject project;
+
+ /** Tools for which to generate RefEntry files. */
+ @Parameter
+ private List<CommandLineTool> tools;
+
+ /** Where to write the RefEntry files. */
+ @Parameter(required = true)
+ private File outputDir;
+
+ /** End of line. */
+ public static final String EOL = System.getProperty("line.separator");
+
+ /**
+ * Writes a RefEntry file to the output directory for each tool.
+ * Files names correspond to script names: {@code man-<name>.xml}.
+ *
+ * @throws MojoExecutionException Encountered a problem writing a file.
+ * @throws MojoFailureException Failed to initialize effectively,
+ * or to write one or more RefEntry files.
+ */
+ @Override
+ public void execute() throws MojoExecutionException, MojoFailureException {
+ PrintStream out = System.out;
+
+ // Set the magic property for generating DocBook XML.
+ System.setProperty("org.forgerock.opendj.gendoc", "true");
+
+ // A Maven plugin classpath does not include project files.
+ // Prepare a ClassLoader capable of loading the command-line tools.
+ URLClassLoader toolsClassLoader;
+ try {
+ List<String> runtimeClasspathElements = project.getRuntimeClasspathElements();
+ List<URL> runtimeUrls = new LinkedList<URL>();
+ for (String element : runtimeClasspathElements) {
+ runtimeUrls.add(new File(element).toURI().toURL());
+ }
+ toolsClassLoader = new URLClassLoader(
+ runtimeUrls.toArray(new URL[runtimeClasspathElements.size()]),
+ Thread.currentThread().getContextClassLoader());
+ } catch (DependencyResolutionRequiredException e) {
+ throw new MojoFailureException("Failed to access the runtime classpath.", e);
+ } catch (MalformedURLException e) {
+ throw new MojoFailureException("Failed to add element to classpath.", e);
+ }
+ debugClassPathElements(toolsClassLoader);
+
+ List<String> failures = new LinkedList<String>();
+ for (CommandLineTool tool : tools) {
+ final File manPage = new File(outputDir, "man-" + tool.getName() + ".xml");
+ try {
+ setSystemOut(refEntryFile(manPage.getPath()));
+ } catch (FileNotFoundException e) {
+ setSystemOut(out);
+ failures.add(manPage.getPath());
+ throw new MojoExecutionException("Failed to write " + manPage.getPath(), e);
+ }
+
+ // Set the properties for script name and list of trailing sections.
+ System.setProperty("com.forgerock.opendj.ldap.tools.scriptName", tool.getName());
+ final String xInclude = pathsToXIncludes(tool.getTrailingSectionPaths());
+ System.setProperty("org.forgerock.opendj.gendoc.trailing", xInclude);
+
+ try {
+ final Class<?> toolClass = toolsClassLoader.loadClass(tool.getApplication());
+ final Class[] argTypes = new Class[]{String[].class};
+ final Method main = toolClass.getDeclaredMethod("main", argTypes);
+ final String[] args = {"-?"};
+ main.invoke(null, (Object) args);
+ } catch (ClassNotFoundException e) {
+ failures.add(manPage.getPath());
+ throw new MojoExecutionException(tool.getApplication() + " not found", e);
+ } catch (NoSuchMethodException e) {
+ failures.add(manPage.getPath());
+ throw new MojoExecutionException(tool.getApplication() + " has no main method.", e);
+ } catch (IllegalAccessException e) {
+ failures.add(manPage.getPath());
+ throw new MojoExecutionException("Failed to run " + tool.getApplication() + ".main()", e);
+ } catch (InvocationTargetException e) {
+ failures.add(manPage.getPath());
+ throw new MojoExecutionException("Failed to run " + tool.getApplication() + ".main()", e);
+ } finally {
+ setSystemOut(out);
+ }
+ }
+
+ final StringBuilder list = new StringBuilder();
+ if (!failures.isEmpty()) {
+ for (final String failure : failures) {
+ list.append(failure).append(EOL);
+ }
+ throw new MojoFailureException("Failed to write the following RefEntry files: " + list);
+ }
+ }
+
+ /**
+ * Logs what is on the classpath for debugging.
+ * @param classLoader The ClassLoader with the classpath.
+ */
+ private void debugClassPathElements(ClassLoader classLoader) {
+ if (null == classLoader) {
+ return;
+ }
+ getLog().debug("--------------------");
+ getLog().debug(classLoader.toString());
+ if (classLoader instanceof URLClassLoader) {
+ final URLClassLoader ucl = (URLClassLoader) classLoader;
+ int i = 0;
+ for (URL url : ucl.getURLs()) {
+ getLog().debug("url[" + (i++) + "]=" + url);
+ }
+ }
+ debugClassPathElements(classLoader.getParent());
+ }
+
+ /**
+ * Returns a PrintStream to a file to which to write a RefEntry.
+ * @param path Path to the file to be written.
+ * @return PrintStream to a file to which to write a RefEntry.
+ * @throws FileNotFoundException Failed to open the file for writing.
+ */
+ private PrintStream refEntryFile(final String path) throws FileNotFoundException {
+ return new PrintStream(new BufferedOutputStream(new FileOutputStream(path)), true);
+ }
+
+ /**
+ * Sets the System output stream.
+ * @param out The stream to use.
+ */
+ private void setSystemOut(PrintStream out) {
+ if (out != null) {
+ System.setOut(out);
+ }
+ }
+
+ /**
+ * Translates relative paths to XML files into XInclude elements.
+ *
+ * @param paths Paths to XInclude'd files, relative to the RefEntry.
+ * @return String of XInclude elements corresponding to the paths.
+ */
+ private String pathsToXIncludes(final List<String> paths) {
+ if (paths == null) {
+ return "";
+ }
+
+ // Assume xmlns:xinclude="http://www.w3.org/2001/XInclude",
+ // as in the declaration of resources/templates/refEntry.ftl.
+ final String nameSpace = "xinclude";
+ final StringBuilder result = new StringBuilder();
+ for (String path : paths) {
+ result.append("<").append(nameSpace).append(":include href=\"").append(path).append("\" />").append(EOL);
+ }
+ return result.toString();
+ }
+}
diff --git a/opendj-server-legacy/pom.xml b/opendj-server-legacy/pom.xml
index 75d28c3..173618a 100644
--- a/opendj-server-legacy/pom.xml
+++ b/opendj-server-legacy/pom.xml
@@ -529,7 +529,28 @@
</messageFileNames>
</configuration>
</execution>
- </executions>
+
+ <!-- TODO: Generate man page sources
+ <execution>
+ <id>generate-doc</id>
+ <goals>
+ <goal>generate-refentry</goal>
+ </goals>
+ <configuration>
+ <outputDir>${project.build.directory}</outputDir>
+ <tools>
+ <tool>
+ <name>ldapsearch</name>
+ <application>org.opends.server.tools.LDAPSearch</application>
+ <trailingSectionPaths>
+ <trailingSectionPath>../shared/refsect1.xml</trailingSectionPath>
+ </trailingSectionPaths>
+ </tool>
+ </tools>
+ </configuration>
+ </execution>
+ -->
+ </executions>
</plugin>
<plugin>
--
Gitblit v1.10.0