]> git.argeo.org Git - lgpl/argeo-commons.git/blob - HelpCommand.java
cd51d76953b6e4f63b23914ad9edbac4313e45dd
[lgpl/argeo-commons.git] / HelpCommand.java
1 package org.argeo.api.cli;
2
3 import java.io.PrintWriter;
4 import java.io.StringWriter;
5 import java.util.List;
6 import java.util.function.Function;
7
8 import org.apache.commons.cli.HelpFormatter;
9 import org.apache.commons.cli.Option;
10 import org.apache.commons.cli.Options;
11
12 /** A special command that can describe {@link DescribedCommand}. */
13 public class HelpCommand implements DescribedCommand<String> {
14 /**
15 * System property forcing the root command to this value (typically the name of
16 * a script).
17 */
18 public final static String ROOT_COMMAND_PROPERTY = "org.argeo.api.cli.rootCommand";
19
20 final static String HELP = "help";
21 final static Option HELP_OPTION = Option.builder().longOpt(HELP).desc("print this help").build();
22
23 private CommandsCli commandsCli;
24 private CommandsCli parentCommandsCli;
25
26 // Help formatting
27 private static int helpWidth = 80;
28 private static int helpLeftPad = 4;
29 private static int helpDescPad = 20;
30
31 public HelpCommand(CommandsCli parentCommandsCli, CommandsCli commandsCli) {
32 super();
33 this.parentCommandsCli = parentCommandsCli;
34 this.commandsCli = commandsCli;
35 }
36
37 @Override
38 public String apply(List<String> args) {
39 StringWriter out = new StringWriter();
40
41 if (args.size() == 0) {// overview
42 printHelp(commandsCli, out);
43 } else {
44 String cmd = args.get(0);
45 Function<List<String>, ?> function = commandsCli.getCommand(cmd);
46 if (function == null)
47 return "Command " + cmd + " not found.";
48 Options options;
49 String examples;
50 DescribedCommand<?> command = null;
51 if (function instanceof DescribedCommand) {
52 command = (DescribedCommand<?>) function;
53 options = command.getOptions();
54 examples = command.getExamples();
55 } else {
56 options = new Options();
57 examples = null;
58 }
59 String description = getShortDescription(function);
60 String commandCall = getCommandUsage(cmd, command);
61 HelpFormatter formatter = new HelpFormatter();
62 formatter.printHelp(new PrintWriter(out), helpWidth, commandCall, description, options, helpLeftPad,
63 helpDescPad, examples, false);
64 }
65 return out.toString();
66 }
67
68 private static String getShortDescription(Function<List<String>, ?> function) {
69 if (function instanceof DescribedCommand) {
70 return ((DescribedCommand<?>) function).getDescription();
71 } else {
72 return function.toString();
73 }
74 }
75
76 public String getCommandUsage(String cmd, DescribedCommand<?> command) {
77 String commandCall = getCommandCall(commandsCli) + " " + cmd;
78 assert command != null;
79 if (command != null && command.getUsage() != null) {
80 commandCall = commandCall + " " + command.getUsage();
81 }
82 return commandCall;
83 }
84
85 @Override
86 public String getDescription() {
87 return "Shows this help or describes a command";
88 }
89
90 @Override
91 public String getUsage() {
92 return "[command]";
93 }
94
95 public CommandsCli getParentCommandsCli() {
96 return parentCommandsCli;
97 }
98
99 protected String getCommandCall(CommandsCli commandsCli) {
100 HelpCommand hc = commandsCli.getHelpCommand();
101 if (hc.getParentCommandsCli() != null) {
102 return getCommandCall(hc.getParentCommandsCli()) + " " + commandsCli.getCommandName();
103 } else {
104 String rootCommand = System.getProperty(ROOT_COMMAND_PROPERTY);
105 if (rootCommand != null)
106 return rootCommand;
107 return commandsCli.getCommandName();
108 }
109 }
110
111 public static void printHelp(DescribedCommand<?> command, StringWriter out) {
112 String usage = "java " + command.getClass().getName()
113 + (command.getUsage() != null ? " " + command.getUsage() : "");
114 HelpFormatter formatter = new HelpFormatter();
115 Options options = command.getOptions();
116 options.addOption(HelpCommand.HELP_OPTION);
117 formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), options, helpLeftPad,
118 helpDescPad, command.getExamples(), false);
119
120 }
121
122 public static void printHelp(CommandsCli commandsCli, String commandName, StringWriter out) {
123 if (commandName == null) {
124 printHelp(commandsCli, out);
125 return;
126 }
127 DescribedCommand<?> command = (DescribedCommand<?>) commandsCli.getCommand(commandName);
128 String usage = commandsCli.getHelpCommand().getCommandUsage(commandName, command);
129 HelpFormatter formatter = new HelpFormatter();
130 Options options = command.getOptions();
131 options.addOption(HelpCommand.HELP_OPTION);
132 formatter.printHelp(new PrintWriter(out), helpWidth, usage, command.getDescription(), options, helpLeftPad,
133 helpDescPad, command.getExamples(), false);
134
135 }
136
137 public static void printHelp(CommandsCli commandsCli, StringWriter out) {
138 out.append(commandsCli.getDescription()).append('\n');
139 String leftPad = spaces(helpLeftPad);
140 for (String cmd : commandsCli.getSubCommands()) {
141 Function<List<String>, ?> function = commandsCli.getCommand(cmd);
142 assert function != null;
143 out.append(leftPad);
144 out.append(cmd);
145 // TODO deal with long commands
146 out.append(spaces(helpDescPad - cmd.length()));
147 out.append(getShortDescription(function));
148 out.append('\n');
149 }
150 }
151
152 private static String spaces(int count) {
153 // Java 11
154 // return " ".repeat(count);
155 if (count <= 0)
156 return "";
157 else {
158 StringBuilder sb = new StringBuilder(count);
159 for (int i = 0; i < count; i++)
160 sb.append(' ');
161 return sb.toString();
162 }
163 }
164 }