mirror of https://github.com/sbt/sbt.git
Merge pull request #8705 from eed3si9n/wip/console-task-follow-up
[2.x] client-side console and fixes
This commit is contained in:
commit
4681dc714c
|
|
@ -10,6 +10,7 @@ package sbt
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.net.URL
|
||||||
import java.nio.file.Paths
|
import java.nio.file.Paths
|
||||||
import sbt.internal.inc.{
|
import sbt.internal.inc.{
|
||||||
AnalyzingCompiler,
|
AnalyzingCompiler,
|
||||||
|
|
@ -34,11 +35,13 @@ class ConsoleMain:
|
||||||
val si = scalaInstance(config.scalaInstanceConfig)
|
val si = scalaInstance(config.scalaInstanceConfig)
|
||||||
val compiler = analyzingCompiler(config, si)
|
val compiler = analyzingCompiler(config, si)
|
||||||
given log: Logger = ConsoleMain.consoleLogger
|
given log: Logger = ConsoleMain.consoleLogger
|
||||||
val externalCp = config.externalDependencyJars.map(Paths.get(_))
|
val classpathJars = config.classpathJars.map(Paths.get(_))
|
||||||
val cpFiles = externalCp.map(_.toFile)
|
val products = config.products.map(Paths.get(_))
|
||||||
|
val cpFiles = products.map(_.toFile()) ++ classpathJars.map(_.toFile())
|
||||||
IO.withTemporaryDirectory: tempDir =>
|
IO.withTemporaryDirectory: tempDir =>
|
||||||
val fullCp = cpFiles ++ si.allJars
|
val fullCp = cpFiles ++ si.allJars
|
||||||
val loader = ClasspathUtil.makeLoader(fullCp.map(_.toPath), si, tempDir.toPath)
|
val loader =
|
||||||
|
ClasspathUtil.makeLoader(fullCp.map(_.toPath), ConsoleMain.jlineLoader, si, tempDir.toPath)
|
||||||
runConsole(
|
runConsole(
|
||||||
compiler = compiler,
|
compiler = compiler,
|
||||||
classpath = cpFiles,
|
classpath = cpFiles,
|
||||||
|
|
@ -98,8 +101,7 @@ class ConsoleMain:
|
||||||
.distinct
|
.distinct
|
||||||
val allJars = libraryJars ++ compilerJars ++ extraToolJars
|
val allJars = libraryJars ++ compilerJars ++ extraToolJars
|
||||||
// Use parent class loader for JLine to avoid conflicts
|
// Use parent class loader for JLine to avoid conflicts
|
||||||
val jlineLoader = classOf[org.jline.terminal.Terminal].getClassLoader
|
val libraryLoader = ClasspathUtil.toLoader(libraryJars, ConsoleMain.jlineLoader)
|
||||||
val libraryLoader = ClasspathUtil.toLoader(libraryJars, jlineLoader)
|
|
||||||
val compilerLoader = ClasspathUtil.toLoader(compilerJars, libraryLoader)
|
val compilerLoader = ClasspathUtil.toLoader(compilerJars, libraryLoader)
|
||||||
val fullLoader =
|
val fullLoader =
|
||||||
if extraToolJars.isEmpty then compilerLoader
|
if extraToolJars.isEmpty then compilerLoader
|
||||||
|
|
@ -128,6 +130,18 @@ object ConsoleMain:
|
||||||
case Level.Warn => scala.Console.err.println(s"[warn] $message")
|
case Level.Warn => scala.Console.err.println(s"[warn] $message")
|
||||||
case Level.Error => scala.Console.err.println(s"[error] $message")
|
case Level.Error => scala.Console.err.println(s"[error] $message")
|
||||||
|
|
||||||
|
class FilteredLoader(parent: ClassLoader) extends ClassLoader(parent):
|
||||||
|
override final def loadClass(className: String, resolve: Boolean): Class[?] =
|
||||||
|
if className.startsWith("org.jline.") || className.startsWith("java.") || className
|
||||||
|
.startsWith("javax.") || className.startsWith("sun.")
|
||||||
|
then super.loadClass(className, resolve)
|
||||||
|
else throw new ClassNotFoundException(className)
|
||||||
|
override def getResources(name: String): java.util.Enumeration[URL] = null
|
||||||
|
override def getResource(name: String): URL = null
|
||||||
|
end FilteredLoader
|
||||||
|
lazy val jlineLoader =
|
||||||
|
FilteredLoader(classOf[org.jline.terminal.Terminal].getClassLoader)
|
||||||
|
|
||||||
def main(args: Array[String]): Unit =
|
def main(args: Array[String]): Unit =
|
||||||
args.toList match
|
args.toList match
|
||||||
case Nil =>
|
case Nil =>
|
||||||
|
|
|
||||||
|
|
@ -51,15 +51,7 @@ private[sbt] object ForkConsole:
|
||||||
args: List[String],
|
args: List[String],
|
||||||
forkOptions: ForkOptions,
|
forkOptions: ForkOptions,
|
||||||
): Int =
|
): Int =
|
||||||
val jlineJars = Seq(
|
val fullCp = classpath.distinct
|
||||||
IO.classLocationPath(classOf[jline.Terminal]),
|
|
||||||
IO.classLocationPath(classOf[org.jline.terminal.Terminal]),
|
|
||||||
IO.classLocationPath(classOf[org.jline.reader.LineReader]),
|
|
||||||
IO.classLocationPath(classOf[org.jline.utils.InfoCmp]),
|
|
||||||
IO.classLocationPath(classOf[org.jline.keymap.KeyMap[?]]),
|
|
||||||
).distinct
|
|
||||||
val fullCp = (classpath ++ jlineJars).distinct
|
|
||||||
|
|
||||||
// Build environment variables for proper terminal handling
|
// Build environment variables for proper terminal handling
|
||||||
val termEnv = sys.env.get("TERM").getOrElse("xterm-256color")
|
val termEnv = sys.env.get("TERM").getOrElse("xterm-256color")
|
||||||
val baseEnv = forkOptions.envVars ++ Map(
|
val baseEnv = forkOptions.envVars ++ Map(
|
||||||
|
|
@ -117,6 +109,11 @@ private[sbt] object ForkConsole:
|
||||||
IO.classLocationPath(classOf[sbt.internal.inc.classpath.ClasspathUtil.type]),
|
IO.classLocationPath(classOf[sbt.internal.inc.classpath.ClasspathUtil.type]),
|
||||||
IO.classLocationPath(classOf[sbt.util.Logger]),
|
IO.classLocationPath(classOf[sbt.util.Logger]),
|
||||||
IO.classLocationPath(classOf[sjsonnew.JsonFormat[?]]),
|
IO.classLocationPath(classOf[sjsonnew.JsonFormat[?]]),
|
||||||
|
IO.classLocationPath(classOf[jline.Terminal]),
|
||||||
|
IO.classLocationPath(classOf[org.jline.terminal.Terminal]),
|
||||||
|
IO.classLocationPath(classOf[org.jline.reader.LineReader]),
|
||||||
|
IO.classLocationPath(classOf[org.jline.utils.InfoCmp]),
|
||||||
|
IO.classLocationPath(classOf[org.jline.keymap.KeyMap[?]]),
|
||||||
)
|
)
|
||||||
(urls.map(u => Paths.get(u.toURI)) ++ extraJars).distinct
|
(urls.map(u => Paths.get(u.toURI)) ++ extraJars).distinct
|
||||||
end ForkConsole
|
end ForkConsole
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
package sbt
|
package sbt
|
||||||
|
|
||||||
import java.io.{ File, PrintWriter }
|
import java.io.File
|
||||||
import java.nio.file.{ Files, Path as NioPath }
|
import java.nio.file.{ Files, Path as NioPath }
|
||||||
import java.util.{ Optional, UUID }
|
import java.util.{ Optional, UUID }
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
@ -30,7 +30,7 @@ import sbt.internal.CommandStrings.ExportStream
|
||||||
import sbt.internal.*
|
import sbt.internal.*
|
||||||
import sbt.internal.classpath.AlternativeZincUtil
|
import sbt.internal.classpath.AlternativeZincUtil
|
||||||
import sbt.internal.inc.JavaInterfaceUtil.*
|
import sbt.internal.inc.JavaInterfaceUtil.*
|
||||||
import sbt.internal.inc.classpath.{ ClasspathFilter, ClasspathUtil }
|
import sbt.internal.inc.classpath.ClasspathFilter
|
||||||
import sbt.internal.inc.{ CompileOutput, MappedFileConverter, Stamps, ZincLmUtil, ZincUtil }
|
import sbt.internal.inc.{ CompileOutput, MappedFileConverter, Stamps, ZincLmUtil, ZincUtil }
|
||||||
import sbt.internal.librarymanagement.ivy.*
|
import sbt.internal.librarymanagement.ivy.*
|
||||||
import sbt.internal.librarymanagement.mavenint.{
|
import sbt.internal.librarymanagement.mavenint.{
|
||||||
|
|
@ -1063,12 +1063,11 @@ object Defaults extends BuildCommon {
|
||||||
cache.get
|
cache.get
|
||||||
},
|
},
|
||||||
compileIncSetup := Def.uncached(compileIncSetupTask.value),
|
compileIncSetup := Def.uncached(compileIncSetupTask.value),
|
||||||
console := Def.taskDyn {
|
console := Compiler.consoleTask.value,
|
||||||
if (console / fork).value then forkedConsoleTask
|
console / forkOptions := Def.uncached(Compiler.consoleForkOptions.value),
|
||||||
else Def.task(consoleTask.value)
|
|
||||||
}.value,
|
|
||||||
collectAnalyses := Definition.collectAnalysesTask.map(_ => ()).value,
|
collectAnalyses := Definition.collectAnalysesTask.map(_ => ()).value,
|
||||||
consoleQuick := consoleQuickTask.value,
|
consoleQuick := consoleQuickTask.value,
|
||||||
|
consoleQuick / forkOptions := Def.uncached((console / forkOptions).value),
|
||||||
discoveredMainClasses := compile
|
discoveredMainClasses := compile
|
||||||
.map(discoverMainClasses)
|
.map(discoverMainClasses)
|
||||||
.storeAs(discoveredMainClasses)
|
.storeAs(discoveredMainClasses)
|
||||||
|
|
@ -2065,7 +2064,7 @@ object Defaults extends BuildCommon {
|
||||||
else Opts.doc.externalAPI(xapisFiles)
|
else Opts.doc.externalAPI(xapisFiles)
|
||||||
val options = sOpts ++ externalApiOpts
|
val options = sOpts ++ externalApiOpts
|
||||||
val scalac = cs.scalac match
|
val scalac = cs.scalac match
|
||||||
case ac: AnalyzingCompiler => ac.onArgs(exported(s, "scaladoc"))
|
case ac: AnalyzingCompiler => ac.onArgs(Compiler.exported(s, "scaladoc"))
|
||||||
val docSrcFiles = if ScalaArtifacts.isScala3(sv) then tFiles else srcs
|
val docSrcFiles = if ScalaArtifacts.isScala3(sv) then tFiles else srcs
|
||||||
// todo: cache this
|
// todo: cache this
|
||||||
if docSrcFiles.nonEmpty then
|
if docSrcFiles.nonEmpty then
|
||||||
|
|
@ -2112,67 +2111,11 @@ object Defaults extends BuildCommon {
|
||||||
}
|
}
|
||||||
|
|
||||||
def consoleProjectTask = ConsoleProject.consoleProjectTask
|
def consoleProjectTask = ConsoleProject.consoleProjectTask
|
||||||
def consoleTask: Initialize[Task[Unit]] = consoleTask(fullClasspath, console)
|
def consoleTask: Initialize[Task[Unit]] =
|
||||||
|
Compiler.consoleTask(console, exportedProductJars, fullClasspathAsJars)
|
||||||
def consoleQuickTask = consoleTask(externalDependencyClasspath, consoleQuick)
|
def consoleQuickTask = consoleTask(externalDependencyClasspath, consoleQuick)
|
||||||
def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[?]): Initialize[Task[Unit]] =
|
def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[?]): Initialize[Task[Unit]] =
|
||||||
Def.task {
|
Compiler.consoleTask(task, Def.task(Nil), classpath)
|
||||||
val si = (task / scalaInstance).value
|
|
||||||
val s = streams.value
|
|
||||||
val cp = data((task / classpath).value)
|
|
||||||
val converter = fileConverter.value
|
|
||||||
val cpFiles = cp.map(converter.toPath).map(_.toFile())
|
|
||||||
val fullcp = (cpFiles ++ si.allJars).distinct
|
|
||||||
val tempDir = IO.createUniqueDirectory((task / taskTemporaryDirectory).value).toPath
|
|
||||||
val loader = ClasspathUtil.makeLoader(fullcp.map(_.toPath), si, tempDir)
|
|
||||||
val compiler =
|
|
||||||
(task / compilers).value.scalac match {
|
|
||||||
case ac: AnalyzingCompiler => ac.onArgs(exported(s, "scala"))
|
|
||||||
}
|
|
||||||
val sc = (task / scalacOptions).value
|
|
||||||
val ic = (task / initialCommands).value
|
|
||||||
val cc = (task / cleanupCommands).value
|
|
||||||
(new Console(compiler))(cpFiles, sc, loader, ic, cc)()(using s.log).get
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
|
|
||||||
private def forkedConsoleTask: Initialize[Task[Unit]] =
|
|
||||||
Def.task {
|
|
||||||
import sbt.internal.worker.ConsoleConfig
|
|
||||||
val s = streams.value
|
|
||||||
val conv = fileConverter.value
|
|
||||||
val depsJars = (console / externalDependencyClasspath).value.toVector
|
|
||||||
.map(_.data)
|
|
||||||
.map(conv.toPath)
|
|
||||||
val siConfig = (console / scalaInstanceConfig).value
|
|
||||||
val bridgeJars = scalaCompilerBridgeJars.value
|
|
||||||
val config = ConsoleConfig(
|
|
||||||
scalaInstanceConfig = siConfig,
|
|
||||||
bridgeJars = bridgeJars.toVector.map(vf => conv.toPath(vf).toUri()),
|
|
||||||
externalDependencyJars = depsJars.map(_.toString),
|
|
||||||
scalacOptions = (console / scalacOptions).value.toVector,
|
|
||||||
initialCommands = (console / initialCommands).value,
|
|
||||||
cleanupCommands = (console / cleanupCommands).value,
|
|
||||||
)
|
|
||||||
val fo = (console / forkOptions).value
|
|
||||||
val terminal = ITerminal.console
|
|
||||||
s.log.info("running console (fork)")
|
|
||||||
try
|
|
||||||
terminal.restore()
|
|
||||||
val exitCode = ForkConsole(config, fo)
|
|
||||||
if exitCode != 0 then
|
|
||||||
throw MessageOnlyException(s"Forked console exited with code $exitCode")
|
|
||||||
finally terminal.restore()
|
|
||||||
println()
|
|
||||||
}
|
|
||||||
|
|
||||||
private def exported(w: PrintWriter, command: String): Seq[String] => Unit =
|
|
||||||
args => w.println((command +: args).mkString(" "))
|
|
||||||
|
|
||||||
private def exported(s: TaskStreams, command: String): Seq[String] => Unit = {
|
|
||||||
val w = s.text(ExportStream)
|
|
||||||
try exported(w, command)
|
|
||||||
finally w.close() // workaround for #937
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles traditional Scalac compilation. For non-pipelined compilation,
|
* Handles traditional Scalac compilation. For non-pipelined compilation,
|
||||||
|
|
@ -2319,7 +2262,7 @@ object Defaults extends BuildCommon {
|
||||||
def onArgs(cs: Compilers) =
|
def onArgs(cs: Compilers) =
|
||||||
cs.withScalac(
|
cs.withScalac(
|
||||||
cs.scalac match
|
cs.scalac match
|
||||||
case ac: AnalyzingCompiler => ac.onArgs(exported(x, "scalac"))
|
case ac: AnalyzingCompiler => ac.onArgs(Compiler.exported(x, "scalac"))
|
||||||
case x => x
|
case x => x
|
||||||
)
|
)
|
||||||
def onProgress(s: Setup) =
|
def onProgress(s: Setup) =
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,17 @@
|
||||||
package sbt
|
package sbt
|
||||||
package internal
|
package internal
|
||||||
|
|
||||||
import java.io.File
|
import java.io.{ File, PrintWriter }
|
||||||
import sbt.internal.inc.{ ScalaInstance, ZincLmUtil }
|
import sbt.BuildExtra.*
|
||||||
import sbt.internal.worker.ScalaInstanceConfig
|
import sbt.Keys.Classpath
|
||||||
|
import sbt.internal.CommandStrings
|
||||||
|
import sbt.internal.inc.{ AnalyzingCompiler, ScalaInstance, ZincLmUtil }
|
||||||
|
import sbt.internal.inc.classpath.ClasspathUtil
|
||||||
|
import sbt.internal.worker.{ ClientJobParams, ScalaInstanceConfig }
|
||||||
|
import sbt.internal.worker.codec.JsonProtocol.given
|
||||||
|
import sbt.internal.util.{ Attributed, MessageOnlyException, Terminal as ITerminal }
|
||||||
|
import sbt.io.IO
|
||||||
|
import sbt.protocol.Serialization
|
||||||
import sbt.librarymanagement.{
|
import sbt.librarymanagement.{
|
||||||
Artifact,
|
Artifact,
|
||||||
Configuration,
|
Configuration,
|
||||||
|
|
@ -23,6 +31,7 @@ import sbt.librarymanagement.{
|
||||||
VersionNumber
|
VersionNumber
|
||||||
}
|
}
|
||||||
import sbt.util.Logger
|
import sbt.util.Logger
|
||||||
|
import sjsonnew.support.scalajson.unsafe.{ Converter, CompactPrinter }
|
||||||
import xsbti.{ HashedVirtualFileRef, ScalaProvider }
|
import xsbti.{ HashedVirtualFileRef, ScalaProvider }
|
||||||
|
|
||||||
object Compiler:
|
object Compiler:
|
||||||
|
|
@ -281,4 +290,123 @@ object Compiler:
|
||||||
val conv = Keys.fileConverter.value
|
val conv = Keys.fileConverter.value
|
||||||
jars.map(jar => (conv.toVirtualFile(jar.toPath()): HashedVirtualFileRef))
|
jars.map(jar => (conv.toVirtualFile(jar.toPath()): HashedVirtualFileRef))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def consoleTask: Def.Initialize[Task[Unit]] =
|
||||||
|
consoleTask(Keys.console, Keys.exportedProductJars, Keys.fullClasspath)
|
||||||
|
|
||||||
|
def consoleTask(
|
||||||
|
task: TaskKey[?],
|
||||||
|
products: Def.Initialize[Task[Classpath]],
|
||||||
|
classpath: Def.Initialize[Task[Classpath]],
|
||||||
|
): Def.Initialize[Task[Unit]] =
|
||||||
|
Def.taskIf {
|
||||||
|
if (task / Keys.fork).value then forkedConsoleTask(task, products, classpath).value
|
||||||
|
else serverSideConsoleTask(task, products, classpath).value
|
||||||
|
}
|
||||||
|
|
||||||
|
private def serverSideConsoleTask(
|
||||||
|
task: TaskKey[?],
|
||||||
|
products: Def.Initialize[Task[Classpath]],
|
||||||
|
classpath: Def.Initialize[Task[Classpath]],
|
||||||
|
): Def.Initialize[Task[Unit]] =
|
||||||
|
Def.task {
|
||||||
|
val si = (task / Keys.scalaInstance).value
|
||||||
|
val s = Keys.streams.value
|
||||||
|
val cp = Attributed.data(classpath.value)
|
||||||
|
val converter = Keys.fileConverter.value
|
||||||
|
val cpFiles = cp.map(converter.toPath).map(_.toFile())
|
||||||
|
val fullcp = (cpFiles ++ si.allJars).distinct
|
||||||
|
val tempDir = IO.createUniqueDirectory((task / Keys.taskTemporaryDirectory).value).toPath
|
||||||
|
val loader = ClasspathUtil.makeLoader(fullcp.map(_.toPath), si, tempDir)
|
||||||
|
val compiler =
|
||||||
|
(task / Keys.compilers).value.scalac match
|
||||||
|
case ac: AnalyzingCompiler => ac.onArgs(exported(s, "scala"))
|
||||||
|
val sc = (task / Keys.scalacOptions).value
|
||||||
|
val ic = (task / Keys.initialCommands).value
|
||||||
|
val cc = (task / Keys.cleanupCommands).value
|
||||||
|
(new Console(compiler))(cpFiles, sc, loader, ic, cc)()(using s.log).get
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
private def forkedConsoleTask(
|
||||||
|
task: TaskKey[?],
|
||||||
|
products: Def.Initialize[Task[Classpath]],
|
||||||
|
classpath: Def.Initialize[Task[Classpath]],
|
||||||
|
): Def.Initialize[Task[Unit]] =
|
||||||
|
Def.task {
|
||||||
|
import sbt.internal.worker.ConsoleConfig
|
||||||
|
val s = Keys.streams.value
|
||||||
|
val conv = Keys.fileConverter.value
|
||||||
|
val cside = (task / Keys.clientSide).value
|
||||||
|
val depsJars = (task / Keys.externalDependencyClasspath).value.toVector
|
||||||
|
.map(_.data)
|
||||||
|
.map(conv.toPath)
|
||||||
|
val siConfig = (Keys.console / Keys.scalaInstanceConfig).value
|
||||||
|
val bridgeJars = Keys.scalaCompilerBridgeJars.value
|
||||||
|
val state = Keys.state.value
|
||||||
|
val config = ConsoleConfig(
|
||||||
|
scalaInstanceConfig = siConfig,
|
||||||
|
bridgeJars = bridgeJars.toVector.map(vf => conv.toPath(vf).toUri()),
|
||||||
|
products = products.value.toVector.map(vf => conv.toPath(vf.data).toUri()),
|
||||||
|
classpathJars = classpath.value.toVector.map(vf => conv.toPath(vf.data).toUri()),
|
||||||
|
scalacOptions = (task / Keys.scalacOptions).value.toVector,
|
||||||
|
initialCommands = (task / Keys.initialCommands).value,
|
||||||
|
cleanupCommands = (task / Keys.cleanupCommands).value,
|
||||||
|
)
|
||||||
|
val fo = (task / Keys.forkOptions).value
|
||||||
|
val service = Keys.bgJobService.value
|
||||||
|
if cside && state.isNetworkCommand then
|
||||||
|
val workingDir = service.createWorkingDirectory
|
||||||
|
val cp = service.copyClasspath(
|
||||||
|
products.value,
|
||||||
|
classpath.value,
|
||||||
|
workingDir,
|
||||||
|
conv,
|
||||||
|
)
|
||||||
|
val workerMainClass = classOf[ConsoleMain].getCanonicalName
|
||||||
|
val workerCp = ForkConsole.currentClasspath.map: p =>
|
||||||
|
Attributed.blank(conv.toVirtualFile(p): HashedVirtualFileRef)
|
||||||
|
val json = Converter.toJson[ConsoleConfig](config).get
|
||||||
|
val params = workingDir.toPath.resolve("console-params.json")
|
||||||
|
IO.write(params.toFile, CompactPrinter(json))
|
||||||
|
val info =
|
||||||
|
RunUtil.mkRunInfo(Vector(s"@$params"), workerMainClass, workerCp, fo, conv, None)
|
||||||
|
val result = ClientJobParams(
|
||||||
|
runInfo = info
|
||||||
|
)
|
||||||
|
import sbt.internal.worker.codec.JsonProtocol.given
|
||||||
|
state.notifyEvent(Serialization.clientJob, result)
|
||||||
|
else
|
||||||
|
val terminal = ITerminal.console
|
||||||
|
s.log.info("running console (fork)")
|
||||||
|
try
|
||||||
|
terminal.restore()
|
||||||
|
val exitCode = ForkConsole(config, fo)
|
||||||
|
if exitCode != 0 then
|
||||||
|
throw MessageOnlyException(s"Forked console exited with code $exitCode")
|
||||||
|
finally terminal.restore()
|
||||||
|
println()
|
||||||
|
}
|
||||||
|
|
||||||
|
private[sbt] def exported(w: PrintWriter, command: String): Seq[String] => Unit =
|
||||||
|
args => w.println((command +: args).mkString(" "))
|
||||||
|
|
||||||
|
private[sbt] def exported(s: Keys.TaskStreams, command: String): Seq[String] => Unit =
|
||||||
|
val w = s.text(CommandStrings.ExportStream)
|
||||||
|
try exported(w, command)
|
||||||
|
finally w.close() // workaround for gh-937
|
||||||
|
|
||||||
|
def consoleForkOptions: Def.Initialize[Task[ForkOptions]] = Def.task {
|
||||||
|
// Build environment variables for proper terminal handling
|
||||||
|
val termEnv = sys.env.get("TERM").getOrElse("xterm-256color")
|
||||||
|
ForkOptions()
|
||||||
|
.withConnectInput(true)
|
||||||
|
.withRunJVMOptions(
|
||||||
|
Vector(
|
||||||
|
s"-Dorg.jline.terminal.type=$termEnv",
|
||||||
|
"-Djline.terminal=auto",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.withEnvVars(sys.env)
|
||||||
|
}
|
||||||
end Compiler
|
end Compiler
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ object RunUtil:
|
||||||
private def getMainClass(value: Option[String]): String =
|
private def getMainClass(value: Option[String]): String =
|
||||||
value.getOrElse(sys.error("no main class detected"))
|
value.getOrElse(sys.error("no main class detected"))
|
||||||
|
|
||||||
private def mkRunInfo(
|
private[sbt] def mkRunInfo(
|
||||||
args: Vector[String],
|
args: Vector[String],
|
||||||
mainClass: String,
|
mainClass: String,
|
||||||
cp: Classpath,
|
cp: Classpath,
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,8 @@ package sbt.internal.worker
|
||||||
final class ConsoleConfig private (
|
final class ConsoleConfig private (
|
||||||
val scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig,
|
val scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig,
|
||||||
val bridgeJars: Vector[java.net.URI],
|
val bridgeJars: Vector[java.net.URI],
|
||||||
val externalDependencyJars: Vector[String],
|
val products: Vector[java.net.URI],
|
||||||
|
val classpathJars: Vector[java.net.URI],
|
||||||
val scalacOptions: Vector[String],
|
val scalacOptions: Vector[String],
|
||||||
val initialCommands: String,
|
val initialCommands: String,
|
||||||
val cleanupCommands: String) extends Serializable {
|
val cleanupCommands: String) extends Serializable {
|
||||||
|
|
@ -16,17 +17,17 @@ final class ConsoleConfig private (
|
||||||
|
|
||||||
|
|
||||||
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
|
override def equals(o: Any): Boolean = this.eq(o.asInstanceOf[AnyRef]) || (o match {
|
||||||
case x: ConsoleConfig => (this.scalaInstanceConfig == x.scalaInstanceConfig) && (this.bridgeJars == x.bridgeJars) && (this.externalDependencyJars == x.externalDependencyJars) && (this.scalacOptions == x.scalacOptions) && (this.initialCommands == x.initialCommands) && (this.cleanupCommands == x.cleanupCommands)
|
case x: ConsoleConfig => (this.scalaInstanceConfig == x.scalaInstanceConfig) && (this.bridgeJars == x.bridgeJars) && (this.products == x.products) && (this.classpathJars == x.classpathJars) && (this.scalacOptions == x.scalacOptions) && (this.initialCommands == x.initialCommands) && (this.cleanupCommands == x.cleanupCommands)
|
||||||
case _ => false
|
case _ => false
|
||||||
})
|
})
|
||||||
override def hashCode: Int = {
|
override def hashCode: Int = {
|
||||||
37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.worker.ConsoleConfig".##) + scalaInstanceConfig.##) + bridgeJars.##) + externalDependencyJars.##) + scalacOptions.##) + initialCommands.##) + cleanupCommands.##)
|
37 * (37 * (37 * (37 * (37 * (37 * (37 * (37 * (17 + "sbt.internal.worker.ConsoleConfig".##) + scalaInstanceConfig.##) + bridgeJars.##) + products.##) + classpathJars.##) + scalacOptions.##) + initialCommands.##) + cleanupCommands.##)
|
||||||
}
|
}
|
||||||
override def toString: String = {
|
override def toString: String = {
|
||||||
"ConsoleConfig(" + scalaInstanceConfig + ", " + bridgeJars + ", " + externalDependencyJars + ", " + scalacOptions + ", " + initialCommands + ", " + cleanupCommands + ")"
|
"ConsoleConfig(" + scalaInstanceConfig + ", " + bridgeJars + ", " + products + ", " + classpathJars + ", " + scalacOptions + ", " + initialCommands + ", " + cleanupCommands + ")"
|
||||||
}
|
}
|
||||||
private def copy(scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig = scalaInstanceConfig, bridgeJars: Vector[java.net.URI] = bridgeJars, externalDependencyJars: Vector[String] = externalDependencyJars, scalacOptions: Vector[String] = scalacOptions, initialCommands: String = initialCommands, cleanupCommands: String = cleanupCommands): ConsoleConfig = {
|
private def copy(scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig = scalaInstanceConfig, bridgeJars: Vector[java.net.URI] = bridgeJars, products: Vector[java.net.URI] = products, classpathJars: Vector[java.net.URI] = classpathJars, scalacOptions: Vector[String] = scalacOptions, initialCommands: String = initialCommands, cleanupCommands: String = cleanupCommands): ConsoleConfig = {
|
||||||
new ConsoleConfig(scalaInstanceConfig, bridgeJars, externalDependencyJars, scalacOptions, initialCommands, cleanupCommands)
|
new ConsoleConfig(scalaInstanceConfig, bridgeJars, products, classpathJars, scalacOptions, initialCommands, cleanupCommands)
|
||||||
}
|
}
|
||||||
def withScalaInstanceConfig(scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig): ConsoleConfig = {
|
def withScalaInstanceConfig(scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig): ConsoleConfig = {
|
||||||
copy(scalaInstanceConfig = scalaInstanceConfig)
|
copy(scalaInstanceConfig = scalaInstanceConfig)
|
||||||
|
|
@ -34,8 +35,11 @@ final class ConsoleConfig private (
|
||||||
def withBridgeJars(bridgeJars: Vector[java.net.URI]): ConsoleConfig = {
|
def withBridgeJars(bridgeJars: Vector[java.net.URI]): ConsoleConfig = {
|
||||||
copy(bridgeJars = bridgeJars)
|
copy(bridgeJars = bridgeJars)
|
||||||
}
|
}
|
||||||
def withExternalDependencyJars(externalDependencyJars: Vector[String]): ConsoleConfig = {
|
def withProducts(products: Vector[java.net.URI]): ConsoleConfig = {
|
||||||
copy(externalDependencyJars = externalDependencyJars)
|
copy(products = products)
|
||||||
|
}
|
||||||
|
def withClasspathJars(classpathJars: Vector[java.net.URI]): ConsoleConfig = {
|
||||||
|
copy(classpathJars = classpathJars)
|
||||||
}
|
}
|
||||||
def withScalacOptions(scalacOptions: Vector[String]): ConsoleConfig = {
|
def withScalacOptions(scalacOptions: Vector[String]): ConsoleConfig = {
|
||||||
copy(scalacOptions = scalacOptions)
|
copy(scalacOptions = scalacOptions)
|
||||||
|
|
@ -49,5 +53,5 @@ final class ConsoleConfig private (
|
||||||
}
|
}
|
||||||
object ConsoleConfig {
|
object ConsoleConfig {
|
||||||
|
|
||||||
def apply(scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig, bridgeJars: Vector[java.net.URI], externalDependencyJars: Vector[String], scalacOptions: Vector[String], initialCommands: String, cleanupCommands: String): ConsoleConfig = new ConsoleConfig(scalaInstanceConfig, bridgeJars, externalDependencyJars, scalacOptions, initialCommands, cleanupCommands)
|
def apply(scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig, bridgeJars: Vector[java.net.URI], products: Vector[java.net.URI], classpathJars: Vector[java.net.URI], scalacOptions: Vector[String], initialCommands: String, cleanupCommands: String): ConsoleConfig = new ConsoleConfig(scalaInstanceConfig, bridgeJars, products, classpathJars, scalacOptions, initialCommands, cleanupCommands)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,13 @@ given ConsoleConfigFormat: JsonFormat[sbt.internal.worker.ConsoleConfig] = new J
|
||||||
unbuilder.beginObject(__js)
|
unbuilder.beginObject(__js)
|
||||||
val scalaInstanceConfig = unbuilder.readField[sbt.internal.worker.ScalaInstanceConfig]("scalaInstanceConfig")
|
val scalaInstanceConfig = unbuilder.readField[sbt.internal.worker.ScalaInstanceConfig]("scalaInstanceConfig")
|
||||||
val bridgeJars = unbuilder.readField[Vector[java.net.URI]]("bridgeJars")
|
val bridgeJars = unbuilder.readField[Vector[java.net.URI]]("bridgeJars")
|
||||||
val externalDependencyJars = unbuilder.readField[Vector[String]]("externalDependencyJars")
|
val products = unbuilder.readField[Vector[java.net.URI]]("products")
|
||||||
|
val classpathJars = unbuilder.readField[Vector[java.net.URI]]("classpathJars")
|
||||||
val scalacOptions = unbuilder.readField[Vector[String]]("scalacOptions")
|
val scalacOptions = unbuilder.readField[Vector[String]]("scalacOptions")
|
||||||
val initialCommands = unbuilder.readField[String]("initialCommands")
|
val initialCommands = unbuilder.readField[String]("initialCommands")
|
||||||
val cleanupCommands = unbuilder.readField[String]("cleanupCommands")
|
val cleanupCommands = unbuilder.readField[String]("cleanupCommands")
|
||||||
unbuilder.endObject()
|
unbuilder.endObject()
|
||||||
sbt.internal.worker.ConsoleConfig(scalaInstanceConfig, bridgeJars, externalDependencyJars, scalacOptions, initialCommands, cleanupCommands)
|
sbt.internal.worker.ConsoleConfig(scalaInstanceConfig, bridgeJars, products, classpathJars, scalacOptions, initialCommands, cleanupCommands)
|
||||||
case None =>
|
case None =>
|
||||||
deserializationError("Expected JsObject but found None")
|
deserializationError("Expected JsObject but found None")
|
||||||
}
|
}
|
||||||
|
|
@ -27,7 +28,8 @@ given ConsoleConfigFormat: JsonFormat[sbt.internal.worker.ConsoleConfig] = new J
|
||||||
builder.beginObject()
|
builder.beginObject()
|
||||||
builder.addField("scalaInstanceConfig", obj.scalaInstanceConfig)
|
builder.addField("scalaInstanceConfig", obj.scalaInstanceConfig)
|
||||||
builder.addField("bridgeJars", obj.bridgeJars)
|
builder.addField("bridgeJars", obj.bridgeJars)
|
||||||
builder.addField("externalDependencyJars", obj.externalDependencyJars)
|
builder.addField("products", obj.products)
|
||||||
|
builder.addField("classpathJars", obj.classpathJars)
|
||||||
builder.addField("scalacOptions", obj.scalacOptions)
|
builder.addField("scalacOptions", obj.scalacOptions)
|
||||||
builder.addField("initialCommands", obj.initialCommands)
|
builder.addField("initialCommands", obj.initialCommands)
|
||||||
builder.addField("cleanupCommands", obj.cleanupCommands)
|
builder.addField("cleanupCommands", obj.cleanupCommands)
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ type ScalaInstanceConfig {
|
||||||
type ConsoleConfig {
|
type ConsoleConfig {
|
||||||
scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig!
|
scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig!
|
||||||
bridgeJars: [java.net.URI]
|
bridgeJars: [java.net.URI]
|
||||||
externalDependencyJars: [String]
|
products: [java.net.URI]
|
||||||
|
classpathJars: [java.net.URI]
|
||||||
scalacOptions: [String]
|
scalacOptions: [String]
|
||||||
initialCommands: String!
|
initialCommands: String!
|
||||||
cleanupCommands: String!
|
cleanupCommands: String!
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue