执行sbt命令时能否运行Scala脚本?指定命令触发脚本实现咨询
先直接给你明确答案:sbt完全可以运行Scala脚本,而且要让sbt compile或sbt assembly自动触发脚本也有成熟的实现方式,下面分两部分详细说:
一、用sbt运行Scala脚本的几种方式
直接执行独立脚本
如果你有一个单独的.scala脚本文件(不属于任何sbt项目),可以直接通过sbt的scala任务来执行,命令格式如下:sbt "scala /absolute/path/to/your/script.scala"这种方式不需要搭建sbt项目结构,适合快速验证小段Scala逻辑。
在sbt项目中定义专属任务
如果脚本是项目的一部分(比如放在scripts目录下),可以在build.sbt里定义一个专门的任务来运行它,示例代码:// 定义一个任务键,用来标识我们的脚本运行任务 lazy val runMyCustomScript = taskKey[Unit]("Execute my project-specific Scala script") runMyCustomScript := { // 指定脚本路径,这里假设脚本在项目根目录的scripts文件夹下 val scriptPath = baseDirectory.value / "scripts" / "my-script.scala" // 调用系统命令执行脚本 scala.sys.process.Process(s"scala ${scriptPath.getAbsolutePath}").! }之后在命令行执行
sbt runMyCustomScript就能触发脚本了。
二、让compile/assembly自动运行脚本的方案
核心思路是利用sbt的任务依赖机制,把脚本运行任务和compile/assembly任务绑定,支持前置触发(任务执行前)和后置触发(任务执行后)两种场景:
场景1:任务执行前自动运行脚本(比如compile前)
比如你希望每次执行sbt compile前先跑一遍脚本(比如做代码检查、生成配置文件),只需要让compile任务依赖我们定义的脚本任务即可:
// 先定义前置脚本任务 lazy val preCompileScript = taskKey[Unit]("Run script before compilation starts") preCompileScript := { val script = baseDirectory.value / "scripts" / "pre-compile-check.scala" scala.sys.process.Process(s"scala ${script.getAbsolutePath}").! } // 绑定compile任务和前置脚本任务 compile in Compile := (compile in Compile).dependsOn(preCompileScript).value
如果要给assembly加前置脚本,只需要把上面的compile in Compile换成assembly:
assembly := assembly.dependsOn(preCompileScript).value
这种方式下,如果脚本运行失败(比如返回非0状态码),后续的compile/assembly任务会自动终止,符合大多数前置检查的需求。
场景2:任务执行后自动运行脚本(比如assembly后)
如果希望脚本在compile/assembly完成后再执行(比如上传打包好的jar、发送通知),可以用sbt的andFinally方法,不管前面的任务成功还是失败,脚本都会执行:
// 定义后置脚本任务 lazy val postAssemblyScript = taskKey[Unit]("Run script after assembly finishes") postAssemblyScript := { val script = baseDirectory.value / "scripts" / "post-assembly-notify.scala" scala.sys.process.Process(s"scala ${script.getAbsolutePath}").! } // 绑定assembly任务和后置脚本任务 assembly := assembly.andFinally(postAssemblyScript).value
同样替换成compile in Compile就能实现编译后触发脚本。
额外小技巧
其实你不一定非要调用外部的.scala脚本,完全可以把脚本里的逻辑直接写到build.sbt的任务定义中,这样更简洁,比如:
preCompileScript := { println("Starting pre-compile validation...") // 直接在这里写Scala逻辑,比如检查配置文件是否存在 val configFile = baseDirectory.value / "conf" / "application.conf" if (!configFile.exists()) { sys.error("Configuration file application.conf is missing!") } println("Pre-compile validation passed.") }
内容的提问来源于stack exchange,提问作者Danny

