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