Как я могу определить, является ли текущий проект проектом root из динамической задачи c в sbt? - PullRequest
2 голосов
/ 22 января 2020

Первоначально об этом спрашивал @ daniel- c -sobral в Gitter:

Как определить, является ли текущий проект проектом root из динамической задачи c ?

Обновление :

Поговорив с Дэниелом немного больше, он уточнил:

Это плагин, который меняется test для запуска задачи, но только для проекта root.

Поэтому, похоже, он хочет определить, относится ли конкретная задача к проекту root или нет.

Ответы [ 2 ]

3 голосов
/ 23 января 2020

С учетом пары определений помощников:

val rootProjectRef: Def.Initialize[ProjectRef] = Def.setting {
  val rootBuildUri  = loadedBuild.value.root
  val rootProjectId = loadedBuild.value.units(rootBuildUri).root
  ProjectRef(rootBuildUri, rootProjectId)
}

val currentProjectRef: Def.Initialize[Task[ProjectRef]] =
  Def.task(Project.session(state.value).current)

Мы можем достаточно четко реализовать обе задачи, чтобы определить, является ли выбранный в данный момент проект (root) проекта root сборки (который вы можете вызывать из любой другой задачи, динамически c или нет), а также из более общего «этот проект root проект?» и "является ли этот проект текущим выбранным проектом?" вопросы:

val isRootProject        = settingKey[Boolean]("Is this the root project?")
val isCurrentProject     = taskKey[Boolean]("Is this the currently selected project?")
val isCurrentProjectRoot = taskKey[Boolean]("Is the currently select project the root project?")

inScope(Global)(Def.settings(
  isCurrentProjectRoot := currentProjectRef.value == rootProjectRef.value,
))

val commonSettings = Def.settings(
  isRootProject    := thisProjectRef.value == rootProjectRef.value,
  isCurrentProject := thisProjectRef.value == currentProjectRef.value,
)

lazy val root = project in file(".") settings commonSettings aggregate app
lazy val app  = project settings commonSettings

В действии:

> show root / isRootProject
[info] true
> show app / isRootProject
[info] false
>
> show root / isCurrentProject
[info] true
[success] Total time: 0 s, completed 23 Jan 2020, 00:02:58
> show app / isCurrentProject
[info] false
[success] Total time: 0 s, completed 23 Jan 2020, 00:03:04
>
> project
[info] root (in build file:/s/t-sbt-amIRoot/)
> 
> show isCurrentProjectRoot
[info] true
[success] Total time: 0 s, completed 23 Jan 2020, 00:03:11
>
>
>
> project app
[info] Set current project to app (in build file:/s/t-sbt-amIRoot/)
>
> show root / isCurrentProject
[info] false
[success] Total time: 0 s, completed 23 Jan 2020, 00:03:34
> show app / isCurrentProject
[info] true
[success] Total time: 0 s, completed 23 Jan 2020, 00:03:37
>
> show isCurrentProjectRoot
[info] false
[success] Total time: 0 s, completed 23 Jan 2020, 00:03:42
[success] Total time: 0 s, completed 22 Jan 2020, 22:04:43

Несколько замечаний:

Во-первых, обратите внимание, что isRootProject может быть реализован как настройка, потому что это неизменяемое значение загруженной сборки.

Во-вторых, обратите внимание, что определение области видимости isCurrentProjectRoot бессмысленно (поэтому оно глобально, так как оно не зависит ни от чего внутри проекта), но не недопустимо, что может ввести в заблуждение, например:

> project /
[info] Set current project to root (in build file:/s/t-sbt-amIRoot/)
> 
> show isCurrentProjectRoot
[info] true
[success] Total time: 0 s, completed 23 Jan 2020, 00:06:23
> 
> show app / isCurrentProjectRoot
[info] true
[success] Total time: 0 s, completed 23 Jan 2020, 00:06:26
2 голосов
/ 22 января 2020

is Root

Вот мой ответ.

ThisBuild / scalaVersion     := "2.13.1"
ThisBuild / version          := "0.1.0-SNAPSHOT"
ThisBuild / organization     := "com.example"
ThisBuild / organizationName := "example"

lazy val foo = taskKey[Int]("")
def whereAmI: Seq[Setting[_]] = Seq(
  foo := (Def.taskDyn {
    val r = resolvedScoped.value
    val st = state.value
    val structure = Project.extract(st).structure
    val isRoot = r.scope.project match {
      case Select(ref: ProjectRef) =>
        structure.rootProject(ref.build) == ref.project
      case _ => false
    }
    if (isRoot) Def.task { 0 }
    else Def.task { 1 }
  }).value
)

lazy val root = (project in file("."))
  .settings(
    name := "hello",
    whereAmI,
  )

lazy val app = project
  .settings(
    name := "app",
    whereAmI,
  )

resolvedScoped ключ будет соответствовать разрешенной области ключа Def.ScopedKey[_]. Поле области действия имеет тип Scope , который содержит project: ScopeAxis[Reference]. Как правило, он содержит ProjectRef.

final case class ProjectRef(build: URI, project: String)
    extends ProjectReference
    with ResolvedReference

. Мы можем проверить значения build: URI и project: String, чтобы увидеть, соответствуют ли они значениям root проекта или нет.

Как проверить это

sbt:hello> show root/foo
[info] 0
[success] Total time: 0 s, completed Jan 22, 2020 2:50:34 PM
sbt:hello> show app/foo
[info] 1
[success] Total time: 0 s, completed Jan 22, 2020 2:50:39 PM

Это динамически возвращается 0 для root проекта, но 1 для приложения.

isCurrent вариант

После разговора с Дэниелом, он сказал, что может быть заинтересован в текущем проекте:

Во-первых, в API много «корня», но, более конкретно, есть проект, в котором вы находитесь, когда вы запускаете sbt.

Вот вариант, который проверяет, выполняется ли в текущем проекте динамическая задача c foo или нет.

ThisBuild / scalaVersion     := "2.13.1"
ThisBuild / version          := "0.1.0-SNAPSHOT"
ThisBuild / organization     := "com.example"
ThisBuild / organizationName := "example"

lazy val foo = taskKey[Int]("")
def whereAmI: Seq[Setting[_]] = Seq(
  foo := (Def.taskDyn {
    val r = resolvedScoped.value
    val st = state.value
    val isCurrent = r.scope.project match {
      case Select(ref: ProjectRef) =>
        ref == Project.extract(st).currentRef
      case _ => false
    }
    if (isCurrent) Def.task { 2 }
    else Def.task { 3 }
  }).value
)

lazy val root = (project in file("."))
  .settings(
    name := "hello",
    whereAmI,
  )

lazy val app = project
  .settings(
    name := "app",
    whereAmI,
  )

Вот как это выглядит в sbt shell:

sbt:hello> show root/foo
[info] 2
[success] Total time: 0 s, completed Jan 22, 2020 3:04:17 PM
sbt:hello> show app/foo
[info] 3
[success] Total time: 0 s, completed Jan 22, 2020 3:04:22 PM

Посмотрим, что произойдет, если вы измените текущий проект на app:

sbt:hello> project app
[info] Set current project to app (in build file:/private/tmp/hello/)
sbt:app> show root/foo
[info] 3
[success] Total time: 0 s, completed Jan 22, 2020 3:04:28 PM
sbt:app> show app/foo
[info] 2
[success] Total time: 0 s, completed Jan 22, 2020 3:04:34 P
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...