1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.cling.invoker;
20
21 import java.io.PrintWriter;
22 import java.util.LinkedHashSet;
23 import java.util.Map;
24 import java.util.Optional;
25 import java.util.Set;
26
27 import org.apache.commons.cli.CommandLine;
28 import org.apache.commons.cli.DefaultParser;
29 import org.apache.commons.cli.DeprecatedAttributes;
30 import org.apache.commons.cli.HelpFormatter;
31 import org.apache.commons.cli.Option;
32 import org.apache.commons.cli.ParseException;
33 import org.apache.maven.api.cli.Options;
34 import org.apache.maven.api.cli.ParserRequest;
35 import org.apache.maven.cli.CleanArgument;
36 import org.apache.maven.jline.MessageUtils;
37
38 import static java.util.Objects.requireNonNull;
39 import static org.apache.maven.cling.invoker.Utils.toMap;
40
41 public abstract class CommonsCliOptions implements Options {
42
43 protected final String source;
44 protected final CLIManager cliManager;
45 protected final CommandLine commandLine;
46
47 protected CommonsCliOptions(String source, CLIManager cliManager, CommandLine commandLine) {
48 this.source = requireNonNull(source);
49 this.cliManager = requireNonNull(cliManager);
50 this.commandLine = requireNonNull(commandLine);
51 }
52
53 @Override
54 public String source() {
55 return source;
56 }
57
58 @Override
59 public Optional<Map<String, String>> userProperties() {
60 if (commandLine.hasOption(CLIManager.USER_PROPERTY)) {
61 return Optional.of(toMap(commandLine.getOptionProperties(CLIManager.USER_PROPERTY)));
62 }
63 return Optional.empty();
64 }
65
66 @Override
67 public Optional<Boolean> showVersionAndExit() {
68 if (commandLine.hasOption(CLIManager.SHOW_VERSION_AND_EXIT)) {
69 return Optional.of(Boolean.TRUE);
70 }
71 return Optional.empty();
72 }
73
74 @Override
75 public Optional<Boolean> showVersion() {
76 if (commandLine.hasOption(CLIManager.SHOW_VERSION)) {
77 return Optional.of(Boolean.TRUE);
78 }
79 return Optional.empty();
80 }
81
82 @Override
83 public Optional<Boolean> quiet() {
84 if (commandLine.hasOption(CLIManager.QUIET)) {
85 return Optional.of(Boolean.TRUE);
86 }
87 return Optional.empty();
88 }
89
90 @Override
91 public Optional<Boolean> verbose() {
92 if (commandLine.hasOption(CLIManager.VERBOSE) || commandLine.hasOption(CLIManager.DEBUG)) {
93 return Optional.of(Boolean.TRUE);
94 }
95 return Optional.empty();
96 }
97
98 @Override
99 public Optional<Boolean> showErrors() {
100 if (commandLine.hasOption(CLIManager.SHOW_ERRORS) || verbose().orElse(false)) {
101 return Optional.of(Boolean.TRUE);
102 }
103 return Optional.empty();
104 }
105
106 @Override
107 public Optional<String> failOnSeverity() {
108 if (commandLine.hasOption(CLIManager.FAIL_ON_SEVERITY)) {
109 return Optional.of(commandLine.getOptionValue(CLIManager.FAIL_ON_SEVERITY));
110 }
111 return Optional.empty();
112 }
113
114 @Override
115 public Optional<Boolean> nonInteractive() {
116 if (commandLine.hasOption(CLIManager.NON_INTERACTIVE) || commandLine.hasOption(CLIManager.BATCH_MODE)) {
117 return Optional.of(Boolean.TRUE);
118 }
119 return Optional.empty();
120 }
121
122 @Override
123 public Optional<Boolean> forceInteractive() {
124 if (commandLine.hasOption(CLIManager.FORCE_INTERACTIVE)) {
125 return Optional.of(Boolean.TRUE);
126 }
127 return Optional.empty();
128 }
129
130 @Override
131 public Optional<String> altUserSettings() {
132 if (commandLine.hasOption(CLIManager.ALTERNATE_USER_SETTINGS)) {
133 return Optional.of(commandLine.getOptionValue(CLIManager.ALTERNATE_USER_SETTINGS));
134 }
135 return Optional.empty();
136 }
137
138 @Override
139 public Optional<String> altProjectSettings() {
140 if (commandLine.hasOption(CLIManager.ALTERNATE_PROJECT_SETTINGS)) {
141 return Optional.of(commandLine.getOptionValue(CLIManager.ALTERNATE_PROJECT_SETTINGS));
142 }
143 return Optional.empty();
144 }
145
146 @Override
147 public Optional<String> altInstallationSettings() {
148 if (commandLine.hasOption(CLIManager.ALTERNATE_INSTALLATION_SETTINGS)) {
149 return Optional.of(commandLine.getOptionValue(CLIManager.ALTERNATE_INSTALLATION_SETTINGS));
150 }
151 if (commandLine.hasOption(CLIManager.ALTERNATE_GLOBAL_SETTINGS)) {
152 return Optional.of(commandLine.getOptionValue(CLIManager.ALTERNATE_GLOBAL_SETTINGS));
153 }
154 return Optional.empty();
155 }
156
157 @Override
158 public Optional<String> altUserToolchains() {
159 if (commandLine.hasOption(CLIManager.ALTERNATE_USER_TOOLCHAINS)) {
160 return Optional.of(commandLine.getOptionValue(CLIManager.ALTERNATE_USER_TOOLCHAINS));
161 }
162 return Optional.empty();
163 }
164
165 @Override
166 public Optional<String> altInstallationToolchains() {
167 if (commandLine.hasOption(CLIManager.ALTERNATE_INSTALLATION_TOOLCHAINS)) {
168 return Optional.of(commandLine.getOptionValue(CLIManager.ALTERNATE_INSTALLATION_TOOLCHAINS));
169 }
170 if (commandLine.hasOption(CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS)) {
171 return Optional.of(commandLine.getOptionValue(CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS));
172 }
173 return Optional.empty();
174 }
175
176 @Override
177 public Optional<String> logFile() {
178 if (commandLine.hasOption(CLIManager.LOG_FILE)) {
179 return Optional.of(commandLine.getOptionValue(CLIManager.LOG_FILE));
180 }
181 return Optional.empty();
182 }
183
184 @Override
185 public Optional<Boolean> rawStreams() {
186 if (commandLine.hasOption(CLIManager.RAW_STREAMS)) {
187 return Optional.of(Boolean.TRUE);
188 }
189 return Optional.empty();
190 }
191
192 @Override
193 public Optional<String> color() {
194 if (commandLine.hasOption(CLIManager.COLOR)) {
195 if (commandLine.getOptionValue(CLIManager.COLOR) != null) {
196 return Optional.of(commandLine.getOptionValue(CLIManager.COLOR));
197 } else {
198 return Optional.of("auto");
199 }
200 }
201 return Optional.empty();
202 }
203
204 @Override
205 public Optional<Boolean> help() {
206 if (commandLine.hasOption(CLIManager.HELP)) {
207 return Optional.of(Boolean.TRUE);
208 }
209 return Optional.empty();
210 }
211
212 @Override
213 public void warnAboutDeprecatedOptions(ParserRequest request, PrintWriter printWriter) {
214 if (cliManager.getUsedDeprecatedOptions().isEmpty()) {
215 return;
216 }
217 printWriter.println("Detected deprecated option use in " + source);
218 for (Option option : cliManager.getUsedDeprecatedOptions()) {
219 StringBuilder sb = new StringBuilder();
220 sb.append("The option -").append(option.getOpt());
221 if (option.getLongOpt() != null) {
222 sb.append(",--").append(option.getLongOpt());
223 }
224 sb.append(" is deprecated ");
225 if (option.getDeprecated().isForRemoval()) {
226 sb.append("and will be removed in a future version");
227 }
228 if (option.getDeprecated().getSince() != null) {
229 sb.append("since ")
230 .append(request.commandName())
231 .append(" ")
232 .append(option.getDeprecated().getSince());
233 }
234 printWriter.println(sb);
235 }
236 }
237
238 @Override
239 public void displayHelp(ParserRequest request, PrintWriter printStream) {
240 cliManager.displayHelp(request.command(), printStream);
241 }
242
243 protected static class CLIManager {
244 public static final String USER_PROPERTY = "D";
245 public static final String SHOW_VERSION_AND_EXIT = "v";
246 public static final String SHOW_VERSION = "V";
247 public static final String QUIET = "q";
248 public static final String VERBOSE = "X";
249
250
251 @Deprecated
252 public static final String DEBUG = "debug";
253
254 public static final String SHOW_ERRORS = "e";
255 public static final String FAIL_ON_SEVERITY = "fos";
256 public static final String NON_INTERACTIVE = "non-interactive";
257 public static final String BATCH_MODE = "B";
258 public static final String FORCE_INTERACTIVE = "force-interactive";
259 public static final String ALTERNATE_USER_SETTINGS = "s";
260 public static final String ALTERNATE_PROJECT_SETTINGS = "ps";
261
262 @Deprecated
263 public static final String ALTERNATE_GLOBAL_SETTINGS = "gs";
264
265 public static final String ALTERNATE_INSTALLATION_SETTINGS = "is";
266 public static final String ALTERNATE_USER_TOOLCHAINS = "t";
267
268 @Deprecated
269 public static final String ALTERNATE_GLOBAL_TOOLCHAINS = "gt";
270
271 public static final String ALTERNATE_INSTALLATION_TOOLCHAINS = "it";
272 public static final String LOG_FILE = "l";
273 public static final String RAW_STREAMS = "raw-streams";
274 public static final String COLOR = "color";
275 public static final String HELP = "h";
276
277 protected org.apache.commons.cli.Options options;
278 protected final LinkedHashSet<Option> usedDeprecatedOptions = new LinkedHashSet<>();
279
280 @SuppressWarnings("checkstyle:MethodLength")
281 protected CLIManager() {
282 options = new org.apache.commons.cli.Options();
283 prepareOptions(options);
284 }
285
286 protected void prepareOptions(org.apache.commons.cli.Options options) {
287 options.addOption(Option.builder(HELP)
288 .longOpt("help")
289 .desc("Display help information")
290 .build());
291 options.addOption(Option.builder(USER_PROPERTY)
292 .numberOfArgs(2)
293 .valueSeparator('=')
294 .desc("Define a user property")
295 .build());
296 options.addOption(Option.builder(SHOW_VERSION_AND_EXIT)
297 .longOpt("version")
298 .desc("Display version information")
299 .build());
300 options.addOption(Option.builder(QUIET)
301 .longOpt("quiet")
302 .desc("Quiet output - only show errors")
303 .build());
304 options.addOption(Option.builder(VERBOSE)
305 .longOpt("verbose")
306 .desc("Produce execution verbose output")
307 .build());
308 options.addOption(Option.builder(SHOW_ERRORS)
309 .longOpt("errors")
310 .desc("Produce execution error messages")
311 .build());
312 options.addOption(Option.builder(BATCH_MODE)
313 .longOpt("batch-mode")
314 .desc("Run in non-interactive mode. Alias for --non-interactive (kept for backwards compatability)")
315 .build());
316 options.addOption(Option.builder()
317 .longOpt(NON_INTERACTIVE)
318 .desc("Run in non-interactive mode. Alias for --batch-mode")
319 .build());
320 options.addOption(Option.builder()
321 .longOpt(FORCE_INTERACTIVE)
322 .desc(
323 "Run in interactive mode. Overrides, if applicable, the CI environment variable and --non-interactive/--batch-mode options")
324 .build());
325 options.addOption(Option.builder(ALTERNATE_USER_SETTINGS)
326 .longOpt("settings")
327 .desc("Alternate path for the user settings file")
328 .hasArg()
329 .build());
330 options.addOption(Option.builder(ALTERNATE_PROJECT_SETTINGS)
331 .longOpt("project-settings")
332 .desc("Alternate path for the project settings file")
333 .hasArg()
334 .build());
335 options.addOption(Option.builder(ALTERNATE_INSTALLATION_SETTINGS)
336 .longOpt("install-settings")
337 .desc("Alternate path for the installation settings file")
338 .hasArg()
339 .build());
340 options.addOption(Option.builder(ALTERNATE_USER_TOOLCHAINS)
341 .longOpt("toolchains")
342 .desc("Alternate path for the user toolchains file")
343 .hasArg()
344 .build());
345 options.addOption(Option.builder(ALTERNATE_INSTALLATION_TOOLCHAINS)
346 .longOpt("install-toolchains")
347 .desc("Alternate path for the installation toolchains file")
348 .hasArg()
349 .build());
350 options.addOption(Option.builder(FAIL_ON_SEVERITY)
351 .longOpt("fail-on-severity")
352 .desc("Configure which severity of logging should cause the build to fail")
353 .hasArg()
354 .build());
355 options.addOption(Option.builder(LOG_FILE)
356 .longOpt("log-file")
357 .hasArg()
358 .desc("Log file where all build output will go (disables output color)")
359 .build());
360 options.addOption(Option.builder()
361 .longOpt(RAW_STREAMS)
362 .desc("Do not decorate standard output and error streams")
363 .build());
364 options.addOption(Option.builder(SHOW_VERSION)
365 .longOpt("show-version")
366 .desc("Display version information WITHOUT stopping build")
367 .build());
368 options.addOption(Option.builder()
369 .longOpt(COLOR)
370 .hasArg()
371 .optionalArg(true)
372 .desc("Defines the color mode of the output. Supported are 'auto', 'always', 'never'.")
373 .build());
374
375
376 options.addOption(Option.builder()
377 .longOpt(DEBUG)
378 .desc("<deprecated> Produce execution verbose output.")
379 .deprecated(DeprecatedAttributes.builder()
380 .setForRemoval(true)
381 .setSince("4.0.0")
382 .setDescription("Use -X,--verbose instead.")
383 .get())
384 .build());
385 options.addOption(Option.builder(ALTERNATE_GLOBAL_SETTINGS)
386 .longOpt("global-settings")
387 .desc("<deprecated> Alternate path for the global settings file.")
388 .hasArg()
389 .deprecated(DeprecatedAttributes.builder()
390 .setForRemoval(true)
391 .setSince("4.0.0")
392 .setDescription("Use -is,--install-settings instead.")
393 .get())
394 .build());
395 options.addOption(Option.builder(ALTERNATE_GLOBAL_TOOLCHAINS)
396 .longOpt("global-toolchains")
397 .desc("<deprecated> Alternate path for the global toolchains file.")
398 .hasArg()
399 .deprecated(DeprecatedAttributes.builder()
400 .setForRemoval(true)
401 .setSince("4.0.0")
402 .setDescription("Use -it,--install-toolchains instead.")
403 .get())
404 .build());
405 }
406
407 public CommandLine parse(String[] args) throws ParseException {
408
409 String[] cleanArgs = CleanArgument.cleanArgs(args);
410 DefaultParser parser = DefaultParser.builder()
411 .setDeprecatedHandler(usedDeprecatedOptions::add)
412 .build();
413 CommandLine commandLine = parser.parse(options, cleanArgs);
414
415 options.getOptions().forEach(commandLine::hasOption);
416 return commandLine;
417 }
418
419 public org.apache.commons.cli.Options getOptions() {
420 return options;
421 }
422
423 public Set<Option> getUsedDeprecatedOptions() {
424 return usedDeprecatedOptions;
425 }
426
427 public void displayHelp(String command, PrintWriter pw) {
428 HelpFormatter formatter = new HelpFormatter();
429
430 int width = MessageUtils.getTerminalWidth();
431 if (width <= 0) {
432 width = HelpFormatter.DEFAULT_WIDTH;
433 }
434
435 pw.println();
436
437 formatter.printHelp(
438 pw,
439 width,
440 commandLineSyntax(command),
441 System.lineSeparator() + "Options:",
442 options,
443 HelpFormatter.DEFAULT_LEFT_PAD,
444 HelpFormatter.DEFAULT_DESC_PAD,
445 System.lineSeparator(),
446 false);
447
448 pw.flush();
449 }
450
451 protected String commandLineSyntax(String command) {
452 return command + " [options] [goals]";
453 }
454 }
455 }