获取用户输入
文档的配方部分以目标为中心,对基础知识仅作最简要的说明。
通常建议使用输入任务,而非将任务或命令设计为交互式。
目标
我想在任务或命令中从控制台读取用户输入。
步骤
- 使用
interactionService键获取sbt.InteractionService:
lazy val demo1 = taskKey[Int]("demo1")
scalaVersion := "3.8.4"
demo1 := Def.uncached {
val srv = interactionService.value
srv.readLine(prompt = "enter a number: ", mask = false) match
case Some(x) => x.toInt
case None => sys.error("error getting an input!")
}
- 对于命令,直接使用
CommandLineUIService:
lazy val demo2 = Command.command("demo2"): s0 =>
val srv = CommandLineUIService
srv.readLine(prompt = "enter a number: ", mask = false) match
case Some(x) => x.toInt
case None => sys.error("error getting an input!")
s0
LocalRootProject / commands += demo2
测试
$ sbt --client
sbt:demo> demo1
enter a number: 1
[success] elapsed time: 1 s
sbt:demo> demo2
enter a number: 1
sbt:demo> shutdown
[info] disconnected
$ sbt --server
sbt:demo> demo1
enter a number: 1
[success] elapsed time: 1 s
sbt:demo> demo2
enter a number: 1
sbt:demo> exit
[info] shutting down sbt server
其他方式
也可以使用 scala.io.StdIn.readLine 函数。
lazy val demo3 = taskKey[Int]("demo3")
demo3 := Def.uncached {
import scala.io.StdIn
Option(StdIn.readLine("enter a number: ")) match
case Some(x) => x.toInt
case None => sys.error("error getting an input!")
}
说明
sbt 2 默认以客户端-服务器模式运行,涉及 sbtn 和 sbt 服务器进程。这意味着当任务提示用户输入时,提示在客户端(sbtn)侧发生,而任务在服务器侧执行。这种客户端-服务器分离在 sbt 0.13 中也存在,当时 Activator 为 sbt 提供了基于 Web 的前端。为了抽象化简单的用户交互,sbt 提供了 interactionService,并初始化为 CommandLineUIService。该键在 sbt 1.x 和 2.x 中均受支持,可实现 sbtn 的终端虚拟化。
也可以在任务或命令定义中使用 scala.io.StdIn.readLine。请注意,这依赖于 sbt 服务器经由 IPC 套接字将终端交互代理到 sbtn。