我正在尝试实施一项简单的任务(并再次学习SBT - 同时)。在花了大约8个小时试图找到解决方案后,尝试了许多死胡同,阅读了大量的SBT文档和SO条目,并积累了大量的愤怒和挫折,我在这里发布了这个问题。
我需要实现一个任务transitiveBaseDirectories
,它将(在sbt控制台中)允许我在多项目构建中查询项目的依赖项目任务(示例结构在本文末尾) )像这样:
projectA/transitiveBaseDirectories
(构成所需的输出)
Seq(File("./projectA"), File("./projectAA"), File("./projectAAA"), File("./projectAB")))
这个示例项目
lazy val transitiveBaseDirectories = taskKey[Seq[File]](
"Returns a list of baseDirectory-ies of all projects a given project transitively depends on."
)
def transitiveBaseDirectoriesImpl = ???
lazy val root = project.dependsOn(projectA, projectB)
lazy val projectA = project.dependsOn(projectAA, projectAB)
lazy val projectAA = project.dependsOn(projectAAA)
lazy val projectAAA = project
lazy val projectAB = project.dependsOn(projectAB)
lazy val projectB = project
然后有必要以某种方式使transitiveBaseDirectories
可用于所有项目 - 我也不知道该怎么做。
我故意不在这里展示我失败的所有尝试(Product.extract(state.value)
,baseDirectory.all(ScopeFilter(inDependencies(...)))
等各种各样的尝试)。在我的SBT探索中,我曾多次感受到“几乎在那里”的感觉,接着是混乱的浪潮,并意识到我只是没有完成任务所需的SBT大图,而且更加沮丧。我已经放弃了,这也许是我在SBT中执行一项非平凡任务的第三次机会,它从未结束(在更好的情况下,我已经成功了,但是我并没有真正明白我做了什么)。
我真的很感激这里有一个简单但完整的解决方案,因为如果我没有提出太多要求,我已经过了很多次了。
非常感谢。
答案 0 :(得分:1)
我假设你想要所有项目的传递依赖。
因此,我首先要完成一项任务,以获得所有直接的项目依赖关系。
val directProjectDeps = taskKey[Map[String,Seq[ProjectRef]]]("project dependencies!")
directProjectDeps := {
val extracted = Project extract state.value
extracted.structure.allProjects.map { p =>
val deps = p.dependencies.map(_.project)
(p.id, deps)
}.toMap
}
然后需要做一些图遍历以获得所有传递依赖。这是一项单独任务中的简单实现。
val transitiveProjectDeps = taskKey[Map[String,Seq[ProjectRef]]]("transitive project dependencies!")
transitiveProjectDeps := {
val deps = directProjectDeps.value
def transitives(id: String): Seq[ProjectRef] = {
val direct = deps(id)
direct ++ direct.flatMap(d => transitives(d.project))
}
deps.map{ case(id,_) => (id,transitives(id)) }
}
为避免处理对任务的动态引用,请使用extract来访问所有ProjectRefs的baseDirectory
设置
val transitiveProjectDirs = taskKey[Map[String,Seq[File]]]("transitive project dependencies!")
transitiveProjectDirs := {
val extracted = Project extract state.value
transitiveProjectDeps.value.mapValues { v =>
v.map(ref => extracted.get(baseDirectory in ref))
}
}
仅为当前项目获取目录。
val myTransitiveProjectDirs = taskKey[Seq[File]]("just my dirs")
myTransitiveProjectDirs :=
transitiveProjectDirs.value.apply(thisProjectRef.value.project)
要在任何子项目中提供所有任务,最简单的方法是将它们放入插件中。
答案 1 :(得分:1)
非常感谢Justin Kaeser。为了完整起见,整个解决方案(也将任务添加到所有项目中)是
使用以下内容创建文件project/TransitiveDirsPlugin.scala
:
import sbt.Keys._
import sbt._
object TransitiveDirsPlugin extends AutoPlugin {
override def trigger: PluginTrigger = allRequirements
private[this] val directProjectDeps =
taskKey[Map[String, Seq[ProjectRef]]]("project dependencies!")
private[this] val transitiveProjectDeps =
taskKey[Map[String, Seq[ProjectRef]]]("transitive project dependencies!")
private[this] val transitiveProjectDirs =
taskKey[Map[String, Seq[File]]]("transitive project dependencies!")
private[this] val myTransitiveProjectDirs: TaskKey[Seq[File]] =
taskKey[Seq[File]]("just my dirs")
override lazy val projectSettings = Seq(
directProjectDeps := {
val extracted = Project extract state.value
extracted.structure.allProjects.map { p ⇒
val deps = p.dependencies.map(_.project)
(p.id, deps)
}.toMap
},
transitiveProjectDeps := {
val deps = directProjectDeps.value
def transitives(id: String): Seq[ProjectRef] = {
val direct = deps(id)
direct ++ direct.flatMap(d => transitives(d.project))
}
deps.map { case (id, _) => (id, transitives(id)) }
},
transitiveProjectDirs := {
val extracted = Project extract state.value
transitiveProjectDeps.value.mapValues { v =>
v.map(ref => extracted.get(baseDirectory in ref))
}
},
myTransitiveProjectDirs :=
transitiveProjectDirs.value.apply(thisProjectRef.value.project)
)
}
现在我可以使用show projectA/myTransitiveProjectDirs
等。谢谢Justin。