1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.cling.invoker;
20
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.PrintWriter;
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.util.ArrayList;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.HashSet;
30 import java.util.List;
31 import java.util.Locale;
32 import java.util.Map;
33 import java.util.Properties;
34 import java.util.function.Function;
35
36 import org.apache.maven.api.Constants;
37 import org.apache.maven.api.Session;
38 import org.apache.maven.api.cli.Invoker;
39 import org.apache.maven.api.cli.InvokerException;
40 import org.apache.maven.api.cli.InvokerRequest;
41 import org.apache.maven.api.cli.Logger;
42 import org.apache.maven.api.cli.Options;
43 import org.apache.maven.api.services.BuilderProblem;
44 import org.apache.maven.api.services.Interpolator;
45 import org.apache.maven.api.services.Lookup;
46 import org.apache.maven.api.services.MavenException;
47 import org.apache.maven.api.services.MessageBuilder;
48 import org.apache.maven.api.services.SettingsBuilder;
49 import org.apache.maven.api.services.SettingsBuilderRequest;
50 import org.apache.maven.api.services.SettingsBuilderResult;
51 import org.apache.maven.api.services.Source;
52 import org.apache.maven.api.settings.Mirror;
53 import org.apache.maven.api.settings.Profile;
54 import org.apache.maven.api.settings.Proxy;
55 import org.apache.maven.api.settings.Repository;
56 import org.apache.maven.api.settings.Server;
57 import org.apache.maven.api.settings.Settings;
58 import org.apache.maven.artifact.InvalidRepositoryException;
59 import org.apache.maven.artifact.repository.ArtifactRepository;
60 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
61 import org.apache.maven.artifact.repository.MavenArtifactRepository;
62 import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
63 import org.apache.maven.bridge.MavenRepositorySystem;
64 import org.apache.maven.cli.CLIReportingUtils;
65 import org.apache.maven.cli.logging.Slf4jConfiguration;
66 import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
67 import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
68 import org.apache.maven.cli.transfer.QuietMavenTransferListener;
69 import org.apache.maven.cli.transfer.SimplexTransferListener;
70 import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
71 import org.apache.maven.cling.invoker.mvn.ProtoSession;
72 import org.apache.maven.execution.MavenExecutionRequest;
73 import org.apache.maven.internal.impl.SettingsUtilsV4;
74 import org.apache.maven.jline.FastTerminal;
75 import org.apache.maven.jline.MessageUtils;
76 import org.apache.maven.logging.BuildEventListener;
77 import org.apache.maven.logging.LoggingOutputStream;
78 import org.apache.maven.logging.ProjectBuildLogAppender;
79 import org.apache.maven.logging.SimpleBuildEventListener;
80 import org.apache.maven.logging.api.LogLevelRecorder;
81 import org.apache.maven.slf4j.MavenSimpleLogger;
82 import org.eclipse.aether.transfer.TransferListener;
83 import org.jline.jansi.AnsiConsole;
84 import org.jline.terminal.Terminal;
85 import org.jline.terminal.TerminalBuilder;
86 import org.slf4j.ILoggerFactory;
87 import org.slf4j.LoggerFactory;
88 import org.slf4j.spi.LocationAwareLogger;
89
90 import static java.util.Objects.requireNonNull;
91 import static org.apache.maven.cling.invoker.Utils.toMavenExecutionRequestLoggingLevel;
92 import static org.apache.maven.cling.invoker.Utils.toProperties;
93
94
95
96
97
98
99
100
101 public abstract class LookupInvoker<
102 O extends Options, R extends InvokerRequest<O>, C extends LookupInvoker.LookupInvokerContext<O, R, C>>
103 implements Invoker<R> {
104
105
106
107
108
109 public static final class ExitException extends InvokerException {
110 private final int exitCode;
111
112 public ExitException(int exitCode) {
113 super("EXIT");
114 this.exitCode = exitCode;
115 }
116 }
117
118 @SuppressWarnings("VisibilityModifier")
119 public static class LookupInvokerContext<
120 O extends Options, R extends InvokerRequest<O>, C extends LookupInvokerContext<O, R, C>>
121 implements AutoCloseable {
122 public final LookupInvoker<O, R, C> invoker;
123 public final ProtoLookup protoLookup;
124 public final R invokerRequest;
125 public final Function<String, Path> cwdResolver;
126 public final Function<String, Path> installationResolver;
127 public final Function<String, Path> userResolver;
128 public final Session session;
129
130 protected LookupInvokerContext(LookupInvoker<O, R, C> invoker, R invokerRequest) {
131 this.invoker = invoker;
132 this.protoLookup = invoker.protoLookup;
133 this.invokerRequest = requireNonNull(invokerRequest);
134 this.cwdResolver = s -> invokerRequest.cwd().resolve(s).normalize().toAbsolutePath();
135 this.installationResolver = s -> invokerRequest
136 .installationDirectory()
137 .resolve(s)
138 .normalize()
139 .toAbsolutePath();
140 this.userResolver = s ->
141 invokerRequest.userHomeDirectory().resolve(s).normalize().toAbsolutePath();
142 this.logger = invokerRequest.parserRequest().logger();
143
144 Map<String, String> user = new HashMap<>(invokerRequest.userProperties());
145 user.put("session.rootDirectory", invokerRequest.rootDirectory().toString());
146 user.put("session.topDirectory", invokerRequest.topDirectory().toString());
147 Map<String, String> system = new HashMap<>(invokerRequest.systemProperties());
148 this.session = ProtoSession.create(user, system);
149 }
150
151 public Logger logger;
152 public ILoggerFactory loggerFactory;
153 public Slf4jConfiguration slf4jConfiguration;
154 public Slf4jConfiguration.Level loggerLevel;
155 public Terminal terminal;
156 public BuildEventListener buildEventListener;
157 public ClassLoader currentThreadContextClassLoader;
158 public ContainerCapsule containerCapsule;
159 public Lookup lookup;
160 public SettingsBuilder settingsBuilder;
161
162 public boolean interactive;
163 public Path localRepositoryPath;
164 public Path installationSettingsPath;
165 public Path projectSettingsPath;
166 public Path userSettingsPath;
167 public Settings effectiveSettings;
168
169 public final List<AutoCloseable> closeables = new ArrayList<>();
170
171 @Override
172 public void close() throws InvokerException {
173 List<Exception> causes = null;
174 List<AutoCloseable> cs = new ArrayList<>(closeables);
175 Collections.reverse(cs);
176 for (AutoCloseable c : cs) {
177 if (c != null) {
178 try {
179 c.close();
180 } catch (Exception e) {
181 if (causes == null) {
182 causes = new ArrayList<>();
183 }
184 causes.add(e);
185 }
186 }
187 }
188 if (causes != null) {
189 InvokerException exception = new InvokerException("Unable to close context");
190 causes.forEach(exception::addSuppressed);
191 throw exception;
192 }
193 }
194 }
195
196 protected final ProtoLookup protoLookup;
197
198 public LookupInvoker(ProtoLookup protoLookup) {
199 this.protoLookup = requireNonNull(protoLookup);
200 }
201
202 @Override
203 public int invoke(R invokerRequest) throws InvokerException {
204 requireNonNull(invokerRequest);
205
206 Properties oldProps = (Properties) System.getProperties().clone();
207 ClassLoader oldCL = Thread.currentThread().getContextClassLoader();
208 try (C context = createContext(invokerRequest)) {
209 try {
210 if (context.currentThreadContextClassLoader != null) {
211 Thread.currentThread().setContextClassLoader(context.currentThreadContextClassLoader);
212 }
213 return doInvoke(context);
214 } catch (ExitException e) {
215 return e.exitCode;
216 } catch (Exception e) {
217 throw handleException(context, e);
218 }
219 } finally {
220 Thread.currentThread().setContextClassLoader(oldCL);
221 System.setProperties(oldProps);
222 }
223 }
224
225 protected int doInvoke(C context) throws Exception {
226 pushProperties(context);
227 validate(context);
228 prepare(context);
229 configureLogging(context);
230 activateLogging(context);
231 helpOrVersionAndMayExit(context);
232 preCommands(context);
233 container(context);
234 lookup(context);
235 init(context);
236 postCommands(context);
237 settings(context);
238 return execute(context);
239 }
240
241 protected InvokerException handleException(LookupInvokerContext<O, R, C> context, Exception e)
242 throws InvokerException {
243 boolean showStackTrace = context.invokerRequest.options().showErrors().orElse(false);
244 if (showStackTrace) {
245 context.logger.error(
246 "Error executing " + context.invokerRequest.parserRequest().commandName() + ".", e);
247 } else {
248 context.logger.error(
249 "Error executing " + context.invokerRequest.parserRequest().commandName() + ".");
250 context.logger.error(e.getMessage());
251 for (Throwable cause = e.getCause(); cause != null && cause != cause.getCause(); cause = cause.getCause()) {
252 context.logger.error("Caused by: " + cause.getMessage());
253 }
254 }
255 return new InvokerException(e.getMessage(), e);
256 }
257
258 protected abstract C createContext(R invokerRequest) throws InvokerException;
259
260 protected void pushProperties(C context) throws Exception {
261 R invokerRequest = context.invokerRequest;
262 HashSet<String> sys = new HashSet<>(invokerRequest.systemProperties().keySet());
263 invokerRequest.userProperties().entrySet().stream()
264 .filter(k -> !sys.contains(k.getKey()))
265 .forEach(k -> System.setProperty(k.getKey(), k.getValue()));
266 System.setProperty(
267 Constants.MAVEN_HOME, invokerRequest.installationDirectory().toString());
268 }
269
270 protected void validate(C context) throws Exception {}
271
272 protected void prepare(C context) throws Exception {}
273
274 protected void configureLogging(C context) throws Exception {
275 R invokerRequest = context.invokerRequest;
276
277 Options mavenOptions = invokerRequest.options();
278 Map<String, String> userProperties = invokerRequest.userProperties();
279 String styleColor = mavenOptions
280 .color()
281 .orElse(userProperties.getOrDefault(
282 Constants.MAVEN_STYLE_COLOR_PROPERTY, userProperties.getOrDefault("style.color", "auto")));
283 if ("always".equals(styleColor) || "yes".equals(styleColor) || "force".equals(styleColor)) {
284 MessageUtils.setColorEnabled(true);
285 } else if ("never".equals(styleColor) || "no".equals(styleColor) || "none".equals(styleColor)) {
286 MessageUtils.setColorEnabled(false);
287 } else if (!"auto".equals(styleColor) && !"tty".equals(styleColor) && !"if-tty".equals(styleColor)) {
288 throw new IllegalArgumentException(
289 "Invalid color configuration value '" + styleColor + "'. Supported are 'auto', 'always', 'never'.");
290 } else {
291 boolean isBatchMode = !mavenOptions.forceInteractive().orElse(false)
292 && mavenOptions.nonInteractive().orElse(false);
293 if (isBatchMode || mavenOptions.logFile().isPresent()) {
294 MessageUtils.setColorEnabled(false);
295 }
296 }
297
298 context.loggerFactory = LoggerFactory.getILoggerFactory();
299 context.slf4jConfiguration = Slf4jConfigurationFactory.getConfiguration(context.loggerFactory);
300
301 context.loggerLevel = Slf4jConfiguration.Level.INFO;
302 if (mavenOptions.verbose().orElse(false)) {
303 context.loggerLevel = Slf4jConfiguration.Level.DEBUG;
304 } else if (mavenOptions.quiet().orElse(false)) {
305 context.loggerLevel = Slf4jConfiguration.Level.ERROR;
306 }
307 context.slf4jConfiguration.setRootLoggerLevel(context.loggerLevel);
308
309
310
311
312
313 context.terminal = createTerminal(context);
314 context.closeables.add(MessageUtils::systemUninstall);
315
316
317 ProjectBuildLogAppender projectBuildLogAppender =
318 new ProjectBuildLogAppender(determineBuildEventListener(context));
319 context.closeables.add(projectBuildLogAppender);
320 }
321
322 protected Terminal createTerminal(C context) {
323 return new FastTerminal(
324 () -> TerminalBuilder.builder()
325 .name("Maven")
326 .streams(
327 context.invokerRequest.in().orElse(null),
328 context.invokerRequest.out().orElse(null))
329 .dumb(true)
330 .build(),
331 terminal -> doConfigureWithTerminal(context, terminal));
332 }
333
334 protected void doConfigureWithTerminal(C context, Terminal terminal) {
335 MessageUtils.systemInstall(terminal);
336 AnsiConsole.setTerminal(terminal);
337 AnsiConsole.systemInstall();
338 MessageUtils.registerShutdownHook();
339
340 O options = context.invokerRequest.options();
341 if (options.rawStreams().isEmpty() || !options.rawStreams().get()) {
342 MavenSimpleLogger stdout = (MavenSimpleLogger) context.loggerFactory.getLogger("stdout");
343 MavenSimpleLogger stderr = (MavenSimpleLogger) context.loggerFactory.getLogger("stderr");
344 stdout.setLogLevel(LocationAwareLogger.INFO_INT);
345 stderr.setLogLevel(LocationAwareLogger.INFO_INT);
346 System.setOut(new LoggingOutputStream(s -> stdout.info("[stdout] " + s)).printStream());
347 System.setErr(new LoggingOutputStream(s -> stderr.warn("[stderr] " + s)).printStream());
348
349 }
350 }
351
352 protected BuildEventListener determineBuildEventListener(C context) {
353 if (context.buildEventListener == null) {
354 context.buildEventListener = doDetermineBuildEventListener(context);
355 }
356 return context.buildEventListener;
357 }
358
359 protected BuildEventListener doDetermineBuildEventListener(C context) {
360 BuildEventListener bel;
361 O options = context.invokerRequest.options();
362 if (options.logFile().isPresent()) {
363 Path logFile = context.cwdResolver.apply(options.logFile().get());
364 try {
365 PrintWriter printWriter = new PrintWriter(Files.newBufferedWriter(logFile));
366 bel = new SimpleBuildEventListener(printWriter::println);
367 } catch (IOException e) {
368 throw new MavenException("Unable to redirect logging to " + logFile, e);
369 }
370 } else {
371
372
373 bel = new SimpleBuildEventListener(msg -> {
374 PrintWriter pw = context.terminal.writer();
375 pw.println(msg);
376 pw.flush();
377 });
378 }
379 return bel;
380 }
381
382 protected void activateLogging(C context) throws Exception {
383 R invokerRequest = context.invokerRequest;
384 Options mavenOptions = invokerRequest.options();
385
386 context.slf4jConfiguration.activate();
387 org.slf4j.Logger l = context.loggerFactory.getLogger(this.getClass().getName());
388 context.logger = (level, message, error) -> l.atLevel(org.slf4j.event.Level.valueOf(level.name()))
389 .setCause(error)
390 .log(message);
391
392 if (mavenOptions.failOnSeverity().isPresent()) {
393 String logLevelThreshold = mavenOptions.failOnSeverity().get();
394 if (context.loggerFactory instanceof LogLevelRecorder recorder) {
395 LogLevelRecorder.Level level =
396 switch (logLevelThreshold.toLowerCase(Locale.ENGLISH)) {
397 case "warn", "warning" -> LogLevelRecorder.Level.WARN;
398 case "error" -> LogLevelRecorder.Level.ERROR;
399 default -> throw new IllegalArgumentException(
400 logLevelThreshold
401 + " is not a valid log severity threshold. Valid severities are WARN/WARNING and ERROR.");
402 };
403 recorder.setMaxLevelAllowed(level);
404 context.logger.info("Enabled to break the build on log level " + logLevelThreshold + ".");
405 } else {
406 context.logger.warn("Expected LoggerFactory to be of type '" + LogLevelRecorder.class.getName()
407 + "', but found '"
408 + context.loggerFactory.getClass().getName() + "' instead. "
409 + "The --fail-on-severity flag will not take effect.");
410 }
411 }
412 }
413
414 protected void helpOrVersionAndMayExit(C context) throws Exception {
415 R invokerRequest = context.invokerRequest;
416 if (invokerRequest.options().help().isPresent()) {
417 invokerRequest.options().displayHelp(context.invokerRequest.parserRequest(), context.terminal.writer());
418 context.terminal.writer().flush();
419 throw new ExitException(0);
420 }
421 if (invokerRequest.options().showVersionAndExit().isPresent()) {
422 if (invokerRequest.options().quiet().orElse(false)) {
423 context.terminal.writer().println(CLIReportingUtils.showVersionMinimal());
424 } else {
425 context.terminal.writer().println(CLIReportingUtils.showVersion());
426 }
427 context.terminal.writer().flush();
428 throw new ExitException(0);
429 }
430 }
431
432 protected void preCommands(C context) throws Exception {
433 Options mavenOptions = context.invokerRequest.options();
434 if (mavenOptions.verbose().orElse(false) || mavenOptions.showVersion().orElse(false)) {
435 context.terminal.writer().println(CLIReportingUtils.showVersion());
436 }
437 }
438
439 protected void container(C context) throws Exception {
440 context.containerCapsule = createContainerCapsuleFactory().createContainerCapsule(context);
441 context.closeables.add(context.containerCapsule);
442 context.lookup = context.containerCapsule.getLookup();
443 context.settingsBuilder = context.lookup.lookup(SettingsBuilder.class);
444
445
446 org.slf4j.Logger l = context.loggerFactory.getLogger(this.getClass().getName());
447 context.logger = (level, message, error) -> l.atLevel(org.slf4j.event.Level.valueOf(level.name()))
448 .setCause(error)
449 .log(message);
450 }
451
452 protected ContainerCapsuleFactory<O, R, C> createContainerCapsuleFactory() {
453 return new PlexusContainerCapsuleFactory<>();
454 }
455
456 protected void lookup(C context) throws Exception {}
457
458 protected void init(C context) throws Exception {}
459
460 protected void postCommands(C context) throws Exception {
461 R invokerRequest = context.invokerRequest;
462 Logger logger = context.logger;
463 if (invokerRequest.options().showErrors().orElse(false)) {
464 logger.info("Error stacktraces are turned on.");
465 }
466 if (context.invokerRequest.options().verbose().orElse(false)) {
467 logger.debug("Message scheme: " + (MessageUtils.isColorEnabled() ? "color" : "plain"));
468 if (MessageUtils.isColorEnabled()) {
469 MessageBuilder buff = MessageUtils.builder();
470 buff.a("Message styles: ");
471 buff.trace("trace").a(' ');
472 buff.debug("debug").a(' ');
473 buff.info("info").a(' ');
474 buff.warning("warning").a(' ');
475 buff.error("error").a(' ');
476 buff.success("success").a(' ');
477 buff.failure("failure").a(' ');
478 buff.strong("strong").a(' ');
479 buff.mojo("mojo").a(' ');
480 buff.project("project");
481 logger.debug(buff.toString());
482 }
483 }
484 }
485
486 protected void settings(C context) throws Exception {
487 settings(context, context.settingsBuilder);
488 }
489
490 protected void settings(C context, SettingsBuilder settingsBuilder) throws Exception {
491 Options mavenOptions = context.invokerRequest.options();
492 Path userSettingsFile = null;
493
494 if (mavenOptions.altUserSettings().isPresent()) {
495 userSettingsFile =
496 context.cwdResolver.apply(mavenOptions.altUserSettings().get());
497
498 if (!Files.isRegularFile(userSettingsFile)) {
499 throw new FileNotFoundException("The specified user settings file does not exist: " + userSettingsFile);
500 }
501 } else {
502 String userSettingsFileStr = context.invokerRequest.userProperties().get(Constants.MAVEN_USER_SETTINGS);
503 if (userSettingsFileStr != null) {
504 userSettingsFile = context.userResolver.apply(userSettingsFileStr);
505 }
506 }
507
508 Path projectSettingsFile = null;
509
510 if (mavenOptions.altProjectSettings().isPresent()) {
511 projectSettingsFile =
512 context.cwdResolver.apply(mavenOptions.altProjectSettings().get());
513
514 if (!Files.isRegularFile(projectSettingsFile)) {
515 throw new FileNotFoundException(
516 "The specified project settings file does not exist: " + projectSettingsFile);
517 }
518 } else {
519 String projectSettingsFileStr =
520 context.invokerRequest.userProperties().get(Constants.MAVEN_PROJECT_SETTINGS);
521 if (projectSettingsFileStr != null) {
522 projectSettingsFile = context.cwdResolver.apply(projectSettingsFileStr);
523 }
524 }
525
526 Path installationSettingsFile = null;
527
528 if (mavenOptions.altInstallationSettings().isPresent()) {
529 installationSettingsFile = context.cwdResolver.apply(
530 mavenOptions.altInstallationSettings().get());
531
532 if (!Files.isRegularFile(installationSettingsFile)) {
533 throw new FileNotFoundException(
534 "The specified installation settings file does not exist: " + installationSettingsFile);
535 }
536 } else {
537 String installationSettingsFileStr =
538 context.invokerRequest.userProperties().get(Constants.MAVEN_INSTALLATION_SETTINGS);
539 if (installationSettingsFileStr != null) {
540 installationSettingsFile = context.installationResolver.apply(installationSettingsFileStr);
541 }
542 }
543
544 context.installationSettingsPath = installationSettingsFile;
545 context.projectSettingsPath = projectSettingsFile;
546 context.userSettingsPath = userSettingsFile;
547
548 Function<String, String> interpolationSource = Interpolator.chain(
549 context.invokerRequest.userProperties()::get, context.invokerRequest.systemProperties()::get);
550 SettingsBuilderRequest settingsRequest = SettingsBuilderRequest.builder()
551 .session(context.session)
552 .installationSettingsSource(
553 installationSettingsFile != null && Files.exists(installationSettingsFile)
554 ? Source.fromPath(installationSettingsFile)
555 : null)
556 .projectSettingsSource(
557 projectSettingsFile != null && Files.exists(projectSettingsFile)
558 ? Source.fromPath(projectSettingsFile)
559 : null)
560 .userSettingsSource(
561 userSettingsFile != null && Files.exists(userSettingsFile)
562 ? Source.fromPath(userSettingsFile)
563 : null)
564 .interpolationSource(interpolationSource)
565 .build();
566
567 customizeSettingsRequest(context, settingsRequest);
568
569 context.logger.debug("Reading installation settings from '" + installationSettingsFile + "'");
570 context.logger.debug("Reading project settings from '" + projectSettingsFile + "'");
571 context.logger.debug("Reading user settings from '" + userSettingsFile + "'");
572
573 SettingsBuilderResult settingsResult = settingsBuilder.build(settingsRequest);
574 customizeSettingsResult(context, settingsResult);
575
576 context.effectiveSettings = settingsResult.getEffectiveSettings();
577 context.interactive = mayDisableInteractiveMode(context, context.effectiveSettings.isInteractiveMode());
578 context.localRepositoryPath = localRepositoryPath(context);
579
580 if (!settingsResult.getProblems().isEmpty()) {
581 context.logger.warn("");
582 context.logger.warn("Some problems were encountered while building the effective settings");
583
584 for (BuilderProblem problem : settingsResult.getProblems()) {
585 context.logger.warn(problem.getMessage() + " @ " + problem.getLocation());
586 }
587 context.logger.warn("");
588 }
589 }
590
591 protected void customizeSettingsRequest(C context, SettingsBuilderRequest settingsBuilderRequest)
592 throws Exception {}
593
594 protected void customizeSettingsResult(C context, SettingsBuilderResult settingsBuilderResult) throws Exception {}
595
596 protected boolean mayDisableInteractiveMode(C context, boolean proposedInteractive) {
597 if (!context.invokerRequest.options().forceInteractive().orElse(false)) {
598 if (context.invokerRequest.options().nonInteractive().orElse(false)) {
599 return false;
600 } else {
601 boolean runningOnCI = isRunningOnCI(context);
602 if (runningOnCI) {
603 context.logger.info(
604 "Making this build non-interactive, because the environment variable CI equals \"true\"."
605 + " Disable this detection by removing that variable or adding --force-interactive.");
606 return false;
607 }
608 }
609 }
610 return proposedInteractive;
611 }
612
613 protected Path localRepositoryPath(C context) {
614
615 String userDefinedLocalRepo = context.invokerRequest.userProperties().get(Constants.MAVEN_REPO_LOCAL);
616 if (userDefinedLocalRepo == null) {
617 userDefinedLocalRepo = context.invokerRequest.systemProperties().get(Constants.MAVEN_REPO_LOCAL);
618 if (userDefinedLocalRepo != null) {
619 context.logger.warn("The property '" + Constants.MAVEN_REPO_LOCAL
620 + "' has been set using a JVM system property which is deprecated. "
621 + "The property can be passed as a Maven argument or in the Maven project configuration file,"
622 + "usually located at ${session.rootDirectory}/.mvn/maven.properties.");
623 }
624 }
625 if (userDefinedLocalRepo != null) {
626 return context.cwdResolver.apply(userDefinedLocalRepo);
627 }
628
629 userDefinedLocalRepo = context.effectiveSettings.getLocalRepository();
630 if (userDefinedLocalRepo != null && !userDefinedLocalRepo.isEmpty()) {
631 return context.userResolver.apply(userDefinedLocalRepo);
632 }
633
634 return context.userResolver
635 .apply(context.invokerRequest.userProperties().get(Constants.MAVEN_USER_CONF))
636 .resolve("repository");
637 }
638
639 protected void populateRequest(C context, MavenExecutionRequest request) throws Exception {
640 populateRequestFromSettings(request, context.effectiveSettings);
641
642 Options options = context.invokerRequest.options();
643 request.setLoggingLevel(toMavenExecutionRequestLoggingLevel(context.loggerLevel));
644 request.setLocalRepositoryPath(context.localRepositoryPath.toFile());
645 request.setLocalRepository(createLocalArtifactRepository(context.localRepositoryPath));
646
647 request.setInteractiveMode(context.interactive);
648 request.setShowErrors(options.showErrors().orElse(false));
649 request.setBaseDirectory(context.invokerRequest.topDirectory().toFile());
650 request.setSystemProperties(toProperties(context.invokerRequest.systemProperties()));
651 request.setUserProperties(toProperties(context.invokerRequest.userProperties()));
652
653 request.setTopDirectory(context.invokerRequest.topDirectory());
654 if (context.invokerRequest.rootDirectory().isPresent()) {
655 request.setMultiModuleProjectDirectory(
656 context.invokerRequest.rootDirectory().get().toFile());
657 request.setRootDirectory(context.invokerRequest.rootDirectory().get());
658 }
659
660 request.addPluginGroup("org.apache.maven.plugins");
661 request.addPluginGroup("org.codehaus.mojo");
662 }
663
664
665
666
667 @Deprecated
668 private ArtifactRepository createLocalArtifactRepository(Path baseDirectory) {
669 DefaultRepositoryLayout layout = new DefaultRepositoryLayout();
670 ArtifactRepositoryPolicy blah = new ArtifactRepositoryPolicy(
671 true, ArtifactRepositoryPolicy.UPDATE_POLICY_ALWAYS, ArtifactRepositoryPolicy.CHECKSUM_POLICY_IGNORE);
672 return new MavenArtifactRepository(
673 "local", "file://" + baseDirectory.toUri().getRawPath(), layout, blah, blah);
674 }
675
676 protected void populateRequestFromSettings(MavenExecutionRequest request, Settings settings) throws Exception {
677 if (settings == null) {
678 return;
679 }
680 request.setOffline(settings.isOffline());
681 request.setInteractiveMode(settings.isInteractiveMode());
682 request.setPluginGroups(settings.getPluginGroups());
683 request.setLocalRepositoryPath(settings.getLocalRepository());
684 for (Server server : settings.getServers()) {
685 request.addServer(new org.apache.maven.settings.Server(server));
686 }
687
688
689
690
691
692
693
694
695
696
697
698
699
700 for (Proxy proxy : settings.getProxies()) {
701 if (!proxy.isActive()) {
702 continue;
703 }
704 request.addProxy(new org.apache.maven.settings.Proxy(proxy));
705 }
706
707
708
709
710
711
712
713
714
715 for (Mirror mirror : settings.getMirrors()) {
716 request.addMirror(new org.apache.maven.settings.Mirror(mirror));
717 }
718
719 for (Repository remoteRepository : settings.getRepositories()) {
720 try {
721 request.addRemoteRepository(MavenRepositorySystem.buildArtifactRepository(
722 new org.apache.maven.settings.Repository(remoteRepository)));
723 } catch (InvalidRepositoryException e) {
724
725 }
726 }
727
728 for (Repository pluginRepository : settings.getPluginRepositories()) {
729 try {
730 request.addPluginArtifactRepository(MavenRepositorySystem.buildArtifactRepository(
731 new org.apache.maven.settings.Repository(pluginRepository)));
732 } catch (InvalidRepositoryException e) {
733
734 }
735 }
736
737 request.setActiveProfiles(settings.getActiveProfiles());
738 for (Profile rawProfile : settings.getProfiles()) {
739 request.addProfile(
740 new org.apache.maven.model.Profile(SettingsUtilsV4.convertFromSettingsProfile(rawProfile)));
741
742 if (settings.getActiveProfiles().contains(rawProfile.getId())) {
743 List<Repository> remoteRepositories = rawProfile.getRepositories();
744 for (Repository remoteRepository : remoteRepositories) {
745 try {
746 request.addRemoteRepository(MavenRepositorySystem.buildArtifactRepository(
747 new org.apache.maven.settings.Repository(remoteRepository)));
748 } catch (InvalidRepositoryException e) {
749
750 }
751 }
752
753 List<Repository> pluginRepositories = rawProfile.getPluginRepositories();
754 for (Repository pluginRepository : pluginRepositories) {
755 try {
756 request.addPluginArtifactRepository(MavenRepositorySystem.buildArtifactRepository(
757 new org.apache.maven.settings.Repository(pluginRepository)));
758 } catch (InvalidRepositoryException e) {
759
760 }
761 }
762 }
763 }
764 }
765
766 protected int calculateDegreeOfConcurrency(String threadConfiguration) {
767 try {
768 if (threadConfiguration.endsWith("C")) {
769 String str = threadConfiguration.substring(0, threadConfiguration.length() - 1);
770 float coreMultiplier = Float.parseFloat(str);
771
772 if (coreMultiplier <= 0.0f) {
773 throw new IllegalArgumentException("Invalid threads core multiplier value: '" + threadConfiguration
774 + "'. Value must be positive.");
775 }
776
777 int procs = Runtime.getRuntime().availableProcessors();
778 int threads = (int) (coreMultiplier * procs);
779 return threads == 0 ? 1 : threads;
780 } else {
781 int threads = Integer.parseInt(threadConfiguration);
782 if (threads <= 0) {
783 throw new IllegalArgumentException(
784 "Invalid threads value: '" + threadConfiguration + "'. Value must be positive.");
785 }
786 return threads;
787 }
788 } catch (NumberFormatException e) {
789 throw new IllegalArgumentException("Invalid threads value: '" + threadConfiguration
790 + "'. Supported are int and float values ending with C.");
791 }
792 }
793
794 protected boolean isRunningOnCI(C context) {
795 String ciEnv = context.invokerRequest.systemProperties().get("env.CI");
796 return ciEnv != null && !"false".equals(ciEnv);
797 }
798
799 protected TransferListener determineTransferListener(C context, boolean noTransferProgress) {
800 boolean quiet = context.invokerRequest.options().quiet().orElse(false);
801 boolean logFile = context.invokerRequest.options().logFile().isPresent();
802 boolean runningOnCI = isRunningOnCI(context);
803 boolean quietCI = runningOnCI
804 && !context.invokerRequest.options().forceInteractive().orElse(false);
805
806 if (quiet || noTransferProgress || quietCI) {
807 return new QuietMavenTransferListener();
808 } else if (context.interactive && !logFile) {
809 return new SimplexTransferListener(new ConsoleMavenTransferListener(
810 context.invokerRequest.messageBuilderFactory(),
811 context.terminal.writer(),
812 context.invokerRequest.options().verbose().orElse(false)));
813 } else {
814 return new Slf4jMavenTransferListener();
815 }
816 }
817
818 protected abstract int execute(C context) throws Exception;
819 }