mirror of
https://github.com/jlengrand/picocli.git
synced 2026-03-10 08:41:17 +00:00
[#1066] improved usage help; added tests
This commit is contained in:
@@ -25,6 +25,7 @@ import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
@@ -46,7 +47,7 @@ import static java.lang.String.format;
|
||||
sortOptions = false,
|
||||
usageHelpAutoWidth = true,
|
||||
usageHelpWidth = 100,
|
||||
description = {"Generates one or more AsciiDoc files with doctype 'manpage' in the specified directory."},
|
||||
description = {"Generates man pages for all commands in the specified directory."},
|
||||
//exitCodeListHeading = "%nExit Codes (if enabled with `--exit`)%n",
|
||||
//exitCodeList = {
|
||||
// "0:Successful program execution.",
|
||||
@@ -66,7 +67,7 @@ import static java.lang.String.format;
|
||||
"See http://man7.org/linux/man-pages/man7/roff.7.html",
|
||||
}
|
||||
)
|
||||
public class ManPageGenerator {
|
||||
public class ManPageGenerator implements Callable<Integer> {
|
||||
static final int EXIT_CODE_TEMPLATE_EXISTS = 4;
|
||||
|
||||
static final IStyle BOLD = new IStyle() {
|
||||
@@ -103,8 +104,7 @@ public class ManPageGenerator {
|
||||
* @throws IOException if a problem occurred writing files.
|
||||
*/
|
||||
public Integer call() throws IOException {
|
||||
List<CommandSpec> specs = Util.flattenHierarchy(spec.root());
|
||||
return generateManPage(config, specs.toArray(new CommandSpec[0]));
|
||||
return generateManPage(config, spec.root());
|
||||
}
|
||||
|
||||
private static Map<String, IStyle> createMarkupMap() {
|
||||
@@ -279,6 +279,8 @@ public class ManPageGenerator {
|
||||
return CommandLine.ExitCode.USAGE;
|
||||
}
|
||||
|
||||
traceAllSpecs(specs, config);
|
||||
|
||||
for (CommandSpec spec : specs) {
|
||||
int result = generateSingleManPage(config, spec);
|
||||
if (result != CommandLine.ExitCode.OK) {
|
||||
@@ -301,6 +303,21 @@ public class ManPageGenerator {
|
||||
return CommandLine.ExitCode.OK;
|
||||
}
|
||||
|
||||
private static void traceAllSpecs(CommandSpec[] specs, Config config) {
|
||||
List<String> all = new ArrayList<String>();
|
||||
for (CommandSpec spec: specs) {
|
||||
Object obj = spec.userObject();
|
||||
if (obj == null) {
|
||||
all.add(spec.name() + " (no user object)");
|
||||
} else if (obj instanceof Method) {
|
||||
all.add(spec.name() + " (" + ((Method) obj).toGenericString() + ")");
|
||||
} else {
|
||||
all.add(obj.getClass().getName());
|
||||
}
|
||||
}
|
||||
config.verbose("Generating man pages for %s and all subcommands%n", all);
|
||||
}
|
||||
|
||||
private static int generateSingleManPage(Config config, CommandSpec spec) throws IOException {
|
||||
if (!mkdirs(config, config.directory)) {
|
||||
return CommandLine.ExitCode.SOFTWARE;
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
package picocli.codegen.docgen.manpage;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import picocli.CommandLine;
|
||||
import picocli.CommandLine.ArgGroup;
|
||||
import picocli.CommandLine.Command;
|
||||
import picocli.CommandLine.Option;
|
||||
import picocli.CommandLine.Parameters;
|
||||
import picocli.codegen.util.Assert;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -259,7 +262,9 @@ public class ManPageGeneratorTest {
|
||||
}
|
||||
|
||||
private String read(String resource) throws IOException {
|
||||
return readAndClose(getClass().getResourceAsStream(resource));
|
||||
URL url = ManPageGenerator.class.getResource(resource);
|
||||
Assert.notNull(url, "resource '" + resource + "'");
|
||||
return readAndClose(url.openStream());
|
||||
}
|
||||
|
||||
private String readAndClose(InputStream in) throws IOException {
|
||||
@@ -322,7 +327,7 @@ public class ManPageGeneratorTest {
|
||||
String expected = String.format("" +
|
||||
"Usage: top-level-command subcommand gen-manpage [-fhVv] [-d=<outdir>] [-t=<template-dir>]%n" +
|
||||
" [@<filename>...]%n" +
|
||||
"Generates one or more AsciiDoc files with doctype 'manpage' in the specified directory.%n" +
|
||||
"Generates man pages for all commands in the specified directory.%n" +
|
||||
" [@<filename>...] One or more argument files containing options.%n" +
|
||||
" -d, --outdir=<outdir> Output directory to write the generated AsciiDoc files to. If not%n" +
|
||||
" specified, files are written to the current directory.%n" +
|
||||
@@ -357,4 +362,70 @@ public class ManPageGeneratorTest {
|
||||
"See http://man7.org/linux/man-pages/man7/roff.7.html%n");
|
||||
assertEquals(expected, sw.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManPageGeneratorAsSubcommandParentHelp() {
|
||||
StringWriter sw = new StringWriter();
|
||||
new CommandLine(new Top()).setOut(new PrintWriter(sw, true))
|
||||
.execute("subcommand", "--help");
|
||||
String expected = String.format("" +
|
||||
"Usage: top-level-command subcommand [-hV] [COMMAND]%n" +
|
||||
"Example subcommand%n" +
|
||||
" -h, --help Show this help message and exit.%n" +
|
||||
" -V, --version Print version information and exit.%n" +
|
||||
"Commands:%n" +
|
||||
" gen-manpage Generates man pages for all commands in the specified directory.%n");
|
||||
assertEquals(expected, sw.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManPageGeneratorAsSubcommand() throws IOException {
|
||||
File outdir = new File(System.getProperty("java.io.tmpdir"), "manpage" + System.currentTimeMillis());
|
||||
outdir.mkdir();
|
||||
File templateDir = new File(outdir, "templates");
|
||||
int exitCode = new CommandLine(new Top())
|
||||
.execute("subcommand", "gen-manpage", /*"-vv",*/ "--outdir=" + outdir, "--template-dir=" + templateDir);
|
||||
try {
|
||||
assertEquals(0, exitCode);
|
||||
|
||||
//System.out.println(Arrays.asList(templateDir.listFiles()));
|
||||
//System.out.println(Arrays.asList(outdir.listFiles()));
|
||||
|
||||
String[] files = new String[] {
|
||||
"top-level-command.adoc", //
|
||||
"top-level-command-visible.adoc", //
|
||||
"top-level-command-subcommand.adoc", //
|
||||
"top-level-command-subcommand-gen-manpage.adoc"
|
||||
};
|
||||
|
||||
for (String f : files) {
|
||||
String expected = read("/manpagegenerator/templates/" + f);
|
||||
String actual = readAndClose(new FileInputStream(new File(templateDir, f)));
|
||||
|
||||
expected = expected.replace("$OUTDIR", outdir.getAbsolutePath().replace('\\', '/'));
|
||||
assertEquals("/manpagegenerator/templates/" + f, expected, actual);
|
||||
}
|
||||
|
||||
for (String f : files) {
|
||||
String expected = read("/manpagegenerator/" + f);
|
||||
String actual = readAndClose(new FileInputStream(new File(outdir, f)));
|
||||
|
||||
expected = expected.replace("$VERSION", CommandLine.VERSION);
|
||||
assertEquals("/manpagegenerator/" + f, expected, actual);
|
||||
}
|
||||
|
||||
} finally {
|
||||
for (File f : templateDir.listFiles()) {
|
||||
f.delete();
|
||||
}
|
||||
try {
|
||||
assertTrue(templateDir.getAbsolutePath(), templateDir.delete());
|
||||
} finally {
|
||||
for (File f : outdir.listFiles()) {
|
||||
f.delete();
|
||||
}
|
||||
assertTrue(outdir.getAbsolutePath(), outdir.delete());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
:includedir: $OUTDIR
|
||||
//include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-full-manpage]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-header]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-name]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-synopsis]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-description]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-options]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-arguments]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-commands]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-exit-status]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand-gen-manpage.adoc[tag=picocli-generated-man-section-footer]
|
||||
@@ -0,0 +1,20 @@
|
||||
:includedir: $OUTDIR
|
||||
//include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-full-manpage]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-header]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-name]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-synopsis]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-description]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-options]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-arguments]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-commands]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-exit-status]
|
||||
|
||||
include::{includedir}/top-level-command-subcommand.adoc[tag=picocli-generated-man-section-footer]
|
||||
@@ -0,0 +1,20 @@
|
||||
:includedir: $OUTDIR
|
||||
//include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-full-manpage]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-header]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-name]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-synopsis]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-description]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-options]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-arguments]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-commands]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-exit-status]
|
||||
|
||||
include::{includedir}/top-level-command-visible.adoc[tag=picocli-generated-man-section-footer]
|
||||
@@ -0,0 +1,20 @@
|
||||
:includedir: $OUTDIR
|
||||
//include::{includedir}/top-level-command.adoc[tag=picocli-generated-full-manpage]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-header]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-name]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-synopsis]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-description]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-options]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-arguments]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-commands]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-exit-status]
|
||||
|
||||
include::{includedir}/top-level-command.adoc[tag=picocli-generated-man-section-footer]
|
||||
@@ -0,0 +1,86 @@
|
||||
// tag::picocli-generated-full-manpage[]
|
||||
// tag::picocli-generated-man-section-header[]
|
||||
:doctype: manpage
|
||||
:revnumber: top-level-command subcommand gen-manpage $VERSION
|
||||
:manmanual: Top-level-command Manual
|
||||
:mansource: top-level-command subcommand gen-manpage $VERSION
|
||||
:man-linkstyle: pass:[blue R < >]
|
||||
= top-level-command-subcommand-gen-manpage(1)
|
||||
|
||||
// end::picocli-generated-man-section-header[]
|
||||
|
||||
// tag::picocli-generated-man-section-name[]
|
||||
== Name
|
||||
|
||||
top-level-command-subcommand-gen-manpage - Generates man pages for all commands in the specified directory.
|
||||
|
||||
// end::picocli-generated-man-section-name[]
|
||||
|
||||
// tag::picocli-generated-man-section-synopsis[]
|
||||
== Synopsis
|
||||
|
||||
*top-level-command subcommand gen-manpage* [*-fhVv*] [*-d*=_<outdir>_] [*-t*=_<template-dir>_] [_@<filename>_...]
|
||||
|
||||
// end::picocli-generated-man-section-synopsis[]
|
||||
|
||||
// tag::picocli-generated-man-section-description[]
|
||||
== Description
|
||||
|
||||
Generates man pages for all commands in the specified directory.
|
||||
|
||||
// end::picocli-generated-man-section-description[]
|
||||
|
||||
// tag::picocli-generated-man-section-options[]
|
||||
== Options
|
||||
|
||||
*-d*, *--outdir*=_<outdir>_::
|
||||
Output directory to write the generated AsciiDoc files to. If not specified, files are written to the current directory.
|
||||
|
||||
*-t*, *--template-dir*=_<template-dir>_::
|
||||
Optional directory to write customizable man page template files. If specified, an additional "template" file is created here for each generated manpage AsciiDoc file.
|
||||
+
|
||||
Each template file contains `include` directives that import content from the corresponding generated manpage AsciiDoc file in the `--outdir` directory. Text can be added after each include to customize the resulting man page. The resulting man page will be a mixture of generated and manually edited text.
|
||||
+
|
||||
These customizable templates are intended to be generated once, and afterwards be manually updated and maintained.
|
||||
|
||||
*-v*, *--verbose*::
|
||||
Specify multiple -v options to increase verbosity.
|
||||
+
|
||||
For example, `-v -v -v` or `-vvv`
|
||||
|
||||
*-f*, *--[no-]force*::
|
||||
Overwrite existing man page templates. The default is `--no-force`, meaning processing is aborted and the process exits with status code 4 if a man page template file already exists.
|
||||
|
||||
*-h*, *--help*::
|
||||
Show this help message and exit.
|
||||
|
||||
*-V*, *--version*::
|
||||
Print version information and exit.
|
||||
|
||||
// end::picocli-generated-man-section-options[]
|
||||
|
||||
// tag::picocli-generated-man-section-arguments[]
|
||||
== Arguments
|
||||
|
||||
[_@<filename>_...]::
|
||||
One or more argument files containing options.
|
||||
|
||||
// end::picocli-generated-man-section-arguments[]
|
||||
|
||||
// tag::picocli-generated-man-section-footer[]
|
||||
== Converting to Man Page Format
|
||||
|
||||
[%hardbreaks]
|
||||
Use the `asciidoctor` tool to convert the generated AsciiDoc files to man pages in roff format:
|
||||
|
||||
[%hardbreaks]
|
||||
`asciidoctor --backend=manpage --source-dir=SOURCE_DIR --destination-dir=DESTINATION *.adoc`
|
||||
|
||||
[%hardbreaks]
|
||||
Point the SOURCE_DIR to either the `--outdir` directory or the `--template-dir` directory. Use some other directory as the DESTINATION.
|
||||
See https://asciidoctor.org/docs/user-manual/#man-pages
|
||||
See http://man7.org/linux/man-pages/man7/roff.7.html
|
||||
|
||||
// end::picocli-generated-man-section-footer[]
|
||||
|
||||
// end::picocli-generated-full-manpage[]
|
||||
@@ -0,0 +1,52 @@
|
||||
// tag::picocli-generated-full-manpage[]
|
||||
// tag::picocli-generated-man-section-header[]
|
||||
:doctype: manpage
|
||||
:revnumber:
|
||||
:manmanual: Top-level-command Manual
|
||||
:mansource:
|
||||
:man-linkstyle: pass:[blue R < >]
|
||||
= top-level-command-subcommand(1)
|
||||
|
||||
// end::picocli-generated-man-section-header[]
|
||||
|
||||
// tag::picocli-generated-man-section-name[]
|
||||
== Name
|
||||
|
||||
top-level-command-subcommand - Example subcommand
|
||||
|
||||
// end::picocli-generated-man-section-name[]
|
||||
|
||||
// tag::picocli-generated-man-section-synopsis[]
|
||||
== Synopsis
|
||||
|
||||
*top-level-command subcommand* [*-hV*] [COMMAND]
|
||||
|
||||
// end::picocli-generated-man-section-synopsis[]
|
||||
|
||||
// tag::picocli-generated-man-section-description[]
|
||||
== Description
|
||||
|
||||
Example subcommand
|
||||
|
||||
// end::picocli-generated-man-section-description[]
|
||||
|
||||
// tag::picocli-generated-man-section-options[]
|
||||
== Options
|
||||
|
||||
*-h*, *--help*::
|
||||
Show this help message and exit.
|
||||
|
||||
*-V*, *--version*::
|
||||
Print version information and exit.
|
||||
|
||||
// end::picocli-generated-man-section-options[]
|
||||
|
||||
// tag::picocli-generated-man-section-commands[]
|
||||
== Commands
|
||||
|
||||
*gen-manpage*::
|
||||
Generates man pages for all commands in the specified directory.
|
||||
|
||||
// end::picocli-generated-man-section-commands[]
|
||||
|
||||
// end::picocli-generated-full-manpage[]
|
||||
@@ -0,0 +1,44 @@
|
||||
// tag::picocli-generated-full-manpage[]
|
||||
// tag::picocli-generated-man-section-header[]
|
||||
:doctype: manpage
|
||||
:revnumber:
|
||||
:manmanual: Top-level-command Manual
|
||||
:mansource:
|
||||
:man-linkstyle: pass:[blue R < >]
|
||||
= top-level-command-visible(1)
|
||||
|
||||
// end::picocli-generated-man-section-header[]
|
||||
|
||||
// tag::picocli-generated-man-section-name[]
|
||||
== Name
|
||||
|
||||
top-level-command-visible - Example visible subcommand
|
||||
|
||||
// end::picocli-generated-man-section-name[]
|
||||
|
||||
// tag::picocli-generated-man-section-synopsis[]
|
||||
== Synopsis
|
||||
|
||||
*top-level-command visible* [*-hV*]
|
||||
|
||||
// end::picocli-generated-man-section-synopsis[]
|
||||
|
||||
// tag::picocli-generated-man-section-description[]
|
||||
== Description
|
||||
|
||||
Example visible subcommand
|
||||
|
||||
// end::picocli-generated-man-section-description[]
|
||||
|
||||
// tag::picocli-generated-man-section-options[]
|
||||
== Options
|
||||
|
||||
*-h*, *--help*::
|
||||
Show this help message and exit.
|
||||
|
||||
*-V*, *--version*::
|
||||
Print version information and exit.
|
||||
|
||||
// end::picocli-generated-man-section-options[]
|
||||
|
||||
// end::picocli-generated-full-manpage[]
|
||||
@@ -0,0 +1,58 @@
|
||||
// tag::picocli-generated-full-manpage[]
|
||||
// tag::picocli-generated-man-section-header[]
|
||||
:doctype: manpage
|
||||
:revnumber:
|
||||
:manmanual: Top-level-command Manual
|
||||
:mansource:
|
||||
:man-linkstyle: pass:[blue R < >]
|
||||
= top-level-command(1)
|
||||
|
||||
// end::picocli-generated-man-section-header[]
|
||||
|
||||
// tag::picocli-generated-man-section-name[]
|
||||
== Name
|
||||
|
||||
top-level-command - example top-level command
|
||||
|
||||
// end::picocli-generated-man-section-name[]
|
||||
|
||||
// tag::picocli-generated-man-section-synopsis[]
|
||||
== Synopsis
|
||||
|
||||
*top-level-command* [*-hV*] [*-x*=_<x>_] [COMMAND]
|
||||
|
||||
// end::picocli-generated-man-section-synopsis[]
|
||||
|
||||
// tag::picocli-generated-man-section-description[]
|
||||
== Description
|
||||
|
||||
example top-level command
|
||||
|
||||
// end::picocli-generated-man-section-description[]
|
||||
|
||||
// tag::picocli-generated-man-section-options[]
|
||||
== Options
|
||||
|
||||
*-h*, *--help*::
|
||||
Show this help message and exit.
|
||||
|
||||
*-V*, *--version*::
|
||||
Print version information and exit.
|
||||
|
||||
*-x*, *--long-option*=_<x>_::
|
||||
Some example option
|
||||
|
||||
// end::picocli-generated-man-section-options[]
|
||||
|
||||
// tag::picocli-generated-man-section-commands[]
|
||||
== Commands
|
||||
|
||||
*subcommand*::
|
||||
Example subcommand
|
||||
|
||||
*visible*::
|
||||
Example visible subcommand
|
||||
|
||||
// end::picocli-generated-man-section-commands[]
|
||||
|
||||
// end::picocli-generated-full-manpage[]
|
||||
Reference in New Issue
Block a user