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