【问题标题】:Gradle multiproject optional subproject's transitive dependency should be resolved to an existing subprojectGradle 多项目可选子项目的传递依赖应解析为现有子项目
【发布时间】:2014-02-09 22:21:26
【问题描述】:

假设以下项目。主项目是一个多项目,但是较大项目的每个部分都可以单独开发或混合开发:

/master/build.gradle
/m1/build.gradle
/m2/build.gradle
/m3/build.gradle

假设m3 使用m2m2 使用m1 (m1 <- m2 <- m3 )

m2 的存在是可选的,具有以下布局的多项目也是合理的

/master/build.gradle
/m1/build.gradle
/m3/build.gradle

但在这种情况下,m2 将从工件存储库中提取,这很好......但是 m1m2 的传递依赖,这很好,但是我如何告诉 gradle 使用本地m1 的版本而不是烘焙的工件?

我坚持这一点,我有权覆盖这些东西的每个地方 gradle 都给了我“只是”ModuleVersionSelector 级别的访问权限,我如何根据下载的工件传递依赖项添加DefaultProjectDependency

如果我可以访问存档工件的完整依赖关系图,并放入一些覆盖/排除项,我可能会有替代方案。

编辑:

我想到的最好的方法是使用 resolutionStrategy 过滤器,我通过进一步开发“elastic-deps”项目创建了一个示例

https://github.com/kgyrtkirk/elastic-deps

【问题讨论】:

    标签: dependencies gradle multi-project build-system transitive-dependency


    【解决方案1】:

    elastic-deps 开始,在this answer(也来自Peter)的帮助下,我想出了下面的技巧。

    在顶层build.gradle()中:

    // make sure we've parsed the subproject dependencies
    evaluationDependsOnChildren()
    
    def subprojectsByName = subprojects.collectEntries { it -> [it.name, it] }
    
    subprojects.each { p ->
      def hacks = [] // list of changes we're going to make
      p.configurations.each { c ->
        c.dependencies.each { d ->
          if (d.group.startsWith("my.group.prefix")) {
            def sub = subprojectsByName[d.name]
            if (sub != null) {
              hacks.add({
                // can't do this immediately or we'll get ConcurrentModificationExceptions
                c.dependencies.remove(d)
                p.dependencies.add(c.name, sub)
              })
            }
          }
        }
      }
      // Now we can safely apply the changes
      for (hack in hacks) {
        hack()
      }
    }
    

    这样做的好处是,与elastic-deps 不同,您不必修改子项目。

    这仍然存在一个问题,即一旦遇到二进制依赖项,任何纯传递依赖项都会被解析为二进制。例如,假设我有一个项目cyan,它直接依赖于greenblue,并通过green 传递到yellow

    compile - Compile classpath for source set 'main'.
    +--- my.shared:blue:+ -> 2.0-SNAPSHOT
    +--- my.shared:green:+ -> 2.0-SNAPSHOT
    |    +--- my.shared:yellow:+ -> 2.0-SNAPSHOT
    |    \--- my.shared:blue:+ -> 2.0-SNAPSHOT
    

    现在,如果我将 blueyellow 添加到我的多模块项目中,而不是 green,我会得到:

    compile - Compile classpath for source set 'main'.
    +--- com.iii.shared:green:+ -> 2.0-SNAPSHOT
    |    +--- com.iii.shared:yellow:+ -> 2.0-SNAPSHOT
    |    \--- com.iii.shared:blue:+ -> project :blue
    \--- project :blue
    

    请注意,blue 可以正确解析为项目,即使它是可传递的,但 yellow 不是。

    我个人认为这是一个特性,而不是错误——它反映了分发时实际发生的情况。我可以对yellow 进行我想要的所有更改,但是如果我没有在我的存储库中放置一个新的yellow 工件并且还没有使用更新的依赖项更新green,那么cyan 的实际发布是不会得到这些改变。

    【讨论】:

      【解决方案2】:

      使用 Gradle 构建的动态子集是一项计划中的功能。与此同时,我想出的最佳解决方案是引入一种新的依赖表示法,它可以动态映射到项目依赖项或外部依赖项。您可以在此处找到概念验证:https://github.com/pniederw/elastic-deps

      PS:在开始自己实现此功能之前,请重新考虑此时是否真的需要它。等到正式支持后,您可能会省去一些麻烦。

      【讨论】:

      • 我们已经实现了它...我们正在探索从二进制工件中获取 sub2 的可能性,在这种情况下 sub3 的传递性被解析为二进制...这是不希望的
      • 好的,你没有提到。我不确定当前的 Gradle 是否以及如何实现这一点。恐怕你必须自己深入挖掘。
      猜你喜欢
      • 1970-01-01
      • 2022-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-19
      • 2018-10-15
      • 1970-01-01
      相关资源
      最近更新 更多