Секвенирование и переопределение задач в SBT
Краткое резюме: Я пытаюсь подождать в проекте верхнего уровня для всех субмодулей SBT для сборки, а затем удалить их каталоги target
. Приложение верхнего уровня агрегирует все подмодули, они не будут разворачиваться отдельно, а только как пакет с зависимостями классов, а дублированные библиотеки в подмодулях взорвут размер всего пакета, а пуля пройдет через ограничение Heroku.
Технически я пытаюсь использовать это - я пытаюсь добавить задачу "очистки", которая будет запускаться после stage
. Решение из ссылки выше не работает для меня (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 $52e59eb09172b3222f9e._
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
ожидает функцию, которая возвращает 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]
)
-
Я пытался поэкспериментировать с композицией внутри overriden stage
, как в:
stage := {
(stage in Universal).map(f => /*follow up*/ f).value
}
но это обычно просто ударяет меня по лицу с помощью illegal dynamic dependency
или illegal dynamic reference
Каким будет предпочтительный способ упорядочивания задач SBT?
Ответы
Ответ 1
Позвольте мне сказать, что 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
Моя батарея умирает, поэтому я не могу смотреть в этот, но это может быть то, что вы ищете.
Ответ 2
См. http://www.scala-sbt.org/0.13/docs/Howto-Sequencing.html, как выполнять задачи.
Так что-то вроде:
stage in Universal := Def.sequential(
stage in Universal,
stageCleanupTask
)