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