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 3cb4342eb..64d84c1da 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 @@ -24,7 +24,6 @@ import org.jline.utils.OSUtils import scala.collection.JavaConverters._ import scala.util.Try import java.util.concurrent.LinkedBlockingQueue -import org.fusesource.jansi.internal.WindowsSupport private[sbt] object JLine3 { private[util] val initialAttributes = new AtomicReference[Attributes] diff --git a/internal/util-logging/src/main/scala/sbt/internal/util/WindowsInputStream.scala b/internal/util-logging/src/main/scala/sbt/internal/util/WindowsInputStream.scala index e3b6df0a1..486759cbb 100644 --- a/internal/util-logging/src/main/scala/sbt/internal/util/WindowsInputStream.scala +++ b/internal/util-logging/src/main/scala/sbt/internal/util/WindowsInputStream.scala @@ -10,11 +10,27 @@ package sbt.internal.util import java.io.InputStream import java.util.concurrent.LinkedBlockingQueue import java.util.concurrent.atomic.AtomicBoolean -import org.fusesource.jansi.internal.WindowsSupport +import org.fusesource.jansi.internal.Kernel32 import org.jline.utils.InfoCmp.Capability import scala.annotation.tailrec import Terminal.SimpleInputStream +private object WindowsSupport { + def getConsoleMode = { + val console = Kernel32.GetStdHandle(Kernel32.STD_INPUT_HANDLE); + val mode = new Array[Int](1); + if (Kernel32.GetConsoleMode(console, mode) == 0) -1 else mode.head + } + def setConsoleMode(mode: Int): Unit = { + val console = Kernel32.GetStdHandle(Kernel32.STD_INPUT_HANDLE); + Kernel32.SetConsoleMode(console, mode) + () + } + def readConsoleInput(count: Int) = { + val console = Kernel32.GetStdHandle(Kernel32.STD_INPUT_HANDLE); + Kernel32.readConsoleInputHelper(console, 1, false) + } +} /* * We need a special input stream for windows because special key events * like arrow keys are not reported by System.in. What makes this extra diff --git a/main/src/main/java/sbt/internal/MetaBuildLoader.java b/main/src/main/java/sbt/internal/MetaBuildLoader.java index 08a80aa24..c91337a44 100644 --- a/main/src/main/java/sbt/internal/MetaBuildLoader.java +++ b/main/src/main/java/sbt/internal/MetaBuildLoader.java @@ -64,7 +64,7 @@ public final class MetaBuildLoader extends URLClassLoader { * library. */ public static MetaBuildLoader makeLoader(final AppProvider appProvider) throws IOException { - final String jlineJars = "jline-(terminal-)?[0-9.]+-sbt-.*|jline-terminal-(jna|jansi)-[0-9.]+"; + final String jlineJars = "jline-?[0-9.]+-sbt-.*|jline-terminal(-(jna|jansi))?-[0-9.]+"; final String fullPattern = "^(test-interface-[0-9.]+|" + jlineJars + "|jansi-[0-9.]+|jna-(platform-)?[0-9.]+)\\.jar"; final Pattern pattern = Pattern.compile(fullPattern); @@ -117,6 +117,21 @@ public final class MetaBuildLoader extends URLClassLoader { if (!foundSBTLoader) topLoader = topLoader.getParent(); } if (topLoader == null) topLoader = scalaProvider.launcher().topLoader(); + // the bundled version of jansi with old versions of the launcher cause + // problems so we need to exclude it from classloading + topLoader = + new ClassLoader(topLoader) { + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + if (name.startsWith("org.fusesource")) throw new ClassNotFoundException(name); + return super.loadClass(name, resolve); + } + + @Override + public String toString() { + return "JansiExclusionClassLoader"; + } + }; final TestInterfaceLoader interfaceLoader = new TestInterfaceLoader(interfaceURLs, topLoader); final JLineLoader jlineLoader = new JLineLoader(jlineURLs, interfaceLoader); diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index 8e5ab3f79..c6200785f 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1059,8 +1059,17 @@ object Defaults extends BuildCommon { classLoaderCache: ClassLoaderCache, topLoader: ClassLoader, ): ScalaInstance = { + // Scala 2.10 shades jline in the console so we need to make sure that it loads a compatible + // jansi version. Because of the shading, console does not work with the thin client for 2.10.x. + val jansiExclusionLoader = if (version.startsWith("2.10.")) new ClassLoader(topLoader) { + override protected def loadClass(name: String, resolve: Boolean): Class[_] = { + if (name.startsWith("org.fusesource")) throw new ClassNotFoundException(name) + super.loadClass(name, resolve) + } + } + else topLoader val allJarsDistinct = allJars.distinct - val libraryLoader = classLoaderCache(libraryJars.toList, topLoader) + val libraryLoader = classLoaderCache(libraryJars.toList, jansiExclusionLoader) val fullLoader = classLoaderCache(allJarsDistinct.toList, libraryLoader) new ScalaInstance( version, diff --git a/project/Dependencies.scala b/project/Dependencies.scala index f40163d8f..2dce163ae 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -84,14 +84,14 @@ object Dependencies { val sjsonNewScalaJson = sjsonNew("sjson-new-scalajson") val sjsonNewMurmurhash = sjsonNew("sjson-new-murmurhash") - val jline = "org.scala-sbt.jline" % "jline" % "2.14.7-sbt-5e51b9d4f9631ebfa29753ce4accc57808e7fd6b" - val jline3Version = "3.16.0" // Once the base jline version is upgraded, we can use the official jline-terminal - val jline3Terminal = "org.scala-sbt.jline3" % "jline-terminal" % s"$jline3Version-sbt-211a082ed6326908dc84ca017ce4430728f18a8a" + val jline = "org.scala-sbt.jline" % "jline" % "2.14.7-sbt-42b717d4418374417765c7651dca69b1b75d8b84" + val jline3Version = "3.17.1" + val jline3Terminal = "org.jline" % "jline-terminal" % jline3Version val jline3Jansi = "org.jline" % "jline-terminal-jansi" % jline3Version val jline3JNA = "org.jline" % "jline-terminal-jna" % jline3Version val jline3Reader = "org.jline" % "jline-reader" % jline3Version val jline3Builtins = "org.jline" % "jline-builtins" % jline3Version - val jansi = "org.fusesource.jansi" % "jansi" % "1.18" + val jansi = "org.fusesource.jansi" % "jansi" % "2.0.1" val scalatest = "org.scalatest" %% "scalatest" % "3.0.8" val scalacheck = "org.scalacheck" %% "scalacheck" % "1.14.0" val specs2 = "org.specs2" %% "specs2-junit" % "4.10.0"