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> help() {
207 if (commandLine.hasOption(CLIManager.HELP)) {
208 return Optional.of(Boolean.TRUE);
209 }
210 return Optional.empty();
211 }
212
213 @Override
214 public void warnAboutDeprecatedOptions(ParserRequest request, Consumer<String> printWriter) {
215 if (cliManager.getUsedDeprecatedOptions().isEmpty()) {
216 return;
217 }
218 printWriter.accept("Detected deprecated option use in " + source);
219 for (Option option : cliManager.getUsedDeprecatedOptions()) {
220 StringBuilder sb = new StringBuilder();
221 sb.append("The option ");
222 if (option.getOpt() != null) {
223 sb.append("-").append(option.getOpt());
224 }
225 if (option.getLongOpt() != null) {
226 if (option.getOpt() != null) {
227 sb.append(",");
228 }
229 sb.append("--").append(option.getLongOpt());
230 }
231 sb.append(" is deprecated ");
232 if (option.getDeprecated().isForRemoval()) {
233 sb.append("and will be removed in a future version");
234 }
235 if (option.getDeprecated().getSince() != null) {
236 sb.append(" since ")
237 .append(request.commandName())
238 .append(" ")
239 .append(option.getDeprecated().getSince());
240 }
241 printWriter.accept(sb.toString());
242 }
243 }
244
245 @Override
246 public void displayHelp(ParserRequest request, Consumer<String> printStream) {
247 cliManager.displayHelp(request.command(), printStream);
248 }
249
250 protected static class CLIManager {
251 public static final String USER_PROPERTY = "D";
252 public static final String SHOW_VERSION_AND_EXIT = "v";
253 public static final String SHOW_VERSION = "V";
254 public static final String QUIET = "q";
255 public static final String VERBOSE = "X";
256
257 public static final String SHOW_ERRORS = "e";
258 public static final String FAIL_ON_SEVERITY = "fos";
259 public static final String NON_INTERACTIVE = "non-interactive";
260 public static final String BATCH_MODE = "B";
261 public static final String FORCE_INTERACTIVE = "force-interactive";
262 public static final String ALTERNATE_USER_SETTINGS = "s";
263 public static final String ALTERNATE_PROJECT_SETTINGS = "ps";
264 public static final String ALTERNATE_INSTALLATION_SETTINGS = "is";
265 public static final String ALTERNATE_USER_TOOLCHAINS = "t";
266 public static final String ALTERNATE_INSTALLATION_TOOLCHAINS = "it";
267 public static final String LOG_FILE = "l";
268 public static final String RAW_STREAMS = "raw-streams";
269 public static final String COLOR = "color";
270 public static final String HELP = "h";
271
272
273 public static final String DEBUG = "debug";
274 public static final String ENC = "enc";
275 public static final String YJP = "yjp";
276
277
278 @Deprecated
279 public static final String ALTERNATE_GLOBAL_SETTINGS = "gs";
280
281 @Deprecated
282 public static final String ALTERNATE_GLOBAL_TOOLCHAINS = "gt";
283
284 protected org.apache.commons.cli.Options options;
285 protected final LinkedHashSet<Option> usedDeprecatedOptions = new LinkedHashSet<>();
286
287 @SuppressWarnings("checkstyle:MethodLength")
288 protected CLIManager() {
289 options = new org.apache.commons.cli.Options();
290 prepareOptions(options);
291 }
292
293 protected void prepareOptions(org.apache.commons.cli.Options options) {
294 options.addOption(Option.builder(HELP)
295 .longOpt("help")
296 .desc("Display help information")
297 .build());
298 options.addOption(Option.builder(USER_PROPERTY)
299 .numberOfArgs(2)
300 .valueSeparator('=')
301 .desc("Define a user property")
302 .build());
303 options.addOption(Option.builder(SHOW_VERSION_AND_EXIT)
304 .longOpt("version")
305 .desc("Display version information")
306 .build());
307 options.addOption(Option.builder(QUIET)
308 .longOpt("quiet")
309 .desc("Quiet output - only show errors")
310 .build());
311 options.addOption(Option.builder(VERBOSE)
312 .longOpt("verbose")
313 .desc("Produce execution verbose output")
314 .build());
315 options.addOption(Option.builder(SHOW_ERRORS)
316 .longOpt("errors")
317 .desc("Produce execution error messages")
318 .build());
319 options.addOption(Option.builder(BATCH_MODE)
320 .longOpt("batch-mode")
321 .desc("Run in non-interactive mode. Alias for --non-interactive (kept for backwards compatability)")
322 .build());
323 options.addOption(Option.builder()
324 .longOpt(NON_INTERACTIVE)
325 .desc("Run in non-interactive mode. Alias for --batch-mode")
326 .build());
327 options.addOption(Option.builder()
328 .longOpt(FORCE_INTERACTIVE)
329 .desc(
330 "Run in interactive mode. Overrides, if applicable, the CI environment variable and --non-interactive/--batch-mode options")
331 .build());
332 options.addOption(Option.builder(ALTERNATE_USER_SETTINGS)
333 .longOpt("settings")
334 .desc("Alternate path for the user settings file")
335 .hasArg()
336 .build());
337 options.addOption(Option.builder(ALTERNATE_PROJECT_SETTINGS)
338 .longOpt("project-settings")
339 .desc("Alternate path for the project settings file")
340 .hasArg()
341 .build());
342 options.addOption(Option.builder(ALTERNATE_INSTALLATION_SETTINGS)
343 .longOpt("install-settings")
344 .desc("Alternate path for the installation settings file")
345 .hasArg()
346 .build());
347 options.addOption(Option.builder(ALTERNATE_USER_TOOLCHAINS)
348 .longOpt("toolchains")
349 .desc("Alternate path for the user toolchains file")
350 .hasArg()
351 .build());
352 options.addOption(Option.builder(ALTERNATE_INSTALLATION_TOOLCHAINS)
353 .longOpt("install-toolchains")
354 .desc("Alternate path for the installation toolchains file")
355 .hasArg()
356 .build());
357 options.addOption(Option.builder(FAIL_ON_SEVERITY)
358 .longOpt("fail-on-severity")
359 .desc("Configure which severity of logging should cause the build to fail")
360 .hasArg()
361 .build());
362 options.addOption(Option.builder(LOG_FILE)
363 .longOpt("log-file")
364 .hasArg()
365 .desc("Log file where all build output will go (disables output color)")
366 .build());
367 options.addOption(Option.builder()
368 .longOpt(RAW_STREAMS)
369 .desc("Do not decorate standard output and error streams")
370 .build());
371 options.addOption(Option.builder(SHOW_VERSION)
372 .longOpt("show-version")
373 .desc("Display version information WITHOUT stopping build")
374 .build());
375 options.addOption(Option.builder()
376 .longOpt(COLOR)
377 .hasArg()
378 .optionalArg(true)
379 .desc("Defines the color mode of the output. Supported are 'auto', 'always', 'never'.")
380 .build());
381
382
383 options.addOption(Option.builder()
384 .longOpt(DEBUG)
385 .desc("Launch the JVM in debug mode (script option).")
386 .build());
387 options.addOption(Option.builder()
388 .longOpt(ENC)
389 .desc("Launch the Maven Encryption tool (script option).")
390 .build());
391 options.addOption(Option.builder()
392 .longOpt(YJP)
393 .desc("Launch the JVM with Yourkit profiler (script option).")
394 .build());
395
396
397 options.addOption(Option.builder(ALTERNATE_GLOBAL_SETTINGS)
398 .longOpt("global-settings")
399 .desc("<deprecated> Alternate path for the global settings file.")
400 .hasArg()
401 .deprecated(DeprecatedAttributes.builder()
402 .setForRemoval(true)
403 .setSince("4.0.0")
404 .setDescription("Use -is,--install-settings instead.")
405 .get())
406 .build());
407 options.addOption(Option.builder(ALTERNATE_GLOBAL_TOOLCHAINS)
408 .longOpt("global-toolchains")
409 .desc("<deprecated> Alternate path for the global toolchains file.")
410 .hasArg()
411 .deprecated(DeprecatedAttributes.builder()
412 .setForRemoval(true)
413 .setSince("4.0.0")
414 .setDescription("Use -it,--install-toolchains instead.")
415 .get())
416 .build());
417 }
418
419 public CommandLine parse(String[] args) throws ParseException {
420
421 String[] cleanArgs = CleanArgument.cleanArgs(args);
422 DefaultParser parser = DefaultParser.builder()
423 .setDeprecatedHandler(this::addDeprecatedOption)
424 .build();
425 CommandLine commandLine = parser.parse(options, cleanArgs);
426
427 options.getOptions().forEach(commandLine::hasOption);
428 return commandLine;
429 }
430
431 protected void addDeprecatedOption(Option option) {
432 usedDeprecatedOptions.add(option);
433 }
434
435 public org.apache.commons.cli.Options getOptions() {
436 return options;
437 }
438
439 public Set<Option> getUsedDeprecatedOptions() {
440 return usedDeprecatedOptions;
441 }
442
443 public void displayHelp(String command, Consumer<String> pw) {
444 HelpFormatter formatter = new HelpFormatter();
445
446 int width = MessageUtils.getTerminalWidth();
447 if (width <= 0) {
448 width = HelpFormatter.DEFAULT_WIDTH;
449 }
450
451 pw.accept("");
452
453 StringWriter sw = new StringWriter();
454 PrintWriter pw2 = new PrintWriter(sw);
455 formatter.printHelp(
456 pw2,
457 width,
458 commandLineSyntax(command),
459 System.lineSeparator() + "Options:",
460 options,
461 HelpFormatter.DEFAULT_LEFT_PAD,
462 HelpFormatter.DEFAULT_DESC_PAD,
463 System.lineSeparator(),
464 false);
465 pw2.flush();
466 for (String s : sw.toString().split(System.lineSeparator())) {
467 pw.accept(s);
468 }
469 }
470
471 protected String commandLineSyntax(String command) {
472 return command + " [options] [goals]";
473 }
474 }
475 }