首页 > 解决方案 > Sbt 插件在其他任务之前/之后运行任务

问题描述

我知道,我看到在标准任务之前/之后自动运行自定义任务,但它似乎已经过时了。我还发现了 SBT before/after hooks for a task,但它没有任何代码示例。

我在SBT 0.13.17

所以我想运行我的任务MyBeforeTaskMyAfterTask在其他任务之后自动运行,说Compile

所以当你这样做时,sbt compile我想看看:

...log...
This is my before test text
...compile log...
This is my after test text

所以我需要:

object MyPlugin extends AutoPlugin {
  object autoImport {
     val MyBeforeTask = taskKey[Unit]("desc...")
     val MyAfterTask = taskKey[Unit]("desc...")
  }

  import autoImport._

  override def projectSettings: Seq[Def.Setting[_]] = {
     MyBeforeTask := {
       println("This is my before test text")
     },
     MyAfterTask := {
       println("This is my after test text")
     }
  }
}

所以我认为我需要类似的东西dependsOnin但我不知道如何设置它们。

标签: scalasbt

解决方案


不可能为特定任务配置在给定任务之后运行,因为这不是任务依赖模型的工作方式 - 当您指定任务时,它的依赖关系和自身将被执行,但无法定义“之后”的依赖。但是,您可以使用动态任务来模拟它。

要在另一个任务之前运行某些任务,您可以使用dependsOn

compile in Compile := (compile in Compile).dependsOn(myBeforeTask).value

这会在两个任务之间建立依赖关系,从而确保myBeforeTask将在compile in Compile.


请注意,有一种更通用的方法可以让多个任务一个接一个地运行:

aggregateTask := Def.sequential(task1, task2, task3, task4).value

Def.sequential依赖于动态任务机制,它在运行时设置任务之间的依赖关系。但是,这种机制有一些限制,特别是您不能引用要执行的任务列表中定义的任务,因此您不能使用它Def.sequential来扩充现有任务:

compile in Compile := Def.sequential(myBeforeTask, compile in Compile).value

此定义将在运行时失败并显示一条奇怪的错误消息,这基本上意味着您的任务依赖关系图中有一个循环。但是,对于某些用例,它非常有用。


但是,要一个接一个地运行某个任务,您必须使用以下方法定义一个动态任务依赖项Def.taskDyn

compile in Compile := Def.taskDyn {
  val result = (compile in Compile).value
  Def.task {
    val _ = myAfterTask.value
    result
  }
}.value

Def.taskDyn接受一个必须返回 a 的块,该块Def.Initialize[Task[T]]将用于在主体Def.taskDyn完成后实例化稍后运行的任务。这允许动态计算任务,并在运行时建立任务之间的依赖关系。然而,正如我上面所说,这可能会导致在运行时发生非常奇怪的错误,这通常是由依赖图中的循环引起的。

因此,包含“之前”和“之后”任务的完整示例将如下所示:

compile in Compile := Def.taskDyn {
  val result = (compile in Compile).value
  Def.task {
    val _ = myAfterTask.value
    result
  }
}.dependsOn(myBeforeTask).value

推荐阅读