You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现sbt任务以获取项目所有依赖项目的源目录?

Collecting Source Directories from sbt Dependent Projects

Hey there! Your approach to fetching source directories via project dependencies is on the right track, but let's refine it to fix edge cases and make it more aligned with sbt's best practices.

Potential Issues in Your Current Code

  • If your project has no dependencies, the reduce call will throw an UnsupportedOperationException—that's a crash waiting to happen.
  • The nested taskDyn and flatMap logic is overcomplicated; sbt's task system can handle dependency resolution automatically without manual task composition here.
  • Overriding the default sources task isn't ideal, since that's meant to collect the current project's source files, not dependencies'.

Refined Implementation

Here's a cleaner, more robust version:

// Helper to fetch source directories from direct dependencies
def sourcesOfDependencies(p: Project): Def.Initialize[Task[Seq[File]]] = Def.task {
  p.dependencies.map { dep =>
    // sbt automatically resolves the task dependency here
    (sourceDirectory in dep.project).value
  }.toSeq
}

// Create a custom task instead of overriding the default `sources`
lazy val collectDependencySources = taskKey[Seq[File]](
  "Collects source directories from all directly dependent projects"
)

// Bind the helper to your custom task
collectDependencySources := sourcesOfDependencies(myProject).value

Key Improvements

  • Crash-proof for empty dependencies: Using map + toSeq returns an empty sequence when there are no dependencies, instead of throwing an error.
  • Simpler task logic: We don't need manual taskDyn or flatMap—sbt handles the task dependencies under the hood when we call .value on each dependency's sourceDirectory.
  • Clearer intent: A custom task key (collectDependencySources) avoids confusion with the default sources task, which has a different purpose.

Bonus: Recursively Collect All Dependencies (Direct + Indirect)

If you need to grab source directories from all dependencies (including indirect ones), here's a recursive version that handles cyclic dependencies too:

def sourcesOfDependenciesRecursive(p: Project): Def.Initialize[Task[Seq[File]]] = Def.task {
  // Recursively fetch all unique dependencies, avoiding cycles
  def getAllDeps(project: Project, visited: Set[Project] = Set.empty): Set[Project] = {
    if (visited.contains(project)) visited
    else {
      val newVisited = visited + project
      project.dependencies.flatMap(dep => getAllDeps(dep.project, newVisited)).toSet ++ newVisited
    }
  }

  // Exclude the current project itself, then get all source directories
  val allDeps = getAllDeps(p) - p
  allDeps.map(dep => (sourceDirectory in dep).value).toSeq
}

lazy val collectAllDependencySources = taskKey[Seq[File]](
  "Collects source directories from all direct and indirect dependent projects"
)

collectAllDependencySources := sourcesOfDependenciesRecursive(myProject).value

This version uses a visited set to prevent infinite loops from cyclic dependencies, and pulls in every dependency's source directory recursively.


内容的提问来源于stack exchange,提问作者visa

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 07:44:00