Подтвердить что ты не робот

Секвенирование и переопределение задач в 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?

4b9b3361

Ответ 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

Моя батарея умирает, поэтому я не могу смотреть в этот, но это может быть то, что вы ищете.