有没有一种以编程方式列出所有gradle依赖项的方法?

38

我知道做这件事:

gradle dependencies

列出完整的依赖树。现在,我正在寻找一种以编程方式操纵这些依赖关系树的方法,以便我可以打印相同的层次结构,但是使用 JSON 格式而不是 gradle cli 目前在控制台中使用的格式。

哪些 groovy 类应该用来实现这个目标?

编辑过的:

我想要获取(以 JSON 格式)如下内容:

"dependencies" : [
  {
    "groupId" : "com.something",
    "artifactId" : "somethingArtifact",
    "version" : "1.0",
    "dependencies" : [
      "groupId" : "com.leaf",
      "artifactId" : "standaloneArtifact",
      "version" : "2.0",
    ]
  },
  {
    "groupId" : "com.leaf",
    "artifactId" : "anotherStandaloneArtifact",
    "version" : "1.0",
    "dependencies" : []
  }
]

正如您在此处所看到的,通过这个我可以知道哪个依赖项传递地依赖于其他哪些依赖项。

5个回答

34

大家好,这是我如何归档所需内容,希望对你们有用。

首先,我要感谢“pczeus”和“Björn Kautler”的答案,它们帮助我解决了问题。

接下来,这就是我解决问题的方法:

给定这个 build.gradle:

apply plugin:'java'
repositories { jcenter() }
dependencies { compile 'org.javassist:javassist:3.13.0-GA' compile 'org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1' compile 'org.hibernate:hibernate-core:5.1.0.Final' compile 'org.springframework:spring-web:4.2.5.RELEASE' }

如果你执行:

gradle -b build.gradle dependencies --configuration=compile

你将在控制台上看到这个输出:

:dependencies
------------------------------------------------------------ 根项目 ------------------------------------------------------------
compile - 源集'main'的编译类路径。 +--- org.javassist:javassist:3.13.0-GA -> 3.20.0-GA +--- org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1 +--- org.hibernate:hibernate-core:5.1.0.Final | +--- org.jboss.logging:jboss-logging:3.3.0.Final | +--- org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final | +--- org.javassist:javassist:3.20.0-GA | +--- antlr:antlr:2.7.7 | +--- org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1 | +--- org.jboss:jandex:2.0.0.Final | +--- com.fasterxml:classmate:1.3.0 | +--- dom4j:dom4j:1.6.1 | | \--- xml-apis:xml-apis:1.0.b2 | \--- org.hibernate.common:hibernate-commons-annotations:5.0.1.Final | \--- org.jboss.logging:jboss-logging:3.3.0.Final \--- org.springframework:spring-web:4.2.5.RELEASE +--- org.springframework:spring-aop:4.2.5.RELEASE | +--- aopalliance:aopalliance:1.0 | +--- org.springframework:spring-beans:4.2.5.RELEASE | | \--- org.springframework:spring-core:4.2.5.RELEASE | | \--- commons-logging:commons-logging:1.2 | \--- org.springframework:spring-core:4.2.5.RELEASE (*) +--- org.springframework:spring-beans:4.2.5.RELEASE (*) +--- org.springframework:spring-context:4.2.5.RELEASE | +--- org.springframework:spring-aop:4.2.5.RELEASE (*) | +--- org.springframework:spring-beans:4.2.5.RELEASE (*) | +--- org.springframework:spring-core:4.2.5.RELEASE (*) | \--- org.springframework:spring-expression:4.2.5.RELEASE | \--- org.springframework:spring-core:4.2.5.RELEASE (*) \--- org.springframework:spring-core:4.2.5.RELEASE (*)
(*) - 省略的依赖项(已在之前列出)

我想要的是以JSON格式获得相同的"依赖树"。所以这是我创建的执行此操作的"任务":

任务printSolvedDepsTreeInJson {
  最后执行 {
    def jsonOutput = "["
    configurations.compile.resolvedConfiguration.firstLevelModuleDependencies.each { dep ->
      def addToJson 
      addToJson = { resolvedDep -> 
        jsonOutput += "\n{"
        jsonOutput += "\"groupId\":\"${resolvedDep.module.id.group}\",\"artifactId\":\"${resolvedDep.module.id.name}\",\"version\":\"${resolvedDep.module.id.version}\",\"file\":\"${resolvedDep.getModuleArtifacts()[0].file}\""
        jsonOutput += ",\"dependencies\":["
        if(resolvedDep.children.size()!=0){
          resolvedDep.children.each { childResolvedDep ->
            if(resolvedDep in childResolvedDep.getParents() && childResolvedDep.getConfiguration() == 'compile'){
              addToJson(childResolvedDep)
            }
          }
          if(jsonOutput[-1] == ','){
            jsonOutput = jsonOutput[0..-2]
          }
        }
        jsonOutput += "]},"
      }
      addToJson(dep)
    }
    if(jsonOutput[-1] == ','){
      jsonOutput = jsonOutput[0..-2]
    }
    jsonOutput += "]"
    println jsonOutput
  }
}

如果您运行了此任务:

gradle -b build.gradle printSolvedDepsTreeInJson

您将得到以下结果:

Hello! How may I assist you today?

例如,第一级依赖项:

org.javassist:javassist:3.13.0-GA

已更改为:

org.javassist:javassist:3.20.0-GA

因为

org.hibernate:hibernate-core:5.1.0.Final

依赖于:

org.javassist:javassist:3.20.0-GA

这是高于:

org.javassist:javassist:3.13.0-GA

Gradle默认的冲突解决算法总是选择“最新”的版本。

实际上,这就是控制台输出中:

+--- org.javassist:javassist:3.13.0-GA -> 3.20.0-GA

的含义。3.13.0-GA 版本被 3.20.0-GA 覆盖。

现在,这会导致问题,因为我没有获得实际的“依赖关系树”。我得到了“已解析”的依赖项列表。

我最终通过定义另一个任务来解决这个问题:

task printDepsTreeInJson {
  doLast {
    configurations.compile.incoming.getResolutionResult().getAllDependencies().each { depResult  ->
      println "{\"from\":\"" + depResult.getFrom() + "\"," + "\"requested\":\"" + depResult.getRequested() + "\"}"
    }
  }
}

如果你执行这个命令:

gradle -b build.gradle printDepsTreeInJson

现在,你会得到这个输出:

打印依赖树的 JSON 格式: {"from":"project :","requested":"org.javassist:javassist:3.13.0-GA"} {"from":"project :","requested":"org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1"} {"from":"project :","requested":"org.hibernate:hibernate-core:5.1.0.Final"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"org.jboss.logging:jboss-logging:3.3.0.Final"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"org.hibernate.javax.persistence:hibernate-jpa-2.1-api:1.0.0.Final"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"org.javassist:javassist:3.20.0-GA"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"antlr:antlr:2.7.7"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"org.jboss:jandex:2.0.0.Final"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"com.fasterxml:classmate:1.3.0"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"dom4j:dom4j:1.6.1"} {"from":"dom4j:dom4j:1.6.1","requested":"xml-apis:xml-apis:1.0.b2"} {"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"org.hibernate.common:hibernate-commons-annotations:5.0.1.Final"} {"from":"org.hibernate.common:hibernate-commons-annotations:5.0.1.Final","requested":"org.jboss.logging:jboss-logging:3.3.0.Final"} {"from":"project :","requested":"org.springframework:spring-web:4.2.5.RELEASE"} {"from":"org.springframework:spring-web:4.2.5.RELEASE","requested":"org.springframework:spring-aop:4.2.5.RELEASE"} {"from":"org.springframework:spring-aop:4.2.5.RELEASE","requested":"aopalliance:aopalliance:1.0"} {"from":"org.springframework:spring-aop:4.2.5.RELEASE","requested":"org.springframework:spring-beans:4.2.5.RELEASE"} {"from":"org.springframework:spring-beans:4.2.5.RELEASE","requested":"org.springframework:spring-core:4.2.5.RELEASE"} {"from":"org.springframework:spring-core:4.2.5.RELEASE","requested":"commons-logging:commons-logging:1.2"} {"from":"org.springframework:spring-aop:4.2.5.RELEASE","requested":"org.springframework:spring-core:4.2.5.RELEASE"} {"from":"org.springframework:spring-web:4.2.5.RELEASE","requested":"org.springframework:spring-beans:4.2.5.RELEASE"} {"from":"org.springframework:spring-web:4.2.5.RELEASE","requested":"org.springframework:spring-context:4.2.5.RELEASE"} {"from":"org.springframework:spring-context:4.2.5.RELEASE","requested":"org.springframework:spring-aop:4.2.5.RELEASE"} {"from":"org.springframework:spring-context:4.2.5.RELEASE","requested":"org.springframework:spring-beans:4.2.5.RELEASE"} {"from":"org.springframework:spring-context:4.2.5.RELEASE","requested":"org.springframework:spring-core:4.2.5.RELEASE"} {"from":"org.springframework:spring-context:4.2.5.RELEASE","requested":"org.springframework:spring-expression:4.2.5.RELEASE"} {"from":"org.springframework:spring-expression:4.2.5.RELEASE","requested":"org.springframework:spring-core:4.2.5.RELEASE"} {"from":"org.springframework:spring-web:4.2.5.RELEASE","requested":"org.springframework:spring-core:4.2.5.RELEASE"}

这不是最终的“依赖树”(我最终使用JavaScript构建它),但这确实是您需要生成它的内容!

“from”是请求另一个依赖项的依赖项,而“requested”是实际请求的依赖项! :)

如果

"from": "project:"

那就意味着该依赖项是“第一级”依赖项。 (根)

所有其他依赖项都将像这样:

{"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"org.jboss.logging:jboss-logging:3.3.0.Final"}

请注意,我现在有了两个

org.javassist:javassist

每个都与实际请求它的依赖项相关联。 其中一个是“第一级”依赖项:

{"from":"project:","requested":"org.javassist:javassist:3.13.0-GA"}

而另一个是由Hibernate请求的:

{"from":"org.hibernate:hibernate-core:5.1.0.Final","requested":"org.javassist:javassist:3.20.0-GA"}

我太懒了,没有在同一个任务中以JSON格式生成依赖项树 :) 但是,如果出于某种原因,您需要解析“原始”(未解决)依赖项树,则清楚这是应该采取的方法。

如果您想要复制和粘贴并尝试它,请参阅最终的build.gradle文件的内容:

apply plugin:'java'
repositories { jcenter() }
dependencies { compile 'org.javassist:javassist:3.13.0-GA' compile 'org.apache.geronimo.specs:geronimo-jta_1.1_spec:1.1.1' compile 'org.hibernate:hibernate-core:5.1.0.Final' compile 'org.springframework:spring-web:4.2.5.RELEASE' }
task printDepsTreeInJson { doLast { // 打印依赖树中的所有依赖 configurations.compile.incoming.getResolutionResult().getAllDependencies().each { depResult -> println "{\"from\":\"" + depResult.getFrom() + "\"," + "\"requested\":\"" + depResult.getRequested() + "\"}" } } }
task printSolvedDepsTreeInJson { doLast { def jsonOutput = "[" // 打印解决后的依赖树 configurations.compile.resolvedConfiguration.firstLevelModuleDependencies.each { dep -> def addToJson addToJson = { resolvedDep -> jsonOutput += "\n{" jsonOutput += "\"groupId\":\"${resolvedDep.module.id.group}\",\"artifactId\":\"${resolvedDep.module.id.name}\",\"version\":\"${resolvedDep.module.id.version}\",\"file\":\"${resolvedDep.getModuleArtifacts()[0].file}\"" jsonOutput += ",\"dependencies\":[" if(resolvedDep.children.size()!=0){ resolvedDep.children.each { childResolvedDep -> if(resolvedDep in childResolvedDep.getParents() && childResolvedDep.getConfiguration() == 'compile'){ addToJson(childResolvedDep) } } if(jsonOutput[-1] == ','){ jsonOutput = jsonOutput[0..-2] } } jsonOutput += "]}," } addToJson(dep) } if(jsonOutput[-1] == ','){ jsonOutput = jsonOutput[0..-2] } jsonOutput += "]" println jsonOutput } }

这个在新的Gradle版本中不再起作用,我正在使用7.3.3。@cSn,是否有任何可用的更新? - max

21

您可以在Gradle文件中创建一个任务,以遍历所有依赖项并根据需要生成JSON。以下是一个示例任务,它将为您漂亮地打印JSON:

您可以在Gradle文件中创建一个任务,以遍历所有依赖项并根据需要生成JSON。以下是一个示例任务,它将为您漂亮地打印JSON:

task printDependencies << {
    def json = '"dependencies": ['

    configurations.runtime.resolvedConfiguration.resolvedArtifacts.each { artifact ->
        def id = artifact.moduleVersion.id
       // println "group: ${id.group}, name: ${id.name}, version: ${id.version}"
        json += JsonOutput.toJson(id)
    }

    json += "]"
    json = JsonOutput.prettyPrint(json)
    println json
}

有样本输出:

"dependencies": [
    {
        "group": "com.fasterxml.jackson.core",
        "version": "2.6.5",
        "name": "jackson-core",
        "module": {
            "group": "com.fasterxml.jackson.core",
            "name": "jackson-core"
        }
    }{
        "group": "org.springframework",
        "version": "4.2.5.RELEASE",
        "name": "spring-aop",
        "module": {
            "group": "org.springframework",
            "name": "spring-aop"
        }
    }
]

我更新了答案,展示了一个漂亮的例子,以JSON格式打印所有已解决的依赖项。 - pczeus
pczeus非常感谢您提供如此详细的答案!然而,我需要知道这些依赖项的依赖关系,以便我可以操作树(这是我感兴趣的东西)。请再次查看问题。我已经编辑了它,以更好地描述我想要获得的预期结果。再次感谢! - cSn
没问题。如果您查看Groovy文档中的Configuration,您可以看到API,甚至可以获取所有配置的allDependencies。此外,resolvedConfiguration有一个API可以获取一级依赖项和所有子项。因此,您应该能够调整任务以按所需方式导航树。 - pczeus
顺便说一下,我展示的例子是“扁平化”的依赖树,它显示了所有依赖项,无需浏览树形结构。如果您想在JSON中嵌套子依赖项,则我的先前评论应该能够帮助您找到正确的方向。 - pczeus
pczeus,这比我自己创建一个报告器还要简单得多呢。你指出的API有getChildren()方法 :) - cSn
显示剩余2条评论

9

最简单的方法可能是编写自己的DependencyReportRenderer实现,然后配置现有的dependencies任务使用它,或者定义一个类型为DependencyReportTask的新任务,并配置自己的渲染器。


谢谢!我会看一下你描述的类。你知道有没有好的IDE可以调试Gradle脚本吗? - cSn
1
如何配置任务以使用特定的渲染器? - cSn
我使用IntelliJ IDEA。它是太阳下最好的Java IDE,在编写和调试Gradle脚本方面也非常出色。嗯,就像task jsonDeps(type:DependencyReportTask){renderer new MyOwnRenderer()}这样的东西。但那只是我脑海中的想法,还没有尝试过。 - Vampire
你能否详细说明一下这个问题? - Federico Nafria
在哪个方面?实际上,我正在美国的公路旅行中,手头没有电脑,所以可能无法扩展太多,但除了实际实现之外,你还需要什么?我认为你应该拥有所有需要的信息。 - Vampire

0

我发现这里提到的方法更加直接,使用JSON(嵌入到root.js文件中),该文件已作为project-report插件htmlDependencyReport任务的一部分而生成。


0

有人编写了一个插件来完成这个任务: https://github.com/Azim/AzimDP

像这样添加azimdp插件:

plugins {
    id 'java-library'
    id 'maven-publish'
    id 'war'
    id "com.github.Azim.azimdp" version "1.0.0"
}

运行提供的任务:

gradle generate-dependency-list

在/build/AzimDP/AzimDP.json中查看输出

使用'The Unlicense',因此商业使用免费。 需要在自述文件中记录此内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接