在某些情况下,需要自定义 artifact 解析过程。ArtifactView
API 是影响 Gradle 中 artifact 选择的主要机制。
ArtifactView
在已解析的图之上操作,但允许您应用不同的属性。它使您可以检索符合新一组条件的 artifact,即使它们不是原始图解析的一部分。
ArtifactView
可以
-
选择替代变体,例如整个解析过程的 sources 或 javadoc:通常,artifact 必须同时匹配图的属性和
ArtifactView
的属性。使用withVariantReselection
,您可以从组件内的任何可用变体中选择 artifact。 -
执行宽松的 Artifact 选择和解析:使用带有
lenient=true
的ArtifactView
允许您忽略缺失的依赖项和其他错误。 -
过滤选定的 Artifact:使用带有
componentFilter
的ArtifactView
允许您从选定的 artifact 中排除特定的组件。 -
触发转换:触发
ArtifactTransform
将一个 artifact 从一种类型转换为另一种类型。
ArtifactView 可以生成 FileCollection 和 ArtifactCollection 两种结果。下面的示例仅演示了将 FileCollection 作为输出。 |
1. 执行变体重新选择
标准 artifact 选择只能在图选择结果所选组件的变体之间进行选择。然而,在某些情况下,可能需要从与被选图节点并行的变体中选择 artifact。
考虑下面的示例组件结构,描述了一个典型的带有 sources 和 javadoc 的本地 Java 库
variant 'apiElements'
artifact set 'jar'
artifact set 'classes'
artifact set 'resources'
variant 'runtimeElements'
artifact set 'jar'
artifact set 'classes'
artifact set 'resources'
variant 'javadocElements'
artifact set 'jar'
variant 'sourcesElements'
artifact set 'jar'
解析 Java 运行时类路径将从上述示例组件中选择 runtimeElements
变体。在标准 artifact 选择过程中,Gradle 将仅从 runtimeElements
下的 artifact 集合中进行选择。
然而,通常希望为图中的每个节点选择所有 sources 或所有 javadoc。考虑以下示例,它为给定的运行时类路径选择所有 sources
此示例使用了孵化中的 API。 |
tasks.register<ResolveFiles>("resolveSources") {
files.from(configurations.runtimeClasspath.map {
it.incoming.artifactView {
withVariantReselection()
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage.JAVA_RUNTIME));
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category.DOCUMENTATION));
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling.EXTERNAL));
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType.SOURCES));
}
}.files
})
}
tasks.register("resolveSources", ResolveFiles) {
files.from(configurations.runtimeClasspath.incoming.artifactView {
withVariantReselection()
attributes {
attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, Usage.JAVA_RUNTIME));
attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, Category.DOCUMENTATION));
attribute(Bundling.BUNDLING_ATTRIBUTE, objects.named(Bundling, Bundling.EXTERNAL));
attribute(DocsType.DOCS_TYPE_ATTRIBUTE, objects.named(DocsType, DocsType.SOURCES));
}
}.files)
}
使用 ArtifactView.withVariantReselection()
API,Gradle 会在对新选定的变体执行 artifact 选择之前,可选地再次执行图变体选择。当 Gradle 为 runtimeElements
节点选择 artifact 时,它将使用在 ArtifactView
上指定的属性重新选择图变体,从而选择 sourcesElements
变体。然后,将在 sourcesElements
变体上执行传统的 artifact 选择以选择 jar
artifact 集合。
结果是,为每个节点解析了 sources jar
junit-platform-commons-1.11.0-sources.jar junit-jupiter-api-5.11.0-sources.jar opentest4j-1.3.0-sources.jar
使用此 API 时,用于变体重新选择的属性仅由 ArtifactView.getAttributes()
方法指定。在变体重新选择期间,配置上指定的图解析属性将完全被忽略。
2. 执行宽松的 artifact 选择和解析
ArtifactView
API 也可用于执行宽松的 artifact 解析。这允许在包含失败的图上执行 artifact 解析,例如请求的模块未找到、请求的模块版本不存在或冲突未解决时。此外,当图已成功解析但相应的 artifact 无法下载时,也可以使用宽松的 artifact 解析来解析 artifact。
考虑以下示例,其中一些依赖项可能不存在
dependencies {
implementation("does:not:exist")
implementation("org.junit.jupiter:junit-jupiter-api:5.11.0")
}
dependencies {
implementation("does:not:exist")
implementation("org.junit.jupiter:junit-jupiter-api:5.11.0")
}
通过使用 ArtifactView.lenient()
方法执行宽松解析
tasks.register<ResolveFiles>("resolveLenient") {
files.from(configurations.runtimeClasspath.map {
it.incoming.artifactView {
isLenient = true
}.files
})
}
tasks.register("resolveLenient", ResolveFiles) {
files.from(configurations.runtimeClasspath.incoming.artifactView {
lenient = true
}.files)
}
我们可以看到任务成功了,并省略了失败的 artifact
> Task :resolveLenient junit-platform-commons-1.11.0.jar junit-jupiter-api-5.11.0.jar opentest4j-1.3.0.jar BUILD SUCCESSFUL in 0s
3. 过滤选定的 artifact
ArtifactView
API 可用于从结果 FileCollection
或 ArtifactCollection
中过滤特定的 artifact。
ArtifactViews
允许按组件过滤结果。使用 ArtifactView.componentFilter(Action)
方法,可以从已解析的结果中过滤所选变体的 artifact。该 action 将收到拥有正在为其选择 artifact 的变体的 ComponentIdentifier
。
考虑以下示例,其中我们有一个项目依赖项和一个外部依赖项
dependencies {
implementation(project(":other"))
implementation("org.junit.jupiter:junit-jupiter-api:5.11.0")
}
dependencies {
implementation(project(":other"))
implementation("org.junit.jupiter:junit-jupiter-api:5.11.0")
}
使用 componentFilter
方法,我们可以指定仅选择特定类型 artifact 的过滤器
tasks.register<ResolveFiles>("resolveProjects") {
files.from(configurations.runtimeClasspath.map {
it.incoming.artifactView {
componentFilter {
it is ProjectComponentIdentifier
}
}.files
})
}
tasks.register<ResolveFiles>("resolveModules") {
files.from(configurations.runtimeClasspath.map {
it.incoming.artifactView {
componentFilter {
it is ModuleComponentIdentifier
}
}.files
})
}
tasks.register("resolveProjects", ResolveFiles) {
files.from(configurations.runtimeClasspath.incoming.artifactView {
componentFilter {
it instanceof ProjectComponentIdentifier
}
}.files)
}
tasks.register("resolveModules", ResolveFiles) {
files.from(configurations.runtimeClasspath.incoming.artifactView {
componentFilter {
it instanceof ModuleComponentIdentifier
}
}.files)
}
注意我们如何分别解析项目依赖项和模块依赖项
> Task :resolveProjects other.jar > Task :resolveModules junit-platform-commons-1.11.0.jar junit-jupiter-api-5.11.0.jar opentest4j-1.3.0.jar
4. 触发 artifact 转换
ArtifactView
可用于使用与解析图所用属性不同的属性来触发 artifact 选择。
对于图中的每个节点,都会对该节点执行 artifact 选择。最常见的是,此 API 用于请求选定 artifact 上不存在的属性。当 Gradle 无法从相关节点找到匹配的 artifact 集合时,它将尝试使用项目中注册的 artifact 转换来转换可用 artifact,以满足请求。
下面,我们使用 artifact 转换章节中的解压缩示例来演示如何使用 ArtifactView
API 请求触发转换的属性
tasks.register<ResolveFiles>("resolveTransformedFiles") {
files.from(configurations.runtimeClasspath.map {
it.incoming.artifactView {
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements.CLASSES_AND_RESOURCES))
attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.DIRECTORY_TYPE)
}
}.files
})
}
tasks.register("resolveTransformedFiles", ResolveFiles) {
files.from(configurations.runtimeClasspath.incoming.artifactView {
attributes {
attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, LibraryElements.CLASSES_AND_RESOURCES))
attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.DIRECTORY_TYPE)
}
}.files)
}
Gradle 使用配置上指定的图解析属性以及 ArtifactView
的 attributes
块中指定的属性串联起来执行 artifact 选择。
任务输出显示 artifact 已被转换
junit-platform-commons-1.11.0.jar-unzipped junit-jupiter-api-5.11.0.jar-unzipped opentest4j-1.3.0.jar-unzipped
用于解压 JAR 文件(从 ZIP
到 UNZIP
)的转换代码(ArtifactTransform
)可以在下一章中看到。
下一步: 了解 Artifact 转换 >>