Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Universal availability check for an interactive console with JDK >= 22 support #4178

Merged
merged 2 commits into from
Dec 27, 2024
Merged
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
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
Loading