From f6799830c704acbc35fbccfe34be8e457a70560a Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 1 Feb 2026 20:50:12 -0500 Subject: [PATCH 1/2] Move consoleTask --- main/src/main/scala/sbt/Defaults.scala | 74 ++-------------- .../main/scala/sbt/internal/Compiler.scala | 84 ++++++++++++++++++- 2 files changed, 89 insertions(+), 69 deletions(-) diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index d837d5939..a472f6a01 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -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) = diff --git a/main/src/main/scala/sbt/internal/Compiler.scala b/main/src/main/scala/sbt/internal/Compiler.scala index f2a65b288..148a46686 100644 --- a/main/src/main/scala/sbt/internal/Compiler.scala +++ b/main/src/main/scala/sbt/internal/Compiler.scala @@ -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 From 138621eacb92b3f267726732fc7554564bcdefed Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Mon, 2 Feb 2026 00:58:32 -0500 Subject: [PATCH 2/2] [2.x] client-side console and fixes **Problem** 1. forked console is missing user code from the classpath. 2. forked console still blocks the server. **Solution** 1. This includes proper products and classpaths to the console. 2. This also implements client-side run for console. --- .../main/scala/sbt/internal/ConsoleMain.scala | 24 +++-- .../main/scala/sbt/internal/ForkConsole.scala | 15 ++-- main/src/main/scala/sbt/Defaults.scala | 7 +- .../main/scala/sbt/internal/Compiler.scala | 90 ++++++++++++++----- .../src/main/scala/sbt/internal/RunUtil.scala | 2 +- .../sbt/internal/worker/ConsoleConfig.scala | 22 +++-- .../worker/codec/ConsoleConfigFormats.scala | 8 +- protocol/src/main/contraband/worker.contra | 3 +- 8 files changed, 120 insertions(+), 51 deletions(-) diff --git a/main-actions/src/main/scala/sbt/internal/ConsoleMain.scala b/main-actions/src/main/scala/sbt/internal/ConsoleMain.scala index 64701b2f8..190a51d99 100644 --- a/main-actions/src/main/scala/sbt/internal/ConsoleMain.scala +++ b/main-actions/src/main/scala/sbt/internal/ConsoleMain.scala @@ -10,6 +10,7 @@ package sbt package internal import java.io.File +import java.net.URL import java.nio.file.Paths import sbt.internal.inc.{ AnalyzingCompiler, @@ -34,11 +35,13 @@ class ConsoleMain: val si = scalaInstance(config.scalaInstanceConfig) val compiler = analyzingCompiler(config, si) given log: Logger = ConsoleMain.consoleLogger - val externalCp = config.externalDependencyJars.map(Paths.get(_)) - val cpFiles = externalCp.map(_.toFile) + val classpathJars = config.classpathJars.map(Paths.get(_)) + val products = config.products.map(Paths.get(_)) + val cpFiles = products.map(_.toFile()) ++ classpathJars.map(_.toFile()) IO.withTemporaryDirectory: tempDir => 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( compiler = compiler, classpath = cpFiles, @@ -98,8 +101,7 @@ class ConsoleMain: .distinct val allJars = libraryJars ++ compilerJars ++ extraToolJars // Use parent class loader for JLine to avoid conflicts - val jlineLoader = classOf[org.jline.terminal.Terminal].getClassLoader - val libraryLoader = ClasspathUtil.toLoader(libraryJars, jlineLoader) + val libraryLoader = ClasspathUtil.toLoader(libraryJars, ConsoleMain.jlineLoader) val compilerLoader = ClasspathUtil.toLoader(compilerJars, libraryLoader) val fullLoader = if extraToolJars.isEmpty then compilerLoader @@ -128,6 +130,18 @@ object ConsoleMain: case Level.Warn => scala.Console.err.println(s"[warn] $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 = args.toList match case Nil => diff --git a/main-actions/src/main/scala/sbt/internal/ForkConsole.scala b/main-actions/src/main/scala/sbt/internal/ForkConsole.scala index d0de36c71..cb170b1d0 100644 --- a/main-actions/src/main/scala/sbt/internal/ForkConsole.scala +++ b/main-actions/src/main/scala/sbt/internal/ForkConsole.scala @@ -51,15 +51,7 @@ private[sbt] object ForkConsole: args: List[String], forkOptions: ForkOptions, ): Int = - val jlineJars = Seq( - 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 - + val fullCp = classpath.distinct // Build environment variables for proper terminal handling val termEnv = sys.env.get("TERM").getOrElse("xterm-256color") 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.util.Logger]), 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 end ForkConsole diff --git a/main/src/main/scala/sbt/Defaults.scala b/main/src/main/scala/sbt/Defaults.scala index a472f6a01..1c24bda64 100644 --- a/main/src/main/scala/sbt/Defaults.scala +++ b/main/src/main/scala/sbt/Defaults.scala @@ -1064,8 +1064,10 @@ object Defaults extends BuildCommon { }, compileIncSetup := Def.uncached(compileIncSetupTask.value), console := Compiler.consoleTask.value, + console / forkOptions := Def.uncached(Compiler.consoleForkOptions.value), collectAnalyses := Definition.collectAnalysesTask.map(_ => ()).value, consoleQuick := consoleQuickTask.value, + consoleQuick / forkOptions := Def.uncached((console / forkOptions).value), discoveredMainClasses := compile .map(discoverMainClasses) .storeAs(discoveredMainClasses) @@ -2109,10 +2111,11 @@ object Defaults extends BuildCommon { } def consoleProjectTask = ConsoleProject.consoleProjectTask - def consoleTask: Initialize[Task[Unit]] = Compiler.consoleTask(fullClasspath, console) + def consoleTask: Initialize[Task[Unit]] = + Compiler.consoleTask(console, exportedProductJars, fullClasspathAsJars) def consoleQuickTask = consoleTask(externalDependencyClasspath, consoleQuick) def consoleTask(classpath: TaskKey[Classpath], task: TaskKey[?]): Initialize[Task[Unit]] = - Compiler.consoleTask(classpath, task) + Compiler.consoleTask(task, Def.task(Nil), classpath) /** * Handles traditional Scalac compilation. For non-pipelined compilation, diff --git a/main/src/main/scala/sbt/internal/Compiler.scala b/main/src/main/scala/sbt/internal/Compiler.scala index 148a46686..baf677433 100644 --- a/main/src/main/scala/sbt/internal/Compiler.scala +++ b/main/src/main/scala/sbt/internal/Compiler.scala @@ -10,12 +10,16 @@ package sbt package internal import java.io.{ File, PrintWriter } +import sbt.BuildExtra.* +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.ScalaInstanceConfig +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.{ Artifact, Configuration, @@ -27,6 +31,7 @@ import sbt.librarymanagement.{ VersionNumber } import sbt.util.Logger +import sjsonnew.support.scalajson.unsafe.{ Converter, CompactPrinter } import xsbti.{ HashedVirtualFileRef, ScalaProvider } object Compiler: @@ -287,25 +292,27 @@ object Compiler: } def consoleTask: Def.Initialize[Task[Unit]] = - consoleTask(Keys.fullClasspath, Keys.console) + consoleTask(Keys.console, Keys.exportedProductJars, Keys.fullClasspath) def consoleTask( - classpath: TaskKey[Keys.Classpath], - task: TaskKey[?] + 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(classpath, task).value - else serverSideConsoleTask(classpath, task).value + if (task / Keys.fork).value then forkedConsoleTask(task, products, classpath).value + else serverSideConsoleTask(task, products, classpath).value } private def serverSideConsoleTask( - classpath: TaskKey[Keys.Classpath], - task: TaskKey[?] + 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((task / classpath).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 @@ -322,36 +329,63 @@ object Compiler: } private def forkedConsoleTask( - classpath: TaskKey[Keys.Classpath], - task: TaskKey[?] + 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()), - externalDependencyJars = depsJars.map(_.toString), + 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 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() + 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 = @@ -361,4 +395,18 @@ object Compiler: 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 diff --git a/main/src/main/scala/sbt/internal/RunUtil.scala b/main/src/main/scala/sbt/internal/RunUtil.scala index 02a0fd292..536978467 100644 --- a/main/src/main/scala/sbt/internal/RunUtil.scala +++ b/main/src/main/scala/sbt/internal/RunUtil.scala @@ -94,7 +94,7 @@ object RunUtil: private def getMainClass(value: Option[String]): String = value.getOrElse(sys.error("no main class detected")) - private def mkRunInfo( + private[sbt] def mkRunInfo( args: Vector[String], mainClass: String, cp: Classpath, diff --git a/protocol/src/main/contraband-scala/sbt/internal/worker/ConsoleConfig.scala b/protocol/src/main/contraband-scala/sbt/internal/worker/ConsoleConfig.scala index a7e5e888d..29cfca061 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/worker/ConsoleConfig.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/worker/ConsoleConfig.scala @@ -8,7 +8,8 @@ package sbt.internal.worker final class ConsoleConfig private ( val scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig, 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 initialCommands: String, 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 { - 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 }) 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 = { - "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 = { - new ConsoleConfig(scalaInstanceConfig, bridgeJars, externalDependencyJars, scalacOptions, initialCommands, cleanupCommands) + 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, products, classpathJars, scalacOptions, initialCommands, cleanupCommands) } def withScalaInstanceConfig(scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig): ConsoleConfig = { copy(scalaInstanceConfig = scalaInstanceConfig) @@ -34,8 +35,11 @@ final class ConsoleConfig private ( def withBridgeJars(bridgeJars: Vector[java.net.URI]): ConsoleConfig = { copy(bridgeJars = bridgeJars) } - def withExternalDependencyJars(externalDependencyJars: Vector[String]): ConsoleConfig = { - copy(externalDependencyJars = externalDependencyJars) + def withProducts(products: Vector[java.net.URI]): ConsoleConfig = { + copy(products = products) + } + def withClasspathJars(classpathJars: Vector[java.net.URI]): ConsoleConfig = { + copy(classpathJars = classpathJars) } def withScalacOptions(scalacOptions: Vector[String]): ConsoleConfig = { copy(scalacOptions = scalacOptions) @@ -49,5 +53,5 @@ final class ConsoleConfig private ( } 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) } diff --git a/protocol/src/main/contraband-scala/sbt/internal/worker/codec/ConsoleConfigFormats.scala b/protocol/src/main/contraband-scala/sbt/internal/worker/codec/ConsoleConfigFormats.scala index 04acf96bf..29e99c68d 100644 --- a/protocol/src/main/contraband-scala/sbt/internal/worker/codec/ConsoleConfigFormats.scala +++ b/protocol/src/main/contraband-scala/sbt/internal/worker/codec/ConsoleConfigFormats.scala @@ -13,12 +13,13 @@ given ConsoleConfigFormat: JsonFormat[sbt.internal.worker.ConsoleConfig] = new J unbuilder.beginObject(__js) val scalaInstanceConfig = unbuilder.readField[sbt.internal.worker.ScalaInstanceConfig]("scalaInstanceConfig") 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 initialCommands = unbuilder.readField[String]("initialCommands") val cleanupCommands = unbuilder.readField[String]("cleanupCommands") 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 => deserializationError("Expected JsObject but found None") } @@ -27,7 +28,8 @@ given ConsoleConfigFormat: JsonFormat[sbt.internal.worker.ConsoleConfig] = new J builder.beginObject() builder.addField("scalaInstanceConfig", obj.scalaInstanceConfig) 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("initialCommands", obj.initialCommands) builder.addField("cleanupCommands", obj.cleanupCommands) diff --git a/protocol/src/main/contraband/worker.contra b/protocol/src/main/contraband/worker.contra index a534b39ee..d24fc0043 100644 --- a/protocol/src/main/contraband/worker.contra +++ b/protocol/src/main/contraband/worker.contra @@ -63,7 +63,8 @@ type ScalaInstanceConfig { type ConsoleConfig { scalaInstanceConfig: sbt.internal.worker.ScalaInstanceConfig! bridgeJars: [java.net.URI] - externalDependencyJars: [String] + products: [java.net.URI] + classpathJars: [java.net.URI] scalacOptions: [String] initialCommands: String! cleanupCommands: String!