diff --git a/client/src/main/java/org/mvndaemon/mvnd/client/DefaultClient.java b/client/src/main/java/org/mvndaemon/mvnd/client/DefaultClient.java index d7a26e57..fc5a6438 100644 --- a/client/src/main/java/org/mvndaemon/mvnd/client/DefaultClient.java +++ b/client/src/main/java/org/mvndaemon/mvnd/client/DefaultClient.java @@ -72,6 +72,12 @@ public class DefaultClient implements Client { } } + // Color + String color = Environment.COLOR.removeCommandLineOption(args); + if (color == null) { + color = Environment.COLOR.getDefault(); + } + // Serial if (Environment.SERIAL.removeCommandLineOption(args) != null) { System.setProperty(Environment.SERIAL.getProperty(), Boolean.toString(true)); @@ -93,7 +99,7 @@ public class DefaultClient implements Client { int exitCode = 0; boolean noBuffering = batchMode || parameters.noBuffering(); - try (TerminalOutput output = new TerminalOutput(noBuffering, parameters.rollingWindowSize(), logFile)) { + try (TerminalOutput output = new TerminalOutput(noBuffering, parameters.rollingWindowSize(), logFile, color)) { try { final ExecutionResult result = new DefaultClient(parameters).execute(output, args); exitCode = result.getExitCode(); diff --git a/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java b/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java index 6a19409a..2bac9690 100644 --- a/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java +++ b/common/src/main/java/org/mvndaemon/mvnd/common/Environment.java @@ -58,6 +58,8 @@ public enum Environment { STOP(null, null, null, OptionType.VOID, Flags.OPTIONAL, "mvnd:--stop"), /** Use one thread, no log buffering and the default project builder to behave like a standard maven */ SERIAL("mvnd.serial", null, Boolean.FALSE, OptionType.VOID, Flags.OPTIONAL, "mvnd:-1", "mvnd:--serial"), + /** Manage color output, can be either auto (the default), always or never */ + COLOR(null, null, "auto", OptionType.STRING, Flags.OPTIONAL, "mvnd:--color"), // // Log properties diff --git a/common/src/main/java/org/mvndaemon/mvnd/common/logging/TerminalOutput.java b/common/src/main/java/org/mvndaemon/mvnd/common/logging/TerminalOutput.java index ca7028b9..585023aa 100644 --- a/common/src/main/java/org/mvndaemon/mvnd/common/logging/TerminalOutput.java +++ b/common/src/main/java/org/mvndaemon/mvnd/common/logging/TerminalOutput.java @@ -35,10 +35,12 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.function.Consumer; import java.util.stream.Collector; import java.util.stream.Collectors; +import org.fusesource.jansi.internal.CLibrary; import org.jline.terminal.Size; import org.jline.terminal.Terminal; import org.jline.terminal.TerminalBuilder; import org.jline.terminal.impl.AbstractPosixTerminal; +import org.jline.utils.AnsiWriter; import org.jline.utils.AttributedString; import org.jline.utils.AttributedStringBuilder; import org.jline.utils.AttributedStyle; @@ -86,6 +88,10 @@ public class TerminalOutput implements ClientOutput { */ public static final int KEY_CTRL_M = 'M' & 0x1f; + public static final String COLOR_AUTO = "auto"; + public static final String COLOR_ALWAYS = "always"; + public static final String COLOR_NEVER = "never"; + private static final AttributedStyle GREEN_FOREGROUND = new AttributedStyle().foreground(AttributedStyle.GREEN); private static final AttributedStyle CYAN_FOREGROUND = new AttributedStyle().foreground(AttributedStyle.CYAN); @@ -143,7 +149,7 @@ public class TerminalOutput implements ClientOutput { } } - public TerminalOutput(boolean noBuffering, int rollingWindowSize, Path logFile) throws IOException { + public TerminalOutput(boolean noBuffering, int rollingWindowSize, Path logFile, String color) throws IOException { this.start = System.currentTimeMillis(); this.terminal = TerminalBuilder.terminal(); this.dumb = terminal.getType().startsWith("dumb"); @@ -159,7 +165,7 @@ public class TerminalOutput implements ClientOutput { this.previousIntHandler = terminal.handle(Terminal.Signal.INT, sig -> daemonDispatch.accept(Message.BareMessage.CANCEL_BUILD_SINGLETON)); this.display = new Display(terminal, false); - this.log = logFile == null ? new MessageCollector() : new FileLog(logFile); + this.log = logFile == null ? new MessageCollector(color) : new FileLog(logFile, color); if (!dumb) { final Thread r = new Thread(this::readInputLoop); r.start(); @@ -763,10 +769,15 @@ public class TerminalOutput implements ClientOutput { private final Writer out; private final Path logFile; + private boolean closed; - public FileLog(Path logFile) throws IOException { + public FileLog(Path logFile, String color) throws IOException { super(); - this.out = Files.newBufferedWriter(logFile, StandardCharsets.UTF_8); + if (COLOR_ALWAYS.equalsIgnoreCase(color)) { + this.out = Files.newBufferedWriter(logFile, StandardCharsets.UTF_8); + } else { + this.out = new AnsiWriter(Files.newBufferedWriter(logFile, StandardCharsets.UTF_8)); + } this.logFile = logFile; } @@ -787,7 +798,10 @@ public class TerminalOutput implements ClientOutput { @Override public void close() throws IOException { - out.close(); + if (!closed) { + out.close(); + closed = true; + } } } @@ -799,6 +813,23 @@ public class TerminalOutput implements ClientOutput { class MessageCollector implements ClientLog { private final List messages = new ArrayList<>(); + private final boolean strip; + + public MessageCollector(String color) { + if (COLOR_NEVER.equalsIgnoreCase(color)) { + this.strip = true; + } else if (COLOR_ALWAYS.equalsIgnoreCase(color)) { + this.strip = false; + } else { + boolean strip; + try { + strip = CLibrary.isatty(1) == 0; + } catch (Throwable t) { + strip = true; + } + this.strip = strip; + } + } @Override public void accept(String message) { @@ -808,7 +839,7 @@ public class TerminalOutput implements ClientOutput { @Override public void flush() { clearDisplay(); - messages.forEach(terminal.writer()::println); + messages.forEach(s -> terminal.writer().println(strip ? AttributedString.stripAnsi(s) : s)); messages.clear(); terminal.flush(); }