Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -532,6 +532,10 @@ void logging(CliRequest cliRequest) throws ExitException {
|| commandLine.hasOption(CLIManager.NON_INTERACTIVE));
if (isBatchMode || commandLine.hasOption(CLIManager.LOG_FILE)) {
MessageUtils.setColorEnabled(false);
} else if (!isConsoleTerminal()) {
// On JDK 22+, System.console() returns non-null even when stdout is
// redirected to a pipe or file. Use Console.isTerminal() to detect this.
MessageUtils.setColorEnabled(false);
}
}

Expand Down Expand Up @@ -628,6 +632,32 @@ void logging(CliRequest cliRequest) throws ExitException {
}
}

/**
* Checks whether the JVM console is connected to a real terminal.
* On JDK 22+, {@code Console.isTerminal()} returns {@code false} when stdout is redirected
* to a pipe or file, even though {@code System.console()} returns non-null.
* On older JDKs (before 22), falls back to checking {@code System.console() != null},
* which is the pre-existing behavior.
*/
static boolean isConsoleTerminal() {
Console cons = System.console();
if (cons == null) {
return false;
}
try {
// JDK 22+ provides Console.isTerminal() to distinguish a real terminal
// from a redirected console (pipe or file).
java.lang.reflect.Method isTerminal = cons.getClass().getMethod("isTerminal");
return (Boolean) isTerminal.invoke(cons);
} catch (NoSuchMethodException e) {
// JDK < 22: System.console() != null was the best heuristic
return true;
} catch (ReflectiveOperationException e) {
// Unexpected reflection error; fall back to assuming terminal
return true;
}
}

private void version(CliRequest cliRequest) {
if (cliRequest.verbose || cliRequest.commandLine.hasOption(CLIManager.SHOW_VERSION)) {
System.out.println(CLIReportingUtils.showVersion());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,8 +360,13 @@ protected final void doConfigureWithTerminal(C context, Terminal terminal) {
// To align Maven with outcomes, we set here color enabled based on these premises.
// Note: Maven3 suffers from similar thing: if you do `mvn3 foo > log.txt`, the output will
// not be not colored (good), but Maven will print out "Message scheme: color".
MessageUtils.setColorEnabled(
context.coloredOutput != null ? context.coloredOutput : !Terminal.TYPE_DUMB.equals(terminal.getType()));
boolean colorEnabled;
if (context.coloredOutput != null) {
colorEnabled = context.coloredOutput;
} else {
colorEnabled = !Terminal.TYPE_DUMB.equals(terminal.getType()) && isConsoleTerminal();
}
MessageUtils.setColorEnabled(colorEnabled);

// handle rawStreams: some would like to act on true, some on false
if (context.options().rawStreams().orElse(false)) {
Expand Down Expand Up @@ -401,6 +406,32 @@ protected void doConfigureWithTerminalWithRawStreamsDisabled(C context) {
// no need to set them back, this is already handled by MessageUtils.systemUninstall() above
}

/**
* Checks whether the JVM console is connected to a real terminal.
* On JDK 22+, {@code Console.isTerminal()} returns {@code false} when stdout is redirected
* to a pipe or file, even though {@code System.console()} returns non-null.
* On older JDKs (before 22), falls back to checking {@code System.console() != null},
* which is the pre-existing behavior.
*/
static boolean isConsoleTerminal() {
java.io.Console console = System.console();
if (console == null) {
return false;
}
try {
// JDK 22+ provides Console.isTerminal() to distinguish a real terminal
// from a redirected console (pipe or file).
java.lang.reflect.Method isTerminal = console.getClass().getMethod("isTerminal");
return (Boolean) isTerminal.invoke(console);
} catch (NoSuchMethodException e) {
// JDK < 22: System.console() != null was the best heuristic
return true;
} catch (ReflectiveOperationException e) {
// Unexpected reflection error; fall back to assuming terminal
return true;
}
}

protected Consumer<String> determineWriter(C context) {
if (context.writer == null) {
context.writer = doDetermineWriter(context);
Expand Down