Skip to content

Commit

Permalink
Universal availability check for an interactive console with JDK >= 2…
Browse files Browse the repository at this point in the history
…2 support (#4178)

JDK 22 introduced some changes to the method `System.console()`:

> In JDK 22, System.console() has been changed to return a Console with
enhanced editing features that improve the experience of programs that
use the Console API. In addition, System.console() now returns a Console
object when the standard streams are redirected or connected to a
virtual terminal. Prior to JDK 22, System.console() instead returned
null for these cases. This change may impact code that checks the return
from System.console() to test if the JVM is connected to a terminal. If
required, the -Djdk.console=java.base flag will restore the old behavior
where the console is only returned when it is connected to a terminal.
Starting JDK 22, one could also use the new Console.isTerminal() method
to test if the console is connected to a terminal.

Mill assumes the old behavior of `System.console` and use
`System.console() != null` to check if we have interactive console,
causing issue like #4161.

This PR added universal availability check for an interactive console,
compatible with JDK < 22 and later.

SBT made similar changes in sbt/sbt#7843.

Closes #4161

---------

Co-authored-by: Nikolay Artamonov <[email protected]>
  • Loading branch information
nartamonov and Nikolay Artamonov authored Dec 27, 2024
1 parent 4f79aa1 commit edc3b54
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 5 deletions.
8 changes: 8 additions & 0 deletions build.mill
Original file line number Diff line number Diff line change
Expand Up @@ -387,6 +387,14 @@ trait MillJavaModule extends JavaModule {
Deps.jline,
Deps.jna
)

def javadocOptions = super.javadocOptions() ++ Seq(
// Disable warnings for missing documentation comments or tags (for example,
// a missing comment or class, or a missing @return tag or similar tag on a method).
// We have many methods without JavaDoc comments, so those warnings are useless
// and significantly clutter the output.
"-Xdoclint:all,-missing"
)
}

trait MillPublishJavaModule extends MillJavaModule with PublishModule {
Expand Down
2 changes: 1 addition & 1 deletion main/client/src/mill/main/client/ServerLauncher.java
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public Result acquireLocksAndRun(String outDir) throws Exception {
int run(Path serverDir, boolean setJnaNoSys, Locks locks) throws Exception {

try (OutputStream f = Files.newOutputStream(serverDir.resolve(ServerFiles.runArgs))) {
f.write(System.console() != null ? 1 : 0);
f.write(Util.hasConsole() ? 1 : 0);
Util.writeString(f, BuildInfo.millVersion);
Util.writeArgs(args, f);
Util.writeMap(env, f);
Expand Down
28 changes: 28 additions & 0 deletions main/client/src/mill/main/client/Util.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package mill.main.client;

import java.io.Console;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
Expand Down Expand Up @@ -38,6 +41,31 @@ public static final int ExitServerCodeWhenVersionMismatch() {
!System.getProperty("java.specification.version").startsWith("1.");
private static Charset utf8 = Charset.forName("UTF-8");

/**
* Determines if we have an interactive console attached to the application.
* <p>
* Before JDK 22 we could use <code>System.console() != null</code> to do that check.
* However, with JDK &gt;= 22 it no longer works because <code>System.console()</code>
* always returns a console instance even for redirected streams. Instead,
* JDK &gt;= 22 introduced the method <a href="https://docs.oracle.com/en/java/javase/22/docs/api/java.base/java/io/Console.html#isTerminal()">`Console.isTerminal`</a>.
* See: JLine As The Default Console Provider (JDK-8308591)
* <p>
* This method takes into account these differences and is compatible with
* both JDK versions before 22 and later.
*/
public static boolean hasConsole() {
Console console = System.console();

if (console != null) {
try {
Method method = console.getClass().getMethod("isTerminal");
return (Boolean) method.invoke(console);
} catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException ignored) {
return true;
}
} else return false;
}

public static String[] parseArgs(InputStream argStream) throws IOException {
int argsLength = readInt(argStream);
String[] args = new String[argsLength];
Expand Down
2 changes: 1 addition & 1 deletion main/util/src/mill/util/Util.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import mill.api.{BuildInfo, Ctx, IO, PathRef, Result}

object Util {

def isInteractive(): Boolean = System.console() != null
def isInteractive(): Boolean = mill.main.client.Util.hasConsole()

val newLine: String = System.lineSeparator()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ static void writeTerminalDims(boolean tputExists, Path serverDir) throws Excepti
String str;

try {
if (java.lang.System.console() == null) str = "0 0";
if (!Util.hasConsole()) str = "0 0";
else {
if (!tputExists) {
// Hardcoded size of a quarter screen terminal on 13" windows laptop
Expand Down
4 changes: 2 additions & 2 deletions runner/src/mill/runner/MillMain.scala
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import mill.java9rtexport.Export
import mill.api.{MillException, SystemStreams, WorkspaceRoot, internal}
import mill.bsp.{BspContext, BspServerResult}
import mill.main.BuildInfo
import mill.main.client.{OutFiles, ServerFiles}
import mill.main.client.{OutFiles, ServerFiles, Util}
import mill.main.client.lock.Lock
import mill.util.{Colors, PrintLogger, PromptLogger}

Expand Down Expand Up @@ -68,7 +68,7 @@ object MillMain {
(initialSystemStreams, Seq(), None)
}

if (Properties.isWin && System.console() != null)
if (Properties.isWin && Util.hasConsole())
io.github.alexarchambault.windowsansi.WindowsAnsi.setup()

val (result, _) =
Expand Down

0 comments on commit edc3b54

Please sign in to comment.