diff --git a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala index 20db30ab0..9b8b86d4f 100644 --- a/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala +++ b/internal/util-complete/src/main/scala/sbt/internal/util/LineReader.scala @@ -130,7 +130,7 @@ object LineReader { Option(mask.map(reader.readLine(prompt, _)).getOrElse(reader.readLine(prompt))) } catch { case e: EndOfFileException => - if (terminal == Terminal.console && System.console == null) None + if (terminal == Terminal.console && !Terminal.hasConsole) None else Some("exit") case _: IOError | _: ClosedException => Some("exit") case _: UserInterruptException | _: ClosedByInterruptException | diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala b/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala index a798b5eb0..51b2c5e40 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/JLine3.scala @@ -20,6 +20,7 @@ import org.jline.terminal.Attributes.{ InputFlag, LocalFlag } import org.jline.terminal.Terminal.SignalHandler import org.jline.terminal.impl.{ AbstractTerminal, DumbTerminal } import org.jline.terminal.spi.{ SystemStream, TerminalProvider } +import sbt.internal.util.Terminal.hasConsole import scala.collection.JavaConverters._ import scala.util.Try import java.util.concurrent.LinkedBlockingQueue @@ -31,7 +32,7 @@ private[sbt] object JLine3 { val term = org.jline.terminal.TerminalBuilder .builder() - .system(System.console != null) + .system(hasConsole) .paused(true) .build() initialAttributes.get match { diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala index 85176a988..9a1a3c8a8 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/Terminal.scala @@ -273,7 +273,7 @@ object Terminal { * the sbt client to detach from the server it launches. */ def close(): Unit = { - if (System.console == null) { + if (!hasConsole) { originalOut.close() originalIn.close() originalErr.close() @@ -350,7 +350,17 @@ object Terminal { private[this] val isDumb = Some("dumb") == sys.env.get("TERM") private[this] def isDumbTerminal = isDumb || System.getProperty("jline.terminal", "") == "none" - private[this] val hasConsole = Option(java.lang.System.console).isDefined + private[sbt] val hasConsole = { + System.console != null && { + try { + val isTerminal = System.console.getClass.getMethod("isTerminal") + isTerminal.invoke(System.console).asInstanceOf[Boolean] + } catch { + case _: NoSuchMethodException => + true + } + } + } private[this] def useColorDefault: Boolean = { // This approximates that both stdin and stdio are connected, // so by default color will be turned off for pipes and redirects. @@ -692,7 +702,7 @@ object Terminal { inputStream.read match { case -1 => case `NO_BOOT_CLIENTS_CONNECTED` => - if (System.console == null) { + if (!Terminal.hasConsole) { result.put(-1) running.set(false) } diff --git a/main-command/src/main/scala/sbt/internal/ui/UITask.scala b/main-command/src/main/scala/sbt/internal/ui/UITask.scala index e3540c570..6e9fcd1be 100644 --- a/main-command/src/main/scala/sbt/internal/ui/UITask.scala +++ b/main-command/src/main/scala/sbt/internal/ui/UITask.scala @@ -17,6 +17,7 @@ import sbt.BasicKeys.{ historyPath, colorShellPrompt } import sbt.State import sbt.internal.CommandChannel import sbt.internal.util.ConsoleAppender.{ ClearPromptLine, ClearScreenAfterCursor, DeleteLine } +import sbt.internal.util.Terminal.hasConsole import sbt.internal.util._ import sbt.internal.util.complete.{ Parser } @@ -70,7 +71,7 @@ private[sbt] object UITask { if (thread.isInterrupted || closed.get) throw interrupted (try reader.readLine(clear + terminal.prompt.mkPrompt()) finally reader.close) match { - case None if terminal == Terminal.console && System.console == null => + case None if terminal == Terminal.console && !hasConsole => // No stdin is attached to the process so just ignore the result and // block until the thread is interrupted. this.synchronized(this.wait()) diff --git a/main/src/main/scala/sbt/Main.scala b/main/src/main/scala/sbt/Main.scala index 48d24b3e5..cae982680 100644 --- a/main/src/main/scala/sbt/Main.scala +++ b/main/src/main/scala/sbt/Main.scala @@ -27,6 +27,7 @@ import sbt.internal.inc.ScalaInstance import sbt.internal.io.Retry import sbt.internal.nio.{ CheckBuildSources, FileTreeRepository } import sbt.internal.server.{ BuildServerProtocol, NetworkChannel } +import sbt.internal.util.Terminal.hasConsole import sbt.internal.util.Types.{ const, idFun } import sbt.internal.util.complete.{ Parser, SizeParser } import sbt.internal.util.{ Terminal => ITerminal, _ } @@ -151,8 +152,7 @@ private[sbt] object xMain { try Some(new BootServerSocket(configuration)) -> None catch { - case e: ServerAlreadyBootingException - if System.console != null && !ITerminal.startedByRemoteClient => + case e: ServerAlreadyBootingException if hasConsole && !ITerminal.startedByRemoteClient => printThrowable(e) println("Create a new server? y/n (default y)") val exit = diff --git a/main/src/main/scala/sbt/TemplateCommandUtil.scala b/main/src/main/scala/sbt/TemplateCommandUtil.scala index 328781dd8..71f803518 100644 --- a/main/src/main/scala/sbt/TemplateCommandUtil.scala +++ b/main/src/main/scala/sbt/TemplateCommandUtil.scala @@ -22,6 +22,7 @@ import sbt.librarymanagement._ import sbt.librarymanagement.ivy.{ IvyConfiguration, IvyDependencyResolution } import sbt.internal.inc.classpath.ClasspathUtil import BasicCommandStrings._, BasicKeys._ +import sbt.internal.util.Terminal.hasConsole private[sbt] object TemplateCommandUtil { def templateCommand: Command = templateCommand0(TemplateCommand) @@ -185,7 +186,7 @@ private[sbt] object TemplateCommandUtil { "disneystreaming/smithy4s.g8" -> "A Smithy4s project", ) private def fortifyArgs(templates: List[(String, String)]): List[String] = - if (System.console eq null) Nil + if (!hasConsole) Nil else ITerminal.withStreams(true, false) { assert(templates.size <= 20, "template list cannot have more than 20 items") diff --git a/main/src/main/scala/sbt/internal/InstallSbtn.scala b/main/src/main/scala/sbt/internal/InstallSbtn.scala index 693830f93..6315a2a6d 100644 --- a/main/src/main/scala/sbt/internal/InstallSbtn.scala +++ b/main/src/main/scala/sbt/internal/InstallSbtn.scala @@ -11,6 +11,7 @@ package internal import Def._ import Keys.{ sbtVersion, state, terminal } +import sbt.internal.util.Terminal.hasConsole import java.io.{ File, FileInputStream, FileOutputStream, InputStream, IOException } import java.net.URI @@ -37,7 +38,7 @@ private[sbt] object InstallSbtn { Files.deleteIfExists(tmp) () } - val shell = if (System.console != null) getShell(term) else "none" + val shell = if (hasConsole) getShell(term) else "none" shell match { case "none" => case s =>