Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Excludes hidden options, params, and subcommands from man page generation #1064

Merged
merged 6 commits into from
May 28, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ static int generateManPage(Config config, CommandSpec... specs) throws IOExcepti
// recursively create man pages for subcommands
for (CommandLine sub : spec.subcommands().values()) {
CommandSpec subSpec = sub.getCommandSpec();
if (done.contains(subSpec)) {continue;}
if (done.contains(subSpec) || subSpec.usageMessage().hidden()) {continue;}
done.add(subSpec);
result = generateManPage(config, subSpec);
if (result != CommandLine.ExitCode.OK) {
Expand Down Expand Up @@ -370,20 +370,26 @@ private static String headerDescriptionString(CommandSpec spec) {
}

static void genOptions(PrintWriter pw, CommandSpec spec) {
if (spec.options().isEmpty()) {
return;
List<OptionSpec> options = new ArrayList<OptionSpec>(spec.options()); // options are stored in order of declaration

// remove hidden options
for (Iterator<OptionSpec> iter = options.iterator(); iter.hasNext();) {
if (iter.next().hidden()) { iter.remove(); }
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe this is the right approach, but we should do this at the top of this method, before rendering the == Options header.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh, I missed that one, i just pushed an update

pw.printf("// tag::picocli-generated-man-section-options[]%n");
pw.printf("== Options%n");

IOptionRenderer optionRenderer = spec.commandLine().getHelp().createDefaultOptionRenderer();
IParamLabelRenderer paramLabelRenderer = spec.commandLine().getHelp().createDefaultParamLabelRenderer();
IParameterRenderer parameterRenderer = spec.commandLine().getHelp().createDefaultParameterRenderer();

List<OptionSpec> options = new ArrayList<OptionSpec>(spec.options()); // options are stored in order of declaration
List<ArgGroupSpec> groups = optionListGroups(spec);
for (ArgGroupSpec group : groups) { options.removeAll(group.options()); }

if (spec.options().isEmpty()) {
return;
}
pw.printf("// tag::picocli-generated-man-section-options[]%n");
pw.printf("== Options%n");

Comparator<OptionSpec> optionSort = spec.usageMessage().sortOptions()
? new SortByShortestOptionNameAlphabetically()
: createOrderComparatorIfNecessary(spec.options());
Expand All @@ -402,7 +408,9 @@ static void genOptions(PrintWriter pw, CommandSpec spec) {
pw.printf("== %s%n", COLOR_SCHEME.text(heading));

for (PositionalParamSpec positional : group.positionalParameters()) {
writePositional(pw, positional, parameterRenderer, paramLabelRenderer);
if (!positional.hidden()) {
writePositional(pw, positional, parameterRenderer, paramLabelRenderer);
}
}
List<OptionSpec> groupOptions = new ArrayList<OptionSpec>(group.options());
if (optionSort != null) {
Expand Down Expand Up @@ -451,7 +459,17 @@ private static void writePositional(PrintWriter pw, PositionalParamSpec position
}

static void genPositionalArgs(PrintWriter pw, CommandSpec spec) {
if (spec.positionalParameters().isEmpty() && !spec.usageMessage().showAtFileInUsageHelp()) {
List<PositionalParamSpec> positionals = new ArrayList<PositionalParamSpec>(spec.positionalParameters());
// remove hidden params
for (Iterator<PositionalParamSpec> iter = positionals.iterator(); iter.hasNext();) {
if (iter.next().hidden()) { iter.remove(); }
}
// positional parameters that are part of a group
// are shown in the custom option section for that group
List<ArgGroupSpec> groups = optionListGroups(spec);
for (ArgGroupSpec group : groups) { positionals.removeAll(group.positionalParameters()); }

if (positionals.isEmpty() && !spec.usageMessage().showAtFileInUsageHelp()) {
return;
}
pw.printf("// tag::picocli-generated-man-section-arguments[]%n");
Expand All @@ -466,12 +484,6 @@ static void genPositionalArgs(PrintWriter pw, CommandSpec spec) {
writePositional(pw, help.AT_FILE_POSITIONAL_PARAM, parameterRenderer, paramLabelRenderer);
}

// positional parameters that are part of a group
// are shown in the custom option section for that group
List<PositionalParamSpec> positionals = new ArrayList<PositionalParamSpec>(spec.positionalParameters());
List<ArgGroupSpec> groups = optionListGroups(spec);
for (ArgGroupSpec group : groups) { positionals.removeAll(group.positionalParameters()); }

for (PositionalParamSpec positional : positionals) {
writePositional(pw, positional, parameterRenderer, paramLabelRenderer);
}
Expand All @@ -481,6 +493,15 @@ static void genPositionalArgs(PrintWriter pw, CommandSpec spec) {
}

static void genCommands(PrintWriter pw, CommandSpec spec) {

// remove hidden subcommands before tags are added
Map<String, CommandLine> subCommands = new LinkedHashMap<String, CommandLine>(spec.subcommands());
for (Iterator<Map.Entry<String, CommandLine>> iter = subCommands.entrySet().iterator(); iter.hasNext();) {
if (iter.next().getValue().getCommandSpec().usageMessage().hidden()) {
iter.remove();
}
}

if (spec.subcommands().isEmpty()) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@

public class ManPageGeneratorTest {

@Test
public void main() {
}

@Test
public void generateManPage() throws IOException {
@Command(name = "myapp", mixinStandardHelpOptions = true,
Expand Down Expand Up @@ -153,6 +149,53 @@ public void setVerbosity(boolean[] verbosity) {
assertEquals(expected, sw.toString());
}

@Test
public void testHidden() throws IOException {

@Command(name = "a-sub", mixinStandardHelpOptions = true, description = "A sub command")
class ASubCommand {
@Option(names = "input-a")
String inputA;
}

@Command(name = "hidden-sub", mixinStandardHelpOptions = true, hidden = true)
class HiddenSubCommand {
@Option(names = "input-b")
String inputB;
}

@Command(name = "testHidden", mixinStandardHelpOptions = true,
version = {
"Versioned Command 1.0",
"Picocli " + picocli.CommandLine.VERSION,
"JVM: ${java.version} (${java.vendor} ${java.vm.name} ${java.vm.version})",
"OS: ${os.name} ${os.version} ${os.arch}"},
description = "This app does great things.",
subcommands = { ASubCommand.class, HiddenSubCommand.class }

)
class MyApp {
@Option(names = {"-o", "--output"}, description = "Output location full path.")
File outputFolder;

@Option(names = {"--hidden-test"}, hidden = true)
File hidden;

@Parameters(hidden = true)
List<String> values;
}

StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw); //System.out, true
ManPageGenerator.writeSingleManPage(pw, new CommandLine(new MyApp()).getCommandSpec());
pw.flush();

String expected = read("/testHidden.manpage.adoc");
expected = expected.replace("\r\n", "\n");
expected = expected.replace("\n", System.getProperty("line.separator"));
assertEquals(expected, sw.toString());
}

private String read(String resource) throws IOException {
return readAndClose(getClass().getResourceAsStream(resource));
}
Expand Down
55 changes: 55 additions & 0 deletions picocli-codegen/src/test/resources/testHidden.manpage.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
// tag::picocli-generated-full-manpage[]
// tag::picocli-generated-man-section-header[]
:doctype: manpage
:revnumber: Versioned Command 1.0
:manmanual: TestHidden Manual
:mansource: Versioned Command 1.0
:man-linkstyle: pass:[blue R < >]
= testHidden(1)

// end::picocli-generated-man-section-header[]

// tag::picocli-generated-man-section-name[]
== Name

testHidden - This app does great things.

// end::picocli-generated-man-section-name[]

// tag::picocli-generated-man-section-synopsis[]
== Synopsis

*testHidden* [*-hV*] [*-o*=_<outputFolder>_] [COMMAND]

// end::picocli-generated-man-section-synopsis[]

// tag::picocli-generated-man-section-description[]
== Description

This app does great things.

// end::picocli-generated-man-section-description[]

// tag::picocli-generated-man-section-options[]
== Options

*-h*, *--help*::
Show this help message and exit.

*-o*, *--output*=_<outputFolder>_::
Output location full path.

*-V*, *--version*::
Print version information and exit.

// end::picocli-generated-man-section-options[]

// tag::picocli-generated-man-section-commands[]
== Commands

*a-sub*::
A sub command

// end::picocli-generated-man-section-commands[]

// end::picocli-generated-full-manpage[]