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