[MNG-8332] Detach CLIng from deprecated Embedder (#1882)

Detach maven-cli from maven-embedder (deprecated). Basically, classes are copied from embedder to cli, while embedder points to old classes and cli to new classes. **One important exception is logging**: the classes are _moved_ to cli, and embedder modified to use those classes (and dependency reversed: embedder now depends on cli). Reason is Verifier, that still calls into "hack method" of deprecated MavenCli, and then without logging classes move would explode due casting.

---

https://issues.apache.org/jira/browse/MNG-8332
This commit is contained in:
Tamas Cservenak 2024-11-08 09:49:11 +01:00 committed by GitHub
parent 37b8a62bd5
commit 4f79f2d876
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
59 changed files with 3497 additions and 77 deletions

View File

@ -30,7 +30,7 @@ under the License.
<artifactId>maven-embedder</artifactId>
<name>Maven Embedder</name>
<name>Maven Embedder (deprecated)</name>
<description>Maven embeddable component, with CLI and logging support.</description>
<dependencies>
@ -38,6 +38,10 @@ under the License.
<groupId>org.apache.maven</groupId>
<artifactId>maven-api-cli</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-cli</artifactId>
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-settings</artifactId>
@ -183,34 +187,6 @@ under the License.
<groupId>org.eclipse.sisu</groupId>
<artifactId>sisu-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.modello</groupId>
<artifactId>modello-maven-plugin</artifactId>
<configuration>
<version>1.2.0</version>
<models>
<model>../../api/maven-api-cli/src/main/mdo/core-extensions.mdo</model>
</models>
<templates>
<template>reader-stax.vm</template>
<template>writer-stax.vm</template>
</templates>
<params>
<param>packageModelV4=org.apache.maven.api.cli.extensions</param>
<param>packageToolV4=org.apache.maven.cli.internal.extension.io</param>
</params>
<velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
</configuration>
<executions>
<execution>
<id>modello</id>
<goals>
<goal>velocity</goal>
<goal>xsd</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -34,6 +34,7 @@ import org.apache.maven.jline.MessageUtils;
/**
*/
@Deprecated
public class CLIManager {
public static final char ALTERNATE_POM_FILE = 'f';

View File

@ -33,6 +33,7 @@ import org.slf4j.Logger;
* Utility class used to report errors, statistics, application version info, etc.
*
*/
@Deprecated
public final class CLIReportingUtils {
// CHECKSTYLE_OFF: MagicNumber
public static final long MB = 1024 * 1024;

View File

@ -24,6 +24,7 @@ import java.util.List;
/**
* CleanArgument
*/
@Deprecated
public class CleanArgument {
public static String[] cleanArgs(String[] args) {
try {

View File

@ -30,6 +30,7 @@ import org.codehaus.plexus.classworlds.ClassWorld;
/**
* CliRequest
*/
@Deprecated
public class CliRequest {
String[] args;

View File

@ -32,6 +32,7 @@ import org.apache.maven.internal.xml.XmlPlexusConfiguration;
import org.apache.maven.model.v4.MavenTransformer;
import org.codehaus.plexus.configuration.PlexusConfiguration;
@Deprecated
public class ExtensionConfigurationModule implements Module {
private final CoreExtensionEntry extension;

View File

@ -70,16 +70,16 @@ import org.apache.maven.cli.configuration.SettingsXmlConfigurationProcessor;
import org.apache.maven.cli.event.DefaultEventSpyContext;
import org.apache.maven.cli.event.ExecutionEventLogger;
import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
import org.apache.maven.cli.internal.extension.io.CoreExtensionsStaxReader;
import org.apache.maven.cli.logging.Slf4jConfiguration;
import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
import org.apache.maven.cli.logging.Slf4jLoggerManager;
import org.apache.maven.cli.logging.Slf4jStdoutLogger;
import org.apache.maven.cli.props.MavenPropertiesLoader;
import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
import org.apache.maven.cli.transfer.QuietMavenTransferListener;
import org.apache.maven.cli.transfer.SimplexTransferListener;
import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
import org.apache.maven.cling.internal.extension.io.CoreExtensionsStaxReader;
import org.apache.maven.cling.logging.Slf4jConfiguration;
import org.apache.maven.cling.logging.Slf4jConfigurationFactory;
import org.apache.maven.cling.logging.Slf4jLoggerManager;
import org.apache.maven.di.Injector;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.exception.DefaultExceptionHandler;
@ -141,6 +141,7 @@ import static org.apache.maven.cli.ResolveFile.resolveFile;
/**
*/
@Deprecated
public class MavenCli {
public static final String MULTIMODULE_PROJECT_DIRECTORY = "maven.multiModuleProjectDirectory";

View File

@ -24,6 +24,7 @@ import java.nio.file.Paths;
/**
* Resolve relative file path against the given base directory
*/
@Deprecated
public class ResolveFile {
public static File resolveFile(File file, String baseDirectory) {
if (file == null) {

View File

@ -23,6 +23,7 @@ import org.apache.maven.cli.CliRequest;
/**
* ConfigurationProcessor
*/
@Deprecated
public interface ConfigurationProcessor {
void process(CliRequest request) throws Exception;
}

View File

@ -58,6 +58,7 @@ import static org.apache.maven.cli.ResolveFile.resolveFile;
*/
@Named(SettingsXmlConfigurationProcessor.HINT)
@Singleton
@Deprecated
public class SettingsXmlConfigurationProcessor implements ConfigurationProcessor {
public static final String HINT = "settings";

View File

@ -26,6 +26,7 @@ import org.apache.maven.eventspy.EventSpy;
/**
* DefaultEventSpyContext
*/
@Deprecated
public class DefaultEventSpyContext implements EventSpy.Context {
private final Map<String, Object> data = new HashMap<>();

View File

@ -46,6 +46,7 @@ import static org.apache.maven.cli.CLIReportingUtils.formatTimestamp;
* Logs execution events to logger, eventually user-supplied.
*
*/
@Deprecated
public class ExecutionEventLogger extends AbstractExecutionListener {
private static final int MAX_LOG_PREFIX_SIZE = 8; // "[ERROR] "
private static final int PROJECT_STATUS_SUFFIX_SIZE = 20; // "SUCCESS [ 0.000 s]"

View File

@ -87,6 +87,7 @@ import org.slf4j.LoggerFactory;
/**
* BootstrapCoreExtensionManager
*/
@Deprecated
@Named
public class BootstrapCoreExtensionManager {
public static final String STRATEGY_PARENT_FIRST = "parent-first";

View File

@ -24,6 +24,7 @@ import org.apache.maven.api.cli.extensions.CoreExtension;
* Exception occurring trying to resolve a plugin.
*
*/
@Deprecated
public class ExtensionResolutionException extends Exception {
private final CoreExtension extension;

View File

@ -28,6 +28,7 @@ import static java.util.Objects.requireNonNull;
/**
* @since 3.1.0
*/
@Deprecated
public class Slf4jStdoutLogger implements Logger {
private static final String ERROR = "[ERROR] ";

View File

@ -50,6 +50,7 @@ import org.apache.maven.internal.impl.model.DefaultInterpolator;
* Enhancement of the standard <code>Properties</code>
* managing the maintain of comments, etc.
*/
@Deprecated
public class MavenProperties extends AbstractMap<String, String> {
/** Constant for the supported comment characters.*/

View File

@ -28,6 +28,7 @@ import java.util.function.Function;
import org.apache.maven.internal.impl.model.DefaultInterpolator;
@Deprecated
public class MavenPropertiesLoader {
public static final String INCLUDES_PROPERTY = "${includes}"; // includes

View File

@ -31,6 +31,7 @@ import org.eclipse.aether.transfer.TransferResource;
/**
* AbstractMavenTransferListener
*/
@Deprecated
public abstract class AbstractMavenTransferListener extends AbstractTransferListener {
public static final String STYLE = ".transfer:-faint";

View File

@ -34,6 +34,7 @@ import org.eclipse.aether.transfer.TransferResource;
* <p>
* This listener is not thread-safe and should be wrapped in the {@link SimplexTransferListener} in a multi-threaded scenario.
*/
@Deprecated
public class ConsoleMavenTransferListener extends AbstractMavenTransferListener {
private final Map<TransferResourceIdentifier, TransferResourceAndSize> transfers = new LinkedHashMap<>();

View File

@ -30,6 +30,7 @@ import org.apache.maven.api.services.MessageBuilder;
* @see <a
* href="https://en.wikipedia.org/wiki/Octet_%28computing%29">https://en.wikipedia.org/wiki/Octet_(computing)</a>
*/
@Deprecated
public class FileSizeFormat {
public enum ScaleUnit {
BYTE {

View File

@ -22,4 +22,5 @@ import org.eclipse.aether.transfer.AbstractTransferListener;
/**
*/
@Deprecated
public class QuietMavenTransferListener extends AbstractTransferListener {}

View File

@ -42,6 +42,7 @@ import static java.util.Objects.requireNonNull;
*
* @since 4.0.0
*/
@Deprecated
public final class SimplexTransferListener extends AbstractTransferListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SimplexTransferListener.class);
private static final int QUEUE_SIZE = 1024;

View File

@ -28,6 +28,7 @@ import org.slf4j.LoggerFactory;
/**
* Slf4jMavenTransferListener
*/
@Deprecated
public class Slf4jMavenTransferListener extends AbstractTransferListener {
protected final Logger out;

View File

@ -28,6 +28,7 @@ import org.eclipse.aether.transfer.TransferResource;
* The {@link TransferResource} is not immutable and does not implement {@code Objects#equals} and {@code Objects#hashCode} methods,
* making it not very suitable for usage in collections.
*/
@Deprecated
record TransferResourceIdentifier(String repositoryId, String repositoryUrl, String resourceName, @Nullable File file) {
TransferResourceIdentifier(TransferResource resource) {
this(resource.getRepositoryId(), resource.getRepositoryUrl(), resource.getResourceName(), resource.getFile());

View File

@ -53,6 +53,7 @@ import org.eclipse.sisu.inject.TypeArguments;
*/
@Singleton
@Priority(10)
@Deprecated
public final class PlexusXmlBeanConverter implements PlexusBeanConverter {
// ----------------------------------------------------------------------
// Constants

View File

@ -28,6 +28,7 @@ import java.util.ArrayList;
* with maven-shared-utils, while Maven has migrated to JLine (into which Jansi has been merged
* since JLine 3.25.0).
*/
@Deprecated
@SuppressWarnings("unused")
public class Ansi implements Appendable {

View File

@ -40,7 +40,7 @@ under the License.
</dependency>
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-embedder</artifactId>
<artifactId>maven-core</artifactId>
</dependency>
<dependency>
<groupId>org.codehaus.plexus</groupId>
@ -78,6 +78,11 @@ under the License.
<groupId>commons-cli</groupId>
<artifactId>commons-cli</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
@ -98,6 +103,33 @@ under the License.
<groupId>org.eclipse.sisu</groupId>
<artifactId>sisu-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.codehaus.modello</groupId>
<artifactId>modello-maven-plugin</artifactId>
<configuration>
<version>1.2.0</version>
<models>
<model>../../api/maven-api-cli/src/main/mdo/core-extensions.mdo</model>
</models>
<templates>
<template>reader-stax.vm</template>
<template>writer-stax.vm</template>
</templates>
<params>
<param>packageModelV4=org.apache.maven.api.cli.extensions</param>
<param>packageToolV4=org.apache.maven.cling.internal.extension.io</param>
</params>
<velocityBasedir>${project.basedir}/../../src/mdo</velocityBasedir>
</configuration>
<executions>
<execution>
<id>modello</id>
<goals>
<goal>velocity</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>

View File

@ -0,0 +1,479 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.event;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.Objects;
import org.apache.maven.api.services.MessageBuilder;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.apache.maven.execution.AbstractExecutionListener;
import org.apache.maven.execution.BuildFailure;
import org.apache.maven.execution.BuildSuccess;
import org.apache.maven.execution.BuildSummary;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.project.MavenProject;
import org.slf4j.ILoggerFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.maven.cling.utils.CLIReportingUtils.formatDuration;
import static org.apache.maven.cling.utils.CLIReportingUtils.formatTimestamp;
/**
* Logs execution events to logger, eventually user-supplied.
*
*/
public class ExecutionEventLogger extends AbstractExecutionListener {
private static final int MAX_LOG_PREFIX_SIZE = 8; // "[ERROR] "
private static final int PROJECT_STATUS_SUFFIX_SIZE = 20; // "SUCCESS [ 0.000 s]"
private static final int MIN_TERMINAL_WIDTH = 60;
private static final int DEFAULT_TERMINAL_WIDTH = 80;
private static final int MAX_TERMINAL_WIDTH = 130;
private static final int MAX_PADDED_BUILD_TIME_DURATION_LENGTH = 9;
private final MessageBuilderFactory messageBuilderFactory;
private final Logger logger;
private int terminalWidth;
private int lineLength;
private int maxProjectNameLength;
private int totalProjects;
private volatile int currentVisitedProjectCount;
public ExecutionEventLogger(MessageBuilderFactory messageBuilderFactory) {
this(messageBuilderFactory, LoggerFactory.getLogger(ExecutionEventLogger.class));
}
public ExecutionEventLogger(MessageBuilderFactory messageBuilderFactory, Logger logger) {
this(messageBuilderFactory, logger, -1);
}
public ExecutionEventLogger(MessageBuilderFactory messageBuilderFactory, Logger logger, int terminalWidth) {
this.logger = Objects.requireNonNull(logger, "logger cannot be null");
this.messageBuilderFactory = messageBuilderFactory;
this.terminalWidth = terminalWidth;
}
private static String chars(char c, int count) {
return String.valueOf(c).repeat(Math.max(0, count));
}
private void infoLine(char c) {
infoMain(chars(c, lineLength));
}
private void infoMain(String msg) {
logger.info(builder().strong(msg).toString());
}
private void init() {
if (maxProjectNameLength == 0) {
if (terminalWidth < 0) {
terminalWidth = messageBuilderFactory.getTerminalWidth();
}
terminalWidth = Math.min(
MAX_TERMINAL_WIDTH,
Math.max(terminalWidth <= 0 ? DEFAULT_TERMINAL_WIDTH : terminalWidth, MIN_TERMINAL_WIDTH));
lineLength = terminalWidth - MAX_LOG_PREFIX_SIZE;
maxProjectNameLength = lineLength - PROJECT_STATUS_SUFFIX_SIZE;
}
}
@Override
public void projectDiscoveryStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
init();
logger.info("Scanning for projects...");
}
}
@Override
public void sessionStarted(ExecutionEvent event) {
if (logger.isInfoEnabled() && event.getSession().getProjects().size() > 1) {
init();
infoLine('-');
infoMain("Reactor Build Order:");
logger.info("");
final List<MavenProject> projects = event.getSession().getProjects();
for (MavenProject project : projects) {
int len = lineLength
- project.getName().length()
- project.getPackaging().length()
- 2;
logger.info("{}{}[{}]", project.getName(), chars(' ', (len > 0) ? len : 1), project.getPackaging());
}
final List<MavenProject> allProjects = event.getSession().getAllProjects();
currentVisitedProjectCount = allProjects.size() - projects.size();
totalProjects = allProjects.size();
}
}
@Override
public void sessionEnded(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
init();
if (event.getSession().getProjects().size() > 1) {
logReactorSummary(event.getSession());
}
ILoggerFactory iLoggerFactory = LoggerFactory.getILoggerFactory();
if (iLoggerFactory instanceof org.apache.maven.logging.api.LogLevelRecorder recorder
&& recorder.hasReachedMaxLevel()) {
event.getSession()
.getResult()
.addException(
new Exception("Build failed due to log statements with a higher severity than allowed. "
+ "Fix the logged issues or remove flag --fail-on-severity (-fos)."));
}
logResult(event.getSession());
logStats(event.getSession());
infoLine('-');
}
}
private boolean isSingleVersionedReactor(MavenSession session) {
boolean result = true;
MavenProject topProject = session.getTopLevelProject();
List<MavenProject> sortedProjects = session.getProjectDependencyGraph().getSortedProjects();
for (MavenProject mavenProject : sortedProjects) {
if (!topProject.getVersion().equals(mavenProject.getVersion())) {
result = false;
break;
}
}
return result;
}
private void logReactorSummary(MavenSession session) {
boolean isSingleVersion = isSingleVersionedReactor(session);
infoLine('-');
StringBuilder summary = new StringBuilder("Reactor Summary");
if (isSingleVersion) {
summary.append(" for ");
summary.append(session.getTopLevelProject().getName());
summary.append(" ");
summary.append(session.getTopLevelProject().getVersion());
}
summary.append(":");
infoMain(summary.toString());
logger.info("");
MavenExecutionResult result = session.getResult();
List<MavenProject> projects = session.getProjects();
StringBuilder buffer = new StringBuilder(128);
for (MavenProject project : projects) {
buffer.append(project.getName());
buffer.append(' ');
if (!isSingleVersion) {
buffer.append(project.getVersion());
buffer.append(' ');
}
if (buffer.length() <= maxProjectNameLength) {
while (buffer.length() < maxProjectNameLength) {
buffer.append('.');
}
buffer.append(' ');
}
BuildSummary buildSummary = result.getBuildSummary(project);
if (buildSummary == null) {
buffer.append(builder().warning("SKIPPED"));
} else if (buildSummary instanceof BuildSuccess) {
buffer.append(builder().success("SUCCESS"));
buffer.append(" [");
String buildTimeDuration = formatDuration(buildSummary.getTime());
int padSize = MAX_PADDED_BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length();
if (padSize > 0) {
buffer.append(chars(' ', padSize));
}
buffer.append(buildTimeDuration);
buffer.append(']');
} else if (buildSummary instanceof BuildFailure) {
buffer.append(builder().failure("FAILURE"));
buffer.append(" [");
String buildTimeDuration = formatDuration(buildSummary.getTime());
int padSize = MAX_PADDED_BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length();
if (padSize > 0) {
buffer.append(chars(' ', padSize));
}
buffer.append(buildTimeDuration);
buffer.append(']');
}
logger.info(buffer.toString());
buffer.setLength(0);
}
}
private void logResult(MavenSession session) {
infoLine('-');
MessageBuilder buffer = builder();
if (session.getResult().hasExceptions()) {
buffer.failure("BUILD FAILURE");
} else {
buffer.success("BUILD SUCCESS");
}
logger.info(buffer.toString());
}
private MessageBuilder builder() {
return messageBuilderFactory.builder();
}
private void logStats(MavenSession session) {
infoLine('-');
long finish = System.currentTimeMillis();
long time = finish - session.getRequest().getStartTime().getTime();
String wallClock = session.getRequest().getDegreeOfConcurrency() > 1 ? " (Wall Clock)" : "";
logger.info("Total time: {}{}", formatDuration(time), wallClock);
logger.info("Finished at: {}", formatTimestamp(finish));
}
@Override
public void projectSkipped(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
init();
logger.info("");
infoLine('-');
String name = event.getProject().getName();
infoMain("Skipping " + name);
logger.info("{} was not built because a module it depends on failed to build.", name);
infoLine('-');
}
}
@Override
public void projectStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
init();
MavenProject project = event.getProject();
logger.info("");
// -------< groupId:artifactId >-------
String projectKey = project.getGroupId() + ':' + project.getArtifactId();
final String preHeader = "--< ";
final String postHeader = " >--";
final int headerLen = preHeader.length() + projectKey.length() + postHeader.length();
String prefix = chars('-', Math.max(0, (lineLength - headerLen) / 2)) + preHeader;
String suffix =
postHeader + chars('-', Math.max(0, lineLength - headerLen - prefix.length() + preHeader.length()));
logger.info(
builder().strong(prefix).project(projectKey).strong(suffix).toString());
// Building Project Name Version [i/n]
String building = "Building " + event.getProject().getName() + " "
+ event.getProject().getVersion();
if (totalProjects <= 1) {
infoMain(building);
} else {
// display progress [i/n]
int number;
synchronized (this) {
number = ++currentVisitedProjectCount;
}
String progress = " [" + number + '/' + totalProjects + ']';
int pad = lineLength - building.length() - progress.length();
infoMain(building + ((pad > 0) ? chars(' ', pad) : "") + progress);
}
// path to pom.xml
File currentPom = project.getFile();
if (currentPom != null) {
MavenSession session = event.getSession();
Path current = currentPom.toPath().toAbsolutePath().normalize();
Path topDirectory = session.getTopDirectory();
if (topDirectory != null && current.startsWith(topDirectory)) {
current = topDirectory.relativize(current);
}
logger.info(" from " + current);
}
// ----------[ packaging ]----------
prefix = chars('-', Math.max(0, (lineLength - project.getPackaging().length() - 4) / 2));
suffix = chars('-', Math.max(0, lineLength - project.getPackaging().length() - 4 - prefix.length()));
infoMain(prefix + "[ " + project.getPackaging() + " ]" + suffix);
}
}
@Override
public void mojoSkipped(ExecutionEvent event) {
if (logger.isWarnEnabled()) {
init();
logger.warn(
"Goal '{}' requires online mode for execution but Maven is currently offline, skipping",
event.getMojoExecution().getGoal());
}
}
/**
* <pre>--- mojo-artifactId:version:goal (mojo-executionId) @ project-artifactId ---</pre>
*/
@Override
public void mojoStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
init();
logger.info("");
MessageBuilder buffer = builder().strong("--- ");
append(buffer, event.getMojoExecution());
append(buffer, event.getProject());
buffer.strong(" ---");
logger.info(buffer.toString());
}
}
// CHECKSTYLE_OFF: LineLength
/**
* <pre>&gt;&gt;&gt; mojo-artifactId:version:goal (mojo-executionId) &gt; :forked-goal @ project-artifactId &gt;&gt;&gt;</pre>
* <pre>&gt;&gt;&gt; mojo-artifactId:version:goal (mojo-executionId) &gt; [lifecycle]phase @ project-artifactId &gt;&gt;&gt;</pre>
*/
// CHECKSTYLE_ON: LineLength
@Override
public void forkStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
init();
logger.info("");
MessageBuilder buffer = builder().strong(">>> ");
append(buffer, event.getMojoExecution());
buffer.strong(" > ");
appendForkInfo(buffer, event.getMojoExecution().getMojoDescriptor());
append(buffer, event.getProject());
buffer.strong(" >>>");
logger.info(buffer.toString());
}
}
// CHECKSTYLE_OFF: LineLength
/**
* <pre>&lt;&lt;&lt; mojo-artifactId:version:goal (mojo-executionId) &lt; :forked-goal @ project-artifactId &lt;&lt;&lt;</pre>
* <pre>&lt;&lt;&lt; mojo-artifactId:version:goal (mojo-executionId) &lt; [lifecycle]phase @ project-artifactId &lt;&lt;&lt;</pre>
*/
// CHECKSTYLE_ON: LineLength
@Override
public void forkSucceeded(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
init();
logger.info("");
MessageBuilder buffer = builder().strong("<<< ");
append(buffer, event.getMojoExecution());
buffer.strong(" < ");
appendForkInfo(buffer, event.getMojoExecution().getMojoDescriptor());
append(buffer, event.getProject());
buffer.strong(" <<<");
logger.info(buffer.toString());
logger.info("");
}
}
private void append(MessageBuilder buffer, MojoExecution me) {
String prefix = me.getMojoDescriptor().getPluginDescriptor().getGoalPrefix();
if (prefix == null || prefix.isEmpty()) {
prefix = me.getGroupId() + ":" + me.getArtifactId();
}
buffer.mojo(prefix + ':' + me.getVersion() + ':' + me.getGoal());
if (me.getExecutionId() != null) {
buffer.a(' ').strong('(' + me.getExecutionId() + ')');
}
}
private void appendForkInfo(MessageBuilder buffer, MojoDescriptor md) {
StringBuilder buff = new StringBuilder();
if (md.getExecutePhase() != null && !md.getExecutePhase().isEmpty()) {
// forked phase
if (md.getExecuteLifecycle() != null && !md.getExecuteLifecycle().isEmpty()) {
buff.append('[');
buff.append(md.getExecuteLifecycle());
buff.append(']');
}
buff.append(md.getExecutePhase());
} else {
// forked goal
buff.append(':');
buff.append(md.getExecuteGoal());
}
buffer.strong(buff.toString());
}
private void append(MessageBuilder buffer, MavenProject project) {
buffer.a(" @ ").project(project.getArtifactId());
}
@Override
public void forkedProjectStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()
&& event.getMojoExecution().getForkedExecutions().size() > 1) {
init();
logger.info("");
infoLine('>');
infoMain("Forking " + event.getProject().getName() + " "
+ event.getProject().getVersion());
infoLine('>');
}
}
}

View File

@ -0,0 +1,283 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.extensions;
import javax.inject.Inject;
import javax.inject.Named;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.apache.maven.RepositoryUtils;
import org.apache.maven.api.Service;
import org.apache.maven.api.Session;
import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.model.Plugin;
import org.apache.maven.api.services.ArtifactCoordinatesFactory;
import org.apache.maven.api.services.ArtifactManager;
import org.apache.maven.api.services.ArtifactResolver;
import org.apache.maven.api.services.Interpolator;
import org.apache.maven.api.services.InterpolatorException;
import org.apache.maven.api.services.RepositoryFactory;
import org.apache.maven.api.services.VersionParser;
import org.apache.maven.api.services.VersionRangeResolver;
import org.apache.maven.execution.DefaultMavenExecutionResult;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry;
import org.apache.maven.internal.impl.DefaultArtifactCoordinatesFactory;
import org.apache.maven.internal.impl.DefaultArtifactManager;
import org.apache.maven.internal.impl.DefaultArtifactResolver;
import org.apache.maven.internal.impl.DefaultModelVersionParser;
import org.apache.maven.internal.impl.DefaultRepositoryFactory;
import org.apache.maven.internal.impl.DefaultSession;
import org.apache.maven.internal.impl.DefaultVersionParser;
import org.apache.maven.internal.impl.DefaultVersionRangeResolver;
import org.apache.maven.internal.impl.InternalSession;
import org.apache.maven.internal.impl.model.DefaultInterpolator;
import org.apache.maven.plugin.PluginResolutionException;
import org.apache.maven.plugin.internal.DefaultPluginDependenciesResolver;
import org.apache.maven.resolver.MavenChainedWorkspaceReader;
import org.apache.maven.resolver.RepositorySystemSessionFactory;
import org.codehaus.plexus.DefaultPlexusContainer;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.classworlds.ClassWorld;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import org.eclipse.aether.RepositorySystem;
import org.eclipse.aether.RepositorySystemSession;
import org.eclipse.aether.RepositorySystemSession.CloseableSession;
import org.eclipse.aether.artifact.Artifact;
import org.eclipse.aether.graph.DependencyFilter;
import org.eclipse.aether.internal.impl.DefaultChecksumPolicyProvider;
import org.eclipse.aether.internal.impl.DefaultRemoteRepositoryManager;
import org.eclipse.aether.internal.impl.DefaultUpdatePolicyAnalyzer;
import org.eclipse.aether.repository.RemoteRepository;
import org.eclipse.aether.repository.WorkspaceReader;
import org.eclipse.aether.resolution.ArtifactResult;
import org.eclipse.aether.resolution.DependencyResult;
import org.eclipse.aether.util.filter.ExclusionsDependencyFilter;
import org.eclipse.aether.util.version.GenericVersionScheme;
import org.eclipse.sisu.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* BootstrapCoreExtensionManager
*/
@Named
public class BootstrapCoreExtensionManager {
public static final String STRATEGY_PARENT_FIRST = "parent-first";
public static final String STRATEGY_PLUGIN = "plugin";
public static final String STRATEGY_SELF_FIRST = "self-first";
private final Logger log = LoggerFactory.getLogger(getClass());
private final DefaultPluginDependenciesResolver pluginDependenciesResolver;
private final RepositorySystemSessionFactory repositorySystemSessionFactory;
private final CoreExports coreExports;
private final ClassWorld classWorld;
private final ClassRealm parentRealm;
private final WorkspaceReader ideWorkspaceReader;
private final RepositorySystem repoSystem;
@Inject
public BootstrapCoreExtensionManager(
DefaultPluginDependenciesResolver pluginDependenciesResolver,
RepositorySystemSessionFactory repositorySystemSessionFactory,
CoreExports coreExports,
PlexusContainer container,
@Nullable @Named("ide") WorkspaceReader ideWorkspaceReader,
RepositorySystem repoSystem) {
this.pluginDependenciesResolver = pluginDependenciesResolver;
this.repositorySystemSessionFactory = repositorySystemSessionFactory;
this.coreExports = coreExports;
this.classWorld = ((DefaultPlexusContainer) container).getClassWorld();
this.parentRealm = container.getContainerRealm();
this.ideWorkspaceReader = ideWorkspaceReader;
this.repoSystem = repoSystem;
}
public List<CoreExtensionEntry> loadCoreExtensions(
MavenExecutionRequest request, Set<String> providedArtifacts, List<CoreExtension> extensions)
throws Exception {
try (CloseableSession repoSession = repositorySystemSessionFactory
.newRepositorySessionBuilder(request)
.setWorkspaceReader(new MavenChainedWorkspaceReader(request.getWorkspaceReader(), ideWorkspaceReader))
.build()) {
MavenSession mSession = new MavenSession(repoSession, request, new DefaultMavenExecutionResult());
InternalSession iSession = new SimpleSession(mSession, repoSystem, null);
InternalSession.associate(repoSession, iSession);
List<RemoteRepository> repositories = RepositoryUtils.toRepos(request.getPluginArtifactRepositories());
Function<String, String> interpolator = createInterpolator(request);
return resolveCoreExtensions(repoSession, repositories, providedArtifacts, extensions, interpolator);
}
}
private List<CoreExtensionEntry> resolveCoreExtensions(
RepositorySystemSession repoSession,
List<RemoteRepository> repositories,
Set<String> providedArtifacts,
List<CoreExtension> configuration,
Function<String, String> interpolator)
throws Exception {
List<CoreExtensionEntry> extensions = new ArrayList<>();
DependencyFilter dependencyFilter = new ExclusionsDependencyFilter(providedArtifacts);
for (CoreExtension extension : configuration) {
List<Artifact> artifacts =
resolveExtension(extension, repoSession, repositories, dependencyFilter, interpolator);
if (!artifacts.isEmpty()) {
extensions.add(createExtension(extension, artifacts));
}
}
return Collections.unmodifiableList(extensions);
}
private CoreExtensionEntry createExtension(CoreExtension extension, List<Artifact> artifacts) throws Exception {
String realmId = "coreExtension>" + extension.getGroupId() + ":" + extension.getArtifactId() + ":"
+ extension.getVersion();
final ClassRealm realm = classWorld.newRealm(realmId, null);
Set<String> providedArtifacts = Collections.emptySet();
String classLoadingStrategy = extension.getClassLoadingStrategy();
if (STRATEGY_PARENT_FIRST.equals(classLoadingStrategy)) {
realm.importFrom(parentRealm, "");
} else if (STRATEGY_PLUGIN.equals(classLoadingStrategy)) {
coreExports.getExportedPackages().forEach((p, cl) -> realm.importFrom(cl, p));
providedArtifacts = coreExports.getExportedArtifacts();
} else if (STRATEGY_SELF_FIRST.equals(classLoadingStrategy)) {
realm.setParentRealm(parentRealm);
} else {
throw new IllegalArgumentException("Unsupported class-loading strategy '"
+ classLoadingStrategy + "'. Supported values are: " + STRATEGY_PARENT_FIRST
+ ", " + STRATEGY_PLUGIN + " and " + STRATEGY_SELF_FIRST);
}
log.debug("Populating class realm {}", realm.getId());
for (Artifact artifact : artifacts) {
String id = artifact.getGroupId() + ":" + artifact.getArtifactId();
if (providedArtifacts.contains(id)) {
log.debug(" Excluded {}", id);
} else {
Path file = artifact.getPath();
log.debug(" Included {} located at {}", id, file);
realm.addURL(file.toUri().toURL());
}
}
return CoreExtensionEntry.discoverFrom(
realm,
Collections.singleton(artifacts.get(0).getPath().toFile()),
extension.getGroupId() + ":" + extension.getArtifactId(),
extension.getConfiguration());
}
private List<Artifact> resolveExtension(
CoreExtension extension,
RepositorySystemSession repoSession,
List<RemoteRepository> repositories,
DependencyFilter dependencyFilter,
Function<String, String> interpolator)
throws ExtensionResolutionException {
try {
/* TODO: Enhance the PluginDependenciesResolver to provide a
* resolveCoreExtension method which uses a CoreExtension
* object instead of a Plugin as this makes no sense.
*/
Plugin plugin = Plugin.newBuilder()
.groupId(interpolator.apply(extension.getGroupId()))
.artifactId(interpolator.apply(extension.getArtifactId()))
.version(interpolator.apply(extension.getVersion()))
.build();
DependencyResult result = pluginDependenciesResolver.resolveCoreExtension(
new org.apache.maven.model.Plugin(plugin), dependencyFilter, repositories, repoSession);
return result.getArtifactResults().stream()
.filter(ArtifactResult::isResolved)
.map(ArtifactResult::getArtifact)
.collect(Collectors.toList());
} catch (PluginResolutionException | InterpolatorException e) {
throw new ExtensionResolutionException(extension, e);
}
}
private static Function<String, String> createInterpolator(MavenExecutionRequest request) {
Interpolator interpolator = new DefaultInterpolator();
Function<String, String> callback = v -> {
String r = request.getUserProperties().getProperty(v);
if (r == null) {
r = request.getSystemProperties().getProperty(v);
}
return r != null ? r : v;
};
return v -> interpolator.interpolate(v, callback);
}
static class SimpleSession extends DefaultSession {
SimpleSession(
MavenSession session,
RepositorySystem repositorySystem,
List<org.apache.maven.api.RemoteRepository> repositories) {
super(session, repositorySystem, repositories, null, null, null);
}
@Override
protected Session newSession(
MavenSession mavenSession, List<org.apache.maven.api.RemoteRepository> repositories) {
return new SimpleSession(mavenSession, getRepositorySystem(), repositories);
}
@Override
public <T extends Service> T getService(Class<T> clazz) throws NoSuchElementException {
if (clazz == ArtifactCoordinatesFactory.class) {
return (T) new DefaultArtifactCoordinatesFactory();
} else if (clazz == VersionParser.class) {
return (T) new DefaultVersionParser(new DefaultModelVersionParser(new GenericVersionScheme()));
} else if (clazz == VersionRangeResolver.class) {
return (T) new DefaultVersionRangeResolver(repositorySystem);
} else if (clazz == ArtifactResolver.class) {
return (T) new DefaultArtifactResolver();
} else if (clazz == ArtifactManager.class) {
return (T) new DefaultArtifactManager(this);
} else if (clazz == RepositoryFactory.class) {
return (T) new DefaultRepositoryFactory(new DefaultRemoteRepositoryManager(
new DefaultUpdatePolicyAnalyzer(), new DefaultChecksumPolicyProvider()));
} else if (clazz == Interpolator.class) {
return (T) new DefaultInterpolator();
// } else if (clazz == ModelResolver.class) {
// return (T) new DefaultModelResolver();
}
throw new NoSuchElementException("No service for " + clazz.getName());
}
}
}

View File

@ -0,0 +1,75 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.extensions;
import java.util.function.Function;
import com.google.inject.Binder;
import com.google.inject.Module;
import com.google.inject.name.Names;
import org.apache.maven.api.services.Interpolator;
import org.apache.maven.api.xml.XmlNode;
import org.apache.maven.extension.internal.CoreExtensionEntry;
import org.apache.maven.internal.impl.model.DefaultInterpolator;
import org.apache.maven.internal.xml.XmlNodeImpl;
import org.apache.maven.internal.xml.XmlPlexusConfiguration;
import org.apache.maven.model.v4.MavenTransformer;
import org.codehaus.plexus.configuration.PlexusConfiguration;
public class ExtensionConfigurationModule implements Module {
private final CoreExtensionEntry extension;
private final Function<String, String> callback;
private final DefaultInterpolator interpolator = new DefaultInterpolator();
public ExtensionConfigurationModule(CoreExtensionEntry extension, Function<String, String> callback) {
this.extension = extension;
this.callback = callback;
}
@Override
public void configure(Binder binder) {
if (extension.getKey() != null) {
XmlNode configuration = extension.getConfiguration();
if (configuration == null) {
configuration = new XmlNodeImpl("configuration");
}
Function<String, String> cb = Interpolator.memoize(callback);
Function<String, String> it = s -> interpolator.interpolate(s, cb);
configuration = new ExtensionInterpolator(it).transform(configuration);
binder.bind(XmlNode.class)
.annotatedWith(Names.named(extension.getKey()))
.toInstance(configuration);
binder.bind(PlexusConfiguration.class)
.annotatedWith(Names.named(extension.getKey()))
.toInstance(XmlPlexusConfiguration.toPlexusConfiguration(configuration));
}
}
static class ExtensionInterpolator extends MavenTransformer {
ExtensionInterpolator(Function<String, String> transformer) {
super(transformer);
}
public XmlNode transform(XmlNode node) {
return super.transform(node);
}
}
}

View File

@ -0,0 +1,42 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.extensions;
import org.apache.maven.api.cli.extensions.CoreExtension;
/**
* Exception occurring trying to resolve a plugin.
*
*/
public class ExtensionResolutionException extends Exception {
private final CoreExtension extension;
public ExtensionResolutionException(CoreExtension extension, Throwable cause) {
super(
"Extension " + extension.getId() + " or one of its dependencies could not be resolved: "
+ cause.getMessage(),
cause);
this.extension = extension;
}
public CoreExtension getExtension() {
return extension;
}
}

View File

@ -42,9 +42,9 @@ import org.apache.maven.api.cli.Parser;
import org.apache.maven.api.cli.ParserException;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.cli.CLIReportingUtils;
import org.apache.maven.cli.internal.extension.io.CoreExtensionsStaxReader;
import org.apache.maven.cli.props.MavenPropertiesLoader;
import org.apache.maven.cling.internal.extension.io.CoreExtensionsStaxReader;
import org.apache.maven.cling.props.MavenPropertiesLoader;
import org.apache.maven.cling.utils.CLIReportingUtils;
import org.apache.maven.properties.internal.EnvironmentUtils;
import org.apache.maven.properties.internal.SystemProperties;

View File

@ -0,0 +1,103 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.invoker;
import java.util.ArrayList;
import java.util.List;
/**
* CleanArgument
*/
public class CleanArgument {
public static String[] cleanArgs(String[] args) {
try {
return doCleanArgs(args);
} catch (RuntimeException e) {
for (String a : args) {
System.out.println("Arg: '" + a + "'");
}
throw e;
}
}
private static String[] doCleanArgs(String[] args) {
List<String> cleaned = new ArrayList<>();
StringBuilder currentArg = null;
for (String arg : args) {
boolean addedToBuffer = false;
if (arg.startsWith("\"")) {
// if we're in the process of building up another arg, push it and start over.
// this is for the case: "-Dfoo=bar "-Dfoo2=bar two" (note the first unterminated quote)
if (currentArg != null) {
cleaned.add(currentArg.toString());
}
// start building an argument here.
currentArg = new StringBuilder(arg.substring(1));
addedToBuffer = true;
}
// this has to be a separate "if" statement, to capture the case of: "-Dfoo=bar"
if (addedToBuffer && arg.endsWith("\"")) {
// if we're building an argument, keep doing so.
// if this is the case of "-Dfoo=bar", then we need to adjust the buffer.
if (!currentArg.isEmpty()) {
currentArg.setLength(currentArg.length() - 1);
}
cleaned.add(currentArg.toString());
currentArg = null;
addedToBuffer = false;
continue;
}
// if we haven't added this arg to the buffer, and we ARE building an argument
// buffer, then append it with a preceding space...again, not sure what else to
// do other than collapse whitespace.
// NOTE: The case of a trailing quote is handled by nullifying the arg buffer.
if (!addedToBuffer) {
if (currentArg != null) {
currentArg.append(' ').append(arg);
} else {
cleaned.add(arg);
}
}
}
if (currentArg != null) {
cleaned.add(currentArg.toString());
}
int cleanedSz = cleaned.size();
String[] cleanArgs;
if (cleanedSz == 0) {
cleanArgs = args;
} else {
cleanArgs = cleaned.toArray(new String[0]);
}
return cleanArgs;
}
}

View File

@ -34,7 +34,6 @@ import org.apache.commons.cli.Option;
import org.apache.commons.cli.ParseException;
import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.ParserRequest;
import org.apache.maven.cli.CleanArgument;
import org.apache.maven.jline.MessageUtils;
import static java.util.Objects.requireNonNull;

View File

@ -62,14 +62,14 @@ import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
import org.apache.maven.artifact.repository.MavenArtifactRepository;
import org.apache.maven.artifact.repository.layout.DefaultRepositoryLayout;
import org.apache.maven.bridge.MavenRepositorySystem;
import org.apache.maven.cli.CLIReportingUtils;
import org.apache.maven.cli.logging.Slf4jConfiguration;
import org.apache.maven.cli.logging.Slf4jConfigurationFactory;
import org.apache.maven.cli.transfer.ConsoleMavenTransferListener;
import org.apache.maven.cli.transfer.QuietMavenTransferListener;
import org.apache.maven.cli.transfer.SimplexTransferListener;
import org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
import org.apache.maven.cling.invoker.mvn.ProtoSession;
import org.apache.maven.cling.logging.Slf4jConfiguration;
import org.apache.maven.cling.logging.Slf4jConfigurationFactory;
import org.apache.maven.cling.transfer.ConsoleMavenTransferListener;
import org.apache.maven.cling.transfer.QuietMavenTransferListener;
import org.apache.maven.cling.transfer.SimplexTransferListener;
import org.apache.maven.cling.transfer.Slf4jMavenTransferListener;
import org.apache.maven.cling.utils.CLIReportingUtils;
import org.apache.maven.execution.MavenExecutionRequest;
import org.apache.maven.internal.impl.SettingsUtilsV4;
import org.apache.maven.jline.FastTerminal;

View File

@ -37,9 +37,9 @@ import org.apache.maven.api.cli.Options;
import org.apache.maven.api.cli.extensions.CoreExtension;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.apache.maven.api.services.SettingsBuilder;
import org.apache.maven.cli.ExtensionConfigurationModule;
import org.apache.maven.cli.internal.BootstrapCoreExtensionManager;
import org.apache.maven.cli.logging.Slf4jLoggerManager;
import org.apache.maven.cling.extensions.BootstrapCoreExtensionManager;
import org.apache.maven.cling.extensions.ExtensionConfigurationModule;
import org.apache.maven.cling.logging.Slf4jLoggerManager;
import org.apache.maven.di.Injector;
import org.apache.maven.execution.DefaultMavenExecutionRequest;
import org.apache.maven.execution.MavenExecutionRequest;

View File

@ -32,7 +32,7 @@ import java.util.function.Function;
import org.apache.maven.api.annotations.Nonnull;
import org.apache.maven.api.annotations.Nullable;
import org.apache.maven.api.services.model.RootLocator;
import org.apache.maven.cli.logging.Slf4jConfiguration;
import org.apache.maven.cling.logging.Slf4jConfiguration;
import org.apache.maven.execution.MavenExecutionRequest;
import org.codehaus.plexus.interpolation.AbstractValueSource;
import org.codehaus.plexus.interpolation.BasicInterpolator;

View File

@ -46,11 +46,11 @@ import org.apache.maven.api.services.ToolchainsBuilder;
import org.apache.maven.api.services.ToolchainsBuilderRequest;
import org.apache.maven.api.services.ToolchainsBuilderResult;
import org.apache.maven.api.services.model.ModelProcessor;
import org.apache.maven.cli.CLIReportingUtils;
import org.apache.maven.cli.event.ExecutionEventLogger;
import org.apache.maven.cling.event.ExecutionEventLogger;
import org.apache.maven.cling.invoker.LookupInvoker;
import org.apache.maven.cling.invoker.ProtoLookup;
import org.apache.maven.cling.invoker.Utils;
import org.apache.maven.cling.utils.CLIReportingUtils;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.exception.DefaultExceptionHandler;
import org.apache.maven.exception.ExceptionHandler;

View File

@ -26,9 +26,9 @@ import java.util.Map;
import org.apache.maven.api.cli.mvnenc.EncryptInvoker;
import org.apache.maven.api.cli.mvnenc.EncryptInvokerRequest;
import org.apache.maven.api.cli.mvnenc.EncryptOptions;
import org.apache.maven.cli.CLIReportingUtils;
import org.apache.maven.cling.invoker.LookupInvoker;
import org.apache.maven.cling.invoker.ProtoLookup;
import org.apache.maven.cling.utils.CLIReportingUtils;
import org.jline.consoleui.prompt.ConsolePrompt;
import org.jline.reader.LineReader;
import org.jline.reader.LineReaderBuilder;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging;
package org.apache.maven.cling.logging;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -29,10 +29,12 @@ import org.slf4j.LoggerFactory;
public class BaseSlf4jConfiguration implements Slf4jConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(BaseSlf4jConfiguration.class);
@Override
public void setRootLoggerLevel(Level level) {
LOGGER.warn("setRootLoggerLevel: operation not supported");
}
@Override
public void activate() {
LOGGER.warn("activate(): operation not supported");
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging;
package org.apache.maven.cling.logging;
/**
* Interface for configuration operations on loggers, which are not available in slf4j, then require per-slf4f-binding

View File

@ -16,15 +16,16 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging;
package org.apache.maven.cling.logging;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Properties;
import org.apache.maven.cli.logging.impl.UnsupportedSlf4jBindingConfiguration;
import org.apache.maven.cling.logging.impl.UnsupportedSlf4jBindingConfiguration;
import org.slf4j.ILoggerFactory;
/**
@ -56,9 +57,15 @@ public class Slf4jConfigurationFactory {
}
String impl = properties.getProperty(slf4jBinding);
if (impl != null) {
return (Slf4jConfiguration) Class.forName(impl).newInstance();
return (Slf4jConfiguration)
Class.forName(impl).getDeclaredConstructor().newInstance();
}
} catch (IOException | ClassNotFoundException | IllegalAccessException | InstantiationException ex) {
} catch (IOException
| ClassNotFoundException
| NoSuchMethodException
| InvocationTargetException
| IllegalAccessException
| InstantiationException ex) {
// ignore and move on to the next
}
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging;
package org.apache.maven.cling.logging;
import org.apache.maven.logging.ProjectBuildLogAppender;
import org.codehaus.plexus.logging.Logger;
@ -29,80 +29,95 @@ import org.codehaus.plexus.logging.Logger;
*/
public class Slf4jLogger implements Logger {
private org.slf4j.Logger logger;
private String projectId;
private final org.slf4j.Logger logger;
private final String projectId;
public Slf4jLogger(org.slf4j.Logger logger) {
this.logger = logger;
this.projectId = ProjectBuildLogAppender.getProjectId();
}
@Override
public void debug(String message) {
setMdc();
logger.debug(message);
}
@Override
public void debug(String message, Throwable throwable) {
setMdc();
logger.debug(message, throwable);
}
@Override
public boolean isDebugEnabled() {
return logger.isDebugEnabled();
}
@Override
public void info(String message) {
setMdc();
logger.info(message);
}
@Override
public void info(String message, Throwable throwable) {
setMdc();
logger.info(message, throwable);
}
@Override
public boolean isInfoEnabled() {
return logger.isInfoEnabled();
}
@Override
public void warn(String message) {
setMdc();
logger.warn(message);
}
@Override
public void warn(String message, Throwable throwable) {
setMdc();
logger.warn(message, throwable);
}
@Override
public boolean isWarnEnabled() {
return logger.isWarnEnabled();
}
@Override
public void error(String message) {
setMdc();
logger.error(message);
}
@Override
public void error(String message, Throwable throwable) {
setMdc();
logger.error(message, throwable);
}
@Override
public boolean isErrorEnabled() {
return logger.isErrorEnabled();
}
@Override
public void fatalError(String message) {
setMdc();
logger.error(message);
}
@Override
public void fatalError(String message, Throwable throwable) {
setMdc();
logger.error(message, throwable);
}
@Override
public boolean isFatalErrorEnabled() {
return logger.isErrorEnabled();
}
@ -110,6 +125,7 @@ public class Slf4jLogger implements Logger {
/**
* <b>Warning</b>: ignored (always return <code>0 == Logger.LEVEL_DEBUG</code>).
*/
@Override
public int getThreshold() {
return 0;
}
@ -117,15 +133,18 @@ public class Slf4jLogger implements Logger {
/**
* <b>Warning</b>: ignored.
*/
@Override
public void setThreshold(int threshold) {}
/**
* <b>Warning</b>: ignored (always return <code>null</code>).
*/
@Override
public Logger getChildLogger(String name) {
return null;
}
@Override
public String getName() {
return logger.getName();
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging;
package org.apache.maven.cling.logging;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.logging.LoggerManager;
@ -24,20 +24,21 @@ import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
/**
* Use an SLF4J {@link org.slf4j.ILoggerFactory} as a backing for a Plexus
* {@link org.codehaus.plexus.logging.LoggerManager},
* Use an SLF4J {@link ILoggerFactory} as a backing for a Plexus
* {@link LoggerManager},
* ignoring Plexus logger API parts that are not classical and probably not really used.
*
* @since 3.1
*/
public class Slf4jLoggerManager implements LoggerManager {
private ILoggerFactory loggerFactory;
private final ILoggerFactory loggerFactory;
public Slf4jLoggerManager() {
loggerFactory = LoggerFactory.getILoggerFactory();
}
@Override
public Logger getLoggerForComponent(String role) {
return new Slf4jLogger(loggerFactory.getLogger(role));
}
@ -47,6 +48,7 @@ public class Slf4jLoggerManager implements LoggerManager {
* <b>Warning</b>: this does not conform to logger name as class name convention.
* (and what about <code>null</code> and <code>default</code> hint equivalence?)
*/
@Override
public Logger getLoggerForComponent(String role, String hint) {
return (null == hint
? getLoggerForComponent(role)
@ -60,16 +62,19 @@ public class Slf4jLoggerManager implements LoggerManager {
/**
* <b>Warning</b>: ignored.
*/
@Override
public void returnComponentLogger(String role) {}
/**
* <b>Warning</b>: ignored.
*/
@Override
public void returnComponentLogger(String role, String hint) {}
/**
* <b>Warning</b>: ignored (always return <code>0</code>).
*/
@Override
public int getThreshold() {
return 0;
}
@ -77,16 +82,19 @@ public class Slf4jLoggerManager implements LoggerManager {
/**
* <b>Warning</b>: ignored.
*/
@Override
public void setThreshold(int threshold) {}
/**
* <b>Warning</b>: ignored.
*/
@Override
public void setThresholds(int threshold) {}
/**
* <b>Warning</b>: ignored (always return <code>0</code>).
*/
@Override
public int getActiveLoggerCount() {
return 0;
}

View File

@ -16,9 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging.impl;
package org.apache.maven.cling.logging.impl;
import org.apache.maven.cli.logging.BaseSlf4jConfiguration;
import org.apache.maven.cling.logging.BaseSlf4jConfiguration;
/**
* Configuration for slf4j-log4j2.

View File

@ -16,9 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging.impl;
package org.apache.maven.cling.logging.impl;
import org.apache.maven.cli.logging.BaseSlf4jConfiguration;
import org.apache.maven.cling.logging.BaseSlf4jConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

View File

@ -16,9 +16,9 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging.impl;
package org.apache.maven.cling.logging.impl;
import org.apache.maven.cli.logging.BaseSlf4jConfiguration;
import org.apache.maven.cling.logging.BaseSlf4jConfiguration;
import org.apache.maven.slf4j.MavenLoggerFactory;
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;

View File

@ -16,13 +16,13 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cli.logging.impl;
package org.apache.maven.cling.logging.impl;
import java.net.URL;
import java.util.Map;
import java.util.Set;
import org.apache.maven.cli.logging.BaseSlf4jConfiguration;
import org.apache.maven.cling.logging.BaseSlf4jConfiguration;
/**
* Pseudo-configuration for unsupported SLF4J binding.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.props;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Enumeration;
import java.util.Map;
import java.util.StringTokenizer;
import java.util.function.Function;
import org.apache.maven.internal.impl.model.DefaultInterpolator;
public class MavenPropertiesLoader {
public static final String INCLUDES_PROPERTY = "${includes}"; // includes
public static final String OVERRIDE_PREFIX =
"maven.override."; // prefix that marks that system property should override defaults.
public static void loadProperties(
java.util.Properties properties, Path path, Function<String, String> callback, boolean escape)
throws IOException {
MavenProperties sp = new MavenProperties(false);
if (Files.exists(path)) {
sp.load(path);
}
properties.forEach(
(k, v) -> sp.put(k.toString(), escape ? DefaultInterpolator.escape(v.toString()) : v.toString()));
loadIncludes(path, sp, callback);
substitute(sp, callback);
sp.forEach(properties::setProperty);
}
public static void substitute(MavenProperties props, Function<String, String> callback) {
for (Enumeration<?> e = props.propertyNames(); e.hasMoreElements(); ) {
String name = (String) e.nextElement();
String value = props.getProperty(name);
if (value == null) {
value = callback.apply(name);
}
if (name.startsWith(OVERRIDE_PREFIX)) {
String overrideName = name.substring(OVERRIDE_PREFIX.length());
props.put(overrideName, substVars(value, name, props, callback));
} else {
props.put(name, substVars(value, name, props, callback));
}
}
props.keySet().removeIf(k -> k.startsWith(OVERRIDE_PREFIX));
}
private static MavenProperties loadPropertiesFile(
Path path, boolean failIfNotFound, Function<String, String> callback) throws IOException {
MavenProperties configProps = new MavenProperties(null, false);
if (Files.exists(path) || failIfNotFound) {
configProps.load(path);
loadIncludes(path, configProps, callback);
trimValues(configProps);
}
return configProps;
}
private static void loadIncludes(Path configProp, MavenProperties configProps, Function<String, String> callback)
throws IOException {
String includes = configProps.get(INCLUDES_PROPERTY);
if (includes != null) {
includes = substVars(includes, INCLUDES_PROPERTY, configProps, callback);
StringTokenizer st = new StringTokenizer(includes, "?\",", true);
if (st.countTokens() > 0) {
String location;
do {
location = nextLocation(st);
if (location != null) {
boolean mandatory = true;
if (location.startsWith("?")) {
mandatory = false;
location = location.substring(1);
}
Path path = configProp.resolveSibling(location);
MavenProperties props = loadPropertiesFile(path, mandatory, s -> {
var v = callback.apply(s);
return v != null ? v : configProps.getProperty(s);
});
configProps.putAll(props);
}
} while (location != null);
}
}
configProps.remove(INCLUDES_PROPERTY);
}
private static void trimValues(MavenProperties configProps) {
configProps.replaceAll((k, v) -> v.trim());
}
private static String nextLocation(StringTokenizer st) {
boolean optional = false;
String retVal = null;
if (st.countTokens() > 0) {
String tokenList = "?\",";
StringBuilder tokBuf = new StringBuilder(10);
String tok;
boolean inQuote = false;
boolean tokStarted = false;
boolean exit = false;
while ((st.hasMoreTokens()) && (!exit)) {
tok = st.nextToken(tokenList);
switch (tok) {
case "\"":
inQuote = !inQuote;
if (inQuote) {
tokenList = "\"";
} else {
tokenList = "\" ";
}
break;
case ",":
if (tokStarted) {
retVal = tokBuf.toString();
tokStarted = false;
tokBuf = new StringBuilder(10);
exit = true;
}
break;
case "?":
optional = true;
break;
default:
tokStarted = true;
tokBuf.append(tok.trim());
break;
}
}
// Handle case where end of token stream and
// still got data
if ((!exit) && (tokStarted)) {
retVal = tokBuf.toString();
}
}
return optional ? "?" + retVal : retVal;
}
public static String substVars(
String value, String name, Map<String, String> props, Function<String, String> callback) {
return DefaultInterpolator.substVars(value, name, null, props, callback, null, false);
}
}

View File

@ -0,0 +1,99 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.transfer;
import java.io.PrintStream;
import java.io.PrintWriter;
import org.apache.maven.api.services.MessageBuilder;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.eclipse.aether.transfer.AbstractTransferListener;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.aether.transfer.TransferEvent;
import org.eclipse.aether.transfer.TransferResource;
/**
* AbstractMavenTransferListener
*/
public abstract class AbstractMavenTransferListener extends AbstractTransferListener {
public static final String STYLE = ".transfer:-faint";
protected final MessageBuilderFactory messageBuilderFactory;
protected final PrintWriter out;
protected AbstractMavenTransferListener(MessageBuilderFactory messageBuilderFactory, PrintStream out) {
this(messageBuilderFactory, new PrintWriter(out));
}
protected AbstractMavenTransferListener(MessageBuilderFactory messageBuilderFactory, PrintWriter out) {
this.messageBuilderFactory = messageBuilderFactory;
this.out = out;
}
@Override
public void transferInitiated(TransferEvent event) {
String action = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
TransferResource resource = event.getResource();
MessageBuilder message = messageBuilderFactory.builder();
message.style(STYLE).append(action).append(' ').append(direction).append(' ');
message.resetStyle().append(resource.getRepositoryId());
message.style(STYLE).append(": ").append(resource.getRepositoryUrl());
message.resetStyle().append(resource.getResourceName());
out.println(message.toString());
}
@Override
public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
TransferResource resource = event.getResource();
// TODO This needs to be colorized
out.println("[WARNING] " + event.getException().getMessage() + " from " + resource.getRepositoryId() + " for "
+ resource.getRepositoryUrl() + resource.getResourceName());
}
@Override
public void transferSucceeded(TransferEvent event) {
String action = (event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded");
String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
TransferResource resource = event.getResource();
long contentLength = event.getTransferredBytes();
FileSizeFormat format = new FileSizeFormat();
MessageBuilder message = messageBuilderFactory.builder();
message.append(action).style(STYLE).append(' ').append(direction).append(' ');
message.resetStyle().append(resource.getRepositoryId());
message.style(STYLE).append(": ").append(resource.getRepositoryUrl());
message.resetStyle().append(resource.getResourceName());
message.style(STYLE).append(" (").append(format.format(contentLength));
long duration = System.currentTimeMillis() - resource.getTransferStartTime();
if (duration > 0L) {
double bytesPerSecond = contentLength / (duration / 1000.0);
message.append(" at ");
format.format(message, (long) bytesPerSecond);
message.append("/s");
}
message.append(')').resetStyle();
out.println(message.toString());
}
}

View File

@ -0,0 +1,157 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.transfer;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.maven.api.services.MessageBuilderFactory;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.aether.transfer.TransferEvent;
import org.eclipse.aether.transfer.TransferResource;
/**
* Console download progress meter.
* <p>
* This listener is not thread-safe and should be wrapped in the {@link SimplexTransferListener} in a multi-threaded scenario.
*/
public class ConsoleMavenTransferListener extends AbstractMavenTransferListener {
private final Map<TransferResourceIdentifier, TransferResourceAndSize> transfers = new LinkedHashMap<>();
private final FileSizeFormat format = new FileSizeFormat(); // use in a synchronized fashion
private final StringBuilder buffer = new StringBuilder(128); // use in a synchronized fashion
private final boolean printResourceNames;
private int lastLength;
public ConsoleMavenTransferListener(
MessageBuilderFactory messageBuilderFactory, PrintStream out, boolean printResourceNames) {
this(messageBuilderFactory, new PrintWriter(out), printResourceNames);
}
public ConsoleMavenTransferListener(
MessageBuilderFactory messageBuilderFactory, PrintWriter out, boolean printResourceNames) {
super(messageBuilderFactory, out);
this.printResourceNames = printResourceNames;
}
@Override
public void transferInitiated(TransferEvent event) {
overridePreviousTransfer(event);
super.transferInitiated(event);
}
@Override
public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
overridePreviousTransfer(event);
super.transferCorrupted(event);
}
@Override
public void transferProgressed(TransferEvent event) throws TransferCancelledException {
TransferResource resource = event.getResource();
transfers.put(
new TransferResourceIdentifier(resource),
new TransferResourceAndSize(resource, event.getTransferredBytes()));
buffer.append("Progress (").append(transfers.size()).append("): ");
Iterator<TransferResourceAndSize> entries = transfers.values().iterator();
while (entries.hasNext()) {
TransferResourceAndSize entry = entries.next();
// just in case, make sure 0 <= complete <= total
long complete = Math.max(0, entry.transferredBytes);
long total = Math.max(complete, entry.resource.getContentLength());
String resourceName = entry.resource.getResourceName();
if (printResourceNames) {
int idx = resourceName.lastIndexOf('/');
if (idx < 0) {
buffer.append(resourceName);
} else {
buffer.append(resourceName, idx + 1, resourceName.length());
}
buffer.append(" (");
}
format.formatProgress(buffer, complete, total);
if (printResourceNames) {
buffer.append(")");
}
if (entries.hasNext()) {
buffer.append(" | ");
}
}
int pad = lastLength - buffer.length();
lastLength = buffer.length();
pad(buffer, pad);
buffer.append('\r');
out.print(buffer);
out.flush();
buffer.setLength(0);
}
private void pad(StringBuilder buffer, int spaces) {
String block = " ";
while (spaces > 0) {
int n = Math.min(spaces, block.length());
buffer.append(block, 0, n);
spaces -= n;
}
}
@Override
public void transferSucceeded(TransferEvent event) {
transfers.remove(new TransferResourceIdentifier(event.getResource()));
overridePreviousTransfer(event);
super.transferSucceeded(event);
}
@Override
public void transferFailed(TransferEvent event) {
transfers.remove(new TransferResourceIdentifier(event.getResource()));
overridePreviousTransfer(event);
super.transferFailed(event);
}
private void overridePreviousTransfer(TransferEvent event) {
if (lastLength > 0) {
pad(buffer, lastLength);
buffer.append('\r');
out.print(buffer);
out.flush();
lastLength = 0;
buffer.setLength(0);
}
}
private record TransferResourceAndSize(TransferResource resource, long transferredBytes) {}
}

View File

@ -0,0 +1,204 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.transfer;
import org.apache.maven.api.services.MessageBuilder;
/**
* Formats file size with the associated <a href="https://en.wikipedia.org/wiki/Metric_prefix">SI</a> prefix
* (GB, MB, kB) and using the patterns <code>#0.0</code> for numbers between 1 and 10
* and <code>###0</code> for numbers between 10 and 1000+ by default.
*
* @see <a href="https://en.wikipedia.org/wiki/Metric_prefix">https://en.wikipedia.org/wiki/Metric_prefix</a>
* @see <a href="https://en.wikipedia.org/wiki/Binary_prefix">https://en.wikipedia.org/wiki/Binary_prefix</a>
* @see <a
* href="https://en.wikipedia.org/wiki/Octet_%28computing%29">https://en.wikipedia.org/wiki/Octet_(computing)</a>
*/
public class FileSizeFormat {
public enum ScaleUnit {
BYTE {
@Override
public long bytes() {
return 1L;
}
@Override
public String symbol() {
return "B";
}
},
KILOBYTE {
@Override
public long bytes() {
return 1000L;
}
@Override
public String symbol() {
return "kB";
}
},
MEGABYTE {
@Override
public long bytes() {
return KILOBYTE.bytes() * KILOBYTE.bytes();
}
@Override
public String symbol() {
return "MB";
}
},
GIGABYTE {
@Override
public long bytes() {
return MEGABYTE.bytes() * KILOBYTE.bytes();
}
;
@Override
public String symbol() {
return "GB";
}
};
public abstract long bytes();
public abstract String symbol();
public static ScaleUnit getScaleUnit(long size) {
if (size < 0L) {
throw new IllegalArgumentException("file size cannot be negative: " + size);
}
if (size >= GIGABYTE.bytes()) {
return GIGABYTE;
} else if (size >= MEGABYTE.bytes()) {
return MEGABYTE;
} else if (size >= KILOBYTE.bytes()) {
return KILOBYTE;
} else {
return BYTE;
}
}
}
public String format(long size) {
return format(size, null);
}
public String format(long size, ScaleUnit unit) {
return format(size, unit, false);
}
public String format(long size, ScaleUnit unit, boolean omitSymbol) {
StringBuilder sb = new StringBuilder();
format(sb, size, unit, omitSymbol);
return sb.toString();
}
public void format(StringBuilder builder, long size) {
format(builder, size, null, false);
}
public void format(StringBuilder builder, long size, ScaleUnit unit) {
format(builder, size, unit, false);
}
private void format(StringBuilder builder, long size, ScaleUnit unit, boolean omitSymbol) {
if (size < 0L) {
throw new IllegalArgumentException("file size cannot be negative: " + size);
}
if (unit == null) {
unit = ScaleUnit.getScaleUnit(size);
}
double scaledSize = (double) size / unit.bytes();
if (unit == ScaleUnit.BYTE) {
builder.append(size);
} else if (scaledSize < 0.05d || scaledSize >= 10.0d) {
builder.append(Math.round(scaledSize));
} else {
builder.append(Math.round(scaledSize * 10d) / 10d);
}
if (!omitSymbol) {
builder.append(" ").append(unit.symbol());
}
}
public void format(MessageBuilder builder, long size) {
format(builder, size, null, false);
}
public void format(MessageBuilder builder, long size, ScaleUnit unit) {
format(builder, size, unit, false);
}
private void format(MessageBuilder builder, long size, ScaleUnit unit, boolean omitSymbol) {
if (size < 0L) {
throw new IllegalArgumentException("file size cannot be negative: " + size);
}
if (unit == null) {
unit = ScaleUnit.getScaleUnit(size);
}
double scaledSize = (double) size / unit.bytes();
if (unit == ScaleUnit.BYTE) {
builder.append(Long.toString(size));
} else if (scaledSize < 0.05d || scaledSize >= 10.0d) {
builder.append(Long.toString(Math.round(scaledSize)));
} else {
builder.append(Double.toString(Math.round(scaledSize * 10d) / 10d));
}
if (!omitSymbol) {
builder.append(" ").append(unit.symbol());
}
}
public String formatProgress(long progressedSize, long size) {
StringBuilder sb = new StringBuilder();
formatProgress(sb, progressedSize, size);
return sb.toString();
}
public void formatProgress(StringBuilder builder, long progressedSize, long size) {
if (progressedSize < 0L) {
throw new IllegalArgumentException("progressed file size cannot be negative: " + size);
}
if (size >= 0 && progressedSize > size) {
throw new IllegalArgumentException(
"progressed file size cannot be greater than size: " + progressedSize + " > " + size);
}
if (size >= 0L && progressedSize != size) {
ScaleUnit unit = ScaleUnit.getScaleUnit(size);
format(builder, progressedSize, unit, true);
builder.append("/");
format(builder, size, unit, false);
} else {
ScaleUnit unit = ScaleUnit.getScaleUnit(progressedSize);
format(builder, progressedSize, unit, false);
}
}
}

View File

@ -0,0 +1,25 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.transfer;
import org.eclipse.aether.transfer.AbstractTransferListener;
/**
*/
public class QuietMavenTransferListener extends AbstractTransferListener {}

View File

@ -0,0 +1,230 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.transfer;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.function.Consumer;
import org.eclipse.aether.transfer.AbstractTransferListener;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.aether.transfer.TransferEvent;
import org.eclipse.aether.transfer.TransferListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static java.util.Objects.requireNonNull;
/**
* A {@link TransferListener} implementation that wraps another delegate {@link TransferListener} but makes it run
* on single thread, keeping the listener logic simple. This listener also blocks on last transfer event to allow
* output to perform possible cleanup. It spawns a daemon thread to consume queued events that may fall in even
* concurrently.
*
* @since 4.0.0
*/
public final class SimplexTransferListener extends AbstractTransferListener {
private static final Logger LOGGER = LoggerFactory.getLogger(SimplexTransferListener.class);
private static final int QUEUE_SIZE = 1024;
private static final int BATCH_MAX_SIZE = 500;
private final TransferListener delegate;
private final int batchMaxSize;
private final boolean blockOnLastEvent;
private final ArrayBlockingQueue<Exchange> eventQueue;
/**
* Constructor that makes passed in delegate run on single thread, and will block on last event.
*/
public SimplexTransferListener(TransferListener delegate) {
this(delegate, QUEUE_SIZE, BATCH_MAX_SIZE, true);
}
/**
* Constructor that may alter behaviour of this listener.
*
* @param delegate The delegate that should run on single thread.
* @param queueSize The event queue size (default {@code 1024}).
* @param batchMaxSize The maximum batch size delegate should receive (default {@code 500}).
* @param blockOnLastEvent Should this listener block on last transfer end (completed or corrupted) block? (default {@code true}).
*/
public SimplexTransferListener(
TransferListener delegate, int queueSize, int batchMaxSize, boolean blockOnLastEvent) {
this.delegate = requireNonNull(delegate);
if (queueSize < 1 || batchMaxSize < 1) {
throw new IllegalArgumentException("Queue and batch sizes must be greater than 1");
}
this.batchMaxSize = batchMaxSize;
this.blockOnLastEvent = blockOnLastEvent;
this.eventQueue = new ArrayBlockingQueue<>(queueSize);
Thread updater = new Thread(this::feedConsumer);
updater.setDaemon(true);
updater.start();
}
public TransferListener getDelegate() {
return delegate;
}
private void feedConsumer() {
final ArrayList<Exchange> batch = new ArrayList<>(batchMaxSize);
try {
while (true) {
batch.clear();
if (eventQueue.drainTo(batch, BATCH_MAX_SIZE) == 0) {
batch.add(eventQueue.take());
}
demux(batch);
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private void demux(List<Exchange> exchanges) {
for (Exchange exchange : exchanges) {
exchange.process(transferEvent -> {
TransferEvent.EventType type = transferEvent.getType();
try {
switch (type) {
case INITIATED:
delegate.transferInitiated(transferEvent);
break;
case STARTED:
delegate.transferStarted(transferEvent);
break;
case PROGRESSED:
delegate.transferProgressed(transferEvent);
break;
case CORRUPTED:
delegate.transferCorrupted(transferEvent);
break;
case SUCCEEDED:
delegate.transferSucceeded(transferEvent);
break;
case FAILED:
delegate.transferFailed(transferEvent);
break;
default:
LOGGER.warn("Invalid TransferEvent.EventType={}; ignoring it", type);
}
} catch (TransferCancelledException e) {
ongoing.put(new TransferResourceIdentifier(transferEvent.getResource()), Boolean.FALSE);
}
});
}
}
private void put(TransferEvent event, boolean last) {
try {
Exchange exchange;
if (blockOnLastEvent && last) {
exchange = new BlockingExchange(event);
} else {
exchange = new Exchange(event);
}
eventQueue.put(exchange);
exchange.waitForProcessed();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
private final ConcurrentHashMap<TransferResourceIdentifier, Boolean> ongoing = new ConcurrentHashMap<>();
@Override
public void transferInitiated(TransferEvent event) {
ongoing.putIfAbsent(new TransferResourceIdentifier(event.getResource()), Boolean.TRUE);
put(event, false);
}
@Override
public void transferStarted(TransferEvent event) throws TransferCancelledException {
if (ongoing.get(new TransferResourceIdentifier(event.getResource())) == Boolean.FALSE) {
throw new TransferCancelledException();
}
put(event, false);
}
@Override
public void transferProgressed(TransferEvent event) throws TransferCancelledException {
if (ongoing.get(new TransferResourceIdentifier(event.getResource())) == Boolean.FALSE) {
throw new TransferCancelledException();
}
put(event, false);
}
@Override
public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
if (ongoing.get(new TransferResourceIdentifier(event.getResource())) == Boolean.FALSE) {
throw new TransferCancelledException();
}
put(event, false);
}
@Override
public void transferSucceeded(TransferEvent event) {
ongoing.remove(new TransferResourceIdentifier(event.getResource()));
put(event, ongoing.isEmpty());
}
@Override
public void transferFailed(TransferEvent event) {
ongoing.remove(new TransferResourceIdentifier(event.getResource()));
put(event, ongoing.isEmpty());
}
private static class Exchange {
private final TransferEvent event;
private Exchange(TransferEvent event) {
this.event = event;
}
public void process(Consumer<TransferEvent> consumer) {
consumer.accept(event);
}
public void waitForProcessed() throws InterruptedException {
// nothing, is async
}
}
private static class BlockingExchange extends Exchange {
private final CountDownLatch latch = new CountDownLatch(1);
private BlockingExchange(TransferEvent event) {
super(event);
}
@Override
public void process(Consumer<TransferEvent> consumer) {
super.process(consumer);
latch.countDown();
}
@Override
public void waitForProcessed() throws InterruptedException {
latch.await();
}
}
}

View File

@ -0,0 +1,97 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.transfer;
import org.eclipse.aether.transfer.AbstractTransferListener;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.aether.transfer.TransferEvent;
import org.eclipse.aether.transfer.TransferResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Slf4jMavenTransferListener
*/
public class Slf4jMavenTransferListener extends AbstractTransferListener {
protected final Logger out;
public Slf4jMavenTransferListener() {
this.out = LoggerFactory.getLogger(Slf4jMavenTransferListener.class);
}
// TODO should we deprecate?
public Slf4jMavenTransferListener(Logger out) {
this.out = out;
}
@Override
public void transferInitiated(TransferEvent event) {
String action = event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploading" : "Downloading";
String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
TransferResource resource = event.getResource();
StringBuilder message = new StringBuilder();
message.append(action).append(' ').append(direction).append(' ').append(resource.getRepositoryId());
message.append(": ");
message.append(resource.getRepositoryUrl()).append(resource.getResourceName());
out.info(message.toString());
}
@Override
public void transferCorrupted(TransferEvent event) throws TransferCancelledException {
TransferResource resource = event.getResource();
out.warn(
"{} from {} for {}{}",
event.getException().getMessage(),
resource.getRepositoryId(),
resource.getRepositoryUrl(),
resource.getResourceName());
}
@Override
public void transferSucceeded(TransferEvent event) {
String action = (event.getRequestType() == TransferEvent.RequestType.PUT ? "Uploaded" : "Downloaded");
String direction = event.getRequestType() == TransferEvent.RequestType.PUT ? "to" : "from";
TransferResource resource = event.getResource();
long contentLength = event.getTransferredBytes();
FileSizeFormat format = new FileSizeFormat();
StringBuilder message = new StringBuilder();
message.append(action).append(' ').append(direction).append(' ').append(resource.getRepositoryId());
message.append(": ");
message.append(resource.getRepositoryUrl())
.append(resource.getResourceName())
.append(" (");
format.format(message, contentLength);
long duration = System.currentTimeMillis() - resource.getTransferStartTime();
if (duration > 0L) {
double bytesPerSecond = contentLength / (duration / 1000.0);
message.append(" at ");
format.format(message, (long) bytesPerSecond);
message.append("/s");
}
message.append(')');
out.info(message.toString());
}
}

View File

@ -0,0 +1,35 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.transfer;
import java.nio.file.Path;
import org.apache.maven.api.annotations.Nullable;
import org.eclipse.aether.transfer.TransferResource;
/**
* Immutable identifier of a {@link TransferResource}.
* The {@link TransferResource} is not immutable and does not implement {@code Objects#equals} and {@code Objects#hashCode} methods,
* making it not very suitable for usage in collections.
*/
record TransferResourceIdentifier(String repositoryId, String repositoryUrl, String resourceName, @Nullable Path file) {
TransferResourceIdentifier(TransferResource resource) {
this(resource.getRepositoryId(), resource.getRepositoryUrl(), resource.getResourceName(), resource.getPath());
}
}

View File

@ -0,0 +1,203 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.cling.utils;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.Properties;
import org.apache.maven.jline.MessageUtils;
import org.codehaus.plexus.util.Os;
import org.slf4j.Logger;
/**
* Utility class used to report errors, statistics, application version info, etc.
*
*/
public final class CLIReportingUtils {
// CHECKSTYLE_OFF: MagicNumber
public static final long MB = 1024 * 1024;
private static final long ONE_SECOND = 1000L;
private static final long ONE_MINUTE = 60 * ONE_SECOND;
private static final long ONE_HOUR = 60 * ONE_MINUTE;
private static final long ONE_DAY = 24 * ONE_HOUR;
// CHECKSTYLE_ON: MagicNumber
public static final String BUILD_VERSION_PROPERTY = "version";
public static String showVersion() {
return showVersion(null, null);
}
public static String showVersion(String commandLine, String terminal) {
final String ls = System.lineSeparator();
Properties properties = getBuildProperties();
StringBuilder version = new StringBuilder(256);
version.append(MessageUtils.builder().strong(createMavenVersionString(properties)))
.append(ls);
version.append(reduce(properties.getProperty("distributionShortName") + " home: "
+ System.getProperty("maven.home", "<unknown Maven " + "home>")))
.append(ls);
version.append("Java version: ")
.append(System.getProperty("java.version", "<unknown Java version>"))
.append(", vendor: ")
.append(System.getProperty("java.vendor", "<unknown vendor>"))
.append(", runtime: ")
.append(System.getProperty("java.home", "<unknown runtime>"))
.append(ls);
version.append("Default locale: ")
.append(Locale.getDefault())
.append(", platform encoding: ")
.append(System.getProperty("file.encoding", "<unknown encoding>"))
.append(ls);
version.append("OS name: \"")
.append(Os.OS_NAME)
.append("\", version: \"")
.append(Os.OS_VERSION)
.append("\", arch: \"")
.append(Os.OS_ARCH)
.append("\", family: \"")
.append(Os.OS_FAMILY)
.append('\"');
// Add process information using modern Java API
if (commandLine != null) {
version.append(ls).append("Command line: ").append(commandLine);
}
if (terminal != null) {
version.append(ls).append("Terminal: ").append(terminal);
}
return version.toString();
}
public static String showVersionMinimal() {
Properties properties = getBuildProperties();
String version = reduce(properties.getProperty(BUILD_VERSION_PROPERTY));
return (version != null ? version : "<version unknown>");
}
/**
* Create a human-readable string containing the Maven version, buildnumber, and time of build
*
* @param buildProperties The build properties
* @return Readable build info
*/
public static String createMavenVersionString(Properties buildProperties) {
String timestamp = reduce(buildProperties.getProperty("timestamp"));
String version = reduce(buildProperties.getProperty(BUILD_VERSION_PROPERTY));
String rev = reduce(buildProperties.getProperty("buildNumber"));
String distributionName = reduce(buildProperties.getProperty("distributionName"));
String msg = distributionName + " ";
msg += (version != null ? version : "<version unknown>");
if (rev != null || timestamp != null) {
msg += " (";
msg += (rev != null ? rev : "");
if (timestamp != null && !timestamp.isEmpty()) {
String ts = formatTimestamp(Long.parseLong(timestamp));
msg += (rev != null ? "; " : "") + ts;
}
msg += ")";
}
return msg;
}
private static String reduce(String s) {
return (s != null ? (s.startsWith("${") && s.endsWith("}") ? null : s) : null);
}
public static Properties getBuildProperties() {
Properties properties = new Properties();
try (InputStream resourceAsStream =
CLIReportingUtils.class.getResourceAsStream("/org/apache/maven/messages/build.properties")) {
if (resourceAsStream != null) {
properties.load(resourceAsStream);
}
} catch (IOException e) {
System.err.println("Unable determine version from JAR file: " + e.getMessage());
}
return properties;
}
public static void showError(Logger logger, String message, Throwable e, boolean showStackTrace) {
if (logger == null) {
System.err.println(message);
if (showStackTrace && e != null) {
e.printStackTrace(System.err);
}
return;
}
if (showStackTrace) {
logger.error(message, e);
} else {
logger.error(message);
if (e != null) {
logger.error(e.getMessage());
for (Throwable cause = e.getCause();
cause != null && cause != cause.getCause();
cause = cause.getCause()) {
logger.error("Caused by: {}", cause.getMessage());
}
}
}
}
public static String formatTimestamp(long timestamp) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX");
return sdf.format(new Date(timestamp));
}
public static String formatDuration(long duration) {
// CHECKSTYLE_OFF: MagicNumber
long ms = duration % 1000;
long s = (duration / ONE_SECOND) % 60;
long m = (duration / ONE_MINUTE) % 60;
long h = (duration / ONE_HOUR) % 24;
long d = duration / ONE_DAY;
// CHECKSTYLE_ON: MagicNumber
String format;
if (d > 0) {
// Length 11+ chars
format = "%d d %02d:%02d h";
} else if (h > 0) {
// Length 7 chars
format = "%2$02d:%3$02d h";
} else if (m > 0) {
// Length 9 chars
format = "%3$02d:%4$02d min";
} else {
// Length 7-8 chars
format = "%4$d.%5$03d s";
}
return String.format(format, d, h, m, s, ms);
}
}

View File

@ -17,7 +17,7 @@
# key = Slf4j effective logger factory implementation
# value = corresponding o.a.m.cli.logging.Slf4jConfiguration class
org.slf4j.impl.SimpleLoggerFactory=org.apache.maven.cli.logging.impl.MavenSimpleConfiguration
org.apache.maven.slf4j.MavenLoggerFactory=org.apache.maven.cli.logging.impl.MavenSimpleConfiguration
org.apache.logging.slf4j.Log4jLoggerFactory=org.apache.maven.cli.logging.impl.Log4j2Configuration
ch.qos.logback.classic.LoggerContext=org.apache.maven.cli.logging.impl.LogbackConfiguration
org.slf4j.impl.SimpleLoggerFactory=org.apache.maven.cling.logging.impl.MavenSimpleConfiguration
org.apache.maven.slf4j.MavenLoggerFactory=org.apache.maven.cling.logging.impl.MavenSimpleConfiguration
org.apache.logging.slf4j.Log4jLoggerFactory=org.apache.maven.cling.logging.impl.Log4j2Configuration
ch.qos.logback.classic.LoggerContext=org.apache.maven.cling.logging.impl.LogbackConfiguration