From 4ff27d7ab7aa02fea0d5dced81679441b9252951 Mon Sep 17 00:00:00 2001 From: Eugene Yokota Date: Sun, 30 Jan 2022 13:23:36 -0500 Subject: [PATCH] Port commandProj --- build.sbt | 5 +- .../main/scala/sbt/BasicCommandStrings.scala | 58 +++---- .../src/main/scala/sbt/BasicCommands.scala | 40 ++--- .../src/main/scala/sbt/CommandUtil.scala | 22 +-- main-command/src/main/scala/sbt/State.scala | 73 ++++----- main-command/src/main/scala/sbt/Watched.scala | 2 +- .../scala/sbt/internal/CommandChannel.scala | 2 +- .../scala/sbt/internal/LegacyWatched.scala | 19 +-- .../internal/classpath/ClassLoaderCache.scala | 52 +++---- .../scala/sbt/internal/client/BspClient.scala | 3 +- .../sbt/internal/client/NetworkClient.scala | 141 ++++++++++-------- .../scala/sbt/internal/server/Server.scala | 2 +- .../sbt/internal/server/ServerHandler.scala | 6 +- .../main/scala/sbt/internal/ui/UITask.scala | 2 +- .../util/ReadJsonFromInputStream.scala | 52 ++++--- project/Dependencies.scala | 9 +- 16 files changed, 253 insertions(+), 235 deletions(-) diff --git a/build.sbt b/build.sbt index 0adfa47c1..1a7ee90c4 100644 --- a/build.sbt +++ b/build.sbt @@ -10,10 +10,10 @@ import scala.util.Try // ThisBuild settings take lower precedence, // but can be shared across the multi projects. ThisBuild / version := { - val v = "1.8.1-SNAPSHOT" + val v = "2.0.0-alpha1-SNAPSHOT" nightlyVersion.getOrElse(v) } -ThisBuild / version2_13 := "2.0.0-SNAPSHOT" +ThisBuild / version2_13 := "2.0.0-alpha1-SNAPSHOT" ThisBuild / versionScheme := Some("early-semver") ThisBuild / scalafmtOnCompile := !(Global / insideCI).value ThisBuild / Test / scalafmtOnCompile := !(Global / insideCI).value @@ -183,7 +183,6 @@ lazy val sbtRoot: Project = (project in file(".")) .aggregate( (allProjects diff Seq( actionsProj, - commandProj, mainSettingsProj, zincLmIntegrationProj, scriptedSbtReduxProj, diff --git a/main-command/src/main/scala/sbt/BasicCommandStrings.scala b/main-command/src/main/scala/sbt/BasicCommandStrings.scala index f70e350d6..7945eac96 100644 --- a/main-command/src/main/scala/sbt/BasicCommandStrings.scala +++ b/main-command/src/main/scala/sbt/BasicCommandStrings.scala @@ -19,7 +19,7 @@ object BasicCommandStrings { val TemplateCommand: String = "new" val Cancel: String = "cancel" - /** The command name to terminate the program.*/ + /** The command name to terminate the program. */ val TerminateAction: String = Exit def helpBrief: (String, String) = @@ -74,16 +74,16 @@ $HelpCommand private[this] def logLevelDetail(level: Level.Value): String = s"""$level - Sets the global logging level to $level. - This will be used as the default level for logging from commands, settings, and tasks. - Any explicit `logLevel` configuration in a project overrides this setting. + Sets the global logging level to $level. + This will be used as the default level for logging from commands, settings, and tasks. + Any explicit `logLevel` configuration in a project overrides this setting. -$level OR --$level - Sets the global logging level as described above, but does so before any other commands are executed on startup, including project loading. - This is useful as a startup option: - * it takes effect before any logging occurs - * if no other commands are passed, interactive mode is still entered + Sets the global logging level as described above, but does so before any other commands are executed on startup, including project loading. + This is useful as a startup option: + * it takes effect before any logging occurs + * if no other commands are passed, interactive mode is still entered """ def runEarly(command: String): String = s"$EarlyCommand($command)" @@ -102,8 +102,8 @@ $HelpCommand val EarlyCommandDetailed: String = s"""$EarlyCommand() - Schedules an early command, which will be run before other commands on the command line. - The order is preserved between all early commands, so `sbt "early(a)" "early(b)"` executes `a` and `b` in order. + Schedules an early command, which will be run before other commands on the command line. + The order is preserved between all early commands, so `sbt "early(a)" "early(b)"` executes `a` and `b` in order. """ def addPluginSbtFileHelp(): Help = { @@ -119,21 +119,21 @@ $HelpCommand def ReadDetailed: String = ReadCommand + ReadFiles + """ - Reads the lines from the given files and inserts them as commands. - All empty lines and lines that start with '#' are ignored. - If a file does not exist or is not readable, this command fails. + Reads the lines from the given files and inserts them as commands. + All empty lines and lines that start with '#' are ignored. + If a file does not exist or is not readable, this command fails. - All the lines from all the files are read before any of the commands - are executed. Thus, if any file is not readable, none of commands - from any of the files (even the existing ones) will be run. + All the lines from all the files are read before any of the commands + are executed. Thus, if any file is not readable, none of commands + from any of the files (even the existing ones) will be run. - You probably need to escape this command if entering it at your shell.""" + You probably need to escape this command if entering it at your shell.""" def ApplyCommand: String = "apply" def ApplyDetailed: String = ApplyCommand + """ [-cp|-classpath ] * - Transforms the current State by calling .apply(currentState) for each listed module name. - Here, currentState is of type sbt.State. + Transforms the current State by calling .apply(currentState) for each listed module name. + Here, currentState is of type sbt.State. If a classpath is provided, modules are loaded from a new class loader for this classpath. """ @@ -143,14 +143,14 @@ $HelpCommand def RebootDetailed: String = RebootCommand + """ [dev | full] - This command is equivalent to exiting sbt, restarting, and running the - remaining commands with the exception that the JVM is not shut down. + This command is equivalent to exiting sbt, restarting, and running the + remaining commands with the exception that the JVM is not shut down. - If 'dev' is specified, the current sbt artifacts from the boot directory - (`~/.sbt/boot` by default) are deleted before restarting. - This forces an update of sbt and Scala, which is useful when working with development - versions of sbt. - If 'full' is specified, the boot directory is wiped out before restarting. + If 'dev' is specified, the current sbt artifacts from the boot directory + (`~/.sbt/boot` by default) are deleted before restarting. + This forces an update of sbt and Scala, which is useful when working with development + versions of sbt. + If 'full' is specified, the boot directory is wiped out before restarting. """ def Multi: String = ";" @@ -197,8 +197,8 @@ $AliasCommand name= def StartServer = "startServer" def StartServerDetailed: String = s"""$StartServer - Starts the server if it has not been started. This is intended to be used with - -Dsbt.server.autostart=false.""" + Starts the server if it has not been started. This is intended to be used with + -Dsbt.server.autostart=false.""" def ServerDetailed: String = "--server always runs sbt in not-daemon mode." @@ -243,7 +243,7 @@ $AliasCommand name= def IfLastDetailed = s"""$IfLast - $IfLastCommon""" + $IfLastCommon""" val ContinuousExecutePrefix = "~" def continuousDetail: String = "Executes the specified command whenever source files change." diff --git a/main-command/src/main/scala/sbt/BasicCommands.scala b/main-command/src/main/scala/sbt/BasicCommands.scala index 06b7599f1..b6bcff9a8 100644 --- a/main-command/src/main/scala/sbt/BasicCommands.scala +++ b/main-command/src/main/scala/sbt/BasicCommands.scala @@ -74,7 +74,9 @@ object BasicCommands { def early: Command = Command.arb(earlyParser, earlyHelp)((s, other) => other :: s) private[this] def levelParser: Parser[String] = - Iterator(Level.Debug, Level.Info, Level.Warn, Level.Error) map (l => token(l.toString)) reduce (_ | _) + Iterator(Level.Debug, Level.Info, Level.Warn, Level.Error) map (l => + token(l.toString) + ) reduce (_ | _) private[this] def addPluginSbtFileParser: Parser[File] = { token(AddPluginSbtFileCommand) ~> (":" | "=" | Space.map(_.toString)) ~> (StringBasic).examples( @@ -87,8 +89,8 @@ object BasicCommands { private[this] def addPluginSbtFileStringParser: Parser[String] = { token( token(AddPluginSbtFileCommand) ~ (":" | "=" | Space.map(_.toString)) ~ (StringBasic) - .examples("/some/extra.sbt") map { - case s1 ~ s2 ~ s3 => s1 + s2 + s3 + .examples("/some/extra.sbt") map { case s1 ~ s2 ~ s3 => + s1 + s2 + s3 } ) } @@ -106,7 +108,7 @@ object BasicCommands { * Adds additional *.sbt to the plugin build. * This must be combined with early command as: --addPluginSbtFile=/tmp/extra.sbt */ - def addPluginSbtFile: Command = Command.arb(_ => addPluginSbtFileParser, addPluginSbtFileHelp) { + def addPluginSbtFile: Command = Command.arb(_ => addPluginSbtFileParser, addPluginSbtFileHelp()) { (s, extraSbtFile) => val extraFiles = s.get(BasicKeys.extraMetaSbtFiles).toList.flatten s.put(BasicKeys.extraMetaSbtFiles, (extraFiles: Seq[File]) :+ extraSbtFile) @@ -115,10 +117,9 @@ object BasicCommands { def help: Command = Command.make(HelpCommand, helpBrief, helpDetailed)(helpParser) def helpParser(s: State): Parser[() => State] = { - val h = s.definedCommands.foldLeft(Help.empty)( - (a, b) => - a ++ (try b.help(s) - catch { case NonFatal(_) => Help.empty }) + val h = s.definedCommands.foldLeft(Help.empty)((a, b) => + a ++ (try b.help(s) + catch { case NonFatal(_) => Help.empty }) ) val helpCommands = h.detail.keySet val spacedArg = singleArgument(helpCommands).? @@ -136,8 +137,9 @@ object BasicCommands { case Nil => none[String] case xs => xs.mkString(" ").some } - val message = try Help.message(h, topic) - catch { case NonFatal(ex) => ex.toString } + val message = + try Help.message(h, topic) + catch { case NonFatal(ex) => ex.toString } System.out.println(message) s.copy(remainingCommands = remainingCommands) } @@ -276,8 +278,8 @@ object BasicCommands { matched((s.combinedParser: Parser[_]) | token(any, hide = const(true))) def ifLast: Command = - Command(IfLast, Help.more(IfLast, IfLastDetailed))(otherCommandParser)( - (s, arg) => if (s.remainingCommands.isEmpty) arg :: s else s + Command(IfLast, Help.more(IfLast, IfLastDetailed))(otherCommandParser)((s, arg) => + if (s.remainingCommands.isEmpty) arg :: s else s ) def append: Command = @@ -286,15 +288,15 @@ object BasicCommands { ) def setOnFailure: Command = - Command(OnFailure, Help.more(OnFailure, OnFailureDetailed))(otherCommandParser)( - (s, arg) => s.copy(onFailure = Some(Exec(arg, s.source))) + Command(OnFailure, Help.more(OnFailure, OnFailureDetailed))(otherCommandParser)((s, arg) => + s.copy(onFailure = Some(Exec(arg, s.source))) ) def clearOnFailure: Command = Command.command(ClearOnFailure)(s => s.copy(onFailure = None)) def stashOnFailure: Command = - Command.command(StashOnFailure)( - s => s.copy(onFailure = None).update(OnFailureStack)(s.onFailure :: _.toList.flatten) + Command.command(StashOnFailure)(s => + s.copy(onFailure = None).update(OnFailureStack)(s.onFailure :: _.toList.flatten) ) def popOnFailure: Command = Command.command(PopOnFailure) { s => @@ -346,8 +348,8 @@ object BasicCommands { private[this] def className: Parser[String] = { val base = StringBasic & not('-' ~> any.*, "Class name cannot start with '-'.") def single(s: String) = Completions.single(Completion.displayOnly(s)) - val compl = TokenCompletions.fixed( - (seen, _) => if (seen.startsWith("-")) Completions.nil else single("") + val compl = TokenCompletions.fixed((seen, _) => + if (seen.startsWith("-")) Completions.nil else single("") ) token(base, compl) } @@ -391,7 +393,7 @@ object BasicCommands { val lines = hp.toList.flatMap(p => IO.readLines(p)).toIndexedSeq histFun(CHistory(lines, hp)) match { case Some(commands) => - commands foreach println //printing is more appropriate than logging + commands foreach println // printing is more appropriate than logging (commands ::: s).continue case None => s.fail } diff --git a/main-command/src/main/scala/sbt/CommandUtil.scala b/main-command/src/main/scala/sbt/CommandUtil.scala index dc2f52476..3e80ad437 100644 --- a/main-command/src/main/scala/sbt/CommandUtil.scala +++ b/main-command/src/main/scala/sbt/CommandUtil.scala @@ -9,6 +9,7 @@ package sbt import java.io.File import java.util.regex.{ Pattern, PatternSyntaxException } +import scala.collection.immutable.StringOps import sbt.internal.util.AttributeKey import sbt.internal.util.complete.Parser @@ -42,7 +43,7 @@ object CommandUtil { for ((a, b) <- in) yield pre + fill(a, width) + sep + b } - def fill(s: String, size: Int): String = s + " " * math.max(size - s.length, 0) + def fill(s: String, size: Int): String = s + StringOps(" ") * math.max(size - s.length, 0) def withAttribute[T](s: State, key: AttributeKey[T], ifMissing: String)(f: T => State): State = s get key match { @@ -74,16 +75,15 @@ object CommandUtil { def searchHelp(selected: String, detailMap: Map[String, String]): Map[String, String] = { val pattern = Pattern.compile(selected, HelpPatternFlags) - detailMap flatMap { - case (k, v) => - val contentMatches = Highlight.showMatches(pattern)(v) - val keyMatches = Highlight.showMatches(pattern)(k) - val keyString = Highlight.bold(keyMatches getOrElse k) - val contentString = contentMatches getOrElse v - if (keyMatches.isDefined || contentMatches.isDefined) - Seq((keyString, contentString)) - else - nilSeq + detailMap flatMap { case (k, v) => + val contentMatches = Highlight.showMatches(pattern)(v) + val keyMatches = Highlight.showMatches(pattern)(k) + val keyString = Highlight.bold(keyMatches getOrElse k) + val contentString = contentMatches getOrElse v + if (keyMatches.isDefined || contentMatches.isDefined) + Seq((keyString, contentString)) + else + nilSeq } } diff --git a/main-command/src/main/scala/sbt/State.scala b/main-command/src/main/scala/sbt/State.scala index 00a2d946f..8b43bc7db 100644 --- a/main-command/src/main/scala/sbt/State.scala +++ b/main-command/src/main/scala/sbt/State.scala @@ -99,19 +99,19 @@ trait Identity { trait StateOps extends Any { def process(f: (Exec, State) => State): State - /** Schedules `commands` to be run before any remaining commands.*/ + /** Schedules `commands` to be run before any remaining commands. */ def :::(newCommands: List[String]): State - /** Schedules `commands` to be run before any remaining commands.*/ + /** Schedules `commands` to be run before any remaining commands. */ def ++:(newCommands: List[Exec]): State - /** Schedules `command` to be run before any remaining commands.*/ + /** Schedules `command` to be run before any remaining commands. */ def ::(command: String): State - /** Schedules `command` to be run before any remaining commands.*/ + /** Schedules `command` to be run before any remaining commands. */ def +:(command: Exec): State - /** Sets the next command processing action to be to continue processing the next command.*/ + /** Sets the next command processing action to be to continue processing the next command. */ def continue: State /** @@ -135,7 +135,7 @@ trait StateOps extends Any { */ private[sbt] def reboot(full: Boolean, currentOnly: Boolean): State - /** Sets the next command processing action to do.*/ + /** Sets the next command processing action to do. */ def setNext(n: State.Next): State /** @@ -145,16 +145,16 @@ trait StateOps extends Any { */ def reload: State - /** Sets the next command processing action to be to rotate the global log and continue executing commands.*/ + /** Sets the next command processing action to be to rotate the global log and continue executing commands. */ def clearGlobalLog: State - /** Sets the next command processing action to be to keep the previous log and continue executing commands. */ + /** Sets the next command processing action to be to keep the previous log and continue executing commands. */ def keepLastLog: State - /** Sets the next command processing action to be to exit with a zero exit code if `ok` is true and a nonzero exit code if `ok` if false.*/ + /** Sets the next command processing action to be to exit with a zero exit code if `ok` is true and a nonzero exit code if `ok` if false. */ def exit(ok: Boolean): State - /** Marks the currently executing command as failing. This triggers failure handling by the command processor. See also `State.onFailure`*/ + /** Marks the currently executing command as failing. This triggers failure handling by the command processor. See also `State.onFailure` */ def fail: State /** @@ -171,46 +171,46 @@ trait StateOps extends Any { /** Registers `newCommand` as an available command. */ def +(newCommand: Command): State - /** Gets the value associated with `key` from the custom attributes map.*/ + /** Gets the value associated with `key` from the custom attributes map. */ def get[T](key: AttributeKey[T]): Option[T] - /** Sets the value associated with `key` in the custom attributes map.*/ + /** Sets the value associated with `key` in the custom attributes map. */ def put[T](key: AttributeKey[T], value: T): State - /** Removes the `key` and any associated value from the custom attributes map.*/ + /** Removes the `key` and any associated value from the custom attributes map. */ def remove(key: AttributeKey[_]): State - /** Sets the value associated with `key` in the custom attributes map by transforming the current value.*/ + /** Sets the value associated with `key` in the custom attributes map by transforming the current value. */ def update[T](key: AttributeKey[T])(f: Option[T] => T): State - /** Returns true if `key` exists in the custom attributes map, false if it does not exist.*/ + /** Returns true if `key` exists in the custom attributes map, false if it does not exist. */ def has(key: AttributeKey[_]): Boolean - /** The application base directory, which is not necessarily the current working directory.*/ + /** The application base directory, which is not necessarily the current working directory. */ def baseDir: File - /** The Logger used for general command logging.*/ + /** The Logger used for general command logging. */ def log: Logger - /** Evaluates the provided expression with a JVM-wide and machine-wide lock on `file`.*/ + /** Evaluates the provided expression with a JVM-wide and machine-wide lock on `file`. */ def locked[T](file: File)(t: => T): T - /** Runs any defined exitHooks and then clears them.*/ + /** Runs any defined exitHooks and then clears them. */ def runExitHooks(): State - /** Registers a new exit hook, which will run when sbt exits or restarts.*/ + /** Registers a new exit hook, which will run when sbt exits or restarts. */ def addExitHook(f: => Unit): State - /** An advisory flag that is `true` if this application will execute commands based on user input.*/ + /** An advisory flag that is `true` if this application will execute commands based on user input. */ def interactive: Boolean /** Changes the advisory `interactive` flag. */ def setInteractive(flag: Boolean): State - /** Get the class loader cache for the application.*/ + /** Get the class loader cache for the application. */ def classLoaderCache: IncClassLoaderCache - /** Create and register a class loader cache. This should be called once at the application entry-point.*/ + /** Create and register a class loader cache. This should be called once at the application entry-point. */ def initializeClassLoaderCache: State } @@ -220,22 +220,22 @@ object State { override def getURLs: Array[URL] = cp.map(_.toURI.toURL).toArray } - /** Indicates where command execution should resume after a failure.*/ + /** Indicates where command execution should resume after a failure. */ val FailureWall = BasicCommandStrings.FailureWall - /** Represents the next action for the command processor.*/ + /** Represents the next action for the command processor. */ sealed trait Next - /** Indicates that the command processor should process the next command.*/ + /** Indicates that the command processor should process the next command. */ object Continue extends Next - /** Indicates that the application should exit with the given result.*/ + /** Indicates that the application should exit with the given result. */ final class Return(val result: xsbti.MainResult) extends Next - /** Indicates that global logging should be rotated.*/ + /** Indicates that global logging should be rotated. */ final object ClearGlobalLog extends Next - /** Indicates that the previous log file should be preserved instead of discarded.*/ + /** Indicates that the previous log file should be preserved instead of discarded. */ final object KeepLastLog extends Next /** @@ -246,21 +246,21 @@ object State { */ final class History private[State] (val executed: Seq[Exec], val maxSize: Int) { - /** Adds `command` as the most recently executed command.*/ + /** Adds `command` as the most recently executed command. */ def ::(command: Exec): History = { val prependTo = if (maxSize > 0 && executed.size >= maxSize) executed.take(maxSize - 1) else executed new History(command +: prependTo, maxSize) } - /** Changes the maximum number of commands kept, adjusting the current history if necessary.*/ + /** Changes the maximum number of commands kept, adjusting the current history if necessary. */ def setMaxSize(size: Int): History = new History(if (size <= 0) executed else executed.take(size), size) def currentOption: Option[Exec] = executed.headOption def previous: Option[Exec] = executed.drop(1).headOption } - /** Constructs an empty command History with a default, finite command limit.*/ + /** Constructs an empty command History with a default, finite command limit. */ def newHistory = new History(Vector.empty, HistoryCommands.MaxLines) def defaultReload(state: State): Reboot = { @@ -385,9 +385,12 @@ object State { s.copy(exitHooks = Set.empty) } def locked[T](file: File)(t: => T): T = - s.configuration.provider.scalaProvider.launcher.globalLock.apply(file, new Callable[T] { - def call = t - }) + s.configuration.provider.scalaProvider.launcher.globalLock.apply( + file, + new Callable[T] { + def call = t + } + ) def interactive = getBoolean(s, BasicKeys.interactive, false) def setInteractive(i: Boolean) = s.put(BasicKeys.interactive, i) diff --git a/main-command/src/main/scala/sbt/Watched.scala b/main-command/src/main/scala/sbt/Watched.scala index 3bb4b4666..1cda76284 100644 --- a/main-command/src/main/scala/sbt/Watched.scala +++ b/main-command/src/main/scala/sbt/Watched.scala @@ -39,7 +39,7 @@ trait Watched { */ def antiEntropy: FiniteDuration = Watched.AntiEntropy - /** The message to show when triggered execution waits for sources to change.*/ + /** The message to show when triggered execution waits for sources to change. */ private[sbt] def watchingMessage(s: WatchState): String = Watched.defaultWatchingMessage(s) /** The message to show before an action is run. */ diff --git a/main-command/src/main/scala/sbt/internal/CommandChannel.scala b/main-command/src/main/scala/sbt/internal/CommandChannel.scala index c40375ec7..374497dd1 100644 --- a/main-command/src/main/scala/sbt/internal/CommandChannel.scala +++ b/main-command/src/main/scala/sbt/internal/CommandChannel.scala @@ -91,7 +91,7 @@ abstract class CommandChannel { if (cmd.nonEmpty) append(Exec(cmd, Some(Exec.newExecId), Some(CommandSource(name)))) else false } - private[sbt] def onFastTrackTask: String => Boolean = { s: String => + private[sbt] def onFastTrackTask: String => Boolean = { (s: String) => fastTrack.synchronized(fastTrack.forEach { q => q.add(new FastTrackTask(this, s)) () diff --git a/main-command/src/main/scala/sbt/internal/LegacyWatched.scala b/main-command/src/main/scala/sbt/internal/LegacyWatched.scala index 78a7a25b7..59eaa25e3 100644 --- a/main-command/src/main/scala/sbt/internal/LegacyWatched.scala +++ b/main-command/src/main/scala/sbt/internal/LegacyWatched.scala @@ -46,15 +46,16 @@ private[sbt] object LegacyWatched { case Some(eventMonitor) => Watched.printIfDefined(watched watchingMessage eventMonitor.state()) @tailrec def impl(): State = { - val triggered = try eventMonitor.awaitEvent() - catch { - case NonFatal(e) => - log.error( - "Error occurred obtaining files to watch. Terminating continuous execution..." - ) - s.handleError(e) - false - } + val triggered = + try eventMonitor.awaitEvent() + catch { + case NonFatal(e) => + log.error( + "Error occurred obtaining files to watch. Terminating continuous execution..." + ) + s.handleError(e) + false + } if (triggered) { Watched.printIfDefined(watched triggeredMessage eventMonitor.state()) ClearOnFailure :: next :: FailureWall :: repeat :: s diff --git a/main-command/src/main/scala/sbt/internal/classpath/ClassLoaderCache.scala b/main-command/src/main/scala/sbt/internal/classpath/ClassLoaderCache.scala index 16877ad08..2fe75b257 100644 --- a/main-command/src/main/scala/sbt/internal/classpath/ClassLoaderCache.scala +++ b/main-command/src/main/scala/sbt/internal/classpath/ClassLoaderCache.scala @@ -38,20 +38,21 @@ private[sbt] class ClassLoaderCache( def setParent(parent: ClassLoader): Unit = parentHolder.set(parent) def this(commonParent: ClassLoader) = this(commonParent, None) def this(scalaProvider: ScalaProvider) = - this(scalaProvider.launcher.topLoader, { - scalaProvider.jars.find(_.getName == "scala-library.jar").flatMap { lib => - val clazz = scalaProvider.getClass - try { - val loader = clazz.getDeclaredMethod("libraryLoaderOnly").invoke(scalaProvider) - Some(lib -> loader.asInstanceOf[ClassLoader]) - } catch { case NonFatal(_) => None } - } - }) - private val scalaProviderKey = miniProvider.map { - case (f, cl) => - new Key((f -> IO.getModifiedTimeOrZero(f)) :: Nil, commonParent) { - override def toClassLoader: ClassLoader = cl + this( + scalaProvider.launcher.topLoader, { + scalaProvider.jars.find(_.getName == "scala-library.jar").flatMap { lib => + val clazz = scalaProvider.getClass + try { + val loader = clazz.getDeclaredMethod("libraryLoaderOnly").invoke(scalaProvider) + Some(lib -> loader.asInstanceOf[ClassLoader]) + } catch { case NonFatal(_) => None } + } } + ) + private val scalaProviderKey = miniProvider.map { case (f, cl) => + new Key((f -> IO.getModifiedTimeOrZero(f)) :: Nil, commonParent) { + override def toClassLoader: ClassLoader = cl + } } private class Key(val fileStamps: Seq[(File, Long)], val parent: ClassLoader) { def this(files: List[File], parent: ClassLoader) = @@ -102,19 +103,20 @@ private[sbt] class ClassLoaderCache( start() @tailrec override final def run(): Unit = { - val stop = try { - referenceQueue.remove(1000) match { - case ClassLoaderReference(key, classLoader) => - close(classLoader) - delegate.remove(key) - () - case _ => + val stop = + try { + referenceQueue.remove(1000) match { + case ClassLoaderReference(key, classLoader) => + close(classLoader) + delegate.remove(key) + () + case _ => + } + clearExpiredLoaders() + false + } catch { + case _: InterruptedException => true } - clearExpiredLoaders() - false - } catch { - case _: InterruptedException => true - } if (!stop) run() } } diff --git a/main-command/src/main/scala/sbt/internal/client/BspClient.scala b/main-command/src/main/scala/sbt/internal/client/BspClient.scala index 19b8e106a..375a05f0d 100644 --- a/main-command/src/main/scala/sbt/internal/client/BspClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/BspClient.scala @@ -25,7 +25,8 @@ object BspClient { while (!terminated.get) lock.wait() } 0 - } catch { case _: Throwable => 1 } finally sbtServer.close() + } catch { case _: Throwable => 1 } + finally sbtServer.close() } private[sbt] def transferTo( diff --git a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala index 8909d6d42..e3d344b31 100644 --- a/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala +++ b/main-command/src/main/scala/sbt/internal/client/NetworkClient.scala @@ -190,18 +190,19 @@ class NetworkClient( } } @tailrec def connect(attempt: Int): (Socket, Option[String]) = { - val res = try Some(mkSocket(portfile)) - catch { - // This catches a pipe busy exception which can happen if two windows clients - // attempt to connect in rapid succession - case e: IOException if e.getMessage.contains("Couldn't open") && attempt < 10 => - if (e.getMessage.contains("Access is denied") || e.getMessage.contains("(5)")) { - errorStream.println(s"Access denied for portfile $portfile") - throw new NetworkClient.AccessDeniedException - } - None - case e: IOException => throw new ConnectionRefusedException(e) - } + val res = + try Some(mkSocket(portfile)) + catch { + // This catches a pipe busy exception which can happen if two windows clients + // attempt to connect in rapid succession + case e: IOException if e.getMessage.contains("Couldn't open") && attempt < 10 => + if (e.getMessage.contains("Access is denied") || e.getMessage.contains("(5)")) { + errorStream.println(s"Access denied for portfile $portfile") + throw new NetworkClient.AccessDeniedException + } + None + case e: IOException => throw new ConnectionRefusedException(e) + } res match { case Some(r) => r case None => @@ -431,36 +432,37 @@ class NetworkClient( } @tailrec def blockUntilStart(): Unit = { - val stop = try { - socket match { - case None => - process.foreach { p => - val output = p.getInputStream - while (output.available > 0) { - printStream.write(output.read()) + val stop = + try { + socket match { + case None => + process.foreach { p => + val output = p.getInputStream + while (output.available > 0) { + printStream.write(output.read()) + } } - } - case Some(s) => - while (!gotInputBack && !stdinBytes.isEmpty && socket.isDefined) { - val out = s.getOutputStream - val b = stdinBytes.poll - if (b == -1) { - // server waits for user input but stinBytes has ended - shutdown.run() - } else { - out.write(b) - out.flush() + case Some(s) => + while (!gotInputBack && !stdinBytes.isEmpty && socket.isDefined) { + val out = s.getOutputStream + val b = stdinBytes.poll + if (b == -1) { + // server waits for user input but stinBytes has ended + shutdown.run() + } else { + out.write(b) + out.flush() + } } - } - } - process.foreach { p => - val error = p.getErrorStream - while (error.available > 0) { - errorStream.write(error.read()) } - } - false - } catch { case e: IOException => true } + process.foreach { p => + val error = p.getErrorStream + while (error.available > 0) { + errorStream.write(error.read()) + } + } + false + } catch { case e: IOException => true } Thread.sleep(10) printStream.flush() errorStream.flush() @@ -489,7 +491,8 @@ class NetworkClient( } try blockUntilStart() - catch { case t: Throwable => t.printStackTrace() } finally { + catch { case t: Throwable => t.printStackTrace() } + finally { sbtProcess.set(null) Util.ignoreResult(Runtime.getRuntime.removeShutdownHook(shutdown)) } @@ -558,23 +561,22 @@ class NetworkClient( completions(msg.result match { case Some(o: JObject) => o.value - .foldLeft(CompletionResponse(Vector.empty[String])) { - case (resp, i) => - if (i.field == "items") - resp.withItems( - Converter - .fromJson[Vector[String]](i.value) - .getOrElse(Vector.empty[String]) - ) - else if (i.field == "cachedTestNames") - resp.withCachedTestNames( - Converter.fromJson[Boolean](i.value).getOrElse(true) - ) - else if (i.field == "cachedMainClassNames") - resp.withCachedMainClassNames( - Converter.fromJson[Boolean](i.value).getOrElse(true) - ) - else resp + .foldLeft(CompletionResponse(Vector.empty[String])) { case (resp, i) => + if (i.field == "items") + resp.withItems( + Converter + .fromJson[Vector[String]](i.value) + .getOrElse(Vector.empty[String]) + ) + else if (i.field == "cachedTestNames") + resp.withCachedTestNames( + Converter.fromJson[Boolean](i.value).getOrElse(true) + ) + else if (i.field == "cachedMainClassNames") + resp.withCachedMainClassNames( + Converter.fromJson[Boolean](i.value).getOrElse(true) + ) + else resp } case _ => CompletionResponse(Vector.empty[String]) }) @@ -632,8 +634,8 @@ class NetworkClient( ) ) } - splitToMessage foreach { - case (level, msg) => console.appendLog(level, msg) + splitToMessage foreach { case (level, msg) => + console.appendLog(level, msg) } } @@ -802,7 +804,7 @@ class NetworkClient( } withSignalHandler(handler, Signals.INT) { def block(): Int = { - try this.synchronized(this.wait) + try this.synchronized(this.wait()) catch { case _: InterruptedException => } if (exitClean.get) 0 else 1 } @@ -989,7 +991,8 @@ class NetworkClient( if (attached.get()) drain() } try read() - catch { case _: InterruptedException | NonFatal(_) => stopped.set(true) } finally { + catch { case _: InterruptedException | NonFatal(_) => stopped.set(true) } + finally { inputThread.set(null) } } @@ -1023,6 +1026,7 @@ class NetworkClient( val secs = f"${total % 60}%02d" s" ($maybeHours$mins:$secs)" }) + s"Total time: $totalString, completed $nowString" } } @@ -1156,7 +1160,8 @@ object NetworkClient { try { if (client.connect(log = true, promptCompleteUsers = false)) client.run() else 1 - } catch { case _: Exception => 1 } finally client.close() + } catch { case _: Exception => 1 } + finally client.close() } def client( baseDirectory: File, @@ -1187,7 +1192,8 @@ object NetworkClient { if (client.connect(log = true, promptCompleteUsers = false)) client.run() else 1 } - } catch { case _: Exception => 1 } finally client.close() + } catch { case _: Exception => 1 } + finally client.close() } def client( baseDirectory: File, @@ -1240,7 +1246,8 @@ object NetworkClient { System.exit(Terminal.withStreams(isServer = false, isSubProcess = false) { val term = Terminal.console try client(base, parsed, term.inputStream, System.err, term, useJNI) - catch { case _: AccessDeniedException => 1 } finally { + catch { case _: AccessDeniedException => 1 } + finally { Runtime.getRuntime.removeShutdownHook(hook) hook.run() } @@ -1286,7 +1293,8 @@ object NetworkClient { else Nil out.println(results.sorted.distinct mkString "\n") 0 - } catch { case _: Exception => 1 } finally client.close() + } catch { case _: Exception => 1 } + finally client.close() } catch { case _: AccessDeniedException => 1 } } @@ -1301,7 +1309,8 @@ object NetworkClient { val err = new PrintStream(term.errorStream) val out = if (redirectOutput) err else new PrintStream(term.outputStream) val args = parseArgs(arguments.toArray).withBaseDirectory(configuration.baseDirectory) - val useJNI = BootServerSocket.requiresJNI || System.getProperty("sbt.ipcsocket.jni", "false") == "true" + val useJNI = + BootServerSocket.requiresJNI || System.getProperty("sbt.ipcsocket.jni", "false") == "true" val client = simpleClient(args, term.inputStream, out, err, useJNI = useJNI) clientImpl(client, args.bsp) } diff --git a/main-command/src/main/scala/sbt/internal/server/Server.scala b/main-command/src/main/scala/sbt/internal/server/Server.scala index 6baf8bc1a..588b6eaf8 100644 --- a/main-command/src/main/scala/sbt/internal/server/Server.scala +++ b/main-command/src/main/scala/sbt/internal/server/Server.scala @@ -114,7 +114,7 @@ private[sbt] object Server { } catch { case e: IOException if e.getMessage.contains("connect") => case _: SocketTimeoutException => // its ok - case _: SocketException if !running.get => // the server is shutting down + case _: SocketException if !running.get => // the server is shutting down } } serverSocketHolder.get match { diff --git a/main-command/src/main/scala/sbt/internal/server/ServerHandler.scala b/main-command/src/main/scala/sbt/internal/server/ServerHandler.scala index 4cfbd9e3f..58ed54bb4 100644 --- a/main-command/src/main/scala/sbt/internal/server/ServerHandler.scala +++ b/main-command/src/main/scala/sbt/internal/server/ServerHandler.scala @@ -29,10 +29,10 @@ object ServerHandler { lazy val fallback: ServerHandler = ServerHandler({ handler => ServerIntent( - onRequest = { case x => handler.log.debug(s"Unhandled request received: ${x.method}: $x") }, + onRequest = { case x => handler.log.debug(s"Unhandled request received: ${x.method}: $x") }, onResponse = { case x => handler.log.debug(s"Unhandled responce received") }, - onNotification = { - case x => handler.log.debug(s"Unhandled notification received: ${x.method}: $x") + onNotification = { case x => + handler.log.debug(s"Unhandled notification received: ${x.method}: $x") }, ) }) 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 5c27fc873..e02a2baaf 100644 --- a/main-command/src/main/scala/sbt/internal/ui/UITask.scala +++ b/main-command/src/main/scala/sbt/internal/ui/UITask.scala @@ -23,7 +23,7 @@ import scala.annotation.tailrec private[sbt] trait UITask extends Runnable with AutoCloseable { private[sbt] val channel: CommandChannel - private[sbt] val reader: UITask.Reader + private[sbt] def reader: UITask.Reader private[this] final def handleInput(s: Either[String, String]): Boolean = s match { case Left(m) => channel.onFastTrackTask(m) case Right(cmd) => channel.onCommand(cmd) diff --git a/main-command/src/main/scala/sbt/internal/util/ReadJsonFromInputStream.scala b/main-command/src/main/scala/sbt/internal/util/ReadJsonFromInputStream.scala index 693f2df5f..42bdf3022 100644 --- a/main-command/src/main/scala/sbt/internal/util/ReadJsonFromInputStream.scala +++ b/main-command/src/main/scala/sbt/internal/util/ReadJsonFromInputStream.scala @@ -45,7 +45,8 @@ private[sbt] object ReadJsonFromInputStream { var content: Seq[Byte] = Seq.empty[Byte] var consecutiveLineEndings = 0 var onCarriageReturn = false - do { + + def run(): Unit = val byte = inputStream.read byte match { case `newline` => @@ -54,33 +55,34 @@ private[sbt] object ReadJsonFromInputStream { onCarriageReturn = false if (line.startsWith(contentLength)) { Try(line.drop(contentLength.length).toInt) foreach { len => + def doDrainHeaders(): Unit = + inputStream.read match + case `newline` if onCarriageReturn => + getLine() + onCarriageReturn = false + consecutiveLineEndings += 1 + case `carriageReturn` => onCarriageReturn = true + case -1 => running.set(false) + case c => + if (c == newline) getLine() + else { + if (index >= headerBuffer.length) expandHeaderBuffer() + headerBuffer(index) = c.toByte + index += 1 + } + onCarriageReturn = false + consecutiveLineEndings = 0 + def drainHeaders(): Unit = - do { - inputStream.read match { - case `newline` if onCarriageReturn => - getLine() - onCarriageReturn = false - consecutiveLineEndings += 1 - case `carriageReturn` => onCarriageReturn = true - case -1 => running.set(false) - case c => - if (c == newline) getLine() - else { - if (index >= headerBuffer.length) expandHeaderBuffer() - headerBuffer(index) = c.toByte - index += 1 - } - onCarriageReturn = false - consecutiveLineEndings = 0 - } - } while (consecutiveLineEndings < 2 && running.get) + doDrainHeaders() + while consecutiveLineEndings < 2 && running.get do doDrainHeaders() drainHeaders() if (running.get) { val buf = new Array[Byte](len) var offset = 0 - do { - offset += inputStream.read(buf, offset, len - offset) - } while (offset < len && running.get) + def run1(): Unit = offset += inputStream.read(buf, offset, len - offset) + run1() + while offset < len && running.get do run1() if (running.get) content = buf.toSeq } } @@ -99,7 +101,9 @@ private[sbt] object ReadJsonFromInputStream { index += 1 } - } while (content.isEmpty && running.get) + + run() + while content.isEmpty && running.get do run() content } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 6564bc319..b2ecf1482 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -15,8 +15,8 @@ object Dependencies { // sbt modules private val ioVersion = nightlyVersion.getOrElse("1.8.0") private val lmVersion = - sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("1.8.0") - val zincVersion = nightlyVersion.getOrElse("1.8.0") + sys.props.get("sbt.build.lm.version").orElse(nightlyVersion).getOrElse("2.0.0-alpha1") + val zincVersion = nightlyVersion.getOrElse("2.0.0-alpha1") private val sbtIO = "org.scala-sbt" %% "io" % ioVersion @@ -57,10 +57,7 @@ object Dependencies { c: Option[Configuration] = None ) = (p: Project) => { val m0 = moduleId.withConfigurations(c.map(_.name)) - val m = m0.name match { - case "compiler-interface" => m0 - case _ => m0.cross(CrossVersion.for3Use2_13) - } + val m = m0 path match { case Some(f) => p.dependsOn(ClasspathDependency(ProjectRef(file(f), projectName), c.map(_.name)))