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