mirror of https://github.com/sbt/sbt.git
commit
8eb5879101
|
|
@ -309,6 +309,8 @@ lazy val commandProj = (project in file("main-command"))
|
|||
exclude[ReversedMissingMethodProblem]("sbt.internal.server.ServerInstance.*"),
|
||||
// Added method to CommandChannel. internal.
|
||||
exclude[ReversedMissingMethodProblem]("sbt.internal.CommandChannel.*"),
|
||||
// Added an overload to reboot. The overload is private[sbt].
|
||||
exclude[ReversedMissingMethodProblem]("sbt.StateOps.reboot"),
|
||||
)
|
||||
)
|
||||
.configure(
|
||||
|
|
|
|||
|
|
@ -117,14 +117,17 @@ $HelpCommand <regular expression>
|
|||
|
||||
def RebootCommand = "reboot"
|
||||
def RebootDetailed =
|
||||
RebootCommand + """ [full]
|
||||
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.
|
||||
|
||||
If 'full' is specified, the boot directory (`~/.sbt/boot` by default)
|
||||
is deleted before restarting. This forces an update of sbt and Scala
|
||||
and is useful when working with development versions of sbt or Scala."""
|
||||
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 = ";"
|
||||
def MultiBrief =
|
||||
|
|
|
|||
|
|
@ -175,10 +175,19 @@ object BasicCommands {
|
|||
}
|
||||
|
||||
def reboot: Command =
|
||||
Command(RebootCommand, Help.more(RebootCommand, RebootDetailed))(rebootParser)((s, full) =>
|
||||
s reboot full)
|
||||
Command(RebootCommand, Help.more(RebootCommand, RebootDetailed))(rebootOptionParser) {
|
||||
case (s, (full, currentOnly)) =>
|
||||
s.reboot(full, currentOnly)
|
||||
}
|
||||
|
||||
def rebootParser(s: State): Parser[Boolean] = token(Space ~> "full" ^^^ true) ?? false
|
||||
@deprecated("Use rebootOptionParser", "1.1.0")
|
||||
def rebootParser(s: State): Parser[Boolean] =
|
||||
rebootOptionParser(s) map { case (full, currentOnly) => full }
|
||||
|
||||
private[sbt] def rebootOptionParser(s: State): Parser[(Boolean, Boolean)] =
|
||||
token(
|
||||
Space ~> (("full" ^^^ ((true, false))) |
|
||||
("dev" ^^^ ((false, true))))) ?? ((false, false))
|
||||
|
||||
def call: Command =
|
||||
Command(ApplyCommand, Help.more(ApplyCommand, ApplyDetailed))(_ => callParser) {
|
||||
|
|
|
|||
|
|
@ -89,6 +89,17 @@ trait StateOps {
|
|||
*/
|
||||
def reboot(full: Boolean): State
|
||||
|
||||
/**
|
||||
* Reboots sbt. A reboot restarts execution from the entry point of the launcher.
|
||||
* A reboot is designed to be as close as possible to actually restarting the JVM without actually doing so.
|
||||
* Because the JVM is not restarted, JVM exit hooks are not run.
|
||||
* State.exitHooks should be used instead and those will be run before rebooting.
|
||||
* If `full` is true, the boot directory is deleted before starting again.
|
||||
* If `currentOnly` is true, the artifacts for the current sbt version is deleted.
|
||||
* This command is currently implemented to not return, but may be implemented in the future to only reboot at the next command processing step.
|
||||
*/
|
||||
private[sbt] def reboot(full: Boolean, currentOnly: Boolean): State
|
||||
|
||||
/** Sets the next command processing action to do.*/
|
||||
def setNext(n: State.Next): State
|
||||
|
||||
|
|
@ -248,12 +259,18 @@ object State {
|
|||
def baseDir: File = s.configuration.baseDirectory
|
||||
def setNext(n: Next) = s.copy(next = n)
|
||||
def continue = setNext(Continue)
|
||||
def reboot(full: Boolean) = {
|
||||
runExitHooks();
|
||||
throw new xsbti.FullReload(
|
||||
(s.remainingCommands map { case e: Exec => e.commandLine }).toArray,
|
||||
full)
|
||||
|
||||
/** Implementation of reboot. */
|
||||
def reboot(full: Boolean): State = reboot(full, false)
|
||||
|
||||
/** Implementation of reboot. */
|
||||
private[sbt] def reboot(full: Boolean, currentOnly: Boolean): State = {
|
||||
runExitHooks()
|
||||
val rs = s.remainingCommands map { case e: Exec => e.commandLine }
|
||||
if (currentOnly) throw new RebootCurrent(rs)
|
||||
else throw new xsbti.FullReload(rs.toArray, full)
|
||||
}
|
||||
|
||||
def reload = runExitHooks().setNext(new Return(defaultReload(s)))
|
||||
def clearGlobalLog = setNext(ClearGlobalLog)
|
||||
def keepLastLog = setNext(KeepLastLog)
|
||||
|
|
@ -320,3 +337,5 @@ object State {
|
|||
private[sbt] def getBoolean(s: State, key: AttributeKey[Boolean], default: Boolean): Boolean =
|
||||
s.get(key) getOrElse default
|
||||
}
|
||||
|
||||
private[sbt] final class RebootCurrent(val arguments: List[String]) extends RuntimeException
|
||||
|
|
|
|||
|
|
@ -7,11 +7,12 @@
|
|||
|
||||
package sbt
|
||||
|
||||
import java.util.Properties
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.control.NonFatal
|
||||
import jline.TerminalFactory
|
||||
|
||||
import sbt.io.Using
|
||||
import sbt.io.{ IO, Using }
|
||||
import sbt.internal.util.{ ErrorHandling, GlobalLogBacking }
|
||||
import sbt.internal.util.complete.DefaultParsers
|
||||
import sbt.util.Logger
|
||||
|
|
@ -58,6 +59,10 @@ object MainLoop {
|
|||
case e: xsbti.FullReload =>
|
||||
deleteLastLog(logBacking)
|
||||
throw e // pass along a reboot request
|
||||
case e: RebootCurrent =>
|
||||
deleteLastLog(logBacking)
|
||||
deleteCurrentArtifacts(state)
|
||||
throw new xsbti.FullReload(e.arguments.toArray, false)
|
||||
case NonFatal(e) =>
|
||||
System.err.println(
|
||||
"sbt appears to be exiting abnormally.\n The log file for this session is at " + logBacking.file)
|
||||
|
|
@ -69,6 +74,28 @@ object MainLoop {
|
|||
def deleteLastLog(logBacking: GlobalLogBacking): Unit =
|
||||
logBacking.last.foreach(_.delete())
|
||||
|
||||
/** Deletes the current sbt artifacts from boot. */
|
||||
private[sbt] def deleteCurrentArtifacts(state: State): Unit = {
|
||||
import sbt.io.syntax._
|
||||
val provider = state.configuration.provider
|
||||
val appId = provider.id
|
||||
// If we can obtain boot directory more accurately it'd be better.
|
||||
val defaultBoot = BuildPaths.defaultGlobalBase / "boot"
|
||||
val buildProps = state.baseDir / "project" / "build.properties"
|
||||
// First try reading the sbt version from build.properties file.
|
||||
val sbtVersionOpt = if (buildProps.exists) {
|
||||
val buildProperties = new Properties()
|
||||
IO.load(buildProperties, buildProps)
|
||||
Option(buildProperties.getProperty("sbt.version"))
|
||||
} else None
|
||||
val sbtVersion = sbtVersionOpt.getOrElse(appId.version)
|
||||
val currentArtDirs = defaultBoot * "*" / appId.groupID / appId.name / sbtVersion
|
||||
currentArtDirs.get foreach { dir =>
|
||||
state.log.info(s"Deleting $dir")
|
||||
IO.delete(dir)
|
||||
}
|
||||
}
|
||||
|
||||
/** Runs the next sequence of commands with global logging in place. */
|
||||
def runWithNewLog(state: State, logBacking: GlobalLogBacking): RunNext =
|
||||
Using.fileWriter(append = true)(logBacking.file) { writer =>
|
||||
|
|
@ -109,6 +136,7 @@ object MainLoop {
|
|||
ErrorHandling.wideConvert { state.process(processCommand) } match {
|
||||
case Right(s) => s
|
||||
case Left(t: xsbti.FullReload) => throw t
|
||||
case Left(t: RebootCurrent) => throw t
|
||||
case Left(t) => state.handleError(t)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
### Improvements
|
||||
|
||||
- Adds `reboot dev` command, which deletes the current artifact from the boot directory. This is useful when working with development versions of sbt.
|
||||
Loading…
Reference in New Issue