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 <gno...@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;

Reply via email to