You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@maven.apache.org by gn...@apache.org on 2024/04/03 17:49:46 UTC
(maven) 01/04: Boot JLine in async mode
This is an automated email from the ASF dual-hosted git repository.
gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git
commit a6f52774eb93df5cb0ae20bfb3b68d82aa9f5456
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Tue Apr 2 10:30:47 2024 +0200
Boot JLine in async mode
---
.../maven/cli/event/ExecutionEventLogger.java | 37 ++-
.../java/org/apache/maven/jline/FastTerminal.java | 273 +++++++++++++++++++++
.../java/org/apache/maven/jline/MessageUtils.java | 16 +-
.../org/apache/maven/slf4j/MavenSimpleLogger.java | 17 +-
4 files changed, 319 insertions(+), 24 deletions(-)
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 7567e54ac5..a8085253a8 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
@@ -58,9 +58,9 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
private final MessageBuilderFactory messageBuilderFactory;
private final Logger logger;
- private final int terminalWidth;
- private final int lineLength;
- private final int maxProjectNameLength;
+ private int terminalWidth;
+ private int lineLength;
+ private int maxProjectNameLength;
private int totalProjects;
private volatile int currentVisitedProjectCount;
@@ -69,17 +69,13 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
}
public ExecutionEventLogger(MessageBuilderFactory messageBuilderFactory, Logger logger) {
- this(messageBuilderFactory, logger, messageBuilderFactory.getTerminalWidth());
+ 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 = Math.min(
- MAX_TERMINAL_WIDTH,
- Math.max(terminalWidth < 0 ? DEFAULT_TERMINAL_WIDTH : terminalWidth, MIN_TERMINAL_WIDTH));
- this.lineLength = this.terminalWidth - MAX_LOG_PREFIX_SIZE;
- this.maxProjectNameLength = this.lineLength - PROJECT_STATUS_SUFFIX_SIZE;
+ this.terminalWidth = terminalWidth;
}
private static String chars(char c, int count) {
@@ -100,9 +96,23 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
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...");
}
}
@@ -110,6 +120,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
@Override
public void sessionStarted(ExecutionEvent event) {
if (logger.isInfoEnabled() && event.getSession().getProjects().size() > 1) {
+ init();
infoLine('-');
infoMain("Reactor Build Order:");
@@ -136,6 +147,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
@Override
public void sessionEnded(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
+ init();
if (event.getSession().getProjects().size() > 1) {
logReactorSummary(event.getSession());
}
@@ -280,6 +292,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
@Override
public void projectSkipped(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
+ init();
logger.info("");
infoLine('-');
@@ -293,6 +306,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
@Override
public void projectStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
+ init();
MavenProject project = event.getProject();
logger.info("");
@@ -354,6 +368,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
@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());
@@ -366,6 +381,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
@Override
public void mojoStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
+ init();
logger.info("");
MessageBuilder buffer = builder().strong("--- ");
@@ -386,6 +402,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
@Override
public void forkStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
+ init();
logger.info("");
MessageBuilder buffer = builder().strong(">>> ");
@@ -408,6 +425,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
@Override
public void forkSucceeded(ExecutionEvent event) {
if (logger.isInfoEnabled()) {
+ init();
logger.info("");
MessageBuilder buffer = builder().strong("<<< ");
@@ -460,6 +478,7 @@ public class ExecutionEventLogger extends AbstractExecutionListener {
public void forkedProjectStarted(ExecutionEvent event) {
if (logger.isInfoEnabled()
&& event.getMojoExecution().getForkedExecutions().size() > 1) {
+ init();
logger.info("");
infoLine('>');
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 0000000000..dbdbb06d4c
--- /dev/null
+++ b/maven-jline/src/main/java/org/apache/maven/jline/FastTerminal.java
@@ -0,0 +1,273 @@
+/*
+ * 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.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.function.Consumer;
+import java.util.function.IntConsumer;
+import java.util.function.IntSupplier;
+
+import org.apache.maven.api.services.MavenException;
+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 {
+
+ final Future<Terminal> terminal;
+
+ public FastTerminal(Callable<Terminal> builder, Consumer<Terminal> consumer) {
+ ExecutorService executor = Executors.newSingleThreadExecutor();
+ terminal = executor.submit(() -> {
+ try {
+ Terminal terminal = builder.call();
+ consumer.accept(terminal);
+ return terminal;
+ } catch (Exception e) {
+ throw new MavenException(e);
+ } finally {
+ executor.shutdown();
+ }
+ });
+ }
+
+ 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 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 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();
+ }
+}
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
index a0e8cc338c..878d773a75 100644
--- a/maven-jline/src/main/java/org/apache/maven/jline/MessageUtils.java
+++ b/maven-jline/src/main/java/org/apache/maven/jline/MessageUtils.java
@@ -18,8 +18,6 @@
*/
package org.apache.maven.jline;
-import java.io.IOError;
-import java.io.IOException;
import java.io.PrintStream;
import org.apache.maven.api.services.MessageBuilder;
@@ -43,14 +41,12 @@ public class MessageUtils {
static PrintStream prevErr;
public static void systemInstall() {
- try {
- terminal = TerminalBuilder.builder().name("Maven").dumb(true).build();
- reader = LineReaderBuilder.builder().terminal(terminal).build();
- AnsiConsole.setTerminal(terminal);
- AnsiConsole.systemInstall();
- } catch (IOException e) {
- throw new IOError(e);
- }
+ terminal = new FastTerminal(
+ () -> TerminalBuilder.builder().name("Maven").dumb(true).build(), t -> {
+ reader = LineReaderBuilder.builder().terminal(t).build();
+ AnsiConsole.setTerminal(t);
+ AnsiConsole.systemInstall();
+ });
}
public static void registerShutdownHook() {
diff --git a/maven-slf4j-provider/src/main/java/org/apache/maven/slf4j/MavenSimpleLogger.java b/maven-slf4j-provider/src/main/java/org/apache/maven/slf4j/MavenSimpleLogger.java
index 46a794b160..749d60de88 100644
--- a/maven-slf4j-provider/src/main/java/org/apache/maven/slf4j/MavenSimpleLogger.java
+++ b/maven-slf4j-provider/src/main/java/org/apache/maven/slf4j/MavenSimpleLogger.java
@@ -34,11 +34,11 @@ import static org.apache.maven.jline.MessageUtils.builder;
*/
public class MavenSimpleLogger extends ExtSimpleLogger {
- private final String traceRenderedLevel = builder().trace("TRACE").build();
- private final String debugRenderedLevel = builder().debug("DEBUG").build();
- private final String infoRenderedLevel = builder().info("INFO").build();
- private final String warnRenderedLevel = builder().warning("WARNING").build();
- private final String errorRenderedLevel = builder().error("ERROR").build();
+ private String traceRenderedLevel;
+ private String debugRenderedLevel;
+ private String infoRenderedLevel;
+ private String warnRenderedLevel;
+ private String errorRenderedLevel;
static Consumer<String> logSink;
@@ -52,6 +52,13 @@ public class MavenSimpleLogger extends ExtSimpleLogger {
@Override
protected String renderLevel(int level) {
+ if (traceRenderedLevel == null) {
+ traceRenderedLevel = builder().trace("TRACE").build();
+ debugRenderedLevel = builder().debug("DEBUG").build();
+ infoRenderedLevel = builder().info("INFO").build();
+ warnRenderedLevel = builder().warning("WARNING").build();
+ errorRenderedLevel = builder().error("ERROR").build();
+ }
switch (level) {
case LOG_LEVEL_TRACE:
return traceRenderedLevel;