package sbt
import scala.annotation.tailrec
import java.io.{ File, PrintWriter }
import jline.TerminalFactory
object MainLoop {
def runLogged(state: State): xsbti.MainResult = {
val shutdownHook = new Thread(new Runnable {
def run() {
TerminalFactory.get().restore()
}
})
try {
Runtime.getRuntime.addShutdownHook(shutdownHook)
runLoggedLoop(state, state.globalLogging.backing)
} finally {
Runtime.getRuntime.removeShutdownHook(shutdownHook)
}
}
@tailrec def runLoggedLoop(state: State, logBacking: GlobalLogBacking): xsbti.MainResult =
runAndClearLast(state, logBacking) match {
case ret: Return =>
logBacking.file.delete()
deleteLastLog(logBacking)
ret.result
case clear: ClearGlobalLog =>
deleteLastLog(logBacking)
runLoggedLoop(clear.state, logBacking.shiftNew())
case keep: KeepGlobalLog =>
logBacking.file.delete
runLoggedLoop(keep.state, logBacking.unshift)
}
def runAndClearLast(state: State, logBacking: GlobalLogBacking): RunNext =
try
runWithNewLog(state, logBacking)
catch {
case e: xsbti.FullReload =>
deleteLastLog(logBacking)
throw e
case e: Throwable =>
System.err.println("sbt appears to be exiting abnormally.\n The log file for this session is at " + logBacking.file)
deleteLastLog(logBacking)
throw e
}
def deleteLastLog(logBacking: GlobalLogBacking): Unit =
logBacking.last.foreach(_.delete())
def runWithNewLog(state: State, logBacking: GlobalLogBacking): RunNext =
Using.fileWriter(append = true)(logBacking.file) { writer =>
val out = new java.io.PrintWriter(writer)
val newLogging = state.globalLogging.newLogger(out, logBacking)
transferLevels(state, newLogging)
val loggedState = state.copy(globalLogging = newLogging)
try run(loggedState) finally out.close()
}
private[this] def transferLevels(state: State, logging: GlobalLogging) {
val old = state.globalLogging
Logger.transferLevels(old.backed, logging.backed)
(old.full, logging.full) match {
case (oldLog: AbstractLogger, newLog: AbstractLogger) => Logger.transferLevels(oldLog, newLog)
case _ => ()
}
}
sealed trait RunNext
final class ClearGlobalLog(val state: State) extends RunNext
final class KeepGlobalLog(val state: State) extends RunNext
final class Return(val result: xsbti.MainResult) extends RunNext
@tailrec def run(state: State): RunNext =
state.next match {
case State.Continue => run(next(state))
case State.ClearGlobalLog => new ClearGlobalLog(state.continue)
case State.KeepLastLog => new KeepGlobalLog(state.continue)
case ret: State.Return => new Return(ret.result)
}
def next(state: State): State =
ErrorHandling.wideConvert { state.process(Command.process) } match {
case Right(s) => s
case Left(t: xsbti.FullReload) => throw t
case Left(t) => handleException(t, state)
}
@deprecated("Use State.handleError", "0.13.0")
def handleException(e: Throwable, s: State): State = s.handleError(e)
@deprecated("Use State.handleError", "0.13.0")
def handleException(t: Throwable, s: State, log: Logger): State = State.handleException(t, s, log)
def logFullException(e: Throwable, log: Logger): Unit = State.logFullException(e, log)
}