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


The following commit(s) were added to refs/heads/master by this push:
     new 3425b4dd08 [MNG-8334] Fix output redirection (#1826)
3425b4dd08 is described below

commit 3425b4dd08fa4dd416e0e16c39c5dc8c6d80b6cc
Author: Guillaume Nodet <gno...@gmail.com>
AuthorDate: Tue Oct 22 16:53:58 2024 +0200

    [MNG-8334] Fix output redirection (#1826)
---
 .../java/org/apache/maven/api/cli/Options.java     | 10 +--
 .../org/apache/maven/cling/invoker/BaseParser.java |  4 +-
 .../maven/cling/invoker/CommonsCliOptions.java     | 26 ++++---
 .../apache/maven/cling/invoker/LayeredOptions.java |  6 +-
 .../apache/maven/cling/invoker/LookupInvoker.java  | 84 +++++++++++-----------
 .../cling/invoker/mvn/DefaultMavenInvoker.java     | 26 +++++++
 .../java/org/apache/maven/jline/MessageUtils.java  | 19 ++++-
 7 files changed, 110 insertions(+), 65 deletions(-)

diff --git 
a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Options.java 
b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Options.java
index a267623dc4..fe5629d0d7 100644
--- a/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Options.java
+++ b/api/maven-api-cli/src/main/java/org/apache/maven/api/cli/Options.java
@@ -18,10 +18,10 @@
  */
 package org.apache.maven.api.cli;
 
-import java.io.PrintWriter;
 import java.util.Collection;
 import java.util.Map;
 import java.util.Optional;
+import java.util.function.Consumer;
 
 import org.apache.maven.api.annotations.Experimental;
 import org.apache.maven.api.annotations.Nonnull;
@@ -202,14 +202,14 @@ public interface Options {
     /**
      * Emits warning messages if deprecated options are used.
      *
-     * @param printWriter the PrintWriter to use for output
+     * @param printWriter the string consumer to use for output
      */
-    default void warnAboutDeprecatedOptions(@Nonnull ParserRequest request, 
@Nonnull PrintWriter printWriter) {}
+    default void warnAboutDeprecatedOptions(@Nonnull ParserRequest request, 
@Nonnull Consumer<String> printWriter) {}
 
     /**
      * Displays help information for these options.
      *
-     * @param printWriter the PrintWriter to use for output
+     * @param printWriter the string consumer to use for output
      */
-    void displayHelp(@Nonnull ParserRequest request, @Nonnull PrintWriter 
printWriter);
+    void displayHelp(@Nonnull ParserRequest request, @Nonnull Consumer<String> 
printWriter);
 }
diff --git 
a/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java 
b/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java
index 144ed3d583..cef034fe9a 100644
--- a/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java
+++ b/maven-cli/src/main/java/org/apache/maven/cling/invoker/BaseParser.java
@@ -111,8 +111,8 @@ public abstract class BaseParser<O extends Options, R 
extends InvokerRequest<O>>
         List<O> parsedOptions = parseCliOptions(context);
 
         // warn about deprecated options
-        parsedOptions.forEach(o -> o.warnAboutDeprecatedOptions(
-                parserRequest, new PrintWriter(parserRequest.out() != null ? 
parserRequest.out() : System.out, true)));
+        PrintWriter printWriter = new PrintWriter(parserRequest.out() != null 
? parserRequest.out() : System.out, true);
+        parsedOptions.forEach(o -> o.warnAboutDeprecatedOptions(parserRequest, 
printWriter::println));
 
         // assemble options if needed
         context.options = assembleOptions(parsedOptions);
diff --git 
a/maven-cli/src/main/java/org/apache/maven/cling/invoker/CommonsCliOptions.java 
b/maven-cli/src/main/java/org/apache/maven/cling/invoker/CommonsCliOptions.java
index 56c3b09c67..471757ca4f 100644
--- 
a/maven-cli/src/main/java/org/apache/maven/cling/invoker/CommonsCliOptions.java
+++ 
b/maven-cli/src/main/java/org/apache/maven/cling/invoker/CommonsCliOptions.java
@@ -19,10 +19,12 @@
 package org.apache.maven.cling.invoker;
 
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.LinkedHashSet;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
+import java.util.function.Consumer;
 
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.DefaultParser;
@@ -89,7 +91,7 @@ public abstract class CommonsCliOptions implements Options {
 
     @Override
     public Optional<Boolean> verbose() {
-        if (commandLine.hasOption(CLIManager.VERBOSE) || 
commandLine.hasOption(CLIManager.DEBUG)) {
+        if (commandLine.hasOption(CLIManager.VERBOSE)) {
             return Optional.of(Boolean.TRUE);
         }
         return Optional.empty();
@@ -210,11 +212,11 @@ public abstract class CommonsCliOptions implements 
Options {
     }
 
     @Override
-    public void warnAboutDeprecatedOptions(ParserRequest request, PrintWriter 
printWriter) {
+    public void warnAboutDeprecatedOptions(ParserRequest request, 
Consumer<String> printWriter) {
         if (cliManager.getUsedDeprecatedOptions().isEmpty()) {
             return;
         }
-        printWriter.println("Detected deprecated option use in " + source);
+        printWriter.accept("Detected deprecated option use in " + source);
         for (Option option : cliManager.getUsedDeprecatedOptions()) {
             StringBuilder sb = new StringBuilder();
             sb.append("The option -").append(option.getOpt());
@@ -231,12 +233,12 @@ public abstract class CommonsCliOptions implements 
Options {
                         .append(" ")
                         .append(option.getDeprecated().getSince());
             }
-            printWriter.println(sb);
+            printWriter.accept(sb.toString());
         }
     }
 
     @Override
-    public void displayHelp(ParserRequest request, PrintWriter printStream) {
+    public void displayHelp(ParserRequest request, Consumer<String> 
printStream) {
         cliManager.displayHelp(request.command(), printStream);
     }
 
@@ -429,7 +431,7 @@ public abstract class CommonsCliOptions implements Options {
             return usedDeprecatedOptions;
         }
 
-        public void displayHelp(String command, PrintWriter pw) {
+        public void displayHelp(String command, Consumer<String> pw) {
             HelpFormatter formatter = new HelpFormatter();
 
             int width = MessageUtils.getTerminalWidth();
@@ -437,10 +439,12 @@ public abstract class CommonsCliOptions implements 
Options {
                 width = HelpFormatter.DEFAULT_WIDTH;
             }
 
-            pw.println();
+            pw.accept("");
 
+            StringWriter sw = new StringWriter();
+            PrintWriter pw2 = new PrintWriter(sw);
             formatter.printHelp(
-                    pw,
+                    pw2,
                     width,
                     commandLineSyntax(command),
                     System.lineSeparator() + "Options:",
@@ -449,8 +453,10 @@ public abstract class CommonsCliOptions implements Options 
{
                     HelpFormatter.DEFAULT_DESC_PAD,
                     System.lineSeparator(),
                     false);
-
-            pw.flush();
+            pw2.flush();
+            for (String s : sw.toString().split(System.lineSeparator())) {
+                pw.accept(s);
+            }
         }
 
         protected String commandLineSyntax(String command) {
diff --git 
a/maven-cli/src/main/java/org/apache/maven/cling/invoker/LayeredOptions.java 
b/maven-cli/src/main/java/org/apache/maven/cling/invoker/LayeredOptions.java
index 83219eb27b..c5b9a50ffa 100644
--- a/maven-cli/src/main/java/org/apache/maven/cling/invoker/LayeredOptions.java
+++ b/maven-cli/src/main/java/org/apache/maven/cling/invoker/LayeredOptions.java
@@ -18,12 +18,12 @@
  */
 package org.apache.maven.cling.invoker;
 
-import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Optional;
+import java.util.function.Consumer;
 import java.util.function.Function;
 
 import org.apache.maven.api.cli.Options;
@@ -138,10 +138,10 @@ public abstract class LayeredOptions<O extends Options> 
implements Options {
     }
 
     @Override
-    public void warnAboutDeprecatedOptions(ParserRequest request, PrintWriter 
printWriter) {}
+    public void warnAboutDeprecatedOptions(ParserRequest request, 
Consumer<String> printWriter) {}
 
     @Override
-    public void displayHelp(ParserRequest request, PrintWriter printWriter) {
+    public void displayHelp(ParserRequest request, Consumer<String> 
printWriter) {
         options.get(0).displayHelp(request, printWriter);
     }
 
diff --git 
a/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java 
b/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
index 2530b1d0cf..6f18d0b365 100644
--- a/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
+++ b/maven-cli/src/main/java/org/apache/maven/cling/invoker/LookupInvoker.java
@@ -31,6 +31,7 @@ import java.util.List;
 import java.util.Locale;
 import java.util.Map;
 import java.util.Properties;
+import java.util.function.Consumer;
 import java.util.function.Function;
 
 import org.apache.maven.api.Constants;
@@ -71,16 +72,11 @@ import 
org.apache.maven.cli.transfer.Slf4jMavenTransferListener;
 import org.apache.maven.cling.invoker.mvn.ProtoSession;
 import org.apache.maven.execution.MavenExecutionRequest;
 import org.apache.maven.internal.impl.SettingsUtilsV4;
-import org.apache.maven.jline.FastTerminal;
 import org.apache.maven.jline.MessageUtils;
-import org.apache.maven.logging.BuildEventListener;
 import org.apache.maven.logging.LoggingOutputStream;
-import org.apache.maven.logging.ProjectBuildLogAppender;
-import org.apache.maven.logging.SimpleBuildEventListener;
 import org.apache.maven.logging.api.LogLevelRecorder;
 import org.apache.maven.slf4j.MavenSimpleLogger;
 import org.eclipse.aether.transfer.TransferListener;
-import org.jline.jansi.AnsiConsole;
 import org.jline.terminal.Terminal;
 import org.jline.terminal.TerminalBuilder;
 import org.slf4j.ILoggerFactory;
@@ -152,8 +148,9 @@ public abstract class LookupInvoker<
         public ILoggerFactory loggerFactory;
         public Slf4jConfiguration slf4jConfiguration;
         public Slf4jConfiguration.Level loggerLevel;
+        public Boolean coloredOutput;
         public Terminal terminal;
-        public BuildEventListener buildEventListener;
+        public Consumer<String> writer;
         public ClassLoader currentThreadContextClassLoader;
         public ContainerCapsule containerCapsule;
         public Lookup lookup;
@@ -281,9 +278,9 @@ public abstract class LookupInvoker<
                 .orElse(userProperties.getOrDefault(
                         Constants.MAVEN_STYLE_COLOR_PROPERTY, 
userProperties.getOrDefault("style.color", "auto")));
         if ("always".equals(styleColor) || "yes".equals(styleColor) || 
"force".equals(styleColor)) {
-            MessageUtils.setColorEnabled(true);
+            context.coloredOutput = true;
         } else if ("never".equals(styleColor) || "no".equals(styleColor) || 
"none".equals(styleColor)) {
-            MessageUtils.setColorEnabled(false);
+            context.coloredOutput = false;
         } else if (!"auto".equals(styleColor) && !"tty".equals(styleColor) && 
!"if-tty".equals(styleColor)) {
             throw new IllegalArgumentException(
                     "Invalid color configuration value '" + styleColor + "'. 
Supported are 'auto', 'always', 'never'.");
@@ -291,7 +288,7 @@ public abstract class LookupInvoker<
             boolean isBatchMode = 
!mavenOptions.forceInteractive().orElse(false)
                     && mavenOptions.nonInteractive().orElse(false);
             if (isBatchMode || mavenOptions.logFile().isPresent()) {
-                MessageUtils.setColorEnabled(false);
+                context.coloredOutput = false;
             }
         }
 
@@ -312,31 +309,32 @@ public abstract class LookupInvoker<
         // so boot it asynchronously
         context.terminal = createTerminal(context);
         context.closeables.add(MessageUtils::systemUninstall);
-
-        // Create the build log appender
-        ProjectBuildLogAppender projectBuildLogAppender =
-                new 
ProjectBuildLogAppender(determineBuildEventListener(context));
-        context.closeables.add(projectBuildLogAppender);
+        MessageUtils.registerShutdownHook(); // safety belt
+        if (context.coloredOutput != null) {
+            MessageUtils.setColorEnabled(context.coloredOutput);
+        }
     }
 
     protected Terminal createTerminal(C context) {
-        return new FastTerminal(
-                () -> TerminalBuilder.builder()
-                        .name("Maven")
-                        .streams(
-                                context.invokerRequest.in().orElse(null),
-                                context.invokerRequest.out().orElse(null))
-                        .dumb(true)
-                        .build(),
+        MessageUtils.systemInstall(
+                builder -> {
+                    builder.streams(
+                            context.invokerRequest.in().orElse(null),
+                            context.invokerRequest.out().orElse(null));
+                    
builder.systemOutput(TerminalBuilder.SystemOutput.ForcedSysOut);
+                    // The exec builder suffers from 
https://github.com/jline/jline3/issues/1098
+                    // We could re-enable it when fixed to provide support for 
non-standard architectures,
+                    // for which JLine does not provide any native library.
+                    builder.exec(false);
+                    if (context.coloredOutput != null) {
+                        builder.color(context.coloredOutput);
+                    }
+                },
                 terminal -> doConfigureWithTerminal(context, terminal));
+        return MessageUtils.getTerminal();
     }
 
     protected void doConfigureWithTerminal(C context, Terminal terminal) {
-        MessageUtils.systemInstall(terminal);
-        AnsiConsole.setTerminal(terminal);
-        AnsiConsole.systemInstall();
-        MessageUtils.registerShutdownHook(); // safety belt
-
         O options = context.invokerRequest.options();
         if (options.rawStreams().isEmpty() || !options.rawStreams().get()) {
             MavenSimpleLogger stdout = (MavenSimpleLogger) 
context.loggerFactory.getLogger("stdout");
@@ -349,34 +347,33 @@ public abstract class LookupInvoker<
         }
     }
 
-    protected BuildEventListener determineBuildEventListener(C context) {
-        if (context.buildEventListener == null) {
-            context.buildEventListener = 
doDetermineBuildEventListener(context);
+    protected Consumer<String> determineWriter(C context) {
+        if (context.writer == null) {
+            context.writer = doDetermineWriter(context);
         }
-        return context.buildEventListener;
+        return context.writer;
     }
 
-    protected BuildEventListener doDetermineBuildEventListener(C context) {
-        BuildEventListener bel;
+    protected Consumer<String> doDetermineWriter(C context) {
         O options = context.invokerRequest.options();
         if (options.logFile().isPresent()) {
             Path logFile = context.cwdResolver.apply(options.logFile().get());
             try {
                 PrintWriter printWriter = new 
PrintWriter(Files.newBufferedWriter(logFile));
-                bel = new SimpleBuildEventListener(printWriter::println);
+                context.closeables.add(printWriter);
+                return printWriter::println;
             } catch (IOException e) {
                 throw new MavenException("Unable to redirect logging to " + 
logFile, e);
             }
         } else {
             // Given the terminal creation has been offloaded to a different 
thread,
-            // do not pass directory the terminal writer
-            bel = new SimpleBuildEventListener(msg -> {
+            // do not pass directly the terminal writer
+            return msg -> {
                 PrintWriter pw = context.terminal.writer();
                 pw.println(msg);
                 pw.flush();
-            });
+            };
         }
-        return bel;
     }
 
     protected void activateLogging(C context) throws Exception {
@@ -412,19 +409,18 @@ public abstract class LookupInvoker<
     }
 
     protected void helpOrVersionAndMayExit(C context) throws Exception {
+        Consumer<String> writer = determineWriter(context);
         R invokerRequest = context.invokerRequest;
         if (invokerRequest.options().help().isPresent()) {
-            
invokerRequest.options().displayHelp(context.invokerRequest.parserRequest(), 
context.terminal.writer());
-            context.terminal.writer().flush();
+            
invokerRequest.options().displayHelp(context.invokerRequest.parserRequest(), 
writer);
             throw new ExitException(0);
         }
         if (invokerRequest.options().showVersionAndExit().isPresent()) {
             if (invokerRequest.options().quiet().orElse(false)) {
-                
context.terminal.writer().println(CLIReportingUtils.showVersionMinimal());
+                writer.accept(CLIReportingUtils.showVersionMinimal());
             } else {
-                
context.terminal.writer().println(CLIReportingUtils.showVersion());
+                writer.accept(CLIReportingUtils.showVersion());
             }
-            context.terminal.writer().flush();
             throw new ExitException(0);
         }
     }
@@ -432,7 +428,7 @@ public abstract class LookupInvoker<
     protected void preCommands(C context) throws Exception {
         Options mavenOptions = context.invokerRequest.options();
         if (mavenOptions.verbose().orElse(false) || 
mavenOptions.showVersion().orElse(false)) {
-            context.terminal.writer().println(CLIReportingUtils.showVersion());
+            determineWriter(context).accept(CLIReportingUtils.showVersion());
         }
     }
 
diff --git 
a/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvoker.java
 
b/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvoker.java
index 6bfb5121f5..d08056d3e7 100644
--- 
a/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvoker.java
+++ 
b/maven-cli/src/main/java/org/apache/maven/cling/invoker/mvn/DefaultMavenInvoker.java
@@ -27,6 +27,7 @@ import java.util.HashMap;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
@@ -63,8 +64,11 @@ import org.apache.maven.execution.ProfileActivation;
 import org.apache.maven.execution.ProjectActivation;
 import org.apache.maven.jline.MessageUtils;
 import org.apache.maven.lifecycle.LifecycleExecutionException;
+import org.apache.maven.logging.BuildEventListener;
 import org.apache.maven.logging.LoggingExecutionListener;
 import org.apache.maven.logging.MavenTransferListener;
+import org.apache.maven.logging.ProjectBuildLogAppender;
+import org.apache.maven.logging.SimpleBuildEventListener;
 import org.apache.maven.project.MavenProject;
 import org.codehaus.plexus.PlexusContainer;
 import org.eclipse.aether.DefaultRepositoryCache;
@@ -89,6 +93,7 @@ public abstract class DefaultMavenInvoker<
             super(invoker, invokerRequest);
         }
 
+        public BuildEventListener buildEventListener;
         public MavenExecutionRequest mavenExecutionRequest;
         public EventSpyDispatcher eventSpyDispatcher;
         public MavenExecutionRequestPopulator mavenExecutionRequestPopulator;
@@ -161,6 +166,27 @@ public abstract class DefaultMavenInvoker<
         }
     }
 
+    @Override
+    protected void configureLogging(C context) throws Exception {
+        super.configureLogging(context);
+        // Create the build log appender
+        ProjectBuildLogAppender projectBuildLogAppender =
+                new 
ProjectBuildLogAppender(determineBuildEventListener(context));
+        context.closeables.add(projectBuildLogAppender);
+    }
+
+    protected BuildEventListener determineBuildEventListener(C context) {
+        if (context.buildEventListener == null) {
+            context.buildEventListener = 
doDetermineBuildEventListener(context);
+        }
+        return context.buildEventListener;
+    }
+
+    protected BuildEventListener doDetermineBuildEventListener(C context) {
+        Consumer<String> writer = determineWriter(context);
+        return new SimpleBuildEventListener(writer);
+    }
+
     @Override
     protected void customizeSettingsRequest(C context, SettingsBuilderRequest 
settingsBuilderRequest) {
         if (context.eventSpyDispatcher != null) {
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 43a75aa323..35a5416850 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,6 +18,8 @@
  */
 package org.apache.maven.jline;
 
+import java.util.function.Consumer;
+
 import org.apache.maven.api.services.MessageBuilder;
 import org.apache.maven.api.services.MessageBuilderFactory;
 import org.jline.jansi.AnsiConsole;
@@ -41,11 +43,26 @@ public class MessageUtils {
     }
 
     public static void systemInstall() {
+        systemInstall(null, null);
+    }
+
+    public static void systemInstall(Consumer<TerminalBuilder> 
builderConsumer, Consumer<Terminal> terminalConsumer) {
         MessageUtils.terminal = new FastTerminal(
-                () -> 
TerminalBuilder.builder().name("Maven").dumb(true).build(), terminal -> {
+                () -> {
+                    TerminalBuilder builder =
+                            TerminalBuilder.builder().name("Maven").dumb(true);
+                    if (builderConsumer != null) {
+                        builderConsumer.accept(builder);
+                    }
+                    return builder.build();
+                },
+                terminal -> {
                     MessageUtils.reader = createReader(terminal);
                     AnsiConsole.setTerminal(terminal);
                     AnsiConsole.systemInstall();
+                    if (terminalConsumer != null) {
+                        terminalConsumer.accept(terminal);
+                    }
                 });
     }
 

Reply via email to