1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.cli;
20
21 import javax.xml.stream.XMLStreamException;
22
23 import java.io.Console;
24 import java.io.File;
25 import java.io.FileNotFoundException;
26 import java.io.FileOutputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.PrintStream;
30 import java.nio.charset.Charset;
31 import java.nio.file.FileSystem;
32 import java.nio.file.FileSystems;
33 import java.nio.file.Files;
34 import java.nio.file.Path;
35 import java.util.ArrayList;
36 import java.util.Collections;
37 import java.util.HashSet;
38 import java.util.LinkedHashMap;
39 import java.util.List;
40 import java.util.ListIterator;
41 import java.util.Locale;
42 import java.util.Map;
43 import java.util.Map.Entry;
44 import java.util.Properties;
45 import java.util.ServiceLoader;
46 import java.util.Set;
47 import java.util.function.Consumer;
48 import java.util.function.Function;
49 import java.util.regex.Matcher;
50 import java.util.regex.Pattern;
51 import java.util.stream.Stream;
52
53 import com.google.inject.AbstractModule;
54 import org.apache.commons.cli.CommandLine;
55 import org.apache.commons.cli.Option;
56 import org.apache.commons.cli.ParseException;
57 import org.apache.commons.cli.UnrecognizedOptionException;
58 import org.apache.maven.BuildAbort;
59 import org.apache.maven.InternalErrorException;
60 import org.apache.maven.Maven;
61 import org.apache.maven.api.Constants;
62 import org.apache.maven.api.cli.extensions.CoreExtension;
63 import org.apache.maven.api.services.MessageBuilder;
64 import org.apache.maven.api.services.MessageBuilderFactory;
65 import org.apache.maven.building.FileSource;
66 import org.apache.maven.building.Problem;
67 import org.apache.maven.building.Source;
68 import org.apache.maven.cli.configuration.ConfigurationProcessor;
69 import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor;
70 import org.apache.maven.cli.event.DefaultEventSpyContext;
71 import org.apache.maven.cli.event.ExecutionEventLogger;
72 import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
73 import org.apache.maven.cli.internal.extension.io.CoreExtensionsStaxReader;
74 import org.apache.maven.cli.logging.Slf4jConfiguration;
75 import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
76 import org.apache.maven.cli.logging.Slf4jLoggerManager;
77 import org.apache.maven.cli.logging.Slf4jStdoutLogger;
78 import org.apache.maven.cli.props.MavenPropertiesLoader;
79 import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
80 import org.apache.maven.cli.transfer.QuietMavenTransferListener;
81 import org.apache.maven.cli.transfer.SimplexTransferListener;
82 import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
83 import org.apache.maven.di.Injector;
84 import org.apache.maven.eventspy.internal.EventSpyDispatcher;
85 import org.apache.maven.exception.DefaultExceptionHandler;
86 import org.apache.maven.exception.ExceptionHandler;
87 import org.apache.maven.exception.ExceptionSummary;
88 import org.apache.maven.execution.DefaultMavenExecutionRequest;
89 import org.apache.maven.execution.ExecutionListener;
90 import org.apache.maven.execution.MavenExecutionRequest;
91 import org.apache.maven.execution.MavenExecutionRequestPopulationException;
92 import org.apache.maven.execution.MavenExecutionRequestPopulator;
93 import org.apache.maven.execution.MavenExecutionResult;
94 import org.apache.maven.execution.ProfileActivation;
95 import org.apache.maven.execution.ProjectActivation;
96 import org.apache.maven.execution.scope.internal.MojoExecutionScope;
97 import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
98 import org.apache.maven.extension.internal.CoreExports;
99 import org.apache.maven.extension.internal.CoreExtensionEntry;
100 import org.apache.maven.jline.JLineMessageBuilderFactory;
101 import org.apache.maven.jline.MessageUtils;
102 import org.apache.maven.lifecycle.LifecycleExecutionException;
103 import org.apache.maven.logging.api.LogLevelRecorder;
104 import org.apache.maven.model.building.ModelProcessor;
105 import org.apache.maven.model.root.RootLocator;
106 import org.apache.maven.project.MavenProject;
107 import org.apache.maven.properties.internal.EnvironmentUtils;
108 import org.apache.maven.properties.internal.SystemProperties;
109 import org.apache.maven.session.scope.internal.SessionScope;
110 import org.apache.maven.session.scope.internal.SessionScopeModule;
111 import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest;
112 import org.apache.maven.toolchain.building.ToolchainsBuilder;
113 import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
114 import org.codehaus.plexus.ContainerConfiguration;
115 import org.codehaus.plexus.DefaultContainerConfiguration;
116 import org.codehaus.plexus.DefaultPlexusContainer;
117 import org.codehaus.plexus.PlexusConstants;
118 import org.codehaus.plexus.PlexusContainer;
119 import org.codehaus.plexus.classworlds.ClassWorld;
120 import org.codehaus.plexus.classworlds.realm.ClassRealm;
121 import org.codehaus.plexus.classworlds.realm.NoSuchRealmException;
122 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
123 import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
124 import org.codehaus.plexus.logging.LoggerManager;
125 import org.eclipse.aether.DefaultRepositoryCache;
126 import org.eclipse.aether.transfer.TransferListener;
127 import org.slf4j.ILoggerFactory;
128 import org.slf4j.Logger;
129 import org.slf4j.LoggerFactory;
130
131 import static java.util.Comparator.comparing;
132 import static org.apache.maven.api.Constants.MAVEN_HOME;
133 import static org.apache.maven.api.Constants.MAVEN_INSTALLATION_CONF;
134 import static org.apache.maven.cli.CLIManager.BATCH_MODE;
135 import static org.apache.maven.cli.CLIManager.COLOR;
136 import static org.apache.maven.cli.CLIManager.FORCE_INTERACTIVE;
137 import static org.apache.maven.cli.CLIManager.NON_INTERACTIVE;
138 import static org.apache.maven.cli.ResolveFile.resolveFile;
139
140
141
142
143
144 public class MavenCli {
145
146 public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory";
147
148 private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config";
149
150 private ClassWorld classWorld;
151
152 private LoggerManager plexusLoggerManager;
153
154 private ILoggerFactory slf4jLoggerFactory;
155
156 private Logger slf4jLogger;
157
158 private EventSpyDispatcher eventSpyDispatcher;
159
160 private ModelProcessor modelProcessor;
161
162 private Maven maven;
163
164 private MavenExecutionRequestPopulator executionRequestPopulator;
165
166 private ToolchainsBuilder toolchainsBuilder;
167
168 private SecDispatcher dispatcher;
169
170 private Map<String, ConfigurationProcessor> configurationProcessors;
171
172 private CLIManager cliManager;
173
174 private MessageBuilderFactory messageBuilderFactory;
175
176 private FileSystem fileSystem = FileSystems.getDefault();
177
178 private static final Pattern NEXT_LINE = Pattern.compile("\r?\n");
179
180 public MavenCli() {
181 this(null);
182 }
183
184
185 public MavenCli(ClassWorld classWorld) {
186 this.classWorld = classWorld;
187 this.messageBuilderFactory = new JLineMessageBuilderFactory();
188 }
189
190 public static void main(String[] args) {
191 int result = main(args, null);
192
193 System.exit(result);
194 }
195
196 public static int main(String[] args, ClassWorld classWorld) {
197 MavenCli cli = new MavenCli();
198
199 MessageUtils.systemInstall();
200 MessageUtils.registerShutdownHook();
201 int result = cli.doMain(new CliRequest(args, classWorld));
202 MessageUtils.systemUninstall();
203
204 return result;
205 }
206
207
208 public static int doMain(String[] args, ClassWorld classWorld) {
209 MavenCli cli = new MavenCli();
210 return cli.doMain(new CliRequest(args, classWorld));
211 }
212
213
214
215
216
217
218
219
220
221
222
223
224 public int doMain(String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr) {
225 PrintStream oldout = System.out;
226 PrintStream olderr = System.err;
227
228 final Set<String> realms;
229 if (classWorld != null) {
230 realms = new HashSet<>();
231 for (ClassRealm realm : classWorld.getRealms()) {
232 realms.add(realm.getId());
233 }
234 } else {
235 realms = Collections.emptySet();
236 }
237
238 try {
239 if (stdout != null) {
240 System.setOut(stdout);
241 }
242 if (stderr != null) {
243 System.setErr(stderr);
244 }
245
246 CliRequest cliRequest = new CliRequest(args, classWorld);
247 cliRequest.workingDirectory = workingDirectory;
248
249 return doMain(cliRequest);
250 } finally {
251 if (classWorld != null) {
252 for (ClassRealm realm : new ArrayList<>(classWorld.getRealms())) {
253 String realmId = realm.getId();
254 if (!realms.contains(realmId)) {
255 try {
256 classWorld.disposeRealm(realmId);
257 } catch (NoSuchRealmException ignored) {
258
259 }
260 }
261 }
262 }
263 System.setOut(oldout);
264 System.setErr(olderr);
265 }
266 }
267
268
269 public int doMain(CliRequest cliRequest) {
270 PlexusContainer localContainer = null;
271 try {
272 initialize(cliRequest);
273 cli(cliRequest);
274 properties(cliRequest);
275 logging(cliRequest);
276 informativeCommands(cliRequest);
277 version(cliRequest);
278 localContainer = container(cliRequest);
279 commands(cliRequest);
280 configure(cliRequest);
281 toolchains(cliRequest);
282 populateRequest(cliRequest);
283 encryption(cliRequest);
284 return execute(cliRequest);
285 } catch (ExitException e) {
286 return e.exitCode;
287 } catch (UnrecognizedOptionException e) {
288
289 return 1;
290 } catch (BuildAbort e) {
291 CLIReportingUtils.showError(slf4jLogger, "ABORTED", e, cliRequest.showErrors);
292
293 return 2;
294 } catch (Exception e) {
295 CLIReportingUtils.showError(slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors);
296
297 return 1;
298 } finally {
299 if (localContainer != null) {
300 localContainer.dispose();
301 }
302 }
303 }
304
305 void initialize(CliRequest cliRequest) throws ExitException {
306 if (cliRequest.workingDirectory == null) {
307 cliRequest.workingDirectory = System.getProperty("user.dir");
308 }
309
310 if (cliRequest.multiModuleProjectDirectory == null) {
311 String basedirProperty = System.getProperty(MULTIMODULE_PROJECT_DIRECTORY);
312 if (basedirProperty == null) {
313 System.err.format("-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY);
314 throw new ExitException(1);
315 }
316 File basedir = new File(basedirProperty);
317 try {
318 cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile();
319 } catch (IOException e) {
320 cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile();
321 }
322 }
323
324
325
326
327 Path topDirectory = fileSystem.getPath(cliRequest.workingDirectory);
328 boolean isAltFile = false;
329 for (String arg : cliRequest.args) {
330 if (isAltFile) {
331
332 Path path = topDirectory.resolve(stripLeadingAndTrailingQuotes(arg));
333 if (Files.isDirectory(path)) {
334 topDirectory = path;
335 } else if (Files.isRegularFile(path)) {
336 topDirectory = path.getParent();
337 if (!Files.isDirectory(topDirectory)) {
338 System.err.println("Directory " + topDirectory
339 + " extracted from the -f/--file command-line argument " + arg + " does not exist");
340 throw new ExitException(1);
341 }
342 } else {
343 System.err.println(
344 "POM file " + arg + " specified with the -f/--file command line argument does not exist");
345 throw new ExitException(1);
346 }
347 break;
348 } else {
349
350 isAltFile = arg.equals("-f") || arg.equals("--file");
351 }
352 }
353 topDirectory = getCanonicalPath(topDirectory);
354 cliRequest.topDirectory = topDirectory;
355
356
357
358
359 RootLocator rootLocator =
360 ServiceLoader.load(RootLocator.class).iterator().next();
361 cliRequest.rootDirectory = rootLocator.findRoot(topDirectory);
362
363
364
365
366
367 String mavenHome = System.getProperty(Constants.MAVEN_HOME);
368
369 if (mavenHome != null) {
370 System.setProperty(
371 Constants.MAVEN_HOME,
372 getCanonicalPath(fileSystem.getPath(mavenHome)).toString());
373 }
374 }
375
376 void cli(CliRequest cliRequest) throws Exception {
377
378
379
380
381 slf4jLogger = new Slf4jStdoutLogger();
382
383 cliManager = new CLIManager();
384
385 CommandLine mavenConfig = null;
386 try {
387 File configFile = new File(cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG);
388
389 if (configFile.isFile()) {
390 try (Stream<String> lines = Files.lines(configFile.toPath(), Charset.defaultCharset())) {
391 String[] args = lines.filter(arg -> !arg.isEmpty() && !arg.startsWith("#"))
392 .toArray(String[]::new);
393 mavenConfig = cliManager.parse(args);
394 List<?> unrecognized = mavenConfig.getArgList();
395 if (!unrecognized.isEmpty()) {
396
397 throw new ParseException("Unrecognized maven.config file entries: " + unrecognized);
398 }
399 }
400 }
401 } catch (ParseException e) {
402 System.err.println("Unable to parse maven.config file options: " + e.getMessage());
403 cliManager.displayHelp(System.out);
404 throw e;
405 }
406
407 try {
408 CommandLine mavenCli = cliManager.parse(cliRequest.args);
409 if (mavenConfig == null) {
410 cliRequest.commandLine = mavenCli;
411 } else {
412 cliRequest.commandLine = cliMerge(mavenConfig, mavenCli);
413 }
414 } catch (ParseException e) {
415 System.err.println("Unable to parse command line options: " + e.getMessage());
416 cliManager.displayHelp(System.out);
417 throw e;
418 }
419 }
420
421 private void informativeCommands(CliRequest cliRequest) throws ExitException {
422 if (cliRequest.commandLine.hasOption(CLIManager.HELP)) {
423 cliManager.displayHelp(System.out);
424 throw new ExitException(0);
425 }
426
427 if (cliRequest.commandLine.hasOption(CLIManager.VERSION)) {
428 if (cliRequest.commandLine.hasOption(CLIManager.QUIET)) {
429 System.out.println(CLIReportingUtils.showVersionMinimal());
430 } else {
431 System.out.println(CLIReportingUtils.showVersion());
432 }
433 throw new ExitException(0);
434 }
435
436 if (cliRequest.rootDirectory == null) {
437 slf4jLogger.info(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
438 }
439 }
440
441 private CommandLine cliMerge(CommandLine mavenConfig, CommandLine mavenCli) {
442 CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
443
444
445 for (String arg : mavenCli.getArgs()) {
446 commandLineBuilder.addArg(arg);
447 }
448
449
450
451
452
453
454
455
456
457
458
459 List<Option> setPropertyOptions = new ArrayList<>();
460 for (Option opt : mavenCli.getOptions()) {
461 if (String.valueOf(CLIManager.SET_USER_PROPERTY).equals(opt.getOpt())) {
462 setPropertyOptions.add(opt);
463 } else {
464 commandLineBuilder.addOption(opt);
465 }
466 }
467 for (Option opt : mavenConfig.getOptions()) {
468 commandLineBuilder.addOption(opt);
469 }
470
471 for (Option opt : setPropertyOptions) {
472 commandLineBuilder.addOption(opt);
473 }
474 return commandLineBuilder.build();
475 }
476
477
478
479
480 void logging(CliRequest cliRequest) throws ExitException {
481
482 CommandLine commandLine = cliRequest.commandLine;
483 cliRequest.verbose = commandLine.hasOption(CLIManager.VERBOSE) || commandLine.hasOption(CLIManager.DEBUG);
484 cliRequest.quiet = !cliRequest.verbose && commandLine.hasOption(CLIManager.QUIET);
485 cliRequest.showErrors = cliRequest.verbose || commandLine.hasOption(CLIManager.ERRORS);
486
487
488 String styleColor = cliRequest.getUserProperties().getProperty("style.color", "auto");
489 styleColor = cliRequest.getUserProperties().getProperty(Constants.MAVEN_STYLE_COLOR_PROPERTY, styleColor);
490 styleColor = commandLine.getOptionValue(COLOR, styleColor);
491 if ("always".equals(styleColor) || "yes".equals(styleColor) || "force".equals(styleColor)) {
492 MessageUtils.setColorEnabled(true);
493 } else if ("never".equals(styleColor) || "no".equals(styleColor) || "none".equals(styleColor)) {
494 MessageUtils.setColorEnabled(false);
495 } else if (!"auto".equals(styleColor) && !"tty".equals(styleColor) && !"if-tty".equals(styleColor)) {
496 throw new IllegalArgumentException(
497 "Invalid color configuration value '" + styleColor + "'. Supported are 'auto', 'always', 'never'.");
498 } else {
499 boolean isBatchMode = !commandLine.hasOption(FORCE_INTERACTIVE)
500 && (commandLine.hasOption(BATCH_MODE) || commandLine.hasOption(NON_INTERACTIVE));
501 if (isBatchMode || commandLine.hasOption(CLIManager.LOG_FILE)) {
502 MessageUtils.setColorEnabled(false);
503 }
504 }
505
506 slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
507 Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(slf4jLoggerFactory);
508
509 if (cliRequest.verbose) {
510 cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_DEBUG);
511 slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.DEBUG);
512 } else if (cliRequest.quiet) {
513 cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_ERROR);
514 slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.ERROR);
515 }
516
517
518
519
520 if (commandLine.hasOption(CLIManager.LOG_FILE)) {
521 File logFile = new File(commandLine.getOptionValue(CLIManager.LOG_FILE));
522 logFile = resolveFile(logFile, cliRequest.workingDirectory);
523
524
525 try {
526 PrintStream ps = new PrintStream(new FileOutputStream(logFile));
527 System.setOut(ps);
528 System.setErr(ps);
529 } catch (FileNotFoundException e) {
530
531
532
533 }
534 }
535
536 slf4jConfiguration.activate();
537
538 plexusLoggerManager = new Slf4jLoggerManager();
539 slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName());
540
541 if (commandLine.hasOption(CLIManager.FAIL_ON_SEVERITY)) {
542 String logLevelThreshold = commandLine.getOptionValue(CLIManager.FAIL_ON_SEVERITY);
543
544 if (slf4jLoggerFactory instanceof LogLevelRecorder recorder) {
545 LogLevelRecorder.Level level =
546 switch (logLevelThreshold.toLowerCase(Locale.ENGLISH)) {
547 case "warn", "warning" -> LogLevelRecorder.Level.WARN;
548 case "error" -> LogLevelRecorder.Level.ERROR;
549 default -> throw new IllegalArgumentException(
550 logLevelThreshold
551 + " is not a valid log severity threshold. Valid severities are WARN/WARNING and ERROR.");
552 };
553 recorder.setMaxLevelAllowed(level);
554 slf4jLogger.info("Enabled to break the build on log level {}.", logLevelThreshold);
555 } else {
556 slf4jLogger.warn(
557 "Expected LoggerFactory to be of type '{}', but found '{}' instead. "
558 + "The --fail-on-severity flag will not take effect.",
559 LogLevelRecorder.class.getName(),
560 slf4jLoggerFactory.getClass().getName());
561 }
562 }
563
564
565 boolean fail = false;
566 for (Option option : cliRequest.commandLine.getOptions()) {
567 if (option.isDeprecated()) {
568 StringBuilder sb = new StringBuilder();
569 sb.append("The option -").append(option.getOpt());
570 if (option.getLongOpt() != null) {
571 sb.append(",--").append(option.getLongOpt());
572 }
573 sb.append(" is deprecated ");
574 if (option.getDeprecated().isForRemoval()) {
575 sb.append("and will be removed in a future version");
576 }
577 if (option.getDeprecated().getSince() != null) {
578 sb.append("since Maven ").append(option.getDeprecated().getSince());
579 }
580 boolean error = false;
581 if (option.getDeprecated().getDescription() != null) {
582 sb.append(": ").append(option.getDeprecated().getDescription());
583 error = option.getDeprecated().getDescription().startsWith("UNSUPPORTED:");
584 }
585 if (error) {
586 slf4jLogger.error(sb.toString());
587 fail = true;
588 } else {
589 slf4jLogger.warn(sb.toString());
590 }
591 }
592 }
593 if (fail) {
594 throw new ExitException(1);
595 }
596 }
597
598 private void version(CliRequest cliRequest) {
599 if (cliRequest.verbose || cliRequest.commandLine.hasOption(CLIManager.SHOW_VERSION)) {
600 System.out.println(CLIReportingUtils.showVersion());
601 }
602 }
603
604 private void commands(CliRequest cliRequest) {
605 if (cliRequest.showErrors) {
606 slf4jLogger.info("Error stacktraces are turned on.");
607 }
608
609 if (MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals(cliRequest.request.getGlobalChecksumPolicy())) {
610 slf4jLogger.info("Disabling strict checksum verification on all artifact downloads.");
611 } else if (MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals(cliRequest.request.getGlobalChecksumPolicy())) {
612 slf4jLogger.info("Enabling strict checksum verification on all artifact downloads.");
613 }
614
615 if (slf4jLogger.isDebugEnabled()) {
616 slf4jLogger.debug("Message scheme: {}", (MessageUtils.isColorEnabled() ? "color" : "plain"));
617 if (MessageUtils.isColorEnabled()) {
618 MessageBuilder buff = MessageUtils.builder();
619 buff.a("Message styles: ");
620 buff.trace("trace").a(' ');
621 buff.debug("debug").a(' ');
622 buff.info("info").a(' ');
623 buff.warning("warning").a(' ');
624 buff.error("error").a(' ');
625 buff.success("success").a(' ');
626 buff.failure("failure").a(' ');
627 buff.strong("strong").a(' ');
628 buff.mojo("mojo").a(' ');
629 buff.project("project");
630 slf4jLogger.debug(buff.toString());
631 }
632 }
633 }
634
635
636
637 void properties(CliRequest cliRequest) throws Exception {
638 Properties paths = new Properties();
639 if (cliRequest.topDirectory != null) {
640 paths.put("session.topDirectory", cliRequest.topDirectory.toString());
641 }
642 if (cliRequest.rootDirectory != null) {
643 paths.put("session.rootDirectory", cliRequest.rootDirectory.toString());
644 }
645
646 populateProperties(cliRequest.commandLine, paths, cliRequest.systemProperties, cliRequest.userProperties);
647
648
649 Function<String, String> callback = v -> {
650 String r = paths.getProperty(v);
651 if (r == null) {
652 r = cliRequest.systemProperties.getProperty(v);
653 }
654 if (r == null) {
655 r = cliRequest.userProperties.getProperty(v);
656 }
657 return r != null ? r : v;
658 };
659 CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
660 commandLineBuilder.setDeprecatedHandler(o -> {});
661 for (Option option : cliRequest.commandLine.getOptions()) {
662 if (!String.valueOf(CLIManager.SET_USER_PROPERTY).equals(option.getOpt())) {
663 List<String> values = option.getValuesList();
664 for (ListIterator<String> it = values.listIterator(); it.hasNext(); ) {
665 it.set(MavenPropertiesLoader.substVars(it.next(), null, null, callback));
666 }
667 }
668 commandLineBuilder.addOption(option);
669 }
670 for (String arg : cliRequest.commandLine.getArgList()) {
671 commandLineBuilder.addArg(MavenPropertiesLoader.substVars(arg, null, null, callback));
672 }
673 cliRequest.commandLine = commandLineBuilder.build();
674 }
675
676 PlexusContainer container(CliRequest cliRequest) throws Exception {
677 if (cliRequest.classWorld == null) {
678 cliRequest.classWorld =
679 new ClassWorld("plexus.core", Thread.currentThread().getContextClassLoader());
680 }
681
682 ClassRealm coreRealm = cliRequest.classWorld.getClassRealm("plexus.core");
683 if (coreRealm == null) {
684 coreRealm = cliRequest.classWorld.getRealms().iterator().next();
685 }
686
687 List<File> extClassPath = parseExtClasspath(cliRequest);
688
689 CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom(coreRealm);
690 List<CoreExtensionEntry> extensions =
691 loadCoreExtensions(cliRequest, coreRealm, coreEntry.getExportedArtifacts());
692
693 ClassRealm containerRealm = setupContainerRealm(cliRequest.classWorld, coreRealm, extClassPath, extensions);
694
695 ContainerConfiguration cc = new DefaultContainerConfiguration()
696 .setClassWorld(cliRequest.classWorld)
697 .setRealm(containerRealm)
698 .setClassPathScanning(PlexusConstants.SCANNING_INDEX)
699 .setAutoWiring(true)
700 .setJSR250Lifecycle(true)
701 .setStrictClassPathScanning(true)
702 .setName("maven");
703
704 Set<String> exportedArtifacts = new HashSet<>(coreEntry.getExportedArtifacts());
705 Set<String> exportedPackages = new HashSet<>(coreEntry.getExportedPackages());
706 for (CoreExtensionEntry extension : extensions) {
707 exportedArtifacts.addAll(extension.getExportedArtifacts());
708 exportedPackages.addAll(extension.getExportedPackages());
709 }
710
711 final CoreExports exports = new CoreExports(containerRealm, exportedArtifacts, exportedPackages);
712
713 Thread.currentThread().setContextClassLoader(containerRealm);
714
715 DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
716 @Override
717 protected void configure() {
718 bind(ILoggerFactory.class).toInstance(slf4jLoggerFactory);
719 bind(CoreExports.class).toInstance(exports);
720 bind(MessageBuilderFactory.class).toInstance(messageBuilderFactory);
721 }
722 });
723
724
725 container.setLookupRealm(null);
726 Thread.currentThread().setContextClassLoader(container.getContainerRealm());
727
728 container.setLoggerManager(plexusLoggerManager);
729
730 Function<String, String> extensionSource = expression -> {
731 String value = cliRequest.userProperties.getProperty(expression);
732 if (value == null) {
733 value = cliRequest.systemProperties.getProperty(expression);
734 }
735 return value;
736 };
737 for (CoreExtensionEntry extension : extensions) {
738 container.discoverComponents(
739 extension.getClassRealm(),
740 new AbstractModule() {
741 @Override
742 protected void configure() {
743 try {
744 container.lookup(Injector.class).discover(extension.getClassRealm());
745 } catch (Throwable e) {
746
747 e.printStackTrace();
748 }
749 }
750 },
751 new SessionScopeModule(container.lookup(SessionScope.class)),
752 new MojoExecutionScopeModule(container.lookup(MojoExecutionScope.class)),
753 new ExtensionConfigurationModule(extension, extensionSource));
754 }
755
756 customizeContainer(container);
757
758 container.getLoggerManager().setThresholds(cliRequest.request.getLoggingLevel());
759
760 eventSpyDispatcher = container.lookup(EventSpyDispatcher.class);
761
762 DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
763 Map<String, Object> data = eventSpyContext.getData();
764 data.put("plexus", container);
765 data.put("workingDirectory", cliRequest.workingDirectory);
766 data.put("systemProperties", cliRequest.systemProperties);
767 data.put("userProperties", cliRequest.userProperties);
768 data.put("versionProperties", CLIReportingUtils.getBuildProperties());
769 eventSpyDispatcher.init(eventSpyContext);
770
771
772 slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName());
773
774 maven = container.lookup(Maven.class);
775
776 executionRequestPopulator = container.lookup(MavenExecutionRequestPopulator.class);
777
778 modelProcessor = createModelProcessor(container);
779
780 configurationProcessors = container.lookupMap(ConfigurationProcessor.class);
781
782 toolchainsBuilder = container.lookup(ToolchainsBuilder.class);
783
784 dispatcher = container.lookup(SecDispatcher.class);
785
786 return container;
787 }
788
789 private List<CoreExtensionEntry> loadCoreExtensions(
790 CliRequest cliRequest, ClassRealm containerRealm, Set<String> providedArtifacts) throws Exception {
791 if (cliRequest.multiModuleProjectDirectory == null) {
792 return Collections.emptyList();
793 }
794
795 List<CoreExtension> extensions = new ArrayList<>();
796
797 String installationExtensionsFile =
798 cliRequest.getUserProperties().getProperty(Constants.MAVEN_INSTALLATION_EXTENSIONS);
799 extensions.addAll(readCoreExtensionsDescriptor(installationExtensionsFile));
800
801 String projectExtensionsFile = cliRequest.getUserProperties().getProperty(Constants.MAVEN_PROJECT_EXTENSIONS);
802 extensions.addAll(readCoreExtensionsDescriptor(projectExtensionsFile));
803
804 String userExtensionsFile = cliRequest.getUserProperties().getProperty(Constants.MAVEN_USER_EXTENSIONS);
805 extensions.addAll(readCoreExtensionsDescriptor(userExtensionsFile));
806
807 if (extensions.isEmpty()) {
808 return Collections.emptyList();
809 }
810
811 ContainerConfiguration cc = new DefaultContainerConfiguration()
812 .setClassWorld(cliRequest.classWorld)
813 .setRealm(containerRealm)
814 .setClassPathScanning(PlexusConstants.SCANNING_INDEX)
815 .setAutoWiring(true)
816 .setJSR250Lifecycle(true)
817 .setStrictClassPathScanning(true)
818 .setName("maven");
819
820 DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
821 @Override
822 protected void configure() {
823 bind(ILoggerFactory.class).toInstance(slf4jLoggerFactory);
824 }
825 });
826
827 try {
828 container.setLookupRealm(null);
829
830 container.setLoggerManager(plexusLoggerManager);
831
832 container.getLoggerManager().setThresholds(cliRequest.request.getLoggingLevel());
833
834 Thread.currentThread().setContextClassLoader(container.getContainerRealm());
835
836 executionRequestPopulator = container.lookup(MavenExecutionRequestPopulator.class);
837
838 configurationProcessors = container.lookupMap(ConfigurationProcessor.class);
839
840 configure(cliRequest);
841
842 MavenExecutionRequest request = DefaultMavenExecutionRequest.copy(cliRequest.request);
843
844 populateRequest(cliRequest, request);
845
846 request = executionRequestPopulator.populateDefaults(request);
847
848 BootstrapCoreExtensionManager resolver = container.lookup(BootstrapCoreExtensionManager.class);
849
850 return Collections.unmodifiableList(resolver.loadCoreExtensions(request, providedArtifacts, extensions));
851
852 } finally {
853 executionRequestPopulator = null;
854 container.dispose();
855 }
856 }
857
858 private List<CoreExtension> readCoreExtensionsDescriptor(String extensionsFile)
859 throws IOException, XMLStreamException {
860 if (extensionsFile != null) {
861 Path extensionsPath = Path.of(extensionsFile);
862 if (Files.exists(extensionsPath)) {
863 try (InputStream is = Files.newInputStream(extensionsPath)) {
864 return new CoreExtensionsStaxReader().read(is, true).getExtensions();
865 }
866 }
867 }
868 return List.of();
869 }
870
871 private ClassRealm setupContainerRealm(
872 ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath, List<CoreExtensionEntry> extensions)
873 throws Exception {
874 if (!extClassPath.isEmpty() || !extensions.isEmpty()) {
875 ClassRealm extRealm = classWorld.newRealm("maven.ext", null);
876
877 extRealm.setParentRealm(coreRealm);
878
879 slf4jLogger.debug("Populating class realm '{}'", extRealm.getId());
880
881 for (File file : extClassPath) {
882 slf4jLogger.debug(" included '{}'", file);
883
884 extRealm.addURL(file.toURI().toURL());
885 }
886
887 for (CoreExtensionEntry entry : reverse(extensions)) {
888 Set<String> exportedPackages = entry.getExportedPackages();
889 ClassRealm realm = entry.getClassRealm();
890 for (String exportedPackage : exportedPackages) {
891 extRealm.importFrom(realm, exportedPackage);
892 }
893 if (exportedPackages.isEmpty()) {
894
895 extRealm.importFrom(realm, realm.getId());
896 }
897 }
898
899 return extRealm;
900 }
901
902 return coreRealm;
903 }
904
905 private static <T> List<T> reverse(List<T> list) {
906 List<T> copy = new ArrayList<>(list);
907 Collections.reverse(copy);
908 return copy;
909 }
910
911 private List<File> parseExtClasspath(CliRequest cliRequest) {
912 String extClassPath = cliRequest.userProperties.getProperty(Constants.MAVEN_EXT_CLASS_PATH);
913 if (extClassPath == null) {
914 extClassPath = cliRequest.systemProperties.getProperty(Constants.MAVEN_EXT_CLASS_PATH);
915 if (extClassPath != null) {
916 slf4jLogger.warn(
917 "The property '{}' has been set using a JVM system property which is deprecated. "
918 + "The property can be passed as a Maven argument or in the Maven project configuration file,"
919 + "usually located at ${session.rootDirectory}/.mvn/maven.properties.",
920 Constants.MAVEN_EXT_CLASS_PATH);
921 }
922 }
923
924 List<File> jars = new ArrayList<>();
925
926 if (extClassPath != null && !extClassPath.isEmpty()) {
927 for (String jar : extClassPath.split(File.pathSeparator)) {
928 File file = resolveFile(new File(jar), cliRequest.workingDirectory);
929
930 slf4jLogger.debug(" included '{}'", file);
931
932 jars.add(file);
933 }
934 }
935
936 return jars;
937 }
938
939
940
941
942 private void encryption(CliRequest cliRequest) throws Exception {
943 if (cliRequest.commandLine.hasOption(CLIManager.ENCRYPT_MASTER_PASSWORD)) {
944 System.out.println("Master password encyption is not supported anymore");
945 throw new ExitException(1);
946 } else if (cliRequest.commandLine.hasOption(CLIManager.ENCRYPT_PASSWORD)) {
947 String passwd = cliRequest.commandLine.getOptionValue(CLIManager.ENCRYPT_PASSWORD);
948
949 if (passwd == null) {
950 Console cons = System.console();
951 char[] password = (cons == null) ? null : cons.readPassword("Password: ");
952 if (password != null) {
953
954 passwd = String.copyValueOf(password);
955
956
957 java.util.Arrays.fill(password, ' ');
958 }
959 }
960 System.out.println(dispatcher.encrypt(passwd, null));
961 throw new ExitException(0);
962 }
963 }
964
965 private int execute(CliRequest cliRequest) throws MavenExecutionRequestPopulationException {
966 MavenExecutionRequest request = executionRequestPopulator.populateDefaults(cliRequest.request);
967
968 if (cliRequest.request.getRepositoryCache() == null) {
969 cliRequest.request.setRepositoryCache(new DefaultRepositoryCache());
970 }
971
972 eventSpyDispatcher.onEvent(request);
973
974 MavenExecutionResult result = maven.execute(request);
975
976 eventSpyDispatcher.onEvent(result);
977
978 eventSpyDispatcher.close();
979
980 if (result.hasExceptions()) {
981 ExceptionHandler handler = new DefaultExceptionHandler();
982
983 Map<String, String> references = new LinkedHashMap<>();
984
985 List<MavenProject> failedProjects = new ArrayList<>();
986
987 for (Throwable exception : result.getExceptions()) {
988 ExceptionSummary summary = handler.handleException(exception);
989
990 logSummary(summary, references, "", cliRequest.showErrors);
991
992 if (exception instanceof LifecycleExecutionException) {
993 failedProjects.add(((LifecycleExecutionException) exception).getProject());
994 }
995 }
996
997 slf4jLogger.error("");
998
999 if (!cliRequest.showErrors) {
1000 slf4jLogger.error(
1001 "To see the full stack trace of the errors, re-run Maven with the '{}' switch",
1002 MessageUtils.builder().strong("-e"));
1003 }
1004 if (!slf4jLogger.isDebugEnabled()) {
1005 slf4jLogger.error(
1006 "Re-run Maven using the '{}' switch to enable verbose output",
1007 MessageUtils.builder().strong("-X"));
1008 }
1009
1010 if (!references.isEmpty()) {
1011 slf4jLogger.error("");
1012 slf4jLogger.error("For more information about the errors and possible solutions"
1013 + ", please read the following articles:");
1014
1015 for (Map.Entry<String, String> entry : references.entrySet()) {
1016 slf4jLogger.error("{} {}", MessageUtils.builder().strong(entry.getValue()), entry.getKey());
1017 }
1018 }
1019
1020 if (result.canResume()) {
1021 logBuildResumeHint("mvn [args] -r");
1022 } else if (!failedProjects.isEmpty()) {
1023 List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
1024
1025
1026 failedProjects.sort(comparing(sortedProjects::indexOf));
1027
1028 MavenProject firstFailedProject = failedProjects.get(0);
1029 if (!firstFailedProject.equals(sortedProjects.get(0))) {
1030 String resumeFromSelector = getResumeFromSelector(sortedProjects, firstFailedProject);
1031 logBuildResumeHint("mvn [args] -rf " + resumeFromSelector);
1032 }
1033 }
1034
1035 if (MavenExecutionRequest.REACTOR_FAIL_NEVER.equals(cliRequest.request.getReactorFailureBehavior())) {
1036 slf4jLogger.info("Build failures were ignored.");
1037
1038 return 0;
1039 } else {
1040 return 1;
1041 }
1042 } else {
1043 return 0;
1044 }
1045 }
1046
1047 private void logBuildResumeHint(String resumeBuildHint) {
1048 slf4jLogger.error("");
1049 slf4jLogger.error("After correcting the problems, you can resume the build with the command");
1050 slf4jLogger.error(MessageUtils.builder().a(" ").strong(resumeBuildHint).toString());
1051 }
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070 String getResumeFromSelector(List<MavenProject> mavenProjects, MavenProject firstFailedProject) {
1071 boolean hasOverlappingArtifactId = mavenProjects.stream()
1072 .filter(project -> firstFailedProject.getArtifactId().equals(project.getArtifactId()))
1073 .count()
1074 > 1;
1075
1076 if (hasOverlappingArtifactId) {
1077 return firstFailedProject.getGroupId() + ":" + firstFailedProject.getArtifactId();
1078 }
1079
1080 return ":" + firstFailedProject.getArtifactId();
1081 }
1082
1083 private void logSummary(
1084 ExceptionSummary summary, Map<String, String> references, String indent, boolean showErrors) {
1085 String referenceKey = "";
1086
1087 if (summary.getReference() != null && !summary.getReference().isEmpty()) {
1088 referenceKey =
1089 references.computeIfAbsent(summary.getReference(), k -> "[Help " + (references.size() + 1) + "]");
1090 }
1091
1092 String msg = summary.getMessage();
1093
1094 if (referenceKey != null && !referenceKey.isEmpty()) {
1095 if (msg.indexOf('\n') < 0) {
1096 msg += " -> " + MessageUtils.builder().strong(referenceKey);
1097 } else {
1098 msg += "\n-> " + MessageUtils.builder().strong(referenceKey);
1099 }
1100 }
1101
1102 String[] lines = NEXT_LINE.split(msg);
1103 String currentColor = "";
1104
1105 for (int i = 0; i < lines.length; i++) {
1106
1107 String line = currentColor + lines[i];
1108
1109
1110 Matcher matcher = LAST_ANSI_SEQUENCE.matcher(line);
1111 String nextColor = "";
1112 if (matcher.find()) {
1113 nextColor = matcher.group(1);
1114 if (ANSI_RESET.equals(nextColor)) {
1115
1116 nextColor = "";
1117 }
1118 }
1119
1120
1121 line = indent + line + ("".equals(nextColor) ? "" : ANSI_RESET);
1122
1123 if ((i == lines.length - 1) && (showErrors || (summary.getException() instanceof InternalErrorException))) {
1124 slf4jLogger.error(line, summary.getException());
1125 } else {
1126 slf4jLogger.error(line);
1127 }
1128
1129 currentColor = nextColor;
1130 }
1131
1132 indent += " ";
1133
1134 for (ExceptionSummary child : summary.getChildren()) {
1135 logSummary(child, references, indent, showErrors);
1136 }
1137 }
1138
1139 private static final Pattern LAST_ANSI_SEQUENCE = Pattern.compile("(\u001B\\[[;\\d]*[ -/]*[@-~])[^\u001B]*$");
1140
1141 private static final String ANSI_RESET = "\u001B\u005Bm";
1142
1143 private void configure(CliRequest cliRequest) throws Exception {
1144
1145
1146
1147
1148
1149
1150 cliRequest.request.setEventSpyDispatcher(eventSpyDispatcher);
1151
1152
1153
1154
1155
1156
1157
1158
1159 int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1;
1160
1161 if (userSuppliedConfigurationProcessorCount == 0) {
1162
1163
1164
1165
1166 configurationProcessors.get(SettingsXmlConfigurationProcessor.HINT).process(cliRequest);
1167 } else if (userSuppliedConfigurationProcessorCount == 1) {
1168
1169
1170
1171 for (Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet()) {
1172 String hint = entry.getKey();
1173 if (!hint.equals(SettingsXmlConfigurationProcessor.HINT)) {
1174 ConfigurationProcessor configurationProcessor = entry.getValue();
1175 configurationProcessor.process(cliRequest);
1176 }
1177 }
1178 } else if (userSuppliedConfigurationProcessorCount > 1) {
1179
1180
1181
1182 StringBuilder sb = new StringBuilder(String.format(
1183 "%nThere can only be one user supplied ConfigurationProcessor, there are %s:%n%n",
1184 userSuppliedConfigurationProcessorCount));
1185 for (Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet()) {
1186 String hint = entry.getKey();
1187 if (!hint.equals(SettingsXmlConfigurationProcessor.HINT)) {
1188 ConfigurationProcessor configurationProcessor = entry.getValue();
1189 sb.append(String.format(
1190 "%s%n", configurationProcessor.getClass().getName()));
1191 }
1192 }
1193 throw new Exception(sb.toString());
1194 }
1195 }
1196
1197 void toolchains(CliRequest cliRequest) throws Exception {
1198 File userToolchainsFile = null;
1199
1200 if (cliRequest.commandLine.hasOption(CLIManager.ALTERNATE_USER_TOOLCHAINS)) {
1201 userToolchainsFile = new File(cliRequest.commandLine.getOptionValue(CLIManager.ALTERNATE_USER_TOOLCHAINS));
1202 userToolchainsFile = resolveFile(userToolchainsFile, cliRequest.workingDirectory);
1203
1204 if (!userToolchainsFile.isFile()) {
1205 throw new FileNotFoundException(
1206 "The specified user toolchains file does not exist: " + userToolchainsFile);
1207 }
1208 } else {
1209 String userToolchainsFileStr = cliRequest.getUserProperties().getProperty(Constants.MAVEN_USER_TOOLCHAINS);
1210 if (userToolchainsFileStr != null) {
1211 userToolchainsFile = new File(userToolchainsFileStr);
1212 }
1213 }
1214
1215 File installationToolchainsFile = null;
1216
1217 if (cliRequest.commandLine.hasOption(CLIManager.ALTERNATE_INSTALLATION_TOOLCHAINS)) {
1218 installationToolchainsFile =
1219 new File(cliRequest.commandLine.getOptionValue(CLIManager.ALTERNATE_INSTALLATION_TOOLCHAINS));
1220 installationToolchainsFile = resolveFile(installationToolchainsFile, cliRequest.workingDirectory);
1221
1222 if (!installationToolchainsFile.isFile()) {
1223 throw new FileNotFoundException(
1224 "The specified installation toolchains file does not exist: " + installationToolchainsFile);
1225 }
1226 } else if (cliRequest.commandLine.hasOption(CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS)) {
1227 installationToolchainsFile =
1228 new File(cliRequest.commandLine.getOptionValue(CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS));
1229 installationToolchainsFile = resolveFile(installationToolchainsFile, cliRequest.workingDirectory);
1230
1231 if (!installationToolchainsFile.isFile()) {
1232 throw new FileNotFoundException(
1233 "The specified installation toolchains file does not exist: " + installationToolchainsFile);
1234 }
1235 } else {
1236 String installationToolchainsFileStr =
1237 cliRequest.getUserProperties().getProperty(Constants.MAVEN_INSTALLATION_TOOLCHAINS);
1238 if (installationToolchainsFileStr != null) {
1239 installationToolchainsFile = new File(installationToolchainsFileStr);
1240 installationToolchainsFile = resolveFile(installationToolchainsFile, cliRequest.workingDirectory);
1241 }
1242 }
1243
1244 cliRequest.request.setInstallationToolchainsFile(installationToolchainsFile);
1245 cliRequest.request.setUserToolchainsFile(userToolchainsFile);
1246
1247 DefaultToolchainsBuildingRequest toolchainsRequest = new DefaultToolchainsBuildingRequest();
1248 if (installationToolchainsFile != null && installationToolchainsFile.isFile()) {
1249 toolchainsRequest.setGlobalToolchainsSource(new FileSource(installationToolchainsFile));
1250 }
1251 if (userToolchainsFile != null && userToolchainsFile.isFile()) {
1252 toolchainsRequest.setUserToolchainsSource(new FileSource(userToolchainsFile));
1253 }
1254
1255 eventSpyDispatcher.onEvent(toolchainsRequest);
1256
1257 slf4jLogger.debug(
1258 "Reading installation toolchains from '{}'",
1259 getLocation(toolchainsRequest.getGlobalToolchainsSource(), installationToolchainsFile));
1260 slf4jLogger.debug(
1261 "Reading user toolchains from '{}'",
1262 getLocation(toolchainsRequest.getUserToolchainsSource(), userToolchainsFile));
1263
1264 ToolchainsBuildingResult toolchainsResult = toolchainsBuilder.build(toolchainsRequest);
1265
1266 eventSpyDispatcher.onEvent(toolchainsResult);
1267
1268 executionRequestPopulator.populateFromToolchains(cliRequest.request, toolchainsResult.getEffectiveToolchains());
1269
1270 if (!toolchainsResult.getProblems().isEmpty() && slf4jLogger.isWarnEnabled()) {
1271 slf4jLogger.warn("");
1272 slf4jLogger.warn("Some problems were encountered while building the effective toolchains");
1273
1274 for (Problem problem : toolchainsResult.getProblems()) {
1275 slf4jLogger.warn("{} @ {}", problem.getMessage(), problem.getLocation());
1276 }
1277
1278 slf4jLogger.warn("");
1279 }
1280 }
1281
1282 private Object getLocation(Source source, File defaultLocation) {
1283 if (source != null) {
1284 return source.getLocation();
1285 }
1286 return defaultLocation;
1287 }
1288
1289 protected MavenExecutionRequest populateRequest(CliRequest cliRequest) {
1290 return populateRequest(cliRequest, cliRequest.request);
1291 }
1292
1293 private MavenExecutionRequest populateRequest(CliRequest cliRequest, MavenExecutionRequest request) {
1294 slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
1295 CommandLine commandLine = cliRequest.commandLine;
1296 String workingDirectory = cliRequest.workingDirectory;
1297 boolean quiet = cliRequest.quiet;
1298 boolean verbose = cliRequest.verbose;
1299 request.setShowErrors(cliRequest.showErrors);
1300 File baseDirectory = new File(workingDirectory, "").getAbsoluteFile();
1301
1302 disableInteractiveModeIfNeeded(cliRequest, request);
1303 enableOnPresentOption(commandLine, CLIManager.SUPPRESS_SNAPSHOT_UPDATES, request::setNoSnapshotUpdates);
1304 request.setGoals(commandLine.getArgList());
1305 request.setReactorFailureBehavior(determineReactorFailureBehaviour(commandLine));
1306 disableOnPresentOption(commandLine, CLIManager.NON_RECURSIVE, request::setRecursive);
1307 enableOnPresentOption(commandLine, CLIManager.OFFLINE, request::setOffline);
1308 enableOnPresentOption(commandLine, CLIManager.UPDATE_SNAPSHOTS, request::setUpdateSnapshots);
1309 request.setGlobalChecksumPolicy(determineGlobalCheckPolicy(commandLine));
1310 request.setBaseDirectory(baseDirectory);
1311 request.setSystemProperties(cliRequest.systemProperties);
1312 request.setUserProperties(cliRequest.userProperties);
1313 request.setMultiModuleProjectDirectory(cliRequest.multiModuleProjectDirectory);
1314 request.setRootDirectory(cliRequest.rootDirectory);
1315 request.setTopDirectory(cliRequest.topDirectory);
1316 request.setPom(determinePom(commandLine, workingDirectory, baseDirectory));
1317 request.setTransferListener(determineTransferListener(quiet, verbose, commandLine, request));
1318 request.setExecutionListener(determineExecutionListener());
1319
1320 if ((request.getPom() != null) && (request.getPom().getParentFile() != null)) {
1321 request.setBaseDirectory(request.getPom().getParentFile());
1322 }
1323
1324 request.setResumeFrom(commandLine.getOptionValue(CLIManager.RESUME_FROM));
1325 enableOnPresentOption(commandLine, CLIManager.RESUME, request::setResume);
1326 request.setMakeBehavior(determineMakeBehavior(commandLine));
1327 boolean cacheNotFound = !commandLine.hasOption(CLIManager.CACHE_ARTIFACT_NOT_FOUND)
1328 || Boolean.parseBoolean(commandLine.getOptionValue(CLIManager.CACHE_ARTIFACT_NOT_FOUND));
1329 request.setCacheNotFound(cacheNotFound);
1330 request.setCacheTransferError(false);
1331 boolean strictArtifactDescriptorPolicy = commandLine.hasOption(CLIManager.STRICT_ARTIFACT_DESCRIPTOR_POLICY)
1332 && Boolean.parseBoolean(commandLine.getOptionValue(CLIManager.STRICT_ARTIFACT_DESCRIPTOR_POLICY));
1333 if (strictArtifactDescriptorPolicy) {
1334 request.setIgnoreMissingArtifactDescriptor(false);
1335 request.setIgnoreInvalidArtifactDescriptor(false);
1336 } else {
1337 request.setIgnoreMissingArtifactDescriptor(true);
1338 request.setIgnoreInvalidArtifactDescriptor(true);
1339 }
1340 enableOnPresentOption(
1341 commandLine, CLIManager.IGNORE_TRANSITIVE_REPOSITORIES, request::setIgnoreTransitiveRepositories);
1342
1343 performProjectActivation(commandLine, request.getProjectActivation());
1344 performProfileActivation(commandLine, request.getProfileActivation());
1345
1346 final String localRepositoryPath = determineLocalRepositoryPath(request);
1347 if (localRepositoryPath != null) {
1348 request.setLocalRepositoryPath(localRepositoryPath);
1349 }
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359 final String threadConfiguration = commandLine.getOptionValue(CLIManager.THREADS);
1360
1361 if (threadConfiguration != null) {
1362 int degreeOfConcurrency = calculateDegreeOfConcurrency(threadConfiguration);
1363 if (degreeOfConcurrency > 1) {
1364 request.setBuilderId("multithreaded");
1365 request.setDegreeOfConcurrency(degreeOfConcurrency);
1366 }
1367 }
1368
1369
1370
1371
1372 request.setBuilderId(commandLine.getOptionValue(CLIManager.BUILDER, request.getBuilderId()));
1373
1374 return request;
1375 }
1376
1377 private void disableInteractiveModeIfNeeded(final CliRequest cliRequest, final MavenExecutionRequest request) {
1378 CommandLine commandLine = cliRequest.getCommandLine();
1379 if (commandLine.hasOption(FORCE_INTERACTIVE)) {
1380 return;
1381 }
1382
1383 if (commandLine.hasOption(BATCH_MODE) || commandLine.hasOption(NON_INTERACTIVE)) {
1384 request.setInteractiveMode(false);
1385 } else {
1386 boolean runningOnCI = isRunningOnCI(cliRequest.getSystemProperties());
1387 if (runningOnCI) {
1388 slf4jLogger.info(
1389 "Making this build non-interactive, because the environment variable CI equals \"true\"."
1390 + " Disable this detection by removing that variable or adding --force-interactive.");
1391 request.setInteractiveMode(false);
1392 }
1393 }
1394 }
1395
1396 private static boolean isRunningOnCI(Properties systemProperties) {
1397 String ciEnv = systemProperties.getProperty("env.CI");
1398 return ciEnv != null && !"false".equals(ciEnv);
1399 }
1400
1401 private String determineLocalRepositoryPath(final MavenExecutionRequest request) {
1402 String userDefinedLocalRepo = request.getUserProperties().getProperty(Constants.MAVEN_REPO_LOCAL);
1403 if (userDefinedLocalRepo == null) {
1404 userDefinedLocalRepo = request.getSystemProperties().getProperty(Constants.MAVEN_REPO_LOCAL);
1405 if (userDefinedLocalRepo != null) {
1406 slf4jLogger.warn(
1407 "The property '{}' has been set using a JVM system property which is deprecated. "
1408 + "The property can be passed as a Maven argument or in the Maven project configuration file,"
1409 + "usually located at ${session.rootDirectory}/.mvn/maven.properties.",
1410 Constants.MAVEN_REPO_LOCAL);
1411 }
1412 }
1413 return userDefinedLocalRepo;
1414 }
1415
1416 private File determinePom(final CommandLine commandLine, final String workingDirectory, final File baseDirectory) {
1417 String alternatePomFile = null;
1418 if (commandLine.hasOption(CLIManager.ALTERNATE_POM_FILE)) {
1419 alternatePomFile = commandLine.getOptionValue(CLIManager.ALTERNATE_POM_FILE);
1420 }
1421
1422 File current = baseDirectory;
1423 if (alternatePomFile != null) {
1424 current = resolveFile(new File(alternatePomFile), workingDirectory);
1425 }
1426
1427 if (modelProcessor != null) {
1428 return modelProcessor.locateExistingPom(current);
1429 } else {
1430 return current.isFile() ? current : null;
1431 }
1432 }
1433
1434
1435 static void performProjectActivation(final CommandLine commandLine, final ProjectActivation projectActivation) {
1436 if (commandLine.hasOption(CLIManager.PROJECT_LIST)) {
1437 final String[] optionValues = commandLine.getOptionValues(CLIManager.PROJECT_LIST);
1438
1439 if (optionValues == null || optionValues.length == 0) {
1440 return;
1441 }
1442
1443 for (final String optionValue : optionValues) {
1444 for (String token : optionValue.split(",")) {
1445 String selector = token.trim();
1446 boolean active = true;
1447 if (!selector.isEmpty()) {
1448 if (selector.charAt(0) == '-' || selector.charAt(0) == '!') {
1449 active = false;
1450 selector = selector.substring(1);
1451 } else if (token.charAt(0) == '+') {
1452 selector = selector.substring(1);
1453 }
1454 }
1455 boolean optional = false;
1456 if (!selector.isEmpty() && selector.charAt(0) == '?') {
1457 optional = true;
1458 selector = selector.substring(1);
1459 }
1460 projectActivation.addProjectActivation(selector, active, optional);
1461 }
1462 }
1463 }
1464 }
1465
1466
1467 static void performProfileActivation(final CommandLine commandLine, final ProfileActivation profileActivation) {
1468 if (commandLine.hasOption(CLIManager.ACTIVATE_PROFILES)) {
1469 final String[] optionValues = commandLine.getOptionValues(CLIManager.ACTIVATE_PROFILES);
1470
1471 if (optionValues == null || optionValues.length == 0) {
1472 return;
1473 }
1474
1475 for (final String optionValue : optionValues) {
1476 for (String token : optionValue.split(",")) {
1477 String profileId = token.trim();
1478 boolean active = true;
1479 if (!profileId.isEmpty()) {
1480 if (profileId.charAt(0) == '-' || profileId.charAt(0) == '!') {
1481 active = false;
1482 profileId = profileId.substring(1);
1483 } else if (token.charAt(0) == '+') {
1484 profileId = profileId.substring(1);
1485 }
1486 }
1487 boolean optional = false;
1488 if (!profileId.isEmpty() && profileId.charAt(0) == '?') {
1489 optional = true;
1490 profileId = profileId.substring(1);
1491 }
1492 profileActivation.addProfileActivation(profileId, active, optional);
1493 }
1494 }
1495 }
1496 }
1497
1498 private ExecutionListener determineExecutionListener() {
1499 ExecutionListener executionListener = new ExecutionEventLogger(messageBuilderFactory);
1500 if (eventSpyDispatcher != null) {
1501 return eventSpyDispatcher.chainListener(executionListener);
1502 } else {
1503 return executionListener;
1504 }
1505 }
1506
1507 private String determineReactorFailureBehaviour(final CommandLine commandLine) {
1508 if (commandLine.hasOption(CLIManager.FAIL_FAST)) {
1509 return MavenExecutionRequest.REACTOR_FAIL_FAST;
1510 } else if (commandLine.hasOption(CLIManager.FAIL_AT_END)) {
1511 return MavenExecutionRequest.REACTOR_FAIL_AT_END;
1512 } else if (commandLine.hasOption(CLIManager.FAIL_NEVER)) {
1513 return MavenExecutionRequest.REACTOR_FAIL_NEVER;
1514 } else {
1515
1516 return MavenExecutionRequest.REACTOR_FAIL_FAST;
1517 }
1518 }
1519
1520 private TransferListener determineTransferListener(
1521 final boolean quiet,
1522 final boolean verbose,
1523 final CommandLine commandLine,
1524 final MavenExecutionRequest request) {
1525 boolean runningOnCI = isRunningOnCI(request.getSystemProperties());
1526 boolean quietCI = runningOnCI && !commandLine.hasOption(FORCE_INTERACTIVE);
1527
1528 if (quiet || commandLine.hasOption(CLIManager.NO_TRANSFER_PROGRESS) || quietCI) {
1529 return new QuietMavenTransferListener();
1530 } else if (request.isInteractiveMode() && !commandLine.hasOption(CLIManager.LOG_FILE)) {
1531
1532
1533
1534
1535 return getConsoleTransferListener(verbose);
1536 } else {
1537
1538 return getBatchTransferListener();
1539 }
1540 }
1541
1542 private String determineMakeBehavior(final CommandLine cl) {
1543 if (cl.hasOption(CLIManager.ALSO_MAKE) && !cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
1544 return MavenExecutionRequest.REACTOR_MAKE_UPSTREAM;
1545 } else if (!cl.hasOption(CLIManager.ALSO_MAKE) && cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
1546 return MavenExecutionRequest.REACTOR_MAKE_DOWNSTREAM;
1547 } else if (cl.hasOption(CLIManager.ALSO_MAKE) && cl.hasOption(CLIManager.ALSO_MAKE_DEPENDENTS)) {
1548 return MavenExecutionRequest.REACTOR_MAKE_BOTH;
1549 } else {
1550 return null;
1551 }
1552 }
1553
1554 private String determineGlobalCheckPolicy(final CommandLine commandLine) {
1555 if (commandLine.hasOption(CLIManager.CHECKSUM_FAILURE_POLICY)) {
1556 return MavenExecutionRequest.CHECKSUM_POLICY_FAIL;
1557 } else if (commandLine.hasOption(CLIManager.CHECKSUM_WARNING_POLICY)) {
1558 return MavenExecutionRequest.CHECKSUM_POLICY_WARN;
1559 } else {
1560 return null;
1561 }
1562 }
1563
1564 private void disableOnPresentOption(
1565 final CommandLine commandLine, final String option, final Consumer<Boolean> setting) {
1566 if (commandLine.hasOption(option)) {
1567 setting.accept(false);
1568 }
1569 }
1570
1571 private void disableOnPresentOption(
1572 final CommandLine commandLine, final char option, final Consumer<Boolean> setting) {
1573 disableOnPresentOption(commandLine, String.valueOf(option), setting);
1574 }
1575
1576 private void enableOnPresentOption(
1577 final CommandLine commandLine, final String option, final Consumer<Boolean> setting) {
1578 if (commandLine.hasOption(option)) {
1579 setting.accept(true);
1580 }
1581 }
1582
1583 private void enableOnPresentOption(
1584 final CommandLine commandLine, final char option, final Consumer<Boolean> setting) {
1585 enableOnPresentOption(commandLine, String.valueOf(option), setting);
1586 }
1587
1588 private void enableOnAbsentOption(
1589 final CommandLine commandLine, final char option, final Consumer<Boolean> setting) {
1590 if (!commandLine.hasOption(option)) {
1591 setting.accept(true);
1592 }
1593 }
1594
1595 int calculateDegreeOfConcurrency(String threadConfiguration) {
1596 try {
1597 if (threadConfiguration.endsWith("C")) {
1598 String str = threadConfiguration.substring(0, threadConfiguration.length() - 1);
1599 float coreMultiplier = Float.parseFloat(str);
1600
1601 if (coreMultiplier <= 0.0f) {
1602 throw new IllegalArgumentException("Invalid threads core multiplier value: '" + threadConfiguration
1603 + "'. Value must be positive.");
1604 }
1605
1606 int procs = Runtime.getRuntime().availableProcessors();
1607 int threads = (int) (coreMultiplier * procs);
1608 return threads == 0 ? 1 : threads;
1609 } else {
1610 int threads = Integer.parseInt(threadConfiguration);
1611 if (threads <= 0) {
1612 throw new IllegalArgumentException(
1613 "Invalid threads value: '" + threadConfiguration + "'. Value must be positive.");
1614 }
1615 return threads;
1616 }
1617 } catch (NumberFormatException e) {
1618 throw new IllegalArgumentException("Invalid threads value: '" + threadConfiguration
1619 + "'. Supported are int and float values ending with C.");
1620 }
1621 }
1622
1623
1624
1625
1626
1627 void populateProperties(
1628 CommandLine commandLine, Properties paths, Properties systemProperties, Properties userProperties)
1629 throws Exception {
1630
1631
1632
1633
1634
1635 EnvironmentUtils.addEnvVars(systemProperties);
1636 SystemProperties.addSystemProperties(systemProperties);
1637
1638
1639
1640
1641
1642
1643 Properties buildProperties = CLIReportingUtils.getBuildProperties();
1644
1645 String mavenVersion = buildProperties.getProperty(CLIReportingUtils.BUILD_VERSION_PROPERTY);
1646 systemProperties.setProperty("maven.version", mavenVersion);
1647
1648 String mavenBuildVersion = CLIReportingUtils.createMavenVersionString(buildProperties);
1649 systemProperties.setProperty("maven.build.version", mavenBuildVersion);
1650
1651
1652
1653
1654
1655
1656
1657 Properties userSpecifiedProperties =
1658 commandLine.getOptionProperties(String.valueOf(CLIManager.SET_USER_PROPERTY));
1659 userProperties.putAll(userSpecifiedProperties);
1660
1661
1662
1663
1664 Function<String, String> callback =
1665 or(paths::getProperty, prefix("cli.", commandLine::getOptionValue), systemProperties::getProperty);
1666
1667 Path mavenConf;
1668 if (systemProperties.getProperty(MAVEN_INSTALLATION_CONF) != null) {
1669 mavenConf = fileSystem.getPath(systemProperties.getProperty(MAVEN_INSTALLATION_CONF));
1670 } else if (systemProperties.getProperty("maven.conf") != null) {
1671 mavenConf = fileSystem.getPath(systemProperties.getProperty("maven.conf"));
1672 } else if (systemProperties.getProperty(MAVEN_HOME) != null) {
1673 mavenConf = fileSystem.getPath(systemProperties.getProperty(MAVEN_HOME), "conf");
1674 } else {
1675 mavenConf = fileSystem.getPath("");
1676 }
1677 Path propertiesFile = mavenConf.resolve("maven.properties");
1678 MavenPropertiesLoader.loadProperties(userProperties, propertiesFile, callback, false);
1679
1680
1681
1682
1683
1684 Set<String> sys = SystemProperties.getSystemProperties().stringPropertyNames();
1685 userProperties.stringPropertyNames().stream()
1686 .filter(k -> !sys.contains(k))
1687 .forEach(k -> System.setProperty(k, userProperties.getProperty(k)));
1688 }
1689
1690 private static Function<String, String> prefix(String prefix, Function<String, String> cb) {
1691 return s -> {
1692 String v = null;
1693 if (s.startsWith(prefix)) {
1694 v = cb.apply(s.substring(prefix.length()));
1695 }
1696 return v;
1697 };
1698 }
1699
1700 private static Function<String, String> or(Function<String, String>... callbacks) {
1701 return s -> {
1702 for (Function<String, String> cb : callbacks) {
1703 String r = cb.apply(s);
1704 if (r != null) {
1705 return r;
1706 }
1707 }
1708 return null;
1709 };
1710 }
1711
1712 private static String stripLeadingAndTrailingQuotes(String str) {
1713 final int length = str.length();
1714 if (length > 1
1715 && str.startsWith("\"")
1716 && str.endsWith("\"")
1717 && str.substring(1, length - 1).indexOf('"') == -1) {
1718 str = str.substring(1, length - 1);
1719 }
1720
1721 return str;
1722 }
1723
1724 private static Path getCanonicalPath(Path path) {
1725 try {
1726 return path.toRealPath();
1727 } catch (IOException e) {
1728 return getCanonicalPath(path.getParent()).resolve(path.getFileName());
1729 }
1730 }
1731
1732 static class ExitException extends Exception {
1733 int exitCode;
1734
1735 ExitException(int exitCode) {
1736 this.exitCode = exitCode;
1737 }
1738 }
1739
1740
1741
1742
1743
1744 protected TransferListener getConsoleTransferListener(boolean printResourceNames) {
1745 return new SimplexTransferListener(
1746 new ConsoleMavenTransferListener(messageBuilderFactory, System.out, printResourceNames));
1747 }
1748
1749 protected TransferListener getBatchTransferListener() {
1750 return new Slf4jMavenTransferListener();
1751 }
1752
1753 protected void customizeContainer(PlexusContainer container) {}
1754
1755 protected ModelProcessor createModelProcessor(PlexusContainer container) throws ComponentLookupException {
1756 return container.lookup(ModelProcessor.class);
1757 }
1758
1759 public void setFileSystem(FileSystem fileSystem) {
1760 this.fileSystem = fileSystem;
1761 }
1762 }