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