Gradle多项目可选子项目的传递依赖关系应该被解析为一个现有的子项目 [英] Gradle multiproject optional subproject's transitive dependency should be resolved to an existing subproject

查看:929
本文介绍了Gradle多项目可选子项目的传递依赖关系应该被解析为一个现有的子项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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

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



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

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

,但在这种情况下,将从工件存储库中提取好的$ code> m2 。 m1 是 m2 的传递依赖,这是很好的,但是我怎么能告诉毕业生使用本地版本的 m1 而不是烘焙的神器?



我被卡住了,每个地方,我可以访问OVERR这些东西毕业给我只是 ModuleVersionSelector 级别访问,我如何添加一个 DefaultProjectDependency 根据下载的工件传递依赖关系?



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

编辑:



我所想出的最好的是使用一个使用resolutionStrategy的过滤器,我通过进一步开发创造了一个例子'elastic-deps'项目



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

解决方案

elastic-deps ,并借助此答案(也来自彼得< a))我想出了下面的技巧。



在顶级build.gradle()中:



< pre class =lang-java prettyprint-override> //确保我们已经解析了子项目依赖项
evaluationDependsOnChildren()

def subprojectsByName = subprojects.collectEntries {it - > [it.name,it]}

subprojects.each {p - >
def hacks = [] //我们要做的更改列表
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({
//不能立即做到这一点,否则我们会得到ConcurrentModificationExceptions
c.dependencies.remove(d)
p.dependencies.add(c.name, sub)
})
}
}
}
}
//现在我们可以安全地应用更改
(hack in hacks ){
hack()
}
}

关于这一点的是,与 elastic-deps 不同,您不必修改子项目。



这仍然有一个问题,一旦你打了一个二进制依赖,任何纯传递的依赖关系被解析为二进制。例如,我有一个项目 cyan ,它直接依赖于 green blue 并且通过绿色,在黄色

  compile  - 为源集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

现在如果我添加 blue 黄色到我的多模块项目,但不是绿色,我得到:

  compile  - 为源集main编译类路径。 
+ --- com.iii.shared:green:+ - > 2.0-SNAPSHOT
| + --- com.iii.shared:yellow:+ - > 2.0-SNAPSHOT
| \ --- com.iii.shared:blue:+ - >项目:蓝色
\ ---项目:蓝色

请注意,蓝色正在被解析为项目,即使它是可传递的,但黄色不是。



我认为这是一个功能,而不是一个错误 - 它反映了在分发时间实际发生的情况。我可以将所有更改变为黄色,但如果我没有在我的新的黄色存储库以及更新的绿色与更新的依赖关系,则实际发布的 cyan 不会得到更改。


suppose the following project. the master project is a multi-project, however every part of the larger project can be developed individually or mixed in:

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

suppose m3 uses m2 and m2 uses m1 ( m1 <- m2 <- m3 )

the presence of m2 is optional a multi-project with the following layout also reasonable

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

but in this case m2 would be pulled in from the artifact repository which is fine...however m1 was a transitive dependency of m2 which is good, but how can i tell gradle to use the local version of m1 instead of the baked artifact?

I'm stuck with this, every place i have access to override these thing gradle gives me "just" ModuleVersionSelector level access, how can i add a DefaultProjectDependency according to the downloaded artifact transitive dependencies?

i may have an alternative if i can access the full dependency graph of the archived artifacts, and put in some overrides/excludes.

EDIT:

the best i've come up with is using a filter using resolutionStrategy, i've created an example by further developing the 'elastic-deps' project

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

解决方案

Starting with elastic-deps and with the help of this answer (also from Peter) I came up with the trick below.

In the top-level 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()
  }
}

The nice thing about this is that unlike elastic-deps you don't have to modify the subprojects.

This still has the problem that once you hit a binary dependency, any purely transitive dependencies are resolved as binary. E.g., say I have a project cyan which depends directly on green and blue and transitively, through green, on 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

Now if I add blue and yellow to my multi-module project, but not green, I get:

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

Note that blue is resolved correctly to the project even when it's transitive, but yellow isn't.

Personally I think this is a feature, not a bug -- it reflects what would actually happen at distribution time. I can make all the changes to yellow I want, but if I don't put a new yellow artifact in my repository and also an updated green with the updated dependency, then the actual release of cyan isn't going to get those changes.

这篇关于Gradle多项目可选子项目的传递依赖关系应该被解析为一个现有的子项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆