Merge pull request #3147 from dwijnand/warn-less

Improvements & bug fixes to the new startup messages
This commit is contained in:
Dale Wijnand 2017-04-27 18:21:30 +01:00 committed by GitHub
commit f9c0187870
4 changed files with 105 additions and 57 deletions

View File

@ -178,16 +178,16 @@ object State {
/** Provides operations and transformations on State. */
implicit def stateOps(s: State): StateOps = new StateOps {
def process(f: (String, State) => State): State = {
def doX(x: String, xs: Seq[String]) = {
log.debug(s"> $x")
f(x, s.copy(remainingCommands = xs, history = x :: s.history))
def runCmd(cmd: String, remainingCommands: Seq[String]) = {
log.debug(s"> $cmd")
f(cmd, s.copy(remainingCommands = remainingCommands, history = cmd :: s.history))
}
def isInteractive = System.console() != null
def hasInput = System.console().reader().ready()
def isInteractive = System.console != null
def hasInput = Option(System.console) exists (_.reader.ready())
def hasShellCmd = s.definedCommands exists { case c: SimpleCommand => c.name == Shell; case _ => false }
s.remainingCommands match {
case Seq() => if (isInteractive && hasInput && hasShellCmd) doX(Shell, Nil) else exit(true)
case Seq(x, xs @ _*) => doX(x, xs)
case Seq() => if (isInteractive && hasInput && hasShellCmd) runCmd(Shell, Nil) else exit(true)
case Seq(x, xs @ _*) => runCmd(x, xs)
}
}
def :::(newCommands: Seq[String]): State = s.copy(remainingCommands = newCommands ++ s.remainingCommands)

View File

@ -64,6 +64,7 @@ object Keys {
val shellPrompt = SettingKey(BasicKeys.shellPrompt)
val analysis = AttributeKey[inc.Analysis]("analysis", "Analysis of compilation, including dependencies and generated outputs.", DSetting)
val watch = SettingKey(BasicKeys.watch)
val suppressSbtShellNotification = SettingKey[Boolean]("suppressSbtShellNotification", """True to suppress the "Executing in batch mode.." message.""", CSetting)
val pollInterval = SettingKey[Int]("poll-interval", "Interval between checks for modified sources by the continuous execution command.", BMinusSetting)
val watchSources = TaskKey[Seq[File]]("watch-sources", "Defines the sources in this project for continuous execution to watch for changes.", BMinusSetting)
val watchTransitiveSources = TaskKey[Seq[File]]("watch-transitive-sources", "Defines the sources in all projects for continuous execution to watch.", CSetting)

View File

@ -18,7 +18,7 @@ import java.net.URI
import java.util.Locale
import scala.util.control.NonFatal
import BasicCommandStrings.Shell
import BasicCommandStrings.{ Shell, TemplateCommand }
import CommandStrings.BootCommand
/** This class is the entry point for sbt. */
@ -29,59 +29,11 @@ final class xMain extends xsbti.AppMain {
import BasicCommandStrings.runEarly
import BuiltinCommands.{ initialize, defaults }
import CommandStrings.{ BootCommand, DefaultsCommand, InitCommand }
if (!java.lang.Boolean.getBoolean("sbt.skip.version.write"))
setSbtVersion(configuration.baseDirectory(), configuration.provider().id().version())
val state = initialState(configuration,
Seq(defaults, early),
runEarly(DefaultsCommand) :: runEarly(InitCommand) :: BootCommand :: Nil)
notifyUsersAboutShell(state)
runManaged(state)
}
private val sbtVersionRegex = """sbt\.version\s*=.*""".r
private def isSbtVersionLine(s: String) = sbtVersionRegex.pattern matcher s matches ()
private def isSbtProject(baseDir: File, projectDir: File) =
projectDir.exists() || (baseDir * "*.sbt").get.nonEmpty
private def setSbtVersion(baseDir: File, sbtVersion: String) = {
val projectDir = baseDir / "project"
val buildProps = projectDir / "build.properties"
val buildPropsLines = if (buildProps.canRead) IO.readLines(buildProps) else Nil
val sbtVersionAbsent = buildPropsLines forall (!isSbtVersionLine(_))
if (sbtVersionAbsent) {
val errorMessage = s"WARN: No sbt.version set in project/build.properties, base directory: $baseDir"
try {
if (isSbtProject(baseDir, projectDir)) {
val line = s"sbt.version=$sbtVersion"
IO.writeLines(buildProps, line :: buildPropsLines)
println(s"Updated file $buildProps setting sbt.version to: $sbtVersion")
} else
println(errorMessage)
} catch {
case _: IOException => println(errorMessage)
}
}
}
private def isInteractive = System.console() != null
private def hasShell(state: State) = state.remainingCommands contains Shell
/**
* The "boot" command adds "iflast shell" ("if last shell")
* which basically means it falls back to shell if there are no further commands
*/
private def endsWithBoot(state: State) = state.remainingCommands.lastOption exists (_ == BootCommand)
private def notifyUsersAboutShell(state: State) =
if (isInteractive && !hasShell(state) && !endsWithBoot(state)) {
state.log warn "Executing in batch mode."
state.log warn " For better performance, hit [ENTER] to switch to interactive mode, or"
state.log warn " consider launching sbt without any commands, or explicitly passing 'shell'"
}
}
final class ScriptMain extends xsbti.AppMain {
@ -143,9 +95,11 @@ object BuiltinCommands {
projects, project, reboot, read, history, set, sessionCommand, inspect, loadProjectImpl, loadFailed,
Cross.crossBuild, Cross.switchVersion, PluginCross.pluginCross, PluginCross.pluginSwitch,
setOnFailure, clearOnFailure, stashOnFailure, popOnFailure, setLogLevel, plugin, plugins,
writeSbtVersion, notifyUsersAboutShell,
ifLast, multi, shell, continuous, eval, alias, append, last, lastGrep, export, boot, nop, call, exit, early, initialize, act) ++
compatCommands
def DefaultBootCommands: Seq[String] = LoadProject :: (IfLast + " " + Shell) :: Nil
def DefaultBootCommands: Seq[String] =
WriteSbtVersion :: LoadProject :: NotifyUsersAboutShell :: s"$IfLast $Shell" :: Nil
def boot = Command.make(BootCommand)(bootParser)
@ -573,4 +527,61 @@ object BuiltinCommands {
}
s.put(Keys.stateCompilerCache, cache)
}
private val sbtVersionRegex = """sbt\.version\s*=.*""".r
private def isSbtVersionLine(s: String) = sbtVersionRegex.pattern matcher s matches ()
private def isSbtProject(baseDir: File, projectDir: File) =
projectDir.exists() || (baseDir * "*.sbt").get.nonEmpty
private def writeSbtVersionUnconditionally(state: State) = {
val baseDir = state.baseDir
val sbtVersion = BuiltinCommands.sbtVersion(state)
val projectDir = baseDir / "project"
val buildProps = projectDir / "build.properties"
val buildPropsLines = if (buildProps.canRead) IO.readLines(buildProps) else Nil
val sbtVersionAbsent = buildPropsLines forall (!isSbtVersionLine(_))
if (sbtVersionAbsent) {
val warnMsg = s"No sbt.version set in project/build.properties, base directory: $baseDir"
try {
if (isSbtProject(baseDir, projectDir)) {
val line = s"sbt.version=$sbtVersion"
IO.writeLines(buildProps, line :: buildPropsLines)
state.log info s"Updated file $buildProps: set sbt.version to $sbtVersion"
} else
state.log warn warnMsg
} catch {
case _: IOException => state.log warn warnMsg
}
}
}
private def intendsToInvokeNew(state: State) = state.remainingCommands contains TemplateCommand
private def writeSbtVersion(state: State) =
if (!java.lang.Boolean.getBoolean("sbt.skip.version.write") && !intendsToInvokeNew(state))
writeSbtVersionUnconditionally(state)
private def WriteSbtVersion = "write-sbt-version"
private def writeSbtVersion: Command =
Command.command(WriteSbtVersion) { state => writeSbtVersion(state); state }
private def isInteractive = System.console() != null
private def intendsToInvokeCompile(state: State) = state.remainingCommands contains Keys.compile.key.label
private def notifyUsersAboutShell(state: State): Unit = {
val suppress = Project extract state getOpt Keys.suppressSbtShellNotification getOrElse false
if (!suppress && isInteractive && intendsToInvokeCompile(state))
state.log info "Executing in batch mode. For better performance use sbt's shell; hit [ENTER] to do so now"
}
private def NotifyUsersAboutShell = "notify-users-about-shell"
private def notifyUsersAboutShell: Command =
Command.command(NotifyUsersAboutShell) { state => notifyUsersAboutShell(state); state }
}

View File

@ -0,0 +1,36 @@
### Improvements
- Improves the new startup messages. See below.
### Bug fixes
- Fixes the new startup messages. See below.
### Improvements and bug fixes to the new startup messages
The two new startup messages introduced in sbt 0.13.15 are:
+ when writing out `sbt.version` for build reproducability, and
+ when informing the user sbt shell for the performance improvement
When writing out `sbt.version` the messaging now:
+ correctly uses a logger rather than println
+ honours the log level set, for instance, by `--error`
+ never runs when sbt "new" is being run
When informing the user about sbt shell the messaging now:
+ is a 1 line message, rather than 3
+ is at info level, rather than warn level
+ can be suppressed with `suppressSbtShellNotification := false`
+ only triggers when "compile" is being run
+ never shows when sbt "new" is being run
[#3091][]/[#3097][]/[#3147][] by [@dwijnand][]
[#3091]: https://github.com/sbt/sbt/issues/3091
[#3097]: https://github.com/sbt/sbt/issues/3097
[#3147]: https://github.com/sbt/sbt/pull/3147
[@dwijnand]: https://github.com/dwijnand