diff --git a/apache-maven/pom.xml b/apache-maven/pom.xml
index 2fee6c9747ff..5d04cddad841 100644
--- a/apache-maven/pom.xml
+++ b/apache-maven/pom.xml
@@ -93,8 +93,8 @@ under the License.
maven-slf4j-provider
- org.fusesource.jansi
- jansi
+ org.jline
+ jline-terminal-ffm
org.junit.jupiter
@@ -139,13 +139,13 @@ under the License.
maven-dependency-plugin
- unpack-jansi-native
+ unpack-jline-native
unpack-dependencies
- jansi
- org/fusesource/jansi/internal/native/Windows/**
+ jline-native
+ org/jline/nativ/**
diff --git a/apache-maven/src/bin/mvn b/apache-maven/src/bin/mvn
index 47dc7d7f4ed0..02c7ddd75228 100755
--- a/apache-maven/src/bin/mvn
+++ b/apache-maven/src/bin/mvn
@@ -211,6 +211,6 @@ exec "$JAVACMD" \
-classpath "${CLASSWORLDS_JAR}" \
"-Dclassworlds.conf=${MAVEN_HOME}/bin/m2.conf" \
"-Dmaven.home=${MAVEN_HOME}" \
- "-Dlibrary.jansi.path=${MAVEN_HOME}/lib/jansi-native" \
+ "-Dlibrary.jline.path=${MAVEN_HOME}/lib/jline-native" \
"-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \
${CLASSWORLDS_LAUNCHER} ${MAVEN_ARGS} "$@"
diff --git a/apache-maven/src/bin/mvn.cmd b/apache-maven/src/bin/mvn.cmd
index affbe4318216..bf6b152f2f4d 100644
--- a/apache-maven/src/bin/mvn.cmd
+++ b/apache-maven/src/bin/mvn.cmd
@@ -190,7 +190,7 @@ set "INTERNAL_MAVEN_OPTS=--enable-native-access=ALL-UNNAMED %INTERNAL_MAVEN_OPTS
-classpath %CLASSWORLDS_JAR% ^
"-Dclassworlds.conf=%MAVEN_HOME%\bin\m2.conf" ^
"-Dmaven.home=%MAVEN_HOME%" ^
- "-Dlibrary.jansi.path=%MAVEN_HOME%\lib\jansi-native" ^
+ "-Dlibrary.jline.path=%MAVEN_HOME%\lib\jline-native" ^
"-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^
%CLASSWORLDS_LAUNCHER% %MAVEN_ARGS% %MAVEN_CMD_LINE_ARGS%
if ERRORLEVEL 1 goto error
diff --git a/apache-maven/src/lib/jansi-native/README.txt b/apache-maven/src/lib/jansi-native/README.txt
deleted file mode 100644
index 26a957e1b564..000000000000
--- a/apache-maven/src/lib/jansi-native/README.txt
+++ /dev/null
@@ -1,8 +0,0 @@
-This directory contains Jansi native libraries extracted from Jansi JAR.
-
-You can add your own build for platforms not natively supported by Jansi.
-See here [1] on how to compile for your platform and and here [2] how libraries
-follow Jansi's directory and filename conventions.
-
-[1] https://github.com/fusesource/jansi/tree/master/src/main/native
-[2] https://github.com/fusesource/jansi/blob/321a8ff71c731e10f4ea05c607860180276b2215/src/main/java/org/fusesource/jansi/internal/OSInfo.java
diff --git a/apache-maven/src/lib/jline-native/README.txt b/apache-maven/src/lib/jline-native/README.txt
new file mode 100644
index 000000000000..ed74b45f7e13
--- /dev/null
+++ b/apache-maven/src/lib/jline-native/README.txt
@@ -0,0 +1,8 @@
+This directory contains JLine native libraries extracted from JLine JAR.
+
+You can add your own build for platforms not natively supported by JLine.
+See here [1] on how to compile for your platform and here [2] how libraries
+follow JLine's directory and filename conventions.
+
+[1] https://github.com/jline/jline3/tree/master/native
+[2] https://github.com/jline/jline3/blob/master/native/src/main/java/org/jline/nativ/OSInfo.java
diff --git a/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm b/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
index b87dd6ab7b5d..e2b25312a6e5 100644
--- a/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
+++ b/apache-maven/src/main/appended-resources/META-INF/LICENSE.vm
@@ -41,6 +41,8 @@ subject to the terms and conditions of the following licenses:
#* *##set ( $spdx = 'EPL-2.0' )
#* *##elseif ( $license.url.contains( "www.apache.org/licenses/LICENSE-2.0" ) )
#* *##set ( $spdx = 'Apache-2.0' )
+#* *##elseif ( $license.name == "BSD-3-Clause" || $license.url.contains( "opensource.org/licenses/BSD-3-Clause" ) )
+#* *##set ( $spdx = 'BSD-3-Clause' )
#* *##else
#* *### unrecognized license will require analysis to know obligations
#* *##set ( $spdx = 'unrecognized' )
diff --git a/apache-maven/src/main/appended-resources/licenses/BSD-3-Clause.txt b/apache-maven/src/main/appended-resources/licenses/BSD-3-Clause.txt
new file mode 100644
index 000000000000..4b0469c95f9f
--- /dev/null
+++ b/apache-maven/src/main/appended-resources/licenses/BSD-3-Clause.txt
@@ -0,0 +1,28 @@
+Copyright
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+“AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/apache-maven/src/main/assembly/component.xml b/apache-maven/src/main/assembly/component.xml
index 3413c4f0405a..f63ce88a9766 100644
--- a/apache-maven/src/main/assembly/component.xml
+++ b/apache-maven/src/main/assembly/component.xml
@@ -63,10 +63,12 @@ under the License.
- target/dependency/org/fusesource/jansi/internal/native
- lib/jansi-native
+ target/dependency/org/jline/nativ
+ lib/jline-native
- **
+ **/*.so
+ **/*.jnilib
+ **/*.dll
diff --git a/maven-core/pom.xml b/maven-core/pom.xml
index 5f02119eccd8..6867da4a0347 100644
--- a/maven-core/pom.xml
+++ b/maven-core/pom.xml
@@ -86,10 +86,6 @@ under the License.
org.apache.maven.resolver
maven-resolver-util
-
- org.apache.maven.shared
- maven-shared-utils
-
org.eclipse.sisu
org.eclipse.sisu.plexus
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
index c7b8c085e6e9..8636b78f03a3 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/LifecycleExecutionException.java
@@ -18,11 +18,11 @@
*/
package org.apache.maven.lifecycle;
+import org.apache.maven.message.MessageBuilder;
+import org.apache.maven.message.MessageBuilderFactory;
+import org.apache.maven.message.internal.DefaultMessageBuilderFactory;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
/**
* @author Jason van Zyl
@@ -57,16 +57,33 @@ public LifecycleExecutionException(String message, MojoExecution execution, Mave
this.project = project;
}
+ /**
+ * @deprecated Use {@link #LifecycleExecutionException(MessageBuilderFactory, MojoExecution, MavenProject, Throwable)}
+ * instead to allow for better message formatting.
+ */
+ @Deprecated
public LifecycleExecutionException(MojoExecution execution, MavenProject project, Throwable cause) {
- this(createMessage(execution, project, cause), execution, project, cause);
+ this(createMessage(new DefaultMessageBuilderFactory(), execution, project, cause), execution, project, cause);
+ }
+
+ public LifecycleExecutionException(
+ MessageBuilderFactory messageBuilderFactory,
+ MojoExecution execution,
+ MavenProject project,
+ Throwable cause) {
+ this(createMessage(messageBuilderFactory, execution, project, cause), execution, project, cause);
}
public MavenProject getProject() {
return project;
}
- private static String createMessage(MojoExecution execution, MavenProject project, Throwable cause) {
- MessageBuilder buffer = buffer(256);
+ private static String createMessage(
+ MessageBuilderFactory messageBuilderFactory,
+ MojoExecution execution,
+ MavenProject project,
+ Throwable cause) {
+ MessageBuilder buffer = messageBuilderFactory.builder(256);
buffer.a("Failed to execute goal");
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java
index 87f4f88bc938..ca5937f70633 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/DefaultMojoExecutionConfigurator.java
@@ -26,6 +26,8 @@
import java.util.stream.Stream;
import org.apache.maven.lifecycle.MojoExecutionConfigurator;
+import org.apache.maven.message.MessageBuilder;
+import org.apache.maven.message.MessageBuilderFactory;
import org.apache.maven.model.Plugin;
import org.apache.maven.model.PluginExecution;
import org.apache.maven.plugin.MojoExecution;
@@ -33,9 +35,8 @@
import org.apache.maven.plugin.descriptor.Parameter;
import org.apache.maven.plugin.descriptor.PluginDescriptor;
import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-import org.apache.maven.shared.utils.logging.MessageUtils;
import org.codehaus.plexus.component.annotations.Component;
+import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.Xpp3Dom;
import org.slf4j.Logger;
@@ -50,6 +51,9 @@
public class DefaultMojoExecutionConfigurator implements MojoExecutionConfigurator {
private final Logger logger = LoggerFactory.getLogger(getClass());
+ @Requirement
+ private MessageBuilderFactory messageBuilderFactory;
+
@Override
public void configure(MavenProject project, MojoExecution mojoExecution, boolean allowPluginLevelConfig) {
String g = mojoExecution.getPlugin().getGroupId();
@@ -142,7 +146,8 @@ private void checkUnknownMojoConfigurationParameters(MojoExecution mojoExecution
unknownParameters.stream()
.filter(parameterName -> isNotReportPluginsForMavenSite(parameterName, mojoExecution))
.forEach(name -> {
- MessageBuilder messageBuilder = MessageUtils.buffer()
+ MessageBuilder messageBuilder = messageBuilderFactory
+ .builder()
.warning("Parameter '")
.warning(name)
.warning("' is unknown for plugin '")
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java
index e1251c2d2890..6abb43f9796b 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/LifecycleDependencyResolver.java
@@ -38,6 +38,7 @@
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
import org.apache.maven.execution.MavenSession;
import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.message.MessageBuilderFactory;
import org.apache.maven.project.DefaultDependencyResolutionRequest;
import org.apache.maven.project.DependencyResolutionException;
import org.apache.maven.project.DependencyResolutionResult;
@@ -80,6 +81,9 @@ public class LifecycleDependencyResolver {
@Inject
private ProjectArtifactsCache projectArtifactsCache;
+ @Inject
+ private MessageBuilderFactory messageBuilderFactory;
+
public LifecycleDependencyResolver() {}
public LifecycleDependencyResolver(ProjectDependenciesResolver projectDependenciesResolver, Logger logger) {
@@ -243,7 +247,7 @@ private Set getDependencies(
logger.warn("Try running the build up to the lifecycle phase \"package\"");
} else {
- throw new LifecycleExecutionException(null, project, e);
+ throw new LifecycleExecutionException(messageBuilderFactory, null, project, e);
}
}
diff --git a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
index cf40525c79c1..4061820ac652 100644
--- a/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
+++ b/maven-core/src/main/java/org/apache/maven/lifecycle/internal/MojoExecutor.java
@@ -39,6 +39,7 @@
import org.apache.maven.internal.MultilineMessageHelper;
import org.apache.maven.lifecycle.LifecycleExecutionException;
import org.apache.maven.lifecycle.MissingProjectException;
+import org.apache.maven.message.MessageBuilderFactory;
import org.apache.maven.plugin.BuildPluginManager;
import org.apache.maven.plugin.MavenPluginManager;
import org.apache.maven.plugin.MojoExecution;
@@ -88,6 +89,9 @@ public class MojoExecutor {
@Requirement
private ExecutionEventCatapult eventCatapult;
+ @Requirement
+ private MessageBuilderFactory messageBuilderFactory;
+
private final OwnerReentrantReadWriteLock aggregatorLock = new OwnerReentrantReadWriteLock();
@Requirement
@@ -186,7 +190,7 @@ private void execute(
try {
mavenPluginManager.checkPrerequisites(mojoDescriptor.getPluginDescriptor());
} catch (PluginIncompatibleException e) {
- throw new LifecycleExecutionException(mojoExecution, session.getCurrentProject(), e);
+ throw new LifecycleExecutionException(messageBuilderFactory, mojoExecution, session.getCurrentProject(), e);
}
if (mojoDescriptor.isProjectRequired() && !session.getRequest().isProjectPresent()) {
@@ -194,14 +198,15 @@ private void execute(
"Goal requires a project to execute" + " but there is no POM in this directory ("
+ session.getExecutionRootDirectory() + ")."
+ " Please verify you invoked Maven from the correct directory.");
- throw new LifecycleExecutionException(mojoExecution, null, cause);
+ throw new LifecycleExecutionException(messageBuilderFactory, mojoExecution, null, cause);
}
if (mojoDescriptor.isOnlineRequired() && session.isOffline()) {
if (MojoExecution.Source.CLI.equals(mojoExecution.getSource())) {
Throwable cause = new IllegalStateException(
"Goal requires online mode for execution" + " but Maven is currently offline.");
- throw new LifecycleExecutionException(mojoExecution, session.getCurrentProject(), cause);
+ throw new LifecycleExecutionException(
+ messageBuilderFactory, mojoExecution, session.getCurrentProject(), cause);
} else {
eventCatapult.fire(ExecutionEvent.Type.MojoSkipped, session, mojoExecution);
@@ -330,7 +335,8 @@ private void doExecute2(MavenSession session, MojoExecution mojoExecution) throw
| PluginManagerException
| PluginConfigurationException
| MojoExecutionException e) {
- throw new LifecycleExecutionException(mojoExecution, session.getCurrentProject(), e);
+ throw new LifecycleExecutionException(
+ messageBuilderFactory, mojoExecution, session.getCurrentProject(), e);
}
eventCatapult.fire(ExecutionEvent.Type.MojoSucceeded, session, mojoExecution);
diff --git a/maven-core/src/main/java/org/apache/maven/message/MessageBuilder.java b/maven-core/src/main/java/org/apache/maven/message/MessageBuilder.java
new file mode 100644
index 000000000000..ee834aa374e0
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/message/MessageBuilder.java
@@ -0,0 +1,277 @@
+/*
+ * 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.message;
+
+/**
+ * Message builder that supports configurable styling.
+ *
+ * @since 3.10.0
+ * @see MessageBuilderFactory
+ */
+public interface MessageBuilder extends Appendable {
+
+ /**
+ * Append message content in trace style.
+ * By default, bold magenta
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder trace(Object message) {
+ return style("." + Constants.MAVEN_STYLE_TRACE_NAME + ":-" + Constants.MAVEN_STYLE_TRACE_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in debug style.
+ * By default, bold cyan
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder debug(Object message) {
+ return style("." + Constants.MAVEN_STYLE_DEBUG_NAME + ":-" + Constants.MAVEN_STYLE_DEBUG_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in info style.
+ * By default, bold blue
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder info(Object message) {
+ return style("." + Constants.MAVEN_STYLE_INFO_NAME + ":-" + Constants.MAVEN_STYLE_INFO_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in warning style.
+ * By default, bold yellow
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder warning(Object message) {
+ return style("." + Constants.MAVEN_STYLE_WARNING_NAME + ":-" + Constants.MAVEN_STYLE_WARNING_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in error style.
+ * By default, bold red
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder error(Object message) {
+ return style("." + Constants.MAVEN_STYLE_ERROR_NAME + ":-" + Constants.MAVEN_STYLE_ERROR_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in success style.
+ * By default, bold green
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder success(Object message) {
+ return style("." + Constants.MAVEN_STYLE_SUCCESS_NAME + ":-" + Constants.MAVEN_STYLE_SUCCESS_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in failure style.
+ * By default, bold red
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder failure(Object message) {
+ return style("." + Constants.MAVEN_STYLE_FAILURE_NAME + ":-" + Constants.MAVEN_STYLE_FAILURE_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in strong style.
+ * By default, bold
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder strong(Object message) {
+ return style("." + Constants.MAVEN_STYLE_STRONG_NAME + ":-" + Constants.MAVEN_STYLE_STRONG_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in mojo style.
+ * By default, green
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder mojo(Object message) {
+ return style("." + Constants.MAVEN_STYLE_MOJO_NAME + ":-" + Constants.MAVEN_STYLE_MOJO_DEFAULT, message);
+ }
+
+ /**
+ * Append message content in project style.
+ * By default, cyan
+ *
+ * @param message the message to append
+ * @return the current builder
+ */
+ default MessageBuilder project(Object message) {
+ return style("." + Constants.MAVEN_STYLE_PROJECT_NAME + ":-" + Constants.MAVEN_STYLE_PROJECT_DEFAULT, message);
+ }
+
+ default MessageBuilder style(String style, Object message) {
+ return style(style).a(message).resetStyle();
+ }
+
+ MessageBuilder style(String style);
+
+ MessageBuilder resetStyle();
+
+ //
+ // message building methods modelled after Ansi methods
+ //
+
+ @Override
+ MessageBuilder append(CharSequence cs);
+
+ @Override
+ MessageBuilder append(CharSequence cs, int start, int end);
+
+ @Override
+ MessageBuilder append(char c);
+
+ /**
+ * Append content to the message buffer.
+ *
+ * @param value the content to append
+ * @param offset the index of the first {@code char} to append
+ * @param len the number of {@code char}s to append
+ * @return the current builder
+ */
+ default MessageBuilder a(char[] value, int offset, int len) {
+ return append(String.valueOf(value, offset, len));
+ }
+
+ /**
+ * Append content to the message buffer.
+ *
+ * @param value the content to append
+ * @return the current builder
+ */
+ default MessageBuilder a(char[] value) {
+ return append(String.valueOf(value));
+ }
+
+ /**
+ * Append content to the message buffer.
+ *
+ * @param value the content to append
+ * @param start the starting index of the subsequence to be appended
+ * @param end the end index of the subsequence to be appended
+ * @return the current builder
+ */
+ default MessageBuilder a(CharSequence value, int start, int end) {
+ return append(value, start, end);
+ }
+
+ /**
+ * Append content to the message buffer.
+ *
+ * @param value the content to append
+ * @return the current builder
+ */
+ default MessageBuilder a(CharSequence value) {
+ return append(value);
+ }
+
+ /**
+ * Append content to the message buffer.
+ *
+ * @param value the content to append
+ * @return the current builder
+ */
+ default MessageBuilder a(Object value) {
+ return append(String.valueOf(value));
+ }
+
+ /**
+ * Append newline to the message buffer.
+ *
+ * @return the current builder
+ */
+ default MessageBuilder newline() {
+ return append(System.lineSeparator());
+ }
+
+ /**
+ * Append formatted content to the buffer.
+ * @see String#format(String, Object...)
+ *
+ * @param pattern a format string
+ * @param args arguments referenced by the format specifiers in the format string
+ * @return the current builder
+ */
+ default MessageBuilder format(String pattern, Object... args) {
+ return append(String.format(pattern, args));
+ }
+
+ /**
+ * Set the buffer length.
+ *
+ * @param length the new length
+ * @return the current builder
+ */
+ MessageBuilder setLength(int length);
+
+ /**
+ * Return the built message.
+ *
+ * @return the message
+ */
+ String build();
+
+ class Constants {
+ // Style Names
+ public static final String MAVEN_STYLE_TRANSFER_NAME = "transfer";
+ public static final String MAVEN_STYLE_TRACE_NAME = "trace";
+ public static final String MAVEN_STYLE_DEBUG_NAME = "debug";
+ public static final String MAVEN_STYLE_INFO_NAME = "info";
+ public static final String MAVEN_STYLE_WARNING_NAME = "warning";
+ public static final String MAVEN_STYLE_ERROR_NAME = "error";
+ public static final String MAVEN_STYLE_SUCCESS_NAME = "success";
+ public static final String MAVEN_STYLE_FAILURE_NAME = "failure";
+ public static final String MAVEN_STYLE_STRONG_NAME = "strong";
+ public static final String MAVEN_STYLE_MOJO_NAME = "mojo";
+ public static final String MAVEN_STYLE_PROJECT_NAME = "project";
+
+ // Default Values
+ public static final String MAVEN_STYLE_TRANSFER_DEFAULT = "f:bright-black";
+ public static final String MAVEN_STYLE_TRACE_DEFAULT = "bold,f:magenta";
+ public static final String MAVEN_STYLE_DEBUG_DEFAULT = "bold,f:cyan";
+ public static final String MAVEN_STYLE_INFO_DEFAULT = "bold,f:blue";
+ public static final String MAVEN_STYLE_WARNING_DEFAULT = "bold,f:yellow";
+ public static final String MAVEN_STYLE_ERROR_DEFAULT = "bold,f:red";
+ public static final String MAVEN_STYLE_SUCCESS_DEFAULT = "bold,f:green";
+ public static final String MAVEN_STYLE_FAILURE_DEFAULT = "bold,f:red";
+ public static final String MAVEN_STYLE_STRONG_DEFAULT = "bold";
+ public static final String MAVEN_STYLE_MOJO_DEFAULT = "f:green";
+ public static final String MAVEN_STYLE_PROJECT_DEFAULT = "f:cyan";
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/message/MessageBuilderFactory.java b/maven-core/src/main/java/org/apache/maven/message/MessageBuilderFactory.java
new file mode 100644
index 000000000000..642ca7d773de
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/message/MessageBuilderFactory.java
@@ -0,0 +1,51 @@
+/*
+ * 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.message;
+
+/**
+ * A factory for {@link MessageBuilder}.
+ *
+ * @since 3.10.0
+ */
+public interface MessageBuilderFactory {
+ /**
+ * Checks if the underlying output does support styling or not.
+ * @return whether color styling is supported or not
+ */
+ boolean isColorEnabled();
+
+ /**
+ * Returns the terminal width or -1 if not supported.
+ * @return the terminal width
+ */
+ int getTerminalWidth();
+
+ /**
+ * Creates a new message builder.
+ * @return a new message builder
+ */
+ MessageBuilder builder();
+
+ /**
+ * Creates a new message builder of the specified size.
+ * @param size the initial size of the message builder buffer
+ * @return a new message builder
+ */
+ MessageBuilder builder(int size);
+}
diff --git a/maven-core/src/main/java/org/apache/maven/message/internal/DefaultMessageBuilder.java b/maven-core/src/main/java/org/apache/maven/message/internal/DefaultMessageBuilder.java
new file mode 100644
index 000000000000..474244f738dd
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/message/internal/DefaultMessageBuilder.java
@@ -0,0 +1,78 @@
+/*
+ * 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.message.internal;
+
+import org.apache.maven.message.MessageBuilder;
+
+class DefaultMessageBuilder implements MessageBuilder {
+
+ private final StringBuilder buffer;
+
+ DefaultMessageBuilder() {
+ this(new StringBuilder());
+ }
+
+ DefaultMessageBuilder(StringBuilder buffer) {
+ this.buffer = buffer;
+ }
+
+ @Override
+ public MessageBuilder style(String style) {
+ return this;
+ }
+
+ @Override
+ public MessageBuilder resetStyle() {
+ return this;
+ }
+
+ @Override
+ public MessageBuilder append(CharSequence cs) {
+ buffer.append(cs);
+ return this;
+ }
+
+ @Override
+ public MessageBuilder append(CharSequence cs, int start, int end) {
+ buffer.append(cs, start, end);
+ return this;
+ }
+
+ @Override
+ public MessageBuilder append(char c) {
+ buffer.append(c);
+ return this;
+ }
+
+ @Override
+ public MessageBuilder setLength(int length) {
+ buffer.setLength(length);
+ return this;
+ }
+
+ @Override
+ public String build() {
+ return buffer.toString();
+ }
+
+ @Override
+ public String toString() {
+ return build();
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/message/internal/DefaultMessageBuilderFactory.java b/maven-core/src/main/java/org/apache/maven/message/internal/DefaultMessageBuilderFactory.java
new file mode 100644
index 000000000000..a3e1daf9241e
--- /dev/null
+++ b/maven-core/src/main/java/org/apache/maven/message/internal/DefaultMessageBuilderFactory.java
@@ -0,0 +1,52 @@
+/*
+ * 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.message.internal;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import org.apache.maven.message.MessageBuilder;
+import org.apache.maven.message.MessageBuilderFactory;
+import org.eclipse.sisu.Priority;
+
+@Named
+@Singleton
+@Priority(-1)
+public class DefaultMessageBuilderFactory implements MessageBuilderFactory {
+
+ @Override
+ public boolean isColorEnabled() {
+ return false;
+ }
+
+ @Override
+ public int getTerminalWidth() {
+ return -1;
+ }
+
+ @Override
+ public MessageBuilder builder() {
+ return new DefaultMessageBuilder();
+ }
+
+ @Override
+ public MessageBuilder builder(int size) {
+ return new DefaultMessageBuilder(new StringBuilder(size));
+ }
+}
diff --git a/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java b/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java
index 5544a74f34cc..b876969d9a36 100644
--- a/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java
+++ b/maven-core/src/main/java/org/apache/maven/plugin/internal/DeprecatedPluginValidator.java
@@ -23,10 +23,10 @@
import javax.inject.Singleton;
import org.apache.maven.execution.MavenSession;
+import org.apache.maven.message.MessageBuilderFactory;
import org.apache.maven.plugin.PluginValidationManager;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.plugin.descriptor.Parameter;
-import org.apache.maven.shared.utils.logging.MessageUtils;
import org.codehaus.plexus.component.configurator.expression.ExpressionEvaluator;
import org.codehaus.plexus.configuration.PlexusConfiguration;
@@ -39,9 +39,13 @@
@Named
class DeprecatedPluginValidator extends AbstractMavenPluginDescriptorSourcedParametersValidator {
+ private final MessageBuilderFactory messageBuilderFactory;
+
@Inject
- DeprecatedPluginValidator(PluginValidationManager pluginValidationManager) {
+ DeprecatedPluginValidator(
+ PluginValidationManager pluginValidationManager, MessageBuilderFactory messageBuilderFactory) {
super(pluginValidationManager);
+ this.messageBuilderFactory = messageBuilderFactory;
}
@Override
@@ -94,7 +98,8 @@ private void checkParameter(
}
private String logDeprecatedMojo(MojoDescriptor mojoDescriptor) {
- return MessageUtils.buffer()
+ return messageBuilderFactory
+ .builder()
.warning("Goal '")
.warning(mojoDescriptor.getGoal())
.warning("' is deprecated: ")
diff --git a/maven-embedder/pom.xml b/maven-embedder/pom.xml
index 9817dc1043c9..f8b548f9eb7a 100644
--- a/maven-embedder/pom.xml
+++ b/maven-embedder/pom.xml
@@ -69,8 +69,8 @@ under the License.
maven-resolver-util
- org.apache.maven.shared
- maven-shared-utils
+ org.apache.maven
+ maven-jline
com.google.inject
@@ -160,11 +160,6 @@ under the License.
mockito-core
test
-
- org.fusesource.jansi
- jansi
- test
-
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java b/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java
index e220ce783f4b..7bc661fa7402 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/CLIReportingUtils.java
@@ -29,7 +29,7 @@
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
+import static org.apache.maven.jline.MessageUtils.builder;
/**
* Utility class used to report errors, statistics, application version info, etc.
@@ -53,7 +53,7 @@ public static String showVersion() {
final String ls = System.lineSeparator();
Properties properties = getBuildProperties();
StringBuilder version = new StringBuilder(256);
- version.append(buffer().strong(createMavenVersionString(properties))).append(ls);
+ version.append(builder().strong(createMavenVersionString(properties))).append(ls);
version.append(reduce(properties.getProperty("distributionShortName") + " home: "
+ System.getProperty("maven.home", "")))
.append(ls);
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
index 5c62edfa179e..985362b680d5 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/MavenCli.java
@@ -84,14 +84,14 @@
import org.apache.maven.execution.scope.internal.MojoExecutionScopeModule;
import org.apache.maven.extension.internal.CoreExports;
import org.apache.maven.extension.internal.CoreExtensionEntry;
+import org.apache.maven.jline.MessageUtils;
import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.message.MessageBuilder;
import org.apache.maven.model.building.ModelProcessor;
import org.apache.maven.project.MavenProject;
import org.apache.maven.properties.internal.EnvironmentUtils;
import org.apache.maven.properties.internal.SystemProperties;
import org.apache.maven.session.scope.internal.SessionScopeModule;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
-import org.apache.maven.shared.utils.logging.MessageUtils;
import org.apache.maven.toolchain.building.DefaultToolchainsBuildingRequest;
import org.apache.maven.toolchain.building.ToolchainsBuilder;
import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
@@ -123,7 +123,7 @@
import static org.apache.maven.cli.CLIManager.COLOR;
import static org.apache.maven.cli.ResolveFile.resolveFile;
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
+import static org.apache.maven.jline.MessageUtils.builder;
// TODO push all common bits back to plexus cli and prepare for transition to Guice. We don't need 50 ways to make CLIs
@@ -525,6 +525,12 @@ void logging(CliRequest cliRequest) {
} else if (cliRequest.commandLine.hasOption(CLIManager.BATCH_MODE)
|| cliRequest.commandLine.hasOption(CLIManager.LOG_FILE)) {
MessageUtils.setColorEnabled(false);
+ } else {
+ // if the terminal is detected as dumb terminal, disable colors
+ if (MessageUtils.getTerminal() != null
+ && MessageUtils.getTerminal().getType().startsWith("dumb")) {
+ MessageUtils.setColorEnabled(false);
+ }
}
// LOG STREAMS
@@ -569,14 +575,15 @@ private void commands(CliRequest cliRequest) {
if (slf4jLogger.isDebugEnabled()) {
slf4jLogger.debug("Message scheme: {}", (MessageUtils.isColorEnabled() ? "color" : "plain"));
+ slf4jLogger.debug("Message terminal: {}", MessageUtils.getTerminal());
if (MessageUtils.isColorEnabled()) {
- MessageBuilder buff = MessageUtils.buffer();
+ MessageBuilder buff = builder();
buff.a("Message styles: ");
- buff.a(MessageUtils.level().debug("debug")).a(' ');
- buff.a(MessageUtils.level().info("info")).a(' ');
- buff.a(MessageUtils.level().warning("warning")).a(' ');
- buff.a(MessageUtils.level().error("error")).a(' ');
-
+ buff.a(builder().trace("trace")).a(' ');
+ buff.a(builder().debug("debug")).a(' ');
+ buff.a(builder().info("info")).a(' ');
+ buff.a(builder().warning("warning")).a(' ');
+ buff.a(builder().error("error")).a(' ');
buff.success("success").a(' ');
buff.failure("failure").a(' ');
buff.strong("strong").a(' ');
@@ -1014,11 +1021,12 @@ private int execute(CliRequest cliRequest) throws MavenExecutionRequestPopulatio
if (!cliRequest.showErrors) {
slf4jLogger.error(
"To see the full stack trace of the errors, re-run Maven with the {} switch.",
- buffer().strong("-e"));
+ builder().strong("-e"));
}
if (!slf4jLogger.isDebugEnabled()) {
slf4jLogger.error(
- "Re-run Maven using the {} switch to enable full debug logging.", buffer().strong("-X"));
+ "Re-run Maven using the {} switch to enable full debug logging.",
+ builder().strong("-X"));
}
if (!references.isEmpty()) {
@@ -1027,7 +1035,7 @@ private int execute(CliRequest cliRequest) throws MavenExecutionRequestPopulatio
+ ", please read the following articles:");
for (Map.Entry entry : references.entrySet()) {
- slf4jLogger.error("{} {}", buffer().strong(entry.getValue()), entry.getKey());
+ slf4jLogger.error("{} {}", builder().strong(entry.getValue()), entry.getKey());
}
}
@@ -1035,7 +1043,8 @@ private int execute(CliRequest cliRequest) throws MavenExecutionRequestPopulatio
&& !project.equals(result.getTopologicallySortedProjects().get(0))) {
slf4jLogger.error("");
slf4jLogger.error("After correcting the problems, you can resume the build with the command");
- slf4jLogger.error(buffer().a(" ")
+ slf4jLogger.error(builder()
+ .a(" ")
.strong("mvn -rf " + getResumeFrom(result.getTopologicallySortedProjects(), project))
.toString());
}
@@ -1094,9 +1103,9 @@ private void logSummary(
if (StringUtils.isNotEmpty(referenceKey)) {
if (msg.indexOf('\n') < 0) {
- msg += " -> " + buffer().strong(referenceKey);
+ msg += " -> " + builder().strong(referenceKey);
} else {
- msg += "\n-> " + buffer().strong(referenceKey);
+ msg += "\n-> " + builder().strong(referenceKey);
}
}
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/event/ExecutionEventLogger.java b/maven-embedder/src/main/java/org/apache/maven/cli/event/ExecutionEventLogger.java
index f7e2b48633e3..b6f8af98a552 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/event/ExecutionEventLogger.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/event/ExecutionEventLogger.java
@@ -30,17 +30,18 @@
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.MavenExecutionResult;
import org.apache.maven.execution.MavenSession;
+import org.apache.maven.jline.MessageUtils;
+import org.apache.maven.message.MessageBuilder;
import org.apache.maven.plugin.MojoExecution;
import org.apache.maven.plugin.descriptor.MojoDescriptor;
import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageBuilder;
import org.codehaus.plexus.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.maven.cli.CLIReportingUtils.formatDuration;
import static org.apache.maven.cli.CLIReportingUtils.formatTimestamp;
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
+import static org.apache.maven.jline.MessageUtils.builder;
/**
* Logs execution events to logger, eventually user-supplied.
@@ -81,7 +82,7 @@ private void infoLine(char c) {
}
private void infoMain(String msg) {
- logger.info(buffer().strong(msg).toString());
+ logger.info(builder().strong(msg).toString());
}
@Override
@@ -185,9 +186,9 @@ private void logReactorSummary(MavenSession session) {
BuildSummary buildSummary = result.getBuildSummary(project);
if (buildSummary == null) {
- buffer.append(buffer().warning("SKIPPED"));
+ buffer.append(builder().warning("SKIPPED"));
} else if (buildSummary instanceof BuildSuccess) {
- buffer.append(buffer().success("SUCCESS"));
+ buffer.append(builder().success("SUCCESS"));
buffer.append(" [");
String buildTimeDuration = formatDuration(buildSummary.getTime());
int padSize = MAX_PADDED_BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length();
@@ -197,7 +198,7 @@ private void logReactorSummary(MavenSession session) {
buffer.append(buildTimeDuration);
buffer.append(']');
} else if (buildSummary instanceof BuildFailure) {
- buffer.append(buffer().failure("FAILURE"));
+ buffer.append(builder().failure("FAILURE"));
buffer.append(" [");
String buildTimeDuration = formatDuration(buildSummary.getTime());
int padSize = MAX_PADDED_BUILD_TIME_DURATION_LENGTH - buildTimeDuration.length();
@@ -214,7 +215,7 @@ private void logReactorSummary(MavenSession session) {
private void logResult(MavenSession session) {
infoLine('-');
- MessageBuilder buffer = buffer();
+ MessageBuilder buffer = MessageUtils.builder();
if (session.getResult().hasExceptions()) {
buffer.failure("BUILD FAILURE");
@@ -272,7 +273,7 @@ public void projectStarted(ExecutionEvent event) {
+ chars('-', Math.max(0, LINE_LENGTH - headerLen - prefix.length() + preHeader.length()));
logger.info(
- buffer().strong(prefix).project(projectKey).strong(suffix).toString());
+ builder().strong(prefix).project(projectKey).strong(suffix).toString());
// Building Project Name Version [i/n]
String building = "Building " + event.getProject().getName() + " "
@@ -330,7 +331,7 @@ public void mojoStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
logger.info("");
- MessageBuilder buffer = buffer().strong("--- ");
+ MessageBuilder buffer = builder().strong("--- ");
append(buffer, event.getMojoExecution());
append(buffer, event.getProject());
buffer.strong(" ---");
@@ -350,7 +351,7 @@ public void forkStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
logger.info("");
- MessageBuilder buffer = buffer().strong(">>> ");
+ MessageBuilder buffer = builder().strong(">>> ");
append(buffer, event.getMojoExecution());
buffer.strong(" > ");
appendForkInfo(buffer, event.getMojoExecution().getMojoDescriptor());
@@ -372,7 +373,7 @@ public void forkSucceeded(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
logger.info("");
- MessageBuilder buffer = buffer().strong("<<< ");
+ MessageBuilder buffer = builder().strong("<<< ");
append(buffer, event.getMojoExecution());
buffer.strong(" < ");
appendForkInfo(buffer, event.getMojoExecution().getMojoDescriptor());
diff --git a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
index 3f5f2cb1380f..a283adff0524 100644
--- a/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
+++ b/maven-embedder/src/main/java/org/apache/maven/cli/transfer/AbstractMavenTransferListener.java
@@ -23,7 +23,7 @@
import java.text.DecimalFormatSymbols;
import java.util.Locale;
-import org.apache.maven.shared.utils.logging.MessageUtils;
+import org.apache.maven.jline.MessageUtils;
import org.eclipse.aether.transfer.AbstractTransferListener;
import org.eclipse.aether.transfer.TransferCancelledException;
import org.eclipse.aether.transfer.TransferEvent;
@@ -192,6 +192,7 @@ protected AbstractMavenTransferListener(PrintStream out) {
@Override
public void transferInitiated(TransferEvent event) {
+ // TODO use MessageBuilder
String darkOn = MessageUtils.isColorEnabled() ? ANSI_DARK_SET : "";
String darkOff = MessageUtils.isColorEnabled() ? ANSI_DARK_RESET : "";
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
index 5c5e7e72e24e..1a7563917aac 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/MavenCliTest.java
@@ -27,12 +27,13 @@
import org.apache.commons.cli.ParseException;
import org.apache.maven.Maven;
import org.apache.maven.eventspy.internal.EventSpyDispatcher;
-import org.apache.maven.shared.utils.logging.MessageUtils;
+import org.apache.maven.jline.MessageUtils;
import org.apache.maven.toolchain.building.ToolchainsBuildingRequest;
import org.apache.maven.toolchain.building.ToolchainsBuildingResult;
import org.codehaus.plexus.PlexusContainer;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.mockito.InOrder;
@@ -42,7 +43,6 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
-import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock;
@@ -258,58 +258,86 @@ public void testMVNConfigurationFunkyArguments() throws Exception {
assertEquals("-Dpom.xml", request.getCommandLine().getOptionValue(CLIManager.ALTERNATE_POM_FILE));
}
- @Test
- public void testStyleColors() throws Exception {
- assumeTrue(MessageUtils.isColorEnabled(), "ANSI not supported");
- CliRequest request;
+ @Nested
+ class StyleColors {
- MessageUtils.setColorEnabled(true);
- request = new CliRequest(new String[] {"-B"}, null);
- cli.cli(request);
- cli.properties(request);
- cli.logging(request);
- assertFalse(MessageUtils.isColorEnabled());
+ @BeforeEach
+ public void setUp() {
+ MessageUtils.systemInstall();
+ MessageUtils.getTerminalWidth(); // wait for fast terminal initialize
+ }
- MessageUtils.setColorEnabled(true);
- request = new CliRequest(new String[] {"-l", "target/temp/mvn.log"}, null);
- request.workingDirectory = "target/temp";
- cli.cli(request);
- cli.properties(request);
- cli.logging(request);
- assertFalse(MessageUtils.isColorEnabled());
+ @AfterEach
+ public void tearDown() {
+ MessageUtils.systemUninstall();
+ }
- MessageUtils.setColorEnabled(false);
- request = new CliRequest(new String[] {"-Dstyle.color=always"}, null);
- cli.cli(request);
- cli.properties(request);
- cli.logging(request);
- assertTrue(MessageUtils.isColorEnabled());
+ @Test
+ public void testStyleColors() throws Exception {
+ CliRequest request;
- MessageUtils.setColorEnabled(true);
- request = new CliRequest(new String[] {"-Dstyle.color=never"}, null);
- cli.cli(request);
- cli.properties(request);
- cli.logging(request);
- assertFalse(MessageUtils.isColorEnabled());
+ MessageUtils.setColorEnabled(true);
+ request = new CliRequest(new String[] {"-B"}, null);
+ cli.cli(request);
+ cli.properties(request);
+ cli.logging(request);
+ assertFalse(MessageUtils.isColorEnabled());
- MessageUtils.setColorEnabled(false);
- request = new CliRequest(new String[] {"-Dstyle.color=always", "-B", "-l", "target/temp/mvn.log"}, null);
- request.workingDirectory = "target/temp";
- cli.cli(request);
- cli.properties(request);
- cli.logging(request);
- assertTrue(MessageUtils.isColorEnabled());
+ MessageUtils.setColorEnabled(true);
+ request = new CliRequest(new String[] {"-l", "target/temp/mvn.log"}, null);
+ request.workingDirectory = "target/temp";
+ cli.cli(request);
+ cli.properties(request);
+ cli.logging(request);
+ assertFalse(MessageUtils.isColorEnabled());
+
+ MessageUtils.setColorEnabled(false);
+ request = new CliRequest(new String[] {"-Dstyle.color=always"}, null);
+ cli.cli(request);
+ cli.properties(request);
+ cli.logging(request);
+ assertTrue(MessageUtils.isColorEnabled());
+
+ MessageUtils.setColorEnabled(true);
+ request = new CliRequest(new String[] {"-Dstyle.color=never"}, null);
+ cli.cli(request);
+ cli.properties(request);
+ cli.logging(request);
+ assertFalse(MessageUtils.isColorEnabled());
- try {
MessageUtils.setColorEnabled(false);
- request = new CliRequest(new String[] {"-Dstyle.color=maybe", "-B", "-l", "target/temp/mvn.log"}, null);
+ request = new CliRequest(new String[] {"-Dstyle.color=always", "-B", "-l", "target/temp/mvn.log"}, null);
request.workingDirectory = "target/temp";
cli.cli(request);
cli.properties(request);
cli.logging(request);
- fail("maybe is not a valid option");
- } catch (IllegalArgumentException e) {
- // noop
+ assertTrue(MessageUtils.isColorEnabled());
+
+ try {
+ MessageUtils.setColorEnabled(false);
+ request = new CliRequest(new String[] {"-Dstyle.color=maybe", "-B", "-l", "target/temp/mvn.log"}, null);
+ request.workingDirectory = "target/temp";
+ cli.cli(request);
+ cli.properties(request);
+ cli.logging(request);
+ fail("maybe is not a valid option");
+ } catch (IllegalArgumentException e) {
+ // noop
+ }
+ }
+
+ @Test
+ void testDumpTerminal() throws Exception {
+ // test provide own sys out which is not a tty
+ // similar will be with redirected output
+ // check that colors are disabled
+
+ MessageUtils.setColorEnabled(true);
+ CliRequest request = new CliRequest(new String[] {}, null);
+ cli.cli(request);
+ cli.properties(request);
+ cli.logging(request);
+ assertFalse(MessageUtils.isColorEnabled());
}
}
@@ -357,17 +385,20 @@ public void testVersionStringWithoutAnsi() throws Exception {
PrintStream oldOut = System.out;
System.setOut(new PrintStream(systemOut));
+ System.setProperty(MavenCli.MULTIMODULE_PROJECT_DIRECTORY, ".");
+
// when
try {
- cli.cli(cliRequest);
- } catch (MavenCli.ExitException exitException) {
- // expected
+ assertEquals(0, cli.doMain(cliRequest));
} finally {
// restore sysout
System.setOut(oldOut);
+ System.clearProperty(MavenCli.MULTIMODULE_PROJECT_DIRECTORY);
}
String versionOut = new String(systemOut.toByteArray(), StandardCharsets.UTF_8);
+ assertTrue(versionOut.contains("Apache Maven"));
+
// then
assertEquals(MessageUtils.stripAnsiCodes(versionOut), versionOut);
}
diff --git a/maven-embedder/src/test/java/org/apache/maven/cli/event/ExecutionEventLoggerTest.java b/maven-embedder/src/test/java/org/apache/maven/cli/event/ExecutionEventLoggerTest.java
index b68d62b5e374..e48362a90dad 100644
--- a/maven-embedder/src/test/java/org/apache/maven/cli/event/ExecutionEventLoggerTest.java
+++ b/maven-embedder/src/test/java/org/apache/maven/cli/event/ExecutionEventLoggerTest.java
@@ -23,8 +23,8 @@
import org.apache.commons.io.FilenameUtils;
import org.apache.maven.execution.ExecutionEvent;
import org.apache.maven.execution.MavenSession;
+import org.apache.maven.jline.MessageUtils;
import org.apache.maven.project.MavenProject;
-import org.apache.maven.shared.utils.logging.MessageUtils;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
diff --git a/maven-jline/pom.xml b/maven-jline/pom.xml
new file mode 100644
index 000000000000..e7db3548d685
--- /dev/null
+++ b/maven-jline/pom.xml
@@ -0,0 +1,60 @@
+
+
+
+ 4.0.0
+
+
+ org.apache.maven
+ maven
+ 3.10.0-SNAPSHOT
+
+
+ maven-jline
+ Maven 3 JLine integration
+ Provides the JLine integration in Maven
+
+
+
+ org.jline
+ jansi-core
+
+
+ org.jline
+ jline-terminal
+
+
+ org.jline
+ jline-terminal-jni
+
+
+ org.jline
+ jline-terminal-ffm
+ true
+
+
+ javax.inject
+ javax.inject
+
+
+ org.apache.maven
+ maven-core
+
+
+
diff --git a/maven-jline/src/main/java/org/apache/maven/jline/FastTerminal.java b/maven-jline/src/main/java/org/apache/maven/jline/FastTerminal.java
new file mode 100644
index 000000000000..1c4d9b124c7b
--- /dev/null
+++ b/maven-jline/src/main/java/org/apache/maven/jline/FastTerminal.java
@@ -0,0 +1,291 @@
+/*
+ * 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.jline;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.nio.charset.Charset;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletableFuture;
+import java.util.function.Consumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.jline.terminal.Attributes;
+import org.jline.terminal.Cursor;
+import org.jline.terminal.MouseEvent;
+import org.jline.terminal.Size;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.spi.SystemStream;
+import org.jline.terminal.spi.TerminalExt;
+import org.jline.terminal.spi.TerminalProvider;
+import org.jline.utils.ColorPalette;
+import org.jline.utils.InfoCmp;
+import org.jline.utils.NonBlockingReader;
+
+public class FastTerminal implements TerminalExt {
+
+ private final CompletableFuture terminal;
+
+ public FastTerminal(Callable builder, Consumer consumer) {
+ this.terminal = new CompletableFuture<>();
+ new Thread(
+ () -> {
+ try {
+ Terminal term = builder.call();
+ consumer.accept(term);
+ terminal.complete(term);
+ } catch (Exception e) {
+ terminal.completeExceptionally(e);
+ }
+ },
+ "fast-terminal-thread")
+ .start();
+ }
+
+ public TerminalExt getTerminal() {
+ try {
+ return (TerminalExt) terminal.get();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public String getName() {
+ return getTerminal().getName();
+ }
+
+ @Override
+ public SignalHandler handle(Signal signal, SignalHandler signalHandler) {
+ return getTerminal().handle(signal, signalHandler);
+ }
+
+ @Override
+ public void raise(Signal signal) {
+ getTerminal().raise(signal);
+ }
+
+ @Override
+ public NonBlockingReader reader() {
+ return getTerminal().reader();
+ }
+
+ @Override
+ public PrintWriter writer() {
+ return getTerminal().writer();
+ }
+
+ @Override
+ public Charset encoding() {
+ return getTerminal().encoding();
+ }
+
+ @Override
+ public InputStream input() {
+ return getTerminal().input();
+ }
+
+ @Override
+ public OutputStream output() {
+ return getTerminal().output();
+ }
+
+ @Override
+ public boolean canPauseResume() {
+ return getTerminal().canPauseResume();
+ }
+
+ @Override
+ public void pause() {
+ getTerminal().pause();
+ }
+
+ @Override
+ public void pause(boolean b) throws InterruptedException {
+ getTerminal().pause(b);
+ }
+
+ @Override
+ public void resume() {
+ getTerminal().resume();
+ }
+
+ @Override
+ public boolean paused() {
+ return getTerminal().paused();
+ }
+
+ @Override
+ public Attributes enterRawMode() {
+ return getTerminal().enterRawMode();
+ }
+
+ @Override
+ public boolean echo() {
+ return getTerminal().echo();
+ }
+
+ @Override
+ public boolean echo(boolean b) {
+ return getTerminal().echo(b);
+ }
+
+ @Override
+ public Attributes getAttributes() {
+ return getTerminal().getAttributes();
+ }
+
+ @Override
+ public void setAttributes(Attributes attributes) {
+ getTerminal().setAttributes(attributes);
+ }
+
+ @Override
+ public Size getSize() {
+ return getTerminal().getSize();
+ }
+
+ @Override
+ public void setSize(Size size) {
+ getTerminal().setSize(size);
+ }
+
+ @Override
+ public int getWidth() {
+ return getTerminal().getWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return getTerminal().getHeight();
+ }
+
+ @Override
+ public Size getBufferSize() {
+ return getTerminal().getBufferSize();
+ }
+
+ @Override
+ public void flush() {
+ getTerminal().flush();
+ }
+
+ @Override
+ public String getType() {
+ return getTerminal().getType();
+ }
+
+ @Override
+ public boolean puts(InfoCmp.Capability capability, Object... objects) {
+ return getTerminal().puts(capability, objects);
+ }
+
+ @Override
+ public boolean getBooleanCapability(InfoCmp.Capability capability) {
+ return getTerminal().getBooleanCapability(capability);
+ }
+
+ @Override
+ public Integer getNumericCapability(InfoCmp.Capability capability) {
+ return getTerminal().getNumericCapability(capability);
+ }
+
+ @Override
+ public String getStringCapability(InfoCmp.Capability capability) {
+ return getTerminal().getStringCapability(capability);
+ }
+
+ @Override
+ public Cursor getCursorPosition(IntConsumer intConsumer) {
+ return getTerminal().getCursorPosition(intConsumer);
+ }
+
+ @Override
+ public boolean hasMouseSupport() {
+ return getTerminal().hasMouseSupport();
+ }
+
+ @Override
+ public MouseTracking getCurrentMouseTracking() {
+ return getTerminal().getCurrentMouseTracking();
+ }
+
+ @Override
+ public boolean trackMouse(MouseTracking mouseTracking) {
+ return getTerminal().trackMouse(mouseTracking);
+ }
+
+ @Override
+ public MouseEvent readMouseEvent() {
+ return getTerminal().readMouseEvent();
+ }
+
+ @Override
+ public MouseEvent readMouseEvent(IntSupplier intSupplier) {
+ return getTerminal().readMouseEvent(intSupplier);
+ }
+
+ @Override
+ public MouseEvent readMouseEvent(String prefix) {
+ return getTerminal().readMouseEvent(prefix);
+ }
+
+ @Override
+ public MouseEvent readMouseEvent(IntSupplier reader, String prefix) {
+ return getTerminal().readMouseEvent(reader, prefix);
+ }
+
+ @Override
+ public boolean hasFocusSupport() {
+ return getTerminal().hasFocusSupport();
+ }
+
+ @Override
+ public boolean trackFocus(boolean b) {
+ return getTerminal().trackFocus(b);
+ }
+
+ @Override
+ public ColorPalette getPalette() {
+ return getTerminal().getPalette();
+ }
+
+ @Override
+ public void close() throws IOException {
+ getTerminal().close();
+ }
+
+ @Override
+ public TerminalProvider getProvider() {
+ return getTerminal().getProvider();
+ }
+
+ @Override
+ public SystemStream getSystemStream() {
+ return getTerminal().getSystemStream();
+ }
+
+ @Override
+ public String toString() {
+ return getTerminal().toString();
+ }
+}
diff --git a/maven-jline/src/main/java/org/apache/maven/jline/JLineMessageBuilderFactory.java b/maven-jline/src/main/java/org/apache/maven/jline/JLineMessageBuilderFactory.java
new file mode 100644
index 000000000000..ff17bd59da0d
--- /dev/null
+++ b/maven-jline/src/main/java/org/apache/maven/jline/JLineMessageBuilderFactory.java
@@ -0,0 +1,156 @@
+/*
+ * 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.jline;
+
+import javax.inject.Named;
+import javax.inject.Singleton;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.maven.message.MessageBuilder;
+import org.apache.maven.message.MessageBuilderFactory;
+import org.eclipse.sisu.Priority;
+import org.jline.utils.AttributedStringBuilder;
+import org.jline.utils.AttributedStyle;
+import org.jline.utils.StyleResolver;
+
+@Named
+@Singleton
+@Priority(10)
+public class JLineMessageBuilderFactory implements MessageBuilderFactory {
+ private final StyleResolver resolver;
+
+ public JLineMessageBuilderFactory() {
+ this.resolver = new MavenStyleResolver();
+ }
+
+ @Override
+ public boolean isColorEnabled() {
+ return MessageUtils.isColorEnabled();
+ }
+
+ @Override
+ public int getTerminalWidth() {
+ return MessageUtils.getTerminalWidth();
+ }
+
+ @Override
+ public MessageBuilder builder() {
+ return builder(64);
+ }
+
+ @Override
+ public MessageBuilder builder(int size) {
+ return new JlineMessageBuilder(resolver, size);
+ }
+
+ private static class JlineMessageBuilder implements MessageBuilder {
+ private final StyleResolver styleResolver;
+ private final AttributedStringBuilder builder;
+
+ private JlineMessageBuilder(StyleResolver styleResolver, int size) {
+ this.styleResolver = styleResolver;
+ this.builder = new AttributedStringBuilder(size);
+ }
+
+ @Override
+ public MessageBuilder style(String style) {
+ if (MessageUtils.isColorEnabled()) {
+ builder.style(styleResolver.resolve(style));
+ }
+ return this;
+ }
+
+ @Override
+ public MessageBuilder resetStyle() {
+ builder.style(AttributedStyle.DEFAULT);
+ return this;
+ }
+
+ @Override
+ public MessageBuilder append(CharSequence cs) {
+ builder.append(cs);
+ return this;
+ }
+
+ @Override
+ public MessageBuilder append(CharSequence cs, int start, int end) {
+ builder.append(cs, start, end);
+ return this;
+ }
+
+ @Override
+ public MessageBuilder append(char c) {
+ builder.append(c);
+ return this;
+ }
+
+ @Override
+ public MessageBuilder setLength(int length) {
+ builder.setLength(length);
+ return this;
+ }
+
+ @Override
+ public String build() {
+ return builder.toAnsi(MessageUtils.terminal);
+ }
+
+ @Override
+ public String toString() {
+ return build();
+ }
+ }
+
+ private static class MavenStyleResolver extends StyleResolver {
+ private final Map styles = new ConcurrentHashMap<>();
+
+ private MavenStyleResolver() {
+ super(key -> {
+ String v = System.getProperty("maven.style." + key);
+ if (v == null) {
+ v = System.getProperty("style." + key);
+ }
+ return v;
+ });
+ }
+
+ @Override
+ public AttributedStyle resolve(String spec) {
+ return styles.computeIfAbsent(spec, this::doResolve);
+ }
+
+ @Override
+ public AttributedStyle resolve(String spec, String defaultSpec) {
+ return resolve(defaultSpec != null ? spec + ":-" + defaultSpec : spec);
+ }
+
+ private AttributedStyle doResolve(String spec) {
+ String def = null;
+ int i = spec.indexOf(":-");
+ if (i != -1) {
+ String[] parts = spec.split(":-");
+ spec = parts[0].trim();
+ def = parts[1].trim();
+ }
+ return super.resolve(spec, def);
+ }
+ }
+}
diff --git a/maven-jline/src/main/java/org/apache/maven/jline/MessageUtils.java b/maven-jline/src/main/java/org/apache/maven/jline/MessageUtils.java
new file mode 100644
index 000000000000..94b3f10baa12
--- /dev/null
+++ b/maven-jline/src/main/java/org/apache/maven/jline/MessageUtils.java
@@ -0,0 +1,130 @@
+/*
+ * 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.jline;
+
+import java.util.function.Consumer;
+
+import org.apache.maven.message.MessageBuilder;
+import org.apache.maven.message.MessageBuilderFactory;
+import org.jline.jansi.AnsiConsole;
+import org.jline.terminal.Terminal;
+import org.jline.terminal.TerminalBuilder;
+
+public class MessageUtils {
+
+ static Terminal terminal;
+ static MessageBuilderFactory messageBuilderFactory = new JLineMessageBuilderFactory();
+ static boolean colorEnabled = true;
+ static Thread shutdownHook;
+ static final Object STARTUP_SHUTDOWN_MONITOR = new Object();
+
+ public static void systemInstall(Terminal terminal) {
+ MessageUtils.terminal = terminal;
+ }
+
+ public static void systemInstall() {
+ systemInstall(null, null);
+ }
+
+ public static void systemInstall(Consumer builderConsumer, Consumer terminalConsumer) {
+ MessageUtils.terminal = new FastTerminal(
+ () -> {
+ TerminalBuilder builder = TerminalBuilder.builder()
+ .name("Maven")
+ .dumb(true)
+ .systemOutput(TerminalBuilder.SystemOutput.SysOut)
+ .color(true);
+ if (builderConsumer != null) {
+ builderConsumer.accept(builder);
+ }
+ return builder.build();
+ },
+ terminal -> {
+ AnsiConsole.setTerminal(terminal);
+ AnsiConsole.systemInstall();
+ if (terminalConsumer != null) {
+ terminalConsumer.accept(terminal);
+ }
+ });
+ }
+
+ public static void registerShutdownHook() {
+ if (shutdownHook == null) {
+ shutdownHook = new Thread(() -> {
+ synchronized (MessageUtils.STARTUP_SHUTDOWN_MONITOR) {
+ MessageUtils.doSystemUninstall();
+ }
+ });
+ Runtime.getRuntime().addShutdownHook(shutdownHook);
+ }
+ }
+
+ public static void systemUninstall() {
+ doSystemUninstall();
+ if (shutdownHook != null) {
+ try {
+ Runtime.getRuntime().removeShutdownHook(shutdownHook);
+ } catch (IllegalStateException var3) {
+ // ignore
+ }
+ }
+ }
+
+ private static void doSystemUninstall() {
+ try {
+ if (terminal instanceof FastTerminal) {
+ // wait for the asynchronous systemInstall call before we uninstall to ensure a consistent state
+ ((FastTerminal) terminal).getTerminal();
+ }
+ AnsiConsole.systemUninstall();
+ } finally {
+ terminal = null;
+ }
+ }
+
+ public static void setColorEnabled(boolean enabled) {
+ colorEnabled = enabled;
+ }
+
+ public static boolean isColorEnabled() {
+ return colorEnabled && terminal != null;
+ }
+
+ public static int getTerminalWidth() {
+ return terminal != null ? terminal.getWidth() : -1;
+ }
+
+ public static MessageBuilder builder() {
+ return messageBuilderFactory.builder();
+ }
+
+ public static Terminal getTerminal() {
+ return terminal;
+ }
+
+ /**
+ * Remove any ANSI code from a message (colors or other escape sequences).
+ *
+ * @param msg message eventually containing ANSI codes
+ * @return the message with ANSI codes removed
+ */
+ public static String stripAnsiCodes(String msg) {
+ return msg.replaceAll("\u001B\\[[;\\d]*[ -/]*[@-~]", "");
+ }
+}
diff --git a/maven-jline/src/main/java/org/fusesource/jansi/Ansi.java b/maven-jline/src/main/java/org/fusesource/jansi/Ansi.java
new file mode 100644
index 000000000000..f861da0098b0
--- /dev/null
+++ b/maven-jline/src/main/java/org/fusesource/jansi/Ansi.java
@@ -0,0 +1,957 @@
+/*
+ * 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.fusesource.jansi;
+
+import java.util.ArrayList;
+
+/**
+ * Provides a fluent API for generating
+ * ANSI escape sequences.
+ *
+ * This class comes from Jansi and is provided for backward compatibility
+ * 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 {
+
+ private static final char FIRST_ESC_CHAR = 27;
+ private static final char SECOND_ESC_CHAR = '[';
+
+ /**
+ * ANSI 8 colors for fluent API
+ */
+ public enum Color {
+ BLACK(0, "BLACK"),
+ RED(1, "RED"),
+ GREEN(2, "GREEN"),
+ YELLOW(3, "YELLOW"),
+ BLUE(4, "BLUE"),
+ MAGENTA(5, "MAGENTA"),
+ CYAN(6, "CYAN"),
+ WHITE(7, "WHITE"),
+ DEFAULT(9, "DEFAULT");
+
+ private final int value;
+ private final String name;
+
+ Color(int index, String name) {
+ this.value = index;
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public int value() {
+ return value;
+ }
+
+ public int fg() {
+ return value + 30;
+ }
+
+ public int bg() {
+ return value + 40;
+ }
+
+ public int fgBright() {
+ return value + 90;
+ }
+
+ public int bgBright() {
+ return value + 100;
+ }
+ }
+
+ /**
+ * Display attributes, also known as
+ * SGR
+ * (Select Graphic Rendition) parameters.
+ */
+ public enum Attribute {
+ RESET(0, "RESET"),
+ INTENSITY_BOLD(1, "INTENSITY_BOLD"),
+ INTENSITY_FAINT(2, "INTENSITY_FAINT"),
+ ITALIC(3, "ITALIC_ON"),
+ UNDERLINE(4, "UNDERLINE_ON"),
+ BLINK_SLOW(5, "BLINK_SLOW"),
+ BLINK_FAST(6, "BLINK_FAST"),
+ NEGATIVE_ON(7, "NEGATIVE_ON"),
+ CONCEAL_ON(8, "CONCEAL_ON"),
+ STRIKETHROUGH_ON(9, "STRIKETHROUGH_ON"),
+ UNDERLINE_DOUBLE(21, "UNDERLINE_DOUBLE"),
+ INTENSITY_BOLD_OFF(22, "INTENSITY_BOLD_OFF"),
+ ITALIC_OFF(23, "ITALIC_OFF"),
+ UNDERLINE_OFF(24, "UNDERLINE_OFF"),
+ BLINK_OFF(25, "BLINK_OFF"),
+ NEGATIVE_OFF(27, "NEGATIVE_OFF"),
+ CONCEAL_OFF(28, "CONCEAL_OFF"),
+ STRIKETHROUGH_OFF(29, "STRIKETHROUGH_OFF");
+
+ private final int value;
+ private final String name;
+
+ Attribute(int index, String name) {
+ this.value = index;
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public int value() {
+ return value;
+ }
+ }
+
+ /**
+ * ED (Erase in Display) / EL (Erase in Line) parameter (see
+ * CSI sequence J and K)
+ * @see Ansi#eraseScreen(Erase)
+ * @see Ansi#eraseLine(Erase)
+ */
+ public enum Erase {
+ FORWARD(0, "FORWARD"),
+ BACKWARD(1, "BACKWARD"),
+ ALL(2, "ALL");
+
+ private final int value;
+ private final String name;
+
+ Erase(int index, String name) {
+ this.value = index;
+ this.name = name;
+ }
+
+ @Override
+ public String toString() {
+ return name;
+ }
+
+ public int value() {
+ return value;
+ }
+ }
+
+ @FunctionalInterface
+ public interface Consumer {
+ void apply(Ansi ansi);
+ }
+
+ public static boolean isEnabled() {
+ return org.apache.maven.jline.MessageUtils.isColorEnabled() && org.jline.jansi.Ansi.isEnabled();
+ }
+
+ public static void setEnabled(final boolean flag) {
+ org.jline.jansi.Ansi.setEnabled(flag);
+ }
+
+ public static Ansi ansi() {
+ if (isEnabled()) {
+ return new Ansi();
+ } else {
+ return new NoAnsi();
+ }
+ }
+
+ public static Ansi ansi(StringBuilder builder) {
+ if (isEnabled()) {
+ return new Ansi(builder);
+ } else {
+ return new NoAnsi(builder);
+ }
+ }
+
+ public static Ansi ansi(int size) {
+ if (isEnabled()) {
+ return new Ansi(size);
+ } else {
+ return new NoAnsi(size);
+ }
+ }
+
+ private static class NoAnsi extends Ansi {
+ NoAnsi() {
+ super();
+ }
+
+ NoAnsi(int size) {
+ super(size);
+ }
+
+ NoAnsi(StringBuilder builder) {
+ super(builder);
+ }
+
+ @Override
+ public Ansi fg(Color color) {
+ return this;
+ }
+
+ @Override
+ public Ansi bg(Color color) {
+ return this;
+ }
+
+ @Override
+ public Ansi fgBright(Color color) {
+ return this;
+ }
+
+ @Override
+ public Ansi bgBright(Color color) {
+ return this;
+ }
+
+ @Override
+ public Ansi fg(int color) {
+ return this;
+ }
+
+ @Override
+ public Ansi fgRgb(int r, int g, int b) {
+ return this;
+ }
+
+ @Override
+ public Ansi bg(int color) {
+ return this;
+ }
+
+ @Override
+ public Ansi bgRgb(int r, int g, int b) {
+ return this;
+ }
+
+ @Override
+ public Ansi a(Attribute attribute) {
+ return this;
+ }
+
+ @Override
+ public Ansi cursor(int row, int column) {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorToColumn(int x) {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorUp(int y) {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorRight(int x) {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorDown(int y) {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorLeft(int x) {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorDownLine() {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorDownLine(final int n) {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorUpLine() {
+ return this;
+ }
+
+ @Override
+ public Ansi cursorUpLine(final int n) {
+ return this;
+ }
+
+ @Override
+ public Ansi eraseScreen() {
+ return this;
+ }
+
+ @Override
+ public Ansi eraseScreen(Erase kind) {
+ return this;
+ }
+
+ @Override
+ public Ansi eraseLine() {
+ return this;
+ }
+
+ @Override
+ public Ansi eraseLine(Erase kind) {
+ return this;
+ }
+
+ @Override
+ public Ansi scrollUp(int rows) {
+ return this;
+ }
+
+ @Override
+ public Ansi scrollDown(int rows) {
+ return this;
+ }
+
+ @Override
+ public Ansi saveCursorPosition() {
+ return this;
+ }
+
+ @Override
+ @Deprecated
+ public Ansi restorCursorPosition() {
+ return this;
+ }
+
+ @Override
+ public Ansi restoreCursorPosition() {
+ return this;
+ }
+
+ @Override
+ public Ansi reset() {
+ return this;
+ }
+ }
+
+ private final StringBuilder builder;
+ private final ArrayList attributeOptions = new ArrayList<>(5);
+
+ public Ansi() {
+ this(new StringBuilder(80));
+ }
+
+ public Ansi(Ansi parent) {
+ this(new StringBuilder(parent.builder));
+ attributeOptions.addAll(parent.attributeOptions);
+ }
+
+ public Ansi(int size) {
+ this(new StringBuilder(size));
+ }
+
+ public Ansi(StringBuilder builder) {
+ this.builder = builder;
+ }
+
+ public Ansi fg(Color color) {
+ attributeOptions.add(color.fg());
+ return this;
+ }
+
+ public Ansi fg(int color) {
+ attributeOptions.add(38);
+ attributeOptions.add(5);
+ attributeOptions.add(color & 0xff);
+ return this;
+ }
+
+ public Ansi fgRgb(int color) {
+ return fgRgb(color >> 16, color >> 8, color);
+ }
+
+ public Ansi fgRgb(int r, int g, int b) {
+ attributeOptions.add(38);
+ attributeOptions.add(2);
+ attributeOptions.add(r & 0xff);
+ attributeOptions.add(g & 0xff);
+ attributeOptions.add(b & 0xff);
+ return this;
+ }
+
+ public Ansi fgBlack() {
+ return this.fg(Color.BLACK);
+ }
+
+ public Ansi fgBlue() {
+ return this.fg(Color.BLUE);
+ }
+
+ public Ansi fgCyan() {
+ return this.fg(Color.CYAN);
+ }
+
+ public Ansi fgDefault() {
+ return this.fg(Color.DEFAULT);
+ }
+
+ public Ansi fgGreen() {
+ return this.fg(Color.GREEN);
+ }
+
+ public Ansi fgMagenta() {
+ return this.fg(Color.MAGENTA);
+ }
+
+ public Ansi fgRed() {
+ return this.fg(Color.RED);
+ }
+
+ public Ansi fgYellow() {
+ return this.fg(Color.YELLOW);
+ }
+
+ public Ansi bg(Color color) {
+ attributeOptions.add(color.bg());
+ return this;
+ }
+
+ public Ansi bg(int color) {
+ attributeOptions.add(48);
+ attributeOptions.add(5);
+ attributeOptions.add(color & 0xff);
+ return this;
+ }
+
+ public Ansi bgRgb(int color) {
+ return bgRgb(color >> 16, color >> 8, color);
+ }
+
+ public Ansi bgRgb(int r, int g, int b) {
+ attributeOptions.add(48);
+ attributeOptions.add(2);
+ attributeOptions.add(r & 0xff);
+ attributeOptions.add(g & 0xff);
+ attributeOptions.add(b & 0xff);
+ return this;
+ }
+
+ public Ansi bgCyan() {
+ return this.bg(Color.CYAN);
+ }
+
+ public Ansi bgDefault() {
+ return this.bg(Color.DEFAULT);
+ }
+
+ public Ansi bgGreen() {
+ return this.bg(Color.GREEN);
+ }
+
+ public Ansi bgMagenta() {
+ return this.bg(Color.MAGENTA);
+ }
+
+ public Ansi bgRed() {
+ return this.bg(Color.RED);
+ }
+
+ public Ansi bgYellow() {
+ return this.bg(Color.YELLOW);
+ }
+
+ public Ansi fgBright(Color color) {
+ attributeOptions.add(color.fgBright());
+ return this;
+ }
+
+ public Ansi fgBrightBlack() {
+ return this.fgBright(Color.BLACK);
+ }
+
+ public Ansi fgBrightBlue() {
+ return this.fgBright(Color.BLUE);
+ }
+
+ public Ansi fgBrightCyan() {
+ return this.fgBright(Color.CYAN);
+ }
+
+ public Ansi fgBrightDefault() {
+ return this.fgBright(Color.DEFAULT);
+ }
+
+ public Ansi fgBrightGreen() {
+ return this.fgBright(Color.GREEN);
+ }
+
+ public Ansi fgBrightMagenta() {
+ return this.fgBright(Color.MAGENTA);
+ }
+
+ public Ansi fgBrightRed() {
+ return this.fgBright(Color.RED);
+ }
+
+ public Ansi fgBrightYellow() {
+ return this.fgBright(Color.YELLOW);
+ }
+
+ public Ansi bgBright(Color color) {
+ attributeOptions.add(color.bgBright());
+ return this;
+ }
+
+ public Ansi bgBrightCyan() {
+ return this.bgBright(Color.CYAN);
+ }
+
+ public Ansi bgBrightDefault() {
+ return this.bgBright(Color.DEFAULT);
+ }
+
+ public Ansi bgBrightGreen() {
+ return this.bgBright(Color.GREEN);
+ }
+
+ public Ansi bgBrightMagenta() {
+ return this.bgBright(Color.MAGENTA);
+ }
+
+ public Ansi bgBrightRed() {
+ return this.bgBright(Color.RED);
+ }
+
+ public Ansi bgBrightYellow() {
+ return this.bgBright(Color.YELLOW);
+ }
+
+ public Ansi a(Attribute attribute) {
+ attributeOptions.add(attribute.value());
+ return this;
+ }
+
+ /**
+ * Moves the cursor to row n, column m. The values are 1-based.
+ * Any values less than 1 are mapped to 1.
+ *
+ * @param row row (1-based) from top
+ * @param column column (1 based) from left
+ * @return this Ansi instance
+ */
+ public Ansi cursor(final int row, final int column) {
+ return appendEscapeSequence('H', Math.max(1, row), Math.max(1, column));
+ }
+
+ /**
+ * Moves the cursor to column n. The parameter n is 1-based.
+ * If n is less than 1 it is moved to the first column.
+ *
+ * @param x the index (1-based) of the column to move to
+ * @return this Ansi instance
+ */
+ public Ansi cursorToColumn(final int x) {
+ return appendEscapeSequence('G', Math.max(1, x));
+ }
+
+ /**
+ * Moves the cursor up. If the parameter y is negative it moves the cursor down.
+ *
+ * @param y the number of lines to move up
+ * @return this Ansi instance
+ */
+ public Ansi cursorUp(final int y) {
+ return y > 0 ? appendEscapeSequence('A', y) : y < 0 ? cursorDown(-y) : this;
+ }
+
+ /**
+ * Moves the cursor down. If the parameter y is negative it moves the cursor up.
+ *
+ * @param y the number of lines to move down
+ * @return this Ansi instance
+ */
+ public Ansi cursorDown(final int y) {
+ return y > 0 ? appendEscapeSequence('B', y) : y < 0 ? cursorUp(-y) : this;
+ }
+
+ /**
+ * Moves the cursor right. If the parameter x is negative it moves the cursor left.
+ *
+ * @param x the number of characters to move right
+ * @return this Ansi instance
+ */
+ public Ansi cursorRight(final int x) {
+ return x > 0 ? appendEscapeSequence('C', x) : x < 0 ? cursorLeft(-x) : this;
+ }
+
+ /**
+ * Moves the cursor left. If the parameter x is negative it moves the cursor right.
+ *
+ * @param x the number of characters to move left
+ * @return this Ansi instance
+ */
+ public Ansi cursorLeft(final int x) {
+ return x > 0 ? appendEscapeSequence('D', x) : x < 0 ? cursorRight(-x) : this;
+ }
+
+ /**
+ * Moves the cursor relative to the current position. The cursor is moved right if x is
+ * positive, left if negative and down if y is positive and up if negative.
+ *
+ * @param x the number of characters to move horizontally
+ * @param y the number of lines to move vertically
+ * @return this Ansi instance
+ * @since 2.2
+ */
+ public Ansi cursorMove(final int x, final int y) {
+ return cursorRight(x).cursorDown(y);
+ }
+
+ /**
+ * Moves the cursor to the beginning of the line below.
+ *
+ * @return this Ansi instance
+ */
+ public Ansi cursorDownLine() {
+ return appendEscapeSequence('E');
+ }
+
+ /**
+ * Moves the cursor to the beginning of the n-th line below. If the parameter n is negative it
+ * moves the cursor to the beginning of the n-th line above.
+ *
+ * @param n the number of lines to move the cursor
+ * @return this Ansi instance
+ */
+ public Ansi cursorDownLine(final int n) {
+ return n < 0 ? cursorUpLine(-n) : appendEscapeSequence('E', n);
+ }
+
+ /**
+ * Moves the cursor to the beginning of the line above.
+ *
+ * @return this Ansi instance
+ */
+ public Ansi cursorUpLine() {
+ return appendEscapeSequence('F');
+ }
+
+ /**
+ * Moves the cursor to the beginning of the n-th line above. If the parameter n is negative it
+ * moves the cursor to the beginning of the n-th line below.
+ *
+ * @param n the number of lines to move the cursor
+ * @return this Ansi instance
+ */
+ public Ansi cursorUpLine(final int n) {
+ return n < 0 ? cursorDownLine(-n) : appendEscapeSequence('F', n);
+ }
+
+ public Ansi eraseScreen() {
+ return appendEscapeSequence('J', Erase.ALL.value());
+ }
+
+ public Ansi eraseScreen(final Erase kind) {
+ return appendEscapeSequence('J', kind.value());
+ }
+
+ public Ansi eraseLine() {
+ return appendEscapeSequence('K');
+ }
+
+ public Ansi eraseLine(final Erase kind) {
+ return appendEscapeSequence('K', kind.value());
+ }
+
+ public Ansi scrollUp(final int rows) {
+ if (rows == Integer.MIN_VALUE) {
+ return scrollDown(Integer.MAX_VALUE);
+ }
+ return rows > 0 ? appendEscapeSequence('S', rows) : rows < 0 ? scrollDown(-rows) : this;
+ }
+
+ public Ansi scrollDown(final int rows) {
+ if (rows == Integer.MIN_VALUE) {
+ return scrollUp(Integer.MAX_VALUE);
+ }
+ return rows > 0 ? appendEscapeSequence('T', rows) : rows < 0 ? scrollUp(-rows) : this;
+ }
+
+ @Deprecated
+ public Ansi restorCursorPosition() {
+ return restoreCursorPosition();
+ }
+
+ public Ansi saveCursorPosition() {
+ saveCursorPositionSCO();
+ return saveCursorPositionDEC();
+ }
+
+ // SCO command
+ public Ansi saveCursorPositionSCO() {
+ return appendEscapeSequence('s');
+ }
+
+ // DEC command
+ public Ansi saveCursorPositionDEC() {
+ builder.append(FIRST_ESC_CHAR);
+ builder.append('7');
+ return this;
+ }
+
+ public Ansi restoreCursorPosition() {
+ restoreCursorPositionSCO();
+ return restoreCursorPositionDEC();
+ }
+
+ // SCO command
+ public Ansi restoreCursorPositionSCO() {
+ return appendEscapeSequence('u');
+ }
+
+ // DEC command
+ public Ansi restoreCursorPositionDEC() {
+ builder.append(FIRST_ESC_CHAR);
+ builder.append('8');
+ return this;
+ }
+
+ public Ansi reset() {
+ return a(Attribute.RESET);
+ }
+
+ public Ansi bold() {
+ return a(Attribute.INTENSITY_BOLD);
+ }
+
+ public Ansi boldOff() {
+ return a(Attribute.INTENSITY_BOLD_OFF);
+ }
+
+ public Ansi a(String value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(boolean value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(char value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(char[] value, int offset, int len) {
+ flushAttributes();
+ builder.append(value, offset, len);
+ return this;
+ }
+
+ public Ansi a(char[] value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(CharSequence value, int start, int end) {
+ flushAttributes();
+ builder.append(value, start, end);
+ return this;
+ }
+
+ public Ansi a(CharSequence value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(double value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(float value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(int value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(long value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(Object value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi a(StringBuffer value) {
+ flushAttributes();
+ builder.append(value);
+ return this;
+ }
+
+ public Ansi newline() {
+ flushAttributes();
+ builder.append(System.lineSeparator());
+ return this;
+ }
+
+ public Ansi format(String pattern, Object... args) {
+ flushAttributes();
+ builder.append(String.format(pattern, args));
+ return this;
+ }
+
+ /**
+ * Applies another function to this Ansi instance.
+ *
+ * @param fun the function to apply
+ * @return this Ansi instance
+ * @since 2.2
+ */
+ public Ansi apply(Consumer fun) {
+ fun.apply(this);
+ return this;
+ }
+
+ /**
+ * Uses the {@link org.jline.jansi.AnsiRenderer}
+ * to generate the ANSI escape sequences for the supplied text.
+ *
+ * @param text text
+ * @return this
+ * @since 2.2
+ */
+ public Ansi render(final String text) {
+ a(new org.jline.jansi.Ansi().render(text).toString());
+ return this;
+ }
+
+ /**
+ * String formats and renders the supplied arguments. Uses the {@link org.jline.jansi.AnsiRenderer}
+ * to generate the ANSI escape sequences.
+ *
+ * @param text format
+ * @param args arguments
+ * @return this
+ * @since 2.2
+ */
+ public Ansi render(final String text, Object... args) {
+ a(String.format(new org.jline.jansi.Ansi().render(text).toString(), args));
+ return this;
+ }
+
+ @Override
+ public String toString() {
+ flushAttributes();
+ return builder.toString();
+ }
+
+ ///////////////////////////////////////////////////////////////////
+ // Private Helper Methods
+ ///////////////////////////////////////////////////////////////////
+
+ private Ansi appendEscapeSequence(char command) {
+ flushAttributes();
+ builder.append(FIRST_ESC_CHAR);
+ builder.append(SECOND_ESC_CHAR);
+ builder.append(command);
+ return this;
+ }
+
+ private Ansi appendEscapeSequence(char command, int option) {
+ flushAttributes();
+ builder.append(FIRST_ESC_CHAR);
+ builder.append(SECOND_ESC_CHAR);
+ builder.append(option);
+ builder.append(command);
+ return this;
+ }
+
+ private Ansi appendEscapeSequence(char command, Object... options) {
+ flushAttributes();
+ return doAppendEscapeSequence(command, options);
+ }
+
+ private void flushAttributes() {
+ if (attributeOptions.isEmpty()) {
+ return;
+ }
+ if (attributeOptions.size() == 1 && attributeOptions.get(0) == 0) {
+ builder.append(FIRST_ESC_CHAR);
+ builder.append(SECOND_ESC_CHAR);
+ builder.append('m');
+ } else {
+ doAppendEscapeSequence('m', attributeOptions.toArray());
+ }
+ attributeOptions.clear();
+ }
+
+ private Ansi doAppendEscapeSequence(char command, Object... options) {
+ builder.append(FIRST_ESC_CHAR);
+ builder.append(SECOND_ESC_CHAR);
+ int size = options.length;
+ for (int i = 0; i < size; i++) {
+ if (i != 0) {
+ builder.append(';');
+ }
+ if (options[i] != null) {
+ builder.append(options[i]);
+ }
+ }
+ builder.append(command);
+ return this;
+ }
+
+ @Override
+ public Ansi append(CharSequence csq) {
+ builder.append(csq);
+ return this;
+ }
+
+ @Override
+ public Ansi append(CharSequence csq, int start, int end) {
+ builder.append(csq, start, end);
+ return this;
+ }
+
+ @Override
+ public Ansi append(char c) {
+ builder.append(c);
+ return this;
+ }
+}
diff --git a/maven-jline/src/site/site.xml b/maven-jline/src/site/site.xml
new file mode 100644
index 000000000000..4ee3b709cfc4
--- /dev/null
+++ b/maven-jline/src/site/site.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+ ${project.scm.url}
+
+
+
+
+
diff --git a/maven-slf4j-provider/pom.xml b/maven-slf4j-provider/pom.xml
index 12efb164c347..bee59b4c035d 100644
--- a/maven-slf4j-provider/pom.xml
+++ b/maven-slf4j-provider/pom.xml
@@ -38,8 +38,8 @@ under the License.
slf4j-api
- org.apache.maven.shared
- maven-shared-utils
+ org.apache.maven
+ maven-jline
org.junit.jupiter
diff --git a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java
index 0d9b9c390e50..0ef4d2f9af55 100644
--- a/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java
+++ b/maven-slf4j-provider/src/main/java/org/slf4j/impl/MavenSimpleLogger.java
@@ -20,8 +20,7 @@
import java.io.PrintStream;
-import static org.apache.maven.shared.utils.logging.MessageUtils.buffer;
-import static org.apache.maven.shared.utils.logging.MessageUtils.level;
+import static org.apache.maven.jline.MessageUtils.builder;
/**
* Logger for Maven, that support colorization of levels and stacktraces.
@@ -29,6 +28,7 @@
* @since 3.5.0
*/
public class MavenSimpleLogger extends SimpleLogger {
+
MavenSimpleLogger(String name) {
super(name);
}
@@ -37,16 +37,16 @@ public class MavenSimpleLogger extends SimpleLogger {
protected String renderLevel(int level) {
switch (level) {
case LOG_LEVEL_TRACE:
- return level().debug("TRACE").toString();
+ return builder().trace("TRACE").toString();
case LOG_LEVEL_DEBUG:
- return level().debug("DEBUG").toString();
+ return builder().debug("DEBUG").toString();
case LOG_LEVEL_INFO:
- return level().info("INFO").toString();
+ return builder().info("INFO").toString();
case LOG_LEVEL_WARN:
- return level().warning("WARNING").toString();
+ return builder().warning("WARNING").toString();
case LOG_LEVEL_ERROR:
default:
- return level().error("ERROR").toString();
+ return builder().error("ERROR").toString();
}
}
@@ -55,10 +55,10 @@ protected void writeThrowable(Throwable t, PrintStream stream) {
if (t == null) {
return;
}
- stream.print(buffer().failure(t.getClass().getName()));
+ stream.print(builder().failure(t.getClass().getName()));
if (t.getMessage() != null) {
stream.print(": ");
- stream.print(buffer().failure(t.getMessage()));
+ stream.print(builder().failure(t.getMessage()));
}
stream.println();
@@ -69,9 +69,9 @@ private void printStackTrace(Throwable t, PrintStream stream, String prefix) {
for (StackTraceElement e : t.getStackTrace()) {
stream.print(prefix);
stream.print(" ");
- stream.print(buffer().strong("at"));
+ stream.print(builder().strong("at"));
stream.print(" " + e.getClassName() + "." + e.getMethodName());
- stream.print(buffer().a(" (").strong(getLocation(e)).a(")"));
+ stream.print(builder().a(" (").strong(getLocation(e)).a(")"));
stream.println();
}
for (Throwable se : t.getSuppressed()) {
@@ -84,10 +84,10 @@ private void printStackTrace(Throwable t, PrintStream stream, String prefix) {
}
private void writeThrowable(Throwable t, PrintStream stream, String caption, String prefix) {
- stream.print(buffer().a(prefix).strong(caption).a(": ").a(t.getClass().getName()));
+ stream.print(builder().a(prefix).strong(caption).a(": ").a(t.getClass().getName()));
if (t.getMessage() != null) {
stream.print(": ");
- stream.print(buffer().failure(t.getMessage()));
+ stream.print(builder().failure(t.getMessage()));
}
stream.println();
diff --git a/pom.xml b/pom.xml
index 1b93d1168470..e0b72c0dda98 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,6 +97,7 @@ under the License.
maven-repository-metadata
maven-slf4j-provider
maven-embedder
+ maven-jline
maven-compat
apache-maven
@@ -156,6 +157,7 @@ under the License.
None
**/package-info.java
2026-03-24T21:15:50Z
+ 3.30.9
@@ -229,6 +231,11 @@ under the License.
maven-slf4j-provider
${project.version}
+
+ org.apache.maven
+ maven-jline
+ ${project.version}
+
@@ -339,21 +346,24 @@ under the License.
${plexusInterpolationVersion}
- org.apache.maven.shared
- maven-shared-utils
- 3.4.2
-
-
-
- commons-io
- commons-io
-
-
+ org.jline
+ jansi-core
+ ${jlineVersion}
+
+
+ org.jline
+ jline-terminal
+ ${jlineVersion}
+
+
+ org.jline
+ jline-terminal-jni
+ ${jlineVersion}
- org.fusesource.jansi
- jansi
- 2.4.3
+ org.jline
+ jline-terminal-ffm
+ ${jlineVersion}
org.slf4j
@@ -686,6 +696,22 @@ under the License.
true
+
+ enforce-bytecode-version
+
+ enforce
+
+
+
+
+
+ org.jline:jline-terminal-ffm
+
+
+
+ true
+
+