如何在另一个任务失败后执行任务或命令

How to execute a task or command after another task even if it failed

我在 sbt 中有一个相当长的 运行 任务,我希望在它完成后得到声音通知,即使失败了也能收到通知。我以这种粗鲁的方式部分地到达了那里:

lazy val ding = taskKey[Unit]("plays a ding sound")
ding := {
  Seq("play", "-q", "/…/SmallGlockA.wav").run
}

我这样调用上述任务:

sbt> ;test;ding

虽然在任务成功时效果很好,但如果任务失败,它当然不会播放声音,考虑到它是测试,这很可能。

有什么办法可以解决这个问题吗?它不必非常漂亮或超级健壮——这不会被提交,这对我来说只是本地的事情。

我提出的解决方案是为 sbt 创建一个 AutoPlugin 来满足您的需求。

在名为 DingPlugin.scalaproject 文件夹中创建一个包含以下内容的新文件

import sbt.Keys._
import sbt.PluginTrigger.AllRequirements
import sbt._

object DingPlugin extends AutoPlugin {

  private def wavPath = "/path/to/wav"
  private def playSound(wav: String) = ???

  override def trigger = AllRequirements

  override def projectSettings: Seq[Def.Setting[_]] = Seq(
    Test / test := (Test / test).andFinally(playSound(wavPath)).value
  )
}

重点是方法andFinallythat

defines a new task that runs the original task and evaluates a side effect regardless of whether the original task succeeded. The result of the task is the result of the original task

playSound的实现是从这个question导出的,代码如下

  private def playSound(wav: String): Unit = {
    import java.io.BufferedInputStream
    import java.io.FileInputStream
    import javax.sound.sampled.AudioSystem
    val clip = AudioSystem.getClip
    val inputStream =
      AudioSystem.getAudioInputStream(
        new BufferedInputStream(new FileInputStream(wav))
      )
    clip.open(inputStream)
    clip.start()
    Thread.sleep(clip.getMicrosecondLength / 1000)
  }

现在只要运行sbt test不管测试成功与否都会播放声音