#scala #sbt
#скала #сбт
Вопрос:
У меня есть многомодульный веб-проект с графиком зависимостей, подобным этому
WAR-project
- A1
-- A2
-- A3
- B1
-- B2
---- B22
-- B3
то есть проект war зависит от A1, который, в свою очередь, зависит от A2 и A3 и так далее.
Теперь, перед упаковкой проекта war, я хочу скопировать некоторые веб-ресурсы из его зависимых проектов в веб-приложение. Итак, мой вопрос в том, как мне программно пересечь график зависимостей проекта SBT? т. е. в псевдокоде
resourcesToCopy = []
visitedProjects = []
traverseProjectDependencies(project) {
visitedProjects = project
if(project has resourceFolder) {
resourcesToCopy = resourceFolder.getPath
}
for(projectDependency in project) {
if(projectDependency is not visited) {
traverseProjectDependencies(projectDependency)
}
}
}
Обратите внимание, что я знаю, что если я добавлю папку ресурсов в classpath каждой из зависимостей, то я смогу извлечь ее из fullClasspath в веб-проекте. Но я хотел бы избежать этого решения, а также существуют другие сценарии, в которых может быть полезным программный обход и взаимодействие с зависимостями.
Ответ №1:
Следующий код добавляет задачу aggress, которая будет агрегировать все ресурсы для зависимых проектов:
val aggrRes= TaskKey[Seq[File]]("aggr-res", "show aggregate resources")
val aggrResTask = aggrRes in Compile <<= {
(thisProjectRef, buildStructure) flatMap aggrResources(resources in Compile)
}
def aggrResources[T](key: ScopedTask[Seq[T]])(proj: ProjectRef, struct: Load.BuildStructure) = {
val deps = collectDeps(_.dependencies.map(_.project))(proj, struct)
deps.flatMap(key in (_, Compile) get struct.data).join.map(_.flatten)
}
def collectDeps(op: ResolvedProject => Seq[ProjectRef])(projRef: ProjectRef, struct: Load.BuildStructure): Seq[ProjectRef] = {
val deps = Project.getProject(projRef, struct).toSeq.flatMap(op)
deps.flatMap(ref => ref : collectDeps(op)(ref, struct)).distinct
}
Я изложил суть на более полном примере здесь