Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Notify & enable users to stay in the warm shell #2996

Merged
merged 4 commits into from Mar 7, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions main/command/src/main/scala/sbt/MainLoop.scala
Expand Up @@ -65,6 +65,13 @@ object MainLoop {
val newLogging = state.globalLogging.newLogger(out, logBacking)
transferLevels(state, newLogging)
val loggedState = state.copy(globalLogging = newLogging)
def isInteractive = System.console() != null
def hasShell = state.remainingCommands contains "shell"
if (isInteractive && !hasShell) {
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'"
}
try run(loggedState) finally out.close()
}

Expand Down
15 changes: 10 additions & 5 deletions main/command/src/main/scala/sbt/State.scala
Expand Up @@ -176,13 +176,18 @@ object State {

/** Provides operations and transformations on State. */
implicit def stateOps(s: State): StateOps = new StateOps {
def process(f: (String, State) => State): State =
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 isInteractive = System.console() != null
def hasInput = System.console().reader().ready()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if someone runs sbt run that asks user for text input?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or more likely sbt +publishSigned

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/main/scala/t/T.scala

package t

object T {
  def main(args: Array[String]): Unit = {
    val con = System.console()
    val x = con readLine "Give me something: "
    con printf ("You gave me: %s\n", x)
  }
}

->

$ sbt run
[warn] Executing in batch mode.
[warn]   For better performance, hit [ENTER] to switch to interactive mode, or
[warn]   consider launching sbt without any commands, or explicitly passing 'shell'

[info] Loading global plugins from /Users/dnw/.dotfiles/.sbt/0.13/plugins
[info] Loading project definition from /s/t/project
[info] Set current project to t (in build file:/s/t/)
[info] Running t.T
Give me something: You gave me:
[success] Total time: 0 s, completed 07-Mar-2017 14:24:09

project/plugins.sbt

addSbtPlugin("com.jsuereth" % "sbt-pgp" % "1.0.0")

->

$ sbt +publishLocalSigned
[warn] Executing in batch mode.
[warn]   For better performance, hit [ENTER] to switch to interactive mode, or
[warn]   consider launching sbt without any commands, or explicitly passing 'shell'

[info] Loading global plugins from /Users/dnw/.dotfiles/.sbt/0.13/plugins
[info] Loading project definition from /s/t/project
[info] Updating {file:/s/t/project/}t-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Set current project to t (in build file:/s/t/)
[info] Setting version to 2.12.1
[info] Reapplying settings...
[info] Set current project to t (in build file:/s/t/)
[info] Packaging /s/t/target/scala-2.12/t_2.12-0.1.0-SNAPSHOT-sources.jar ...
[info] Done packaging.
[info] Main Scala API documentation to /s/t/target/scala-2.12/api...
[info] Wrote /s/t/target/scala-2.12/t_2.12-0.1.0-SNAPSHOT.pom
[info] :: delivering :: com.dwijnand#t_2.12;0.1.0-SNAPSHOT :: 0.1.0-SNAPSHOT :: integration :: Tue Mar 07 14:28:17 GMT 2017
[info] 	delivering ivy file to /s/t/target/scala-2.12/ivy-0.1.0-SNAPSHOT.xml
[info] Packaging /s/t/target/scala-2.12/t_2.12-0.1.0-SNAPSHOT.jar ...
[info] Done packaging.
model contains 3 documentable templates
[info] Main Scala API documentation successful.
[info] Packaging /s/t/target/scala-2.12/t_2.12-0.1.0-SNAPSHOT-javadoc.jar ...
[info] Done packaging.
Please enter PGP passphrase (or ENTER to abort):
java.lang.RuntimeException: Empty passphrase. aborting...
	at scala.sys.package$.error(package.scala:27)
	at com.typesafe.sbt.pgp.SbtPgpCommandContext.inputPassphrase(SbtPgpCommandContext.scala:27)
	at com.typesafe.sbt.pgp.SbtPgpCommandContext$$anonfun$1$$anonfun$apply$1$$anonfun$apply$2.apply(SbtPgpCommandContext.scala:34)
	at com.typesafe.sbt.pgp.SbtPgpCommandContext$$anonfun$1$$anonfun$apply$1$$anonfun$apply$2.apply(SbtPgpCommandContext.scala:34)
	at scala.Option.getOrElse(Option.scala:120)
	at com.typesafe.sbt.pgp.SbtPgpCommandContext$$anonfun$1$$anonfun$apply$1.apply(SbtPgpCommandContext.scala:34)
	at com.typesafe.sbt.pgp.SbtPgpCommandContext$$anonfun$1$$anonfun$apply$1.apply(SbtPgpCommandContext.scala:34)
	at com.typesafe.sbt.pgp.Cache$$anonfun$withValue$1.apply(SbtHelpers.scala:39)
	at scala.Option.getOrElse(Option.scala:120)
	at com.typesafe.sbt.pgp.Cache$class.withValue(SbtHelpers.scala:38)
	at com.typesafe.sbt.pgp.PasswordCache$.withValue(SbtHelpers.scala:55)
	at com.typesafe.sbt.pgp.SbtPgpCommandContext$$anonfun$1.apply(SbtPgpCommandContext.scala:34)
	at com.typesafe.sbt.pgp.SbtPgpCommandContext.retry(SbtPgpCommandContext.scala:42)
	at com.typesafe.sbt.pgp.SbtPgpCommandContext.withPassphrase(SbtPgpCommandContext.scala:31)
	at com.typesafe.sbt.pgp.BouncyCastlePgpSigner.sign(PgpSigner.scala:37)
	at com.typesafe.sbt.pgp.PgpSettings$$anonfun$signingSettings$1$$anonfun$apply$1.apply(PgpSettings.scala:120)
	at com.typesafe.sbt.pgp.PgpSettings$$anonfun$signingSettings$1$$anonfun$apply$1.apply(PgpSettings.scala:117)
	at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
	at scala.collection.TraversableLike$$anonfun$flatMap$1.apply(TraversableLike.scala:251)
	at scala.collection.immutable.Map$Map4.foreach(Map.scala:181)
	at scala.collection.TraversableLike$class.flatMap(TraversableLike.scala:251)
	at scala.collection.AbstractTraversable.flatMap(Traversable.scala:105)
	at com.typesafe.sbt.pgp.PgpSettings$$anonfun$signingSettings$1.apply(PgpSettings.scala:117)
	at com.typesafe.sbt.pgp.PgpSettings$$anonfun$signingSettings$1.apply(PgpSettings.scala:115)
	at scala.Function4$$anonfun$tupled$1.apply(Function4.scala:35)
	at scala.Function4$$anonfun$tupled$1.apply(Function4.scala:34)
	at scala.Function1$$anonfun$compose$1.apply(Function1.scala:47)
	at sbt.$tilde$greater$$anonfun$$u2219$1.apply(TypeFunctions.scala:40)
	at sbt.std.Transform$$anon$4.work(System.scala:63)
	at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
	at sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:228)
	at sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:17)
	at sbt.Execute.work(Execute.scala:237)
	at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
	at sbt.Execute$$anonfun$submit$1.apply(Execute.scala:228)
	at sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:159)
	at sbt.CompletionService$$anon$2.call(CompletionService.scala:28)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)
[error] (*:signedArtifacts) Empty passphrase. aborting...
[error] Total time: 3 s, completed 07-Mar-2017 14:28:20

s.remainingCommands match {
case Seq() => exit(true)
case Seq(x, xs @ _*) =>
log.debug(s"> $x")
f(x, s.copy(remainingCommands = xs, history = x :: s.history))
case Seq() => if (isInteractive && hasInput) doX("shell", Nil) else exit(true)
case Seq(x, xs @ _*) => doX(x, xs)
}
}
def :::(newCommands: Seq[String]): State = s.copy(remainingCommands = newCommands ++ s.remainingCommands)
def ::(command: String): State = (command :: Nil) ::: this
def ++(newCommands: Seq[Command]): State = s.copy(definedCommands = (s.definedCommands ++ newCommands).distinct)
Expand Down
7 changes: 7 additions & 0 deletions notes/0.13.14/stay-in-shell.md
@@ -0,0 +1,7 @@
### Improvements

- Notifies & enables users to stay in sbt's shell on the warm JVM by hitting \[ENTER\] while sbt is running. [#2987][]/[#2996][] by [@dwijnand][]

[#2987]: https://github.com/sbt/sbt/issues/2987
[#2996]: https://github.com/sbt/sbt/pull/2996
[@dwijnand]: https://github.com/dwijnand