如何从Gradle模型中获取所有插件相关的完整依赖?
我正在开发一个Gradle插件,用于列出项目构建所用的所有依赖。针对简单的compile和buildscript依赖,实现起来较为容易:
val dependencies = project.allprojects.asSequence().flatMap { project -> (project.buildscript.configurations + project.configurations).asSequence() .filter { it.isCanBeResolved } .flatMap { val resolved = it.resolvedConfiguration resolved.rethrowFailure() resolved.firstLevelModuleDependencies.flatMap { dep -> dep.allModuleArtifacts } } }
(随后可通过it.id.componentIdentifier as ModuleComponentIdentifier获取group、module和version,通过it.type和it.classifier获取对应属性)。
但这种方式会遗漏仅由插件使用的JAR包。例如,当应用Kotlin插件:
plugins { kotlin("jvm") version "1.6.10" }
时,生成的依赖列表并不完整——仅包含org.jetbrains.kotlin:kotlin-gradle-plugin及其部分关联依赖,却未包含所需的org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin这一POM依赖。请问能否从Gradle模型中获取这些遗漏的依赖?
可以通过Gradle的插件管理模型获取这些插件标记依赖(即.gradle.plugin类型的POM依赖),具体可从以下方向实现:
1. 直接访问插件解析结果
Gradle在解析plugins块时会维护插件的解析信息,通过gradle.pluginResolutionManager可直接获取已解析的插件标记依赖:
// 遍历所有已解析的插件请求 gradle.pluginResolutionManager.resolvedPlugins.forEach { resolvedPlugin -> val moduleVersion = resolvedPlugin.moduleVersion // 输出格式:org.jetbrains.kotlin.jvm:org.jetbrains.kotlin.jvm.gradle.plugin:1.6.10 println("Plugin marker dependency: ${moduleVersion.group}:${moduleVersion.name}:${moduleVersion.version}") }
2. 从buildscript classpath补充依赖树
plugins块最终会将插件实现依赖注入到buildscript.classpath,但插件标记依赖本身不会直接加入classpath,可通过解析classpath的依赖树筛选出这类标记:
// 解析buildscript classpath的依赖树 project.buildscript.configurations.classpath.resolvedConfiguration.firstLevelModuleDependencies.forEach { dep -> checkAndAddPluginMarker(dep) } // 递归检查子依赖 fun checkAndAddPluginMarker(dep: ResolvedDependency) { if (dep.moduleName.endsWith(".gradle.plugin")) { println("Plugin marker: ${dep.group}:${dep.moduleName}:${dep.moduleVersion}") } dep.children.forEach { checkAndAddPluginMarker(it) } }
3. 整合到现有依赖收集逻辑
将上述两种方式与原有代码结合,即可覆盖所有类型的依赖:
val allDependencies = mutableListOf<Any>() // 原有逻辑收集compile和buildscript依赖 val projectDeps = project.allprojects.asSequence().flatMap { project -> (project.buildscript.configurations + project.configurations).asSequence() .filter { it.isCanBeResolved } .flatMap { val resolved = it.resolvedConfiguration resolved.rethrowFailure() resolved.firstLevelModuleDependencies.flatMap { dep -> dep.allModuleArtifacts } } } allDependencies.addAll(projectDeps) // 收集插件标记依赖 val pluginMarkerDeps = gradle.pluginResolutionManager.resolvedPlugins.map { it.moduleVersion } allDependencies.addAll(pluginMarkerDeps) // 统一处理依赖信息 allDependencies.forEach { dep -> when (dep) { is ModuleVersionIdentifier -> { println("Plugin marker: ${dep.group}:${dep.name}:${dep.version}") } is ResolvedArtifact -> { val id = dep.id.componentIdentifier as ModuleComponentIdentifier println("Artifact: ${id.group}:${id.module}:${id.version} (${dep.type}, ${dep.classifier})") } } }
插件标记artifact本质是用于定位插件实现的POM文件,本身不会进入构建classpath,但如果你的需求是收集构建全流程涉及的所有依赖,这种方式就能覆盖到这类遗漏项。
内容的提问来源于stack exchange,提问作者user8681

