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