SBT 中的排序和覆盖任务
Sequencing and overriding tasks in SBT
快速总结:我试图在顶级项目中等待构建所有 SBT 子模块,然后删除它们的 target
目录。顶级应用程序聚合了所有子模块,它们不会单独部署,而只会作为具有类路径依赖项的捆绑包部署,而子模块中的重复库会炸毁整个包的大小,并且 slug 会超过 Heroku 限制。
从技术上讲,我正在尝试 actually use this - 我正在尝试添加一个 'cleanup' 任务,它将 运行 在 stage
之后。 link 上面的解决方案似乎对我不起作用(Play 2.4,SBT 0.13.5),错误说得比我好:
build.sbt:50: error: reference to stage is ambiguous;
it is imported twice in the same scope by
import _root_.com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport._
and import e59eb09172b3222f9e._
stage := {
假设我有清理任务:
val stageCleanupTask = taskKey[Unit]("Clean after stage task")
stageCleanupTask := {
val log = streams.value.log
if (sys.env.getOrElse("POST_STAGE_CLEAN", "false").equals("true")) {
log.info("Cleaning submodules' target directories")
sbt.IO.delete(baseDirectory.value / "modules" / "a" / "target")
sbt.IO.delete(baseDirectory.value / "modules" / "b" / "target")
sbt.IO.delete(baseDirectory.value / "modules" / "c" / "target")
}
}
我想覆盖 stage
:
stage := {
val f = (stage in Universal).value
stageCleanupTask.value
f
}
这似乎是完全错误的,因为两个任务 运行 同时进行。
SBT 也不是很容易,我在官方文档中没有找到太多,所以我只是在玩:
stage.flatMap
期望函数 returns 是 Task[U]
,但 stageCleanupTask
是 TaskKey[T]
,而 .value
在非常特定的区域之外不起作用,因此通过类似于 stage <<= stage.flatMap(f => stageCleanupTask.map(_ => f))
的组合似乎是不可能的。
dependsOn
只能作为 stage <<= stage dependsOn stageCleanupTask
工作,这与我想要的依赖链完全相反。 stageCleanupTask
应该依赖于 stage
,但类型不匹配(Task[Unit]
vs Task[File]
)
我试图在覆盖 stage
中尝试组合,如:
stage := {
(stage in Universal).map(f => /*follow up*/ f).value
}
但这通常只是用 illegal dynamic dependency
或 illegal dynamic reference
打我的脸
排序 SBT 任务的首选方式是什么?
请参阅 http://www.scala-sbt.org/0.13/docs/Howto-Sequencing.html 了解如何对任务进行排序。
所以像这样:
stage in Universal := Def.sequential(
stage in Universal,
stageCleanupTask
)
首先让我说 baseDirectory.value / "modules" / "a" / "target"
不是您想要使用的那种路径定义,因为使用 SBT 提供的设置要好得多。我推荐的是使用 (target in moduleName).value
.
关于你的主要问题,我建议你这样做:
val stageCleanupTask = taskKey[sbt.File]("Clean after stage task")
lazy val root = project.in(file("."))
...
.settings(
stageCleanupTask := {
val a = (stage in Universal).value
val log = streams.value.log
if (sys.env.getOrElse("POST_STAGE_CLEAN", "false").equals("true")) {
log.info("Cleaning submodules' target directories")
sbt.IO.delete((target in a).value)
sbt.IO.delete((target in b).value)
sbt.IO.delete((target in c).value)
}
a
},
stage <<= stageCleanupTask
我刚刚在我自己的一个项目中进行了测试,它运行得非常完美。
编辑 1
我的电池快没电了,所以我无法进一步查看 this,但这可能就是您要找的东西。
替换以下代码
stage := {
val f = (stage in Universal).value
stageCleanupTask.value
f
}
通过这个
import com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport.Universal
stage := Def.taskDyn {
val x = (stage in Universal).value
Def.task {
stageCleanupTask.value
x
}
}.value
这将导致排序任务并按预期工作。
快速总结:我试图在顶级项目中等待构建所有 SBT 子模块,然后删除它们的 target
目录。顶级应用程序聚合了所有子模块,它们不会单独部署,而只会作为具有类路径依赖项的捆绑包部署,而子模块中的重复库会炸毁整个包的大小,并且 slug 会超过 Heroku 限制。
从技术上讲,我正在尝试 actually use this - 我正在尝试添加一个 'cleanup' 任务,它将 运行 在 stage
之后。 link 上面的解决方案似乎对我不起作用(Play 2.4,SBT 0.13.5),错误说得比我好:
build.sbt:50: error: reference to stage is ambiguous;
it is imported twice in the same scope by
import _root_.com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport._
and import e59eb09172b3222f9e._
stage := {
假设我有清理任务:
val stageCleanupTask = taskKey[Unit]("Clean after stage task")
stageCleanupTask := {
val log = streams.value.log
if (sys.env.getOrElse("POST_STAGE_CLEAN", "false").equals("true")) {
log.info("Cleaning submodules' target directories")
sbt.IO.delete(baseDirectory.value / "modules" / "a" / "target")
sbt.IO.delete(baseDirectory.value / "modules" / "b" / "target")
sbt.IO.delete(baseDirectory.value / "modules" / "c" / "target")
}
}
我想覆盖 stage
:
stage := {
val f = (stage in Universal).value
stageCleanupTask.value
f
}
这似乎是完全错误的,因为两个任务 运行 同时进行。 SBT 也不是很容易,我在官方文档中没有找到太多,所以我只是在玩:
stage.flatMap
期望函数 returns 是Task[U]
,但stageCleanupTask
是TaskKey[T]
,而.value
在非常特定的区域之外不起作用,因此通过类似于stage <<= stage.flatMap(f => stageCleanupTask.map(_ => f))
的组合似乎是不可能的。dependsOn
只能作为stage <<= stage dependsOn stageCleanupTask
工作,这与我想要的依赖链完全相反。stageCleanupTask
应该依赖于stage
,但类型不匹配(Task[Unit]
vsTask[File]
)我试图在覆盖
stage
中尝试组合,如:stage := { (stage in Universal).map(f => /*follow up*/ f).value }
但这通常只是用
illegal dynamic dependency
或illegal dynamic reference
打我的脸
排序 SBT 任务的首选方式是什么?
请参阅 http://www.scala-sbt.org/0.13/docs/Howto-Sequencing.html 了解如何对任务进行排序。
所以像这样:
stage in Universal := Def.sequential(
stage in Universal,
stageCleanupTask
)
首先让我说 baseDirectory.value / "modules" / "a" / "target"
不是您想要使用的那种路径定义,因为使用 SBT 提供的设置要好得多。我推荐的是使用 (target in moduleName).value
.
关于你的主要问题,我建议你这样做:
val stageCleanupTask = taskKey[sbt.File]("Clean after stage task")
lazy val root = project.in(file("."))
...
.settings(
stageCleanupTask := {
val a = (stage in Universal).value
val log = streams.value.log
if (sys.env.getOrElse("POST_STAGE_CLEAN", "false").equals("true")) {
log.info("Cleaning submodules' target directories")
sbt.IO.delete((target in a).value)
sbt.IO.delete((target in b).value)
sbt.IO.delete((target in c).value)
}
a
},
stage <<= stageCleanupTask
我刚刚在我自己的一个项目中进行了测试,它运行得非常完美。
编辑 1
我的电池快没电了,所以我无法进一步查看 this,但这可能就是您要找的东西。
替换以下代码
stage := {
val f = (stage in Universal).value
stageCleanupTask.value
f
}
通过这个
import com.typesafe.sbt.packager.universal.UniversalPlugin.autoImport.Universal
stage := Def.taskDyn {
val x = (stage in Universal).value
Def.task {
stageCleanupTask.value
x
}
}.value
这将导致排序任务并按预期工作。