Move consoleTask

This commit is contained in:
Eugene Yokota 2026-02-01 20:50:12 -05:00
parent 772f616a29
commit f6799830c7
2 changed files with 89 additions and 69 deletions

View File

@ -8,7 +8,7 @@
package sbt
import java.io.{ File, PrintWriter }
import java.io.File
import java.nio.file.{ Files, Path as NioPath }
import java.util.{ Optional, UUID }
import java.util.concurrent.TimeUnit
@ -30,7 +30,7 @@ import sbt.internal.CommandStrings.ExportStream
import sbt.internal.*
import sbt.internal.classpath.AlternativeZincUtil
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.librarymanagement.ivy.*
import sbt.internal.librarymanagement.mavenint.{
@ -1063,10 +1063,7 @@ object Defaults extends BuildCommon {
cache.get
},
compileIncSetup := Def.uncached(compileIncSetupTask.value),
console := Def.taskDyn {
if (console / fork).value then forkedConsoleTask
else Def.task(consoleTask.value)
}.value,
console := Compiler.consoleTask.value,
collectAnalyses := Definition.collectAnalysesTask.map(_ => ()).value,
consoleQuick := consoleQuickTask.value,
discoveredMainClasses := compile
@ -2065,7 +2062,7 @@ object Defaults extends BuildCommon {
else Opts.doc.externalAPI(xapisFiles)
val options = sOpts ++ externalApiOpts
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
// todo: cache this
if docSrcFiles.nonEmpty then
@ -2112,67 +2109,10 @@ object Defaults extends BuildCommon {
}
def consoleProjectTask = ConsoleProject.consoleProjectTask
def consoleTask: Initialize[Task[Unit]] = consoleTask(fullClasspath, console)
def consoleTask: Initialize[Task[Unit]] = Compiler.consoleTask(fullClasspath, console)
def consoleQuickTask = consoleTask(externalDependencyClasspath, consoleQuick)
def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[?]): Initialize[Task[Unit]] =
Def.task {
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
}
Compiler.consoleTask(classpath, task)
/**
* Handles traditional Scalac compilation. For non-pipelined compilation,
@ -2319,7 +2259,7 @@ object Defaults extends BuildCommon {
def onArgs(cs: Compilers) =
cs.withScalac(
cs.scalac match
case ac: AnalyzingCompiler => ac.onArgs(exported(x, "scalac"))
case ac: AnalyzingCompiler => ac.onArgs(Compiler.exported(x, "scalac"))
case x => x
)
def onProgress(s: Setup) =

View File

@ -9,9 +9,13 @@
package sbt
package internal
import java.io.File
import sbt.internal.inc.{ ScalaInstance, ZincLmUtil }
import java.io.{ File, PrintWriter }
import sbt.internal.CommandStrings
import sbt.internal.inc.{ AnalyzingCompiler, ScalaInstance, ZincLmUtil }
import sbt.internal.inc.classpath.ClasspathUtil
import sbt.internal.worker.ScalaInstanceConfig
import sbt.internal.util.{ Attributed, MessageOnlyException, Terminal as ITerminal }
import sbt.io.IO
import sbt.librarymanagement.{
Artifact,
Configuration,
@ -281,4 +285,80 @@ object Compiler:
val conv = Keys.fileConverter.value
jars.map(jar => (conv.toVirtualFile(jar.toPath()): HashedVirtualFileRef))
}
def consoleTask: Def.Initialize[Task[Unit]] =
consoleTask(Keys.fullClasspath, Keys.console)
def consoleTask(
classpath: TaskKey[Keys.Classpath],
task: TaskKey[?]
): Def.Initialize[Task[Unit]] =
Def.taskIf {
if (task / Keys.fork).value then forkedConsoleTask(classpath, task).value
else serverSideConsoleTask(classpath, task).value
}
private def serverSideConsoleTask(
classpath: TaskKey[Keys.Classpath],
task: TaskKey[?]
): Def.Initialize[Task[Unit]] =
Def.task {
val si = (task / Keys.scalaInstance).value
val s = Keys.streams.value
val cp = Attributed.data((task / 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(
classpath: TaskKey[Keys.Classpath],
task: TaskKey[?]
): Def.Initialize[Task[Unit]] =
Def.task {
import sbt.internal.worker.ConsoleConfig
val s = Keys.streams.value
val conv = Keys.fileConverter.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 config = ConsoleConfig(
scalaInstanceConfig = siConfig,
bridgeJars = bridgeJars.toVector.map(vf => conv.toPath(vf).toUri()),
externalDependencyJars = depsJars.map(_.toString),
scalacOptions = (task / Keys.scalacOptions).value.toVector,
initialCommands = (task / Keys.initialCommands).value,
cleanupCommands = (task / Keys.cleanupCommands).value,
)
val fo = (task / Keys.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[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
end Compiler