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