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.logging.Slf4jStdoutLogger;
74 import org.apache.maven.cli.props.MavenPropertiesLoader;
75 import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
76 import org.apache.maven.cli.transfer.QuietMavenTransferListener;
77 import org.apache.maven.cli.transfer.SimplexTransferListener;
78 import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
79 import org.apache.maven.cling.internal.extension.io.CoreExtensionsStaxReader;
80 import org.apache.maven.cling.logging.Slf4jConfiguration;
81 import org.apache.maven.cling.logging.Slf4jConfigurationFactory;
82 import org.apache.maven.cling.logging.Slf4jLoggerManager;
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
135
136
137
138
139 @Deprecated
140 public class MavenCli {
141
142 public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory";
143
144 private static final String MVN_MAVEN_CONFIG = ".mvn/maven.config";
145
146 private ClassWorld classWorld;
147
148 private LoggerManager plexusLoggerManager;
149
150 private ILoggerFactory slf4jLoggerFactory;
151
152 private Logger slf4jLogger;
153
154 private EventSpyDispatcher eventSpyDispatcher;
155
156 private ModelProcessor modelProcessor;
157
158 private Maven maven;
159
160 private MavenExecutionRequestPopulator executionRequestPopulator;
161
162 private ToolchainsBuilder toolchainsBuilder;
163
164 private SecDispatcher dispatcher;
165
166 private Map<String, ConfigurationProcessor> configurationProcessors;
167
168 private CLIManager cliManager;
169
170 private MessageBuilderFactory messageBuilderFactory;
171
172 private FileSystem fileSystem = FileSystems.getDefault();
173
174 private static final Pattern NEXT_LINE = Pattern.compile("\r?\n");
175
176 public MavenCli() {
177 this(null);
178 }
179
180
181 public MavenCli(ClassWorld classWorld) {
182 this.classWorld = classWorld;
183 this.messageBuilderFactory = new JLineMessageBuilderFactory();
184 }
185
186 public static void main(String[] args) {
187 int result = main(args, null);
188
189 System.exit(result);
190 }
191
192 public static int main(String[] args, ClassWorld classWorld) {
193 MavenCli cli = new MavenCli();
194
195 MessageUtils.systemInstall();
196 MessageUtils.registerShutdownHook();
197 int result = cli.doMain(new CliRequest(args, classWorld));
198 MessageUtils.systemUninstall();
199
200 return result;
201 }
202
203
204 public static int doMain(String[] args, ClassWorld classWorld) {
205 MavenCli cli = new MavenCli();
206 return cli.doMain(new CliRequest(args, classWorld));
207 }
208
209
210
211
212
213
214
215
216
217
218
219
220 public int doMain(String[] args, String workingDirectory, PrintStream stdout, PrintStream stderr) {
221 PrintStream oldout = System.out;
222 PrintStream olderr = System.err;
223
224 final Set<String> realms;
225 if (classWorld != null) {
226 realms = new HashSet<>();
227 for (ClassRealm realm : classWorld.getRealms()) {
228 realms.add(realm.getId());
229 }
230 } else {
231 realms = Collections.emptySet();
232 }
233
234 try {
235 if (stdout != null) {
236 System.setOut(stdout);
237 }
238 if (stderr != null) {
239 System.setErr(stderr);
240 }
241
242 CliRequest cliRequest = new CliRequest(args, classWorld);
243 cliRequest.workingDirectory = workingDirectory;
244
245 return doMain(cliRequest);
246 } finally {
247 if (classWorld != null) {
248 for (ClassRealm realm : new ArrayList<>(classWorld.getRealms())) {
249 String realmId = realm.getId();
250 if (!realms.contains(realmId)) {
251 try {
252 classWorld.disposeRealm(realmId);
253 } catch (NoSuchRealmException ignored) {
254
255 }
256 }
257 }
258 }
259 System.setOut(oldout);
260 System.setErr(olderr);
261 }
262 }
263
264
265 public int doMain(CliRequest cliRequest) {
266 PlexusContainer localContainer = null;
267 try {
268 initialize(cliRequest);
269 cli(cliRequest);
270 properties(cliRequest);
271 logging(cliRequest);
272 informativeCommands(cliRequest);
273 version(cliRequest);
274 localContainer = container(cliRequest);
275 commands(cliRequest);
276 configure(cliRequest);
277 toolchains(cliRequest);
278 populateRequest(cliRequest);
279 encryption(cliRequest);
280 return execute(cliRequest);
281 } catch (ExitException e) {
282 return e.exitCode;
283 } catch (UnrecognizedOptionException e) {
284
285 return 1;
286 } catch (BuildAbort e) {
287 CLIReportingUtils.showError(slf4jLogger, "ABORTED", e, cliRequest.showErrors);
288
289 return 2;
290 } catch (Exception e) {
291 CLIReportingUtils.showError(slf4jLogger, "Error executing Maven.", e, cliRequest.showErrors);
292
293 return 1;
294 } finally {
295 if (localContainer != null) {
296 localContainer.dispose();
297 }
298 }
299 }
300
301 void initialize(CliRequest cliRequest) throws ExitException {
302 if (cliRequest.workingDirectory == null) {
303 cliRequest.workingDirectory = System.getProperty("user.dir");
304 }
305
306 if (cliRequest.multiModuleProjectDirectory == null) {
307 String basedirProperty = System.getProperty(MULTIMODULE_PROJECT_DIRECTORY);
308 if (basedirProperty == null) {
309 System.err.format("-D%s system property is not set.", MULTIMODULE_PROJECT_DIRECTORY);
310 throw new ExitException(1);
311 }
312 File basedir = new File(basedirProperty);
313 try {
314 cliRequest.multiModuleProjectDirectory = basedir.getCanonicalFile();
315 } catch (IOException e) {
316 cliRequest.multiModuleProjectDirectory = basedir.getAbsoluteFile();
317 }
318 }
319
320
321
322
323 Path topDirectory = fileSystem.getPath(cliRequest.workingDirectory);
324 boolean isAltFile = false;
325 for (String arg : cliRequest.args) {
326 if (isAltFile) {
327
328 Path path = topDirectory.resolve(stripLeadingAndTrailingQuotes(arg));
329 if (Files.isDirectory(path)) {
330 topDirectory = path;
331 } else if (Files.isRegularFile(path)) {
332 topDirectory = path.getParent();
333 if (!Files.isDirectory(topDirectory)) {
334 System.err.println("Directory " + topDirectory
335 + " extracted from the -f/--file command-line argument " + arg + " does not exist");
336 throw new ExitException(1);
337 }
338 } else {
339 System.err.println(
340 "POM file " + arg + " specified with the -f/--file command line argument does not exist");
341 throw new ExitException(1);
342 }
343 break;
344 } else {
345
346 isAltFile = arg.equals("-f") || arg.equals("--file");
347 }
348 }
349 topDirectory = getCanonicalPath(topDirectory);
350 cliRequest.topDirectory = topDirectory;
351
352
353
354
355 RootLocator rootLocator =
356 ServiceLoader.load(RootLocator.class).iterator().next();
357 cliRequest.rootDirectory = rootLocator.findRoot(topDirectory);
358
359
360
361
362
363 String mavenHome = System.getProperty(Constants.MAVEN_HOME);
364
365 if (mavenHome != null) {
366 System.setProperty(
367 Constants.MAVEN_HOME,
368 getCanonicalPath(fileSystem.getPath(mavenHome)).toString());
369 }
370 }
371
372 void cli(CliRequest cliRequest) throws Exception {
373
374
375
376
377 slf4jLogger = new Slf4jStdoutLogger();
378
379 cliManager = new CLIManager();
380
381 CommandLine mavenConfig = null;
382 try {
383 File configFile = new File(cliRequest.multiModuleProjectDirectory, MVN_MAVEN_CONFIG);
384
385 if (configFile.isFile()) {
386 try (Stream<String> lines = Files.lines(configFile.toPath(), Charset.defaultCharset())) {
387 String[] args = lines.filter(arg -> !arg.isEmpty() && !arg.startsWith("#"))
388 .toArray(String[]::new);
389 mavenConfig = cliManager.parse(args);
390 List<?> unrecognized = mavenConfig.getArgList();
391 if (!unrecognized.isEmpty()) {
392
393 throw new ParseException("Unrecognized maven.config file entries: " + unrecognized);
394 }
395 }
396 }
397 } catch (ParseException e) {
398 System.err.println("Unable to parse maven.config file options: " + e.getMessage());
399 cliManager.displayHelp(System.out);
400 throw e;
401 }
402
403 try {
404 CommandLine mavenCli = cliManager.parse(cliRequest.args);
405 if (mavenConfig == null) {
406 cliRequest.commandLine = mavenCli;
407 } else {
408 cliRequest.commandLine = cliMerge(mavenConfig, mavenCli);
409 }
410 } catch (ParseException e) {
411 System.err.println("Unable to parse command line options: " + e.getMessage());
412 cliManager.displayHelp(System.out);
413 throw e;
414 }
415 }
416
417 private void informativeCommands(CliRequest cliRequest) throws ExitException {
418 if (cliRequest.commandLine.hasOption(CLIManager.HELP)) {
419 cliManager.displayHelp(System.out);
420 throw new ExitException(0);
421 }
422
423 if (cliRequest.commandLine.hasOption(CLIManager.VERSION)) {
424 if (cliRequest.commandLine.hasOption(CLIManager.QUIET)) {
425 System.out.println(CLIReportingUtils.showVersionMinimal());
426 } else {
427 System.out.println(CLIReportingUtils.showVersion());
428 }
429 throw new ExitException(0);
430 }
431
432 if (cliRequest.rootDirectory == null) {
433 slf4jLogger.info(RootLocator.UNABLE_TO_FIND_ROOT_PROJECT_MESSAGE);
434 }
435 }
436
437 private CommandLine cliMerge(CommandLine mavenConfig, CommandLine mavenCli) {
438 CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
439
440
441 for (String arg : mavenCli.getArgs()) {
442 commandLineBuilder.addArg(arg);
443 }
444
445
446
447
448
449
450
451
452
453
454
455 List<Option> setPropertyOptions = new ArrayList<>();
456 for (Option opt : mavenCli.getOptions()) {
457 if (String.valueOf(CLIManager.SET_USER_PROPERTY).equals(opt.getOpt())) {
458 setPropertyOptions.add(opt);
459 } else {
460 commandLineBuilder.addOption(opt);
461 }
462 }
463 for (Option opt : mavenConfig.getOptions()) {
464 commandLineBuilder.addOption(opt);
465 }
466
467 for (Option opt : setPropertyOptions) {
468 commandLineBuilder.addOption(opt);
469 }
470 return commandLineBuilder.build();
471 }
472
473
474
475
476 void logging(CliRequest cliRequest) throws ExitException {
477
478 CommandLine commandLine = cliRequest.commandLine;
479 cliRequest.verbose = commandLine.hasOption(CLIManager.VERBOSE) || commandLine.hasOption(CLIManager.DEBUG);
480 cliRequest.quiet = !cliRequest.verbose && commandLine.hasOption(CLIManager.QUIET);
481 cliRequest.showErrors = cliRequest.verbose || commandLine.hasOption(CLIManager.ERRORS);
482
483
484 String styleColor = cliRequest.getUserProperties().getProperty("style.color", "auto");
485 styleColor = cliRequest.getUserProperties().getProperty(Constants.MAVEN_STYLE_COLOR_PROPERTY, styleColor);
486 styleColor = commandLine.getOptionValue(CLIManager.COLOR, styleColor);
487 if ("always".equals(styleColor) || "yes".equals(styleColor) || "force".equals(styleColor)) {
488 MessageUtils.setColorEnabled(true);
489 } else if ("never".equals(styleColor) || "no".equals(styleColor) || "none".equals(styleColor)) {
490 MessageUtils.setColorEnabled(false);
491 } else if (!"auto".equals(styleColor) && !"tty".equals(styleColor) && !"if-tty".equals(styleColor)) {
492 throw new IllegalArgumentException(
493 "Invalid color configuration value '" + styleColor + "'. Supported are 'auto', 'always', 'never'.");
494 } else {
495 boolean isBatchMode = !commandLine.hasOption(CLIManager.FORCE_INTERACTIVE)
496 && (commandLine.hasOption(CLIManager.BATCH_MODE)
497 || commandLine.hasOption(CLIManager.NON_INTERACTIVE));
498 if (isBatchMode || commandLine.hasOption(CLIManager.LOG_FILE)) {
499 MessageUtils.setColorEnabled(false);
500 }
501 }
502
503 slf4jLoggerFactory = LoggerFactory.getILoggerFactory();
504 Slf4jConfiguration slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(slf4jLoggerFactory);
505
506 if (cliRequest.verbose) {
507 cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_DEBUG);
508 slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.DEBUG);
509 } else if (cliRequest.quiet) {
510 cliRequest.request.setLoggingLevel(MavenExecutionRequest.LOGGING_LEVEL_ERROR);
511 slf4jConfiguration.setRootLoggerLevel(Slf4jConfiguration.Level.ERROR);
512 }
513
514
515
516
517 if (commandLine.hasOption(CLIManager.LOG_FILE)) {
518 File logFile = new File(commandLine.getOptionValue(CLIManager.LOG_FILE));
519 logFile = ResolveFile.resolveFile(logFile, cliRequest.workingDirectory);
520
521
522 try {
523 PrintStream ps = new PrintStream(new FileOutputStream(logFile));
524 System.setOut(ps);
525 System.setErr(ps);
526 } catch (FileNotFoundException e) {
527
528
529
530 }
531 }
532
533 slf4jConfiguration.activate();
534
535 plexusLoggerManager = new Slf4jLoggerManager();
536 slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName());
537
538 if (commandLine.hasOption(CLIManager.FAIL_ON_SEVERITY)) {
539 String logLevelThreshold = commandLine.getOptionValue(CLIManager.FAIL_ON_SEVERITY);
540
541 if (slf4jLoggerFactory instanceof LogLevelRecorder recorder) {
542 LogLevelRecorder.Level level =
543 switch (logLevelThreshold.toLowerCase(Locale.ENGLISH)) {
544 case "warn", "warning" -> LogLevelRecorder.Level.WARN;
545 case "error" -> LogLevelRecorder.Level.ERROR;
546 default -> throw new IllegalArgumentException(
547 logLevelThreshold
548 + " is not a valid log severity threshold. Valid severities are WARN/WARNING and ERROR.");
549 };
550 recorder.setMaxLevelAllowed(level);
551 slf4jLogger.info("Enabled to break the build on log level {}.", logLevelThreshold);
552 } else {
553 slf4jLogger.warn(
554 "Expected LoggerFactory to be of type '{}', but found '{}' instead. "
555 + "The --fail-on-severity flag will not take effect.",
556 LogLevelRecorder.class.getName(),
557 slf4jLoggerFactory.getClass().getName());
558 }
559 }
560
561
562 boolean fail = false;
563 for (Option option : cliRequest.commandLine.getOptions()) {
564 if (option.isDeprecated()) {
565 StringBuilder sb = new StringBuilder();
566 sb.append("The option -").append(option.getOpt());
567 if (option.getLongOpt() != null) {
568 sb.append(",--").append(option.getLongOpt());
569 }
570 sb.append(" is deprecated ");
571 if (option.getDeprecated().isForRemoval()) {
572 sb.append("and will be removed in a future version");
573 }
574 if (option.getDeprecated().getSince() != null) {
575 sb.append("since Maven ").append(option.getDeprecated().getSince());
576 }
577 boolean error = false;
578 if (option.getDeprecated().getDescription() != null) {
579 sb.append(": ").append(option.getDeprecated().getDescription());
580 error = option.getDeprecated().getDescription().startsWith("UNSUPPORTED:");
581 }
582 if (error) {
583 slf4jLogger.error(sb.toString());
584 fail = true;
585 } else {
586 slf4jLogger.warn(sb.toString());
587 }
588 }
589 }
590 if (fail) {
591 throw new ExitException(1);
592 }
593 }
594
595 private void version(CliRequest cliRequest) {
596 if (cliRequest.verbose || cliRequest.commandLine.hasOption(CLIManager.SHOW_VERSION)) {
597 System.out.println(CLIReportingUtils.showVersion());
598 }
599 }
600
601 private void commands(CliRequest cliRequest) {
602 if (cliRequest.showErrors) {
603 slf4jLogger.info("Error stacktraces are turned on.");
604 }
605
606 if (MavenExecutionRequest.CHECKSUM_POLICY_WARN.equals(cliRequest.request.getGlobalChecksumPolicy())) {
607 slf4jLogger.info("Disabling strict checksum verification on all artifact downloads.");
608 } else if (MavenExecutionRequest.CHECKSUM_POLICY_FAIL.equals(cliRequest.request.getGlobalChecksumPolicy())) {
609 slf4jLogger.info("Enabling strict checksum verification on all artifact downloads.");
610 }
611
612 if (slf4jLogger.isDebugEnabled()) {
613 slf4jLogger.debug("Message scheme: {}", (MessageUtils.isColorEnabled() ? "color" : "plain"));
614 if (MessageUtils.isColorEnabled()) {
615 MessageBuilder buff = MessageUtils.builder();
616 buff.a("Message styles: ");
617 buff.trace("trace").a(' ');
618 buff.debug("debug").a(' ');
619 buff.info("info").a(' ');
620 buff.warning("warning").a(' ');
621 buff.error("error").a(' ');
622 buff.success("success").a(' ');
623 buff.failure("failure").a(' ');
624 buff.strong("strong").a(' ');
625 buff.mojo("mojo").a(' ');
626 buff.project("project");
627 slf4jLogger.debug(buff.toString());
628 }
629 }
630 }
631
632
633
634 void properties(CliRequest cliRequest) throws Exception {
635 Properties paths = new Properties();
636 if (cliRequest.topDirectory != null) {
637 paths.put("session.topDirectory", cliRequest.topDirectory.toString());
638 }
639 if (cliRequest.rootDirectory != null) {
640 paths.put("session.rootDirectory", cliRequest.rootDirectory.toString());
641 }
642
643 populateProperties(cliRequest.commandLine, paths, cliRequest.systemProperties, cliRequest.userProperties);
644
645
646 Function<String, String> callback = v -> {
647 String r = paths.getProperty(v);
648 if (r == null) {
649 r = cliRequest.systemProperties.getProperty(v);
650 }
651 if (r == null) {
652 r = cliRequest.userProperties.getProperty(v);
653 }
654 return r != null ? r : v;
655 };
656 CommandLine.Builder commandLineBuilder = new CommandLine.Builder();
657 commandLineBuilder.setDeprecatedHandler(o -> {});
658 for (Option option : cliRequest.commandLine.getOptions()) {
659 if (!String.valueOf(CLIManager.SET_USER_PROPERTY).equals(option.getOpt())) {
660 List<String> values = option.getValuesList();
661 for (ListIterator<String> it = values.listIterator(); it.hasNext(); ) {
662 it.set(MavenPropertiesLoader.substVars(it.next(), null, null, callback));
663 }
664 }
665 commandLineBuilder.addOption(option);
666 }
667 for (String arg : cliRequest.commandLine.getArgList()) {
668 commandLineBuilder.addArg(MavenPropertiesLoader.substVars(arg, null, null, callback));
669 }
670 cliRequest.commandLine = commandLineBuilder.build();
671 }
672
673 PlexusContainer container(CliRequest cliRequest) throws Exception {
674 if (cliRequest.classWorld == null) {
675 cliRequest.classWorld =
676 new ClassWorld("plexus.core", Thread.currentThread().getContextClassLoader());
677 }
678
679 ClassRealm coreRealm = cliRequest.classWorld.getClassRealm("plexus.core");
680 if (coreRealm == null) {
681 coreRealm = cliRequest.classWorld.getRealms().iterator().next();
682 }
683
684 List<File> extClassPath = parseExtClasspath(cliRequest);
685
686 CoreExtensionEntry coreEntry = CoreExtensionEntry.discoverFrom(coreRealm);
687 List<CoreExtensionEntry> extensions =
688 loadCoreExtensions(cliRequest, coreRealm, coreEntry.getExportedArtifacts());
689
690 ClassRealm containerRealm = setupContainerRealm(cliRequest.classWorld, coreRealm, extClassPath, extensions);
691
692 ContainerConfiguration cc = new DefaultContainerConfiguration()
693 .setClassWorld(cliRequest.classWorld)
694 .setRealm(containerRealm)
695 .setClassPathScanning(PlexusConstants.SCANNING_INDEX)
696 .setAutoWiring(true)
697 .setJSR250Lifecycle(true)
698 .setStrictClassPathScanning(true)
699 .setName("maven");
700
701 Set<String> exportedArtifacts = new HashSet<>(coreEntry.getExportedArtifacts());
702 Set<String> exportedPackages = new HashSet<>(coreEntry.getExportedPackages());
703 for (CoreExtensionEntry extension : extensions) {
704 exportedArtifacts.addAll(extension.getExportedArtifacts());
705 exportedPackages.addAll(extension.getExportedPackages());
706 }
707
708 final CoreExports exports = new CoreExports(containerRealm, exportedArtifacts, exportedPackages);
709
710 Thread.currentThread().setContextClassLoader(containerRealm);
711
712 DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
713 @Override
714 protected void configure() {
715 bind(ILoggerFactory.class).toInstance(slf4jLoggerFactory);
716 bind(CoreExports.class).toInstance(exports);
717 bind(MessageBuilderFactory.class).toInstance(messageBuilderFactory);
718 }
719 });
720
721
722 container.setLookupRealm(null);
723 Thread.currentThread().setContextClassLoader(container.getContainerRealm());
724
725 container.setLoggerManager(plexusLoggerManager);
726
727 Function<String, String> extensionSource = expression -> {
728 String value = cliRequest.userProperties.getProperty(expression);
729 if (value == null) {
730 value = cliRequest.systemProperties.getProperty(expression);
731 }
732 return value;
733 };
734 for (CoreExtensionEntry extension : extensions) {
735 container.discoverComponents(
736 extension.getClassRealm(),
737 new AbstractModule() {
738 @Override
739 protected void configure() {
740 try {
741 container.lookup(Injector.class).discover(extension.getClassRealm());
742 } catch (Throwable e) {
743
744 e.printStackTrace();
745 }
746 }
747 },
748 new SessionScopeModule(container.lookup(SessionScope.class)),
749 new MojoExecutionScopeModule(container.lookup(MojoExecutionScope.class)),
750 new ExtensionConfigurationModule(extension, extensionSource));
751 }
752
753 customizeContainer(container);
754
755 container.getLoggerManager().setThresholds(cliRequest.request.getLoggingLevel());
756
757 eventSpyDispatcher = container.lookup(EventSpyDispatcher.class);
758
759 DefaultEventSpyContext eventSpyContext = new DefaultEventSpyContext();
760 Map<String, Object> data = eventSpyContext.getData();
761 data.put("plexus", container);
762 data.put("workingDirectory", cliRequest.workingDirectory);
763 data.put("systemProperties", cliRequest.systemProperties);
764 data.put("userProperties", cliRequest.userProperties);
765 data.put("versionProperties", CLIReportingUtils.getBuildProperties());
766 eventSpyDispatcher.init(eventSpyContext);
767
768
769 slf4jLogger = slf4jLoggerFactory.getLogger(this.getClass().getName());
770
771 maven = container.lookup(Maven.class);
772
773 executionRequestPopulator = container.lookup(MavenExecutionRequestPopulator.class);
774
775 modelProcessor = createModelProcessor(container);
776
777 configurationProcessors = container.lookupMap(ConfigurationProcessor.class);
778
779 toolchainsBuilder = container.lookup(ToolchainsBuilder.class);
780
781 dispatcher = container.lookup(SecDispatcher.class);
782
783 return container;
784 }
785
786 private List<CoreExtensionEntry> loadCoreExtensions(
787 CliRequest cliRequest, ClassRealm containerRealm, Set<String> providedArtifacts) throws Exception {
788 if (cliRequest.multiModuleProjectDirectory == null) {
789 return Collections.emptyList();
790 }
791
792 List<CoreExtension> extensions = new ArrayList<>();
793
794 String installationExtensionsFile =
795 cliRequest.getUserProperties().getProperty(Constants.MAVEN_INSTALLATION_EXTENSIONS);
796 extensions.addAll(readCoreExtensionsDescriptor(installationExtensionsFile));
797
798 String projectExtensionsFile = cliRequest.getUserProperties().getProperty(Constants.MAVEN_PROJECT_EXTENSIONS);
799 extensions.addAll(readCoreExtensionsDescriptor(projectExtensionsFile));
800
801 String userExtensionsFile = cliRequest.getUserProperties().getProperty(Constants.MAVEN_USER_EXTENSIONS);
802 extensions.addAll(readCoreExtensionsDescriptor(userExtensionsFile));
803
804 if (extensions.isEmpty()) {
805 return Collections.emptyList();
806 }
807
808 ContainerConfiguration cc = new DefaultContainerConfiguration()
809 .setClassWorld(cliRequest.classWorld)
810 .setRealm(containerRealm)
811 .setClassPathScanning(PlexusConstants.SCANNING_INDEX)
812 .setAutoWiring(true)
813 .setJSR250Lifecycle(true)
814 .setStrictClassPathScanning(true)
815 .setName("maven");
816
817 DefaultPlexusContainer container = new DefaultPlexusContainer(cc, new AbstractModule() {
818 @Override
819 protected void configure() {
820 bind(ILoggerFactory.class).toInstance(slf4jLoggerFactory);
821 }
822 });
823
824 try {
825 container.setLookupRealm(null);
826
827 container.setLoggerManager(plexusLoggerManager);
828
829 container.getLoggerManager().setThresholds(cliRequest.request.getLoggingLevel());
830
831 Thread.currentThread().setContextClassLoader(container.getContainerRealm());
832
833 executionRequestPopulator = container.lookup(MavenExecutionRequestPopulator.class);
834
835 configurationProcessors = container.lookupMap(ConfigurationProcessor.class);
836
837 configure(cliRequest);
838
839 MavenExecutionRequest request = DefaultMavenExecutionRequest.copy(cliRequest.request);
840
841 populateRequest(cliRequest, request);
842
843 request = executionRequestPopulator.populateDefaults(request);
844
845 BootstrapCoreExtensionManager resolver = container.lookup(BootstrapCoreExtensionManager.class);
846
847 return Collections.unmodifiableList(resolver.loadCoreExtensions(request, providedArtifacts, extensions));
848
849 } finally {
850 executionRequestPopulator = null;
851 container.dispose();
852 }
853 }
854
855 private List<CoreExtension> readCoreExtensionsDescriptor(String extensionsFile)
856 throws IOException, XMLStreamException {
857 if (extensionsFile != null) {
858 Path extensionsPath = Path.of(extensionsFile);
859 if (Files.exists(extensionsPath)) {
860 try (InputStream is = Files.newInputStream(extensionsPath)) {
861 return new CoreExtensionsStaxReader().read(is, true).getExtensions();
862 }
863 }
864 }
865 return List.of();
866 }
867
868 private ClassRealm setupContainerRealm(
869 ClassWorld classWorld, ClassRealm coreRealm, List<File> extClassPath, List<CoreExtensionEntry> extensions)
870 throws Exception {
871 if (!extClassPath.isEmpty() || !extensions.isEmpty()) {
872 ClassRealm extRealm = classWorld.newRealm("maven.ext", null);
873
874 extRealm.setParentRealm(coreRealm);
875
876 slf4jLogger.debug("Populating class realm '{}'", extRealm.getId());
877
878 for (File file : extClassPath) {
879 slf4jLogger.debug(" included '{}'", file);
880
881 extRealm.addURL(file.toURI().toURL());
882 }
883
884 for (CoreExtensionEntry entry : reverse(extensions)) {
885 Set<String> exportedPackages = entry.getExportedPackages();
886 ClassRealm realm = entry.getClassRealm();
887 for (String exportedPackage : exportedPackages) {
888 extRealm.importFrom(realm, exportedPackage);
889 }
890 if (exportedPackages.isEmpty()) {
891
892 extRealm.importFrom(realm, realm.getId());
893 }
894 }
895
896 return extRealm;
897 }
898
899 return coreRealm;
900 }
901
902 private static <T> List<T> reverse(List<T> list) {
903 List<T> copy = new ArrayList<>(list);
904 Collections.reverse(copy);
905 return copy;
906 }
907
908 private List<File> parseExtClasspath(CliRequest cliRequest) {
909 String extClassPath = cliRequest.userProperties.getProperty(Constants.MAVEN_EXT_CLASS_PATH);
910 if (extClassPath == null) {
911 extClassPath = cliRequest.systemProperties.getProperty(Constants.MAVEN_EXT_CLASS_PATH);
912 if (extClassPath != null) {
913 slf4jLogger.warn(
914 "The property '{}' has been set using a JVM system property which is deprecated. "
915 + "The property can be passed as a Maven argument or in the Maven project configuration file,"
916 + "usually located at ${session.rootDirectory}/.mvn/maven.properties.",
917 Constants.MAVEN_EXT_CLASS_PATH);
918 }
919 }
920
921 List<File> jars = new ArrayList<>();
922
923 if (extClassPath != null && !extClassPath.isEmpty()) {
924 for (String jar : extClassPath.split(File.pathSeparator)) {
925 File file = ResolveFile.resolveFile(new File(jar), cliRequest.workingDirectory);
926
927 slf4jLogger.debug(" included '{}'", file);
928
929 jars.add(file);
930 }
931 }
932
933 return jars;
934 }
935
936
937
938
939 private void encryption(CliRequest cliRequest) throws Exception {
940 if (cliRequest.commandLine.hasOption(CLIManager.ENCRYPT_MASTER_PASSWORD)) {
941 System.out.println("Master password encyption is not supported anymore");
942 throw new ExitException(1);
943 } else if (cliRequest.commandLine.hasOption(CLIManager.ENCRYPT_PASSWORD)) {
944 String passwd = cliRequest.commandLine.getOptionValue(CLIManager.ENCRYPT_PASSWORD);
945
946 if (passwd == null) {
947 Console cons = System.console();
948 char[] password = (cons == null) ? null : cons.readPassword("Password: ");
949 if (password != null) {
950
951 passwd = String.copyValueOf(password);
952
953
954 java.util.Arrays.fill(password, ' ');
955 }
956 }
957 System.out.println(dispatcher.encrypt(passwd, null));
958 throw new ExitException(0);
959 }
960 }
961
962 private int execute(CliRequest cliRequest) throws MavenExecutionRequestPopulationException {
963 MavenExecutionRequest request = executionRequestPopulator.populateDefaults(cliRequest.request);
964
965 if (cliRequest.request.getRepositoryCache() == null) {
966 cliRequest.request.setRepositoryCache(new DefaultRepositoryCache());
967 }
968
969 eventSpyDispatcher.onEvent(request);
970
971 MavenExecutionResult result = maven.execute(request);
972
973 eventSpyDispatcher.onEvent(result);
974
975 eventSpyDispatcher.close();
976
977 if (result.hasExceptions()) {
978 ExceptionHandler handler = new DefaultExceptionHandler();
979
980 Map<String, String> references = new LinkedHashMap<>();
981
982 List<MavenProject> failedProjects = new ArrayList<>();
983
984 for (Throwable exception : result.getExceptions()) {
985 ExceptionSummary summary = handler.handleException(exception);
986
987 logSummary(summary, references, "", cliRequest.showErrors);
988
989 if (exception instanceof LifecycleExecutionException) {
990 failedProjects.add(((LifecycleExecutionException) exception).getProject());
991 }
992 }
993
994 slf4jLogger.error("");
995
996 if (!cliRequest.showErrors) {
997 slf4jLogger.error(
998 "To see the full stack trace of the errors, re-run Maven with the '{}' switch",
999 MessageUtils.builder().strong("-e"));
1000 }
1001 if (!slf4jLogger.isDebugEnabled()) {
1002 slf4jLogger.error(
1003 "Re-run Maven using the '{}' switch to enable verbose output",
1004 MessageUtils.builder().strong("-X"));
1005 }
1006
1007 if (!references.isEmpty()) {
1008 slf4jLogger.error("");
1009 slf4jLogger.error("For more information about the errors and possible solutions"
1010 + ", please read the following articles:");
1011
1012 for (Map.Entry<String, String> entry : references.entrySet()) {
1013 slf4jLogger.error("{} {}", MessageUtils.builder().strong(entry.getValue()), entry.getKey());
1014 }
1015 }
1016
1017 if (result.canResume()) {
1018 logBuildResumeHint("mvn [args] -r");
1019 } else if (!failedProjects.isEmpty()) {
1020 List<MavenProject> sortedProjects = result.getTopologicallySortedProjects();
1021
1022
1023 failedProjects.sort(comparing(sortedProjects::indexOf));
1024
1025 MavenProject firstFailedProject = failedProjects.get(0);
1026 if (!firstFailedProject.equals(sortedProjects.get(0))) {
1027 String resumeFromSelector = getResumeFromSelector(sortedProjects, firstFailedProject);
1028 logBuildResumeHint("mvn [args] -rf " + resumeFromSelector);
1029 }
1030 }
1031
1032 if (MavenExecutionRequest.REACTOR_FAIL_NEVER.equals(cliRequest.request.getReactorFailureBehavior())) {
1033 slf4jLogger.info("Build failures were ignored.");
1034
1035 return 0;
1036 } else {
1037 return 1;
1038 }
1039 } else {
1040 return 0;
1041 }
1042 }
1043
1044 private void logBuildResumeHint(String resumeBuildHint) {
1045 slf4jLogger.error("");
1046 slf4jLogger.error("After correcting the problems, you can resume the build with the command");
1047 slf4jLogger.error(MessageUtils.builder().a(" ").strong(resumeBuildHint).toString());
1048 }
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067 String getResumeFromSelector(List<MavenProject> mavenProjects, MavenProject firstFailedProject) {
1068 boolean hasOverlappingArtifactId = mavenProjects.stream()
1069 .filter(project -> firstFailedProject.getArtifactId().equals(project.getArtifactId()))
1070 .count()
1071 > 1;
1072
1073 if (hasOverlappingArtifactId) {
1074 return firstFailedProject.getGroupId() + ":" + firstFailedProject.getArtifactId();
1075 }
1076
1077 return ":" + firstFailedProject.getArtifactId();
1078 }
1079
1080 private void logSummary(
1081 ExceptionSummary summary, Map<String, String> references, String indent, boolean showErrors) {
1082 String referenceKey = "";
1083
1084 if (summary.getReference() != null && !summary.getReference().isEmpty()) {
1085 referenceKey =
1086 references.computeIfAbsent(summary.getReference(), k -> "[Help " + (references.size() + 1) + "]");
1087 }
1088
1089 String msg = summary.getMessage();
1090
1091 if (referenceKey != null && !referenceKey.isEmpty()) {
1092 if (msg.indexOf('\n') < 0) {
1093 msg += " -> " + MessageUtils.builder().strong(referenceKey);
1094 } else {
1095 msg += "\n-> " + MessageUtils.builder().strong(referenceKey);
1096 }
1097 }
1098
1099 String[] lines = NEXT_LINE.split(msg);
1100 String currentColor = "";
1101
1102 for (int i = 0; i < lines.length; i++) {
1103
1104 String line = currentColor + lines[i];
1105
1106
1107 Matcher matcher = LAST_ANSI_SEQUENCE.matcher(line);
1108 String nextColor = "";
1109 if (matcher.find()) {
1110 nextColor = matcher.group(1);
1111 if (ANSI_RESET.equals(nextColor)) {
1112
1113 nextColor = "";
1114 }
1115 }
1116
1117
1118 line = indent + line + ("".equals(nextColor) ? "" : ANSI_RESET);
1119
1120 if ((i == lines.length - 1) && (showErrors || (summary.getException() instanceof InternalErrorException))) {
1121 slf4jLogger.error(line, summary.getException());
1122 } else {
1123 slf4jLogger.error(line);
1124 }
1125
1126 currentColor = nextColor;
1127 }
1128
1129 indent += " ";
1130
1131 for (ExceptionSummary child : summary.getChildren()) {
1132 logSummary(child, references, indent, showErrors);
1133 }
1134 }
1135
1136 private static final Pattern LAST_ANSI_SEQUENCE = Pattern.compile("(\u001B\\[[;\\d]*[ -/]*[@-~])[^\u001B]*$");
1137
1138 private static final String ANSI_RESET = "\u001B\u005Bm";
1139
1140 private void configure(CliRequest cliRequest) throws Exception {
1141
1142
1143
1144
1145
1146
1147 cliRequest.request.setEventSpyDispatcher(eventSpyDispatcher);
1148
1149
1150
1151
1152
1153
1154
1155
1156 int userSuppliedConfigurationProcessorCount = configurationProcessors.size() - 1;
1157
1158 if (userSuppliedConfigurationProcessorCount == 0) {
1159
1160
1161
1162
1163 configurationProcessors.get(SettingsXmlConfigurationProcessor.HINT).process(cliRequest);
1164 } else if (userSuppliedConfigurationProcessorCount == 1) {
1165
1166
1167
1168 for (Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet()) {
1169 String hint = entry.getKey();
1170 if (!hint.equals(SettingsXmlConfigurationProcessor.HINT)) {
1171 ConfigurationProcessor configurationProcessor = entry.getValue();
1172 configurationProcessor.process(cliRequest);
1173 }
1174 }
1175 } else if (userSuppliedConfigurationProcessorCount > 1) {
1176
1177
1178
1179 StringBuilder sb = new StringBuilder(String.format(
1180 "%nThere can only be one user supplied ConfigurationProcessor, there are %s:%n%n",
1181 userSuppliedConfigurationProcessorCount));
1182 for (Entry<String, ConfigurationProcessor> entry : configurationProcessors.entrySet()) {
1183 String hint = entry.getKey();
1184 if (!hint.equals(SettingsXmlConfigurationProcessor.HINT)) {
1185 ConfigurationProcessor configurationProcessor = entry.getValue();
1186 sb.append(String.format(
1187 "%s%n", configurationProcessor.getClass().getName()));
1188 }
1189 }
1190 throw new Exception(sb.toString());
1191 }
1192 }
1193
1194 void toolchains(CliRequest cliRequest) throws Exception {
1195 File userToolchainsFile = null;
1196
1197 if (cliRequest.commandLine.hasOption(CLIManager.ALTERNATE_USER_TOOLCHAINS)) {
1198 userToolchainsFile = new File(cliRequest.commandLine.getOptionValue(CLIManager.ALTERNATE_USER_TOOLCHAINS));
1199 userToolchainsFile = ResolveFile.resolveFile(userToolchainsFile, cliRequest.workingDirectory);
1200
1201 if (!userToolchainsFile.isFile()) {
1202 throw new FileNotFoundException(
1203 "The specified user toolchains file does not exist: " + userToolchainsFile);
1204 }
1205 } else {
1206 String userToolchainsFileStr = cliRequest.getUserProperties().getProperty(Constants.MAVEN_USER_TOOLCHAINS);
1207 if (userToolchainsFileStr != null) {
1208 userToolchainsFile = new File(userToolchainsFileStr);
1209 }
1210 }
1211
1212 File installationToolchainsFile = null;
1213
1214 if (cliRequest.commandLine.hasOption(CLIManager.ALTERNATE_INSTALLATION_TOOLCHAINS)) {
1215 installationToolchainsFile =
1216 new File(cliRequest.commandLine.getOptionValue(CLIManager.ALTERNATE_INSTALLATION_TOOLCHAINS));
1217 installationToolchainsFile =
1218 ResolveFile.resolveFile(installationToolchainsFile, cliRequest.workingDirectory);
1219
1220 if (!installationToolchainsFile.isFile()) {
1221 throw new FileNotFoundException(
1222 "The specified installation toolchains file does not exist: " + installationToolchainsFile);
1223 }
1224 } else if (cliRequest.commandLine.hasOption(CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS)) {
1225 installationToolchainsFile =
1226 new File(cliRequest.commandLine.getOptionValue(CLIManager.ALTERNATE_GLOBAL_TOOLCHAINS));
1227 installationToolchainsFile =
1228 ResolveFile.resolveFile(installationToolchainsFile, cliRequest.workingDirectory);
1229
1230 if (!installationToolchainsFile.isFile()) {
1231 throw new FileNotFoundException(
1232 "The specified installation toolchains file does not exist: " + installationToolchainsFile);
1233 }
1234 } else {
1235 String installationToolchainsFileStr =
1236 cliRequest.getUserProperties().getProperty(Constants.MAVEN_INSTALLATION_TOOLCHAINS);
1237 if (installationToolchainsFileStr != null) {
1238 installationToolchainsFile = new File(installationToolchainsFileStr);
1239 installationToolchainsFile =
1240 ResolveFile.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(CLIManager.FORCE_INTERACTIVE)) {
1380 return;
1381 }
1382
1383 if (commandLine.hasOption(CLIManager.BATCH_MODE) || commandLine.hasOption(CLIManager.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.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(CLIManager.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 }