mirror of https://github.com/sbt/sbt.git
Notify users about shell only if compile is present
This is a change in strategy. The motivation is the need to find a good balance between: + informing the uninformed that would benefit from this information, & + not spamming the already informed Making it dependent on "compile" being present in remainingCommands will probably make it trigger for, for example, Maven users who are used to running "mvn compile" and always run "sbt compile", and who therefore are unneccesarily suffering terribly slow compile speeds by starting up the jvm and sbt every time. Fixes #3091 Fixes #3097
This commit is contained in:
parent
bb16c7b068
commit
b54c0ff059
|
|
@ -222,20 +222,23 @@ object State {
|
|||
/** Provides operations and transformations on State. */
|
||||
implicit def stateOps(s: State): StateOps = new StateOps {
|
||||
def process(f: (Exec, State) => State): State = {
|
||||
def doX(x: Exec, xs: List[Exec]) = {
|
||||
log.debug(s"> $x")
|
||||
f(x, s.copy(remainingCommands = xs, currentCommand = Some(x), history = x :: s.history))
|
||||
def runCmd(cmd: Exec, remainingCommands: List[Exec]) = {
|
||||
log.debug(s"> $cmd")
|
||||
f(cmd,
|
||||
s.copy(remainingCommands = remainingCommands,
|
||||
currentCommand = Some(cmd),
|
||||
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 List() =>
|
||||
if (isInteractive && hasInput && hasShellCmd) doX(Exec(Shell, s.source), Nil)
|
||||
if (isInteractive && hasInput && hasShellCmd) runCmd(Exec(Shell, s.source), Nil)
|
||||
else exit(true)
|
||||
case List(x, xs @ _*) => doX(x, xs.toList)
|
||||
case List(x, xs @ _*) => runCmd(x, xs.toList)
|
||||
}
|
||||
}
|
||||
def :::(newCommands: List[String]): State = ++:(newCommands map { Exec(_, s.source) })
|
||||
|
|
|
|||
|
|
@ -129,6 +129,7 @@ object Keys {
|
|||
val serverPort = SettingKey(BasicKeys.serverPort)
|
||||
val analysis = AttributeKey[CompileAnalysis]("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)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ import java.net.URI
|
|||
import java.util.Locale
|
||||
import scala.util.control.NonFatal
|
||||
|
||||
import BasicCommandStrings.{ Shell, OldShell }
|
||||
import BasicCommandStrings.{ Shell, OldShell, TemplateCommand }
|
||||
import CommandStrings.BootCommand
|
||||
|
||||
/** This class is the entry point for sbt. */
|
||||
|
|
@ -64,67 +64,12 @@ final class xMain extends xsbti.AppMain {
|
|||
import BasicCommandStrings.runEarly
|
||||
import BuiltinCommands.defaults
|
||||
import sbt.internal.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 hasCommand(state: State, cmd: String): Boolean =
|
||||
(state.remainingCommands find { x =>
|
||||
x.commandLine == cmd
|
||||
}).isDefined
|
||||
|
||||
/**
|
||||
* 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 (_.commandLine == BootCommand)
|
||||
|
||||
private def notifyUsersAboutShell(state: State) =
|
||||
if (isInteractive && !hasCommand(state, Shell) && !hasCommand(state, OldShell) && !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 {
|
||||
|
|
@ -238,6 +183,8 @@ object BuiltinCommands {
|
|||
setLogLevel,
|
||||
plugin,
|
||||
plugins,
|
||||
writeSbtVersion,
|
||||
notifyUsersAboutShell,
|
||||
ifLast,
|
||||
multi,
|
||||
shell,
|
||||
|
|
@ -259,7 +206,8 @@ object BuiltinCommands {
|
|||
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)
|
||||
|
||||
|
|
@ -763,4 +711,66 @@ object BuiltinCommands {
|
|||
if (exec.commandLine.trim.isEmpty) newState
|
||||
else newState.clearGlobalLog
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in New Issue