A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://docs.gradle.org/current/userguide/artifact_resolution.html below:

Artifact Resolution

Gradle APIs can be used to influence the process of artifact selection.

Gradle can then expose the results of artifact selection as an ArtifactCollection. More commonly, the results are exposed as a FileCollection, which is a flat list of files.

Implicit Artifact Selection

By default, the attributes used for artifact selection are the same as those used for variant selection during graph resolution. These attributes are specified by the Configuration.getAttributes() property.

To perform artifact selection (and implicitly, graph resolution) using these default attributes, use the FileCollection and ArtifactCollection APIs.

Files can also be accessed from the configuration’s ResolvedConfiguration, LenientConfiguration, ResolvedArtifact and ResolvedDependency APIs. However, these APIs are in maintenance mode and are discouraged for use in new development. These APIs perform artifact selection using the default attributes. Resolving files

To resolve files, we first define a task that accepts a ConfigurableFileCollection as input:

build.gradle.kts

abstract class ResolveFiles : DefaultTask() {

    @get:InputFiles
    abstract val files: ConfigurableFileCollection

    @TaskAction
    fun print() {
        files.forEach {
            println(it.name)
        }
    }
}

build.gradle

abstract class ResolveFiles extends DefaultTask {

    @InputFiles
    abstract ConfigurableFileCollection getFiles()

    @TaskAction
    void print() {
        files.each {
            println(it.name)
        }
    }
}

Then, we can wire up a resolvable configuration’s files to the task’s input. The Configuration directly implements FileCollection and can be wired directly:

build.gradle.kts

tasks.register<ResolveFiles>("resolveConfiguration") {
    files.from(configurations.runtimeClasspath)
}

build.gradle

tasks.register("resolveConfiguration", ResolveFiles) {
    files.from(configurations.runtimeClasspath)
}

Running the resolveConfiguration task produces:

> Task :resolveConfiguration
junit-platform-commons-1.11.0.jar
junit-jupiter-api-5.11.0.jar
opentest4j-1.3.0.jar
Resolving artifacts

Instead of consuming the files directly from the implicit artifact selection process, we can consume the artifacts, which contain both the files and the metadata.

This process is slightly more complicated, as in order to maintain Configuration Cache compatibility, we need to split the fields of ResolvedArtifactResult into two task inputs:

build.gradle.kts

data class ArtifactDetails(
    val id: ComponentArtifactIdentifier,
    val variant: ResolvedVariantResult
)

abstract class ResolveArtifacts : DefaultTask() {

    @get:Input
    abstract val details: ListProperty<ArtifactDetails>

    @get:InputFiles
    abstract val files: ListProperty<File>

    fun from(artifacts: Provider<Set<ResolvedArtifactResult>>) {
        details.set(artifacts.map {
            it.map { artifact -> ArtifactDetails(artifact.id, artifact.variant) }
        })
        files.set(artifacts.map {
            it.map { artifact -> artifact.file }
        })
    }

    @TaskAction
    fun print() {
        assert(details.get().size == files.get().size)
        details.get().zip(files.get()).forEach { (details, file) ->
            println("${details.variant.displayName}:${file.name}")
        }
    }
}

build.gradle

class ArtifactDetails {
    ComponentArtifactIdentifier id
    ResolvedVariantResult variant

    ArtifactDetails(ComponentArtifactIdentifier id, ResolvedVariantResult variant) {
        this.id = id
        this.variant = variant
    }
}

abstract class ResolveArtifacts extends DefaultTask {

    @Input
    abstract ListProperty<ArtifactDetails> getDetails()

    @InputFiles
    abstract ListProperty<File> getFiles()

    void from(Provider<Set<ResolvedArtifactResult>> artifacts) {
        details.set(artifacts.map {
            it.collect { artifact -> new ArtifactDetails(artifact.id, artifact.variant) }
        })
        files.set(artifacts.map {
            it.collect { artifact -> artifact.file }
        })
    }

    @TaskAction
    void print() {
        List<ArtifactDetails> allDetails = details.get()
        List<File> allFiles = files.get()

        assert allDetails.size() == allFiles.size()
        for (int i = 0; i < allDetails.size(); i++) {
            def details = allDetails.get(i)
            def file = allFiles.get(i)
            println("${details.variant.displayName}:${file.name}")
        }
    }
}

This task is initialized similarly to the file resolution task:

build.gradle.kts

tasks.register<ResolveArtifacts>("resolveIncomingArtifacts") {
    from(configurations.runtimeClasspath.flatMap { it.incoming.artifacts.resolvedArtifacts })
}

build.gradle

tasks.register("resolveIncomingArtifacts", ResolveArtifacts) {
    from(configurations.runtimeClasspath.incoming.artifacts.resolvedArtifacts)
}

Running this task, we can see that file metadata is included in the output:

org.junit.platform:junit-platform-commons:1.11.0 variant runtimeElements:junit-platform-commons-1.11.0.jar
org.junit.jupiter:junit-jupiter-api:5.11.0 variant runtimeElements:junit-jupiter-api-5.11.0.jar
org.opentest4j:opentest4j:1.3.0 variant runtimeElements:opentest4j-1.3.0.jar
Custom Artifact Selection

The ArtifactView API operates on top of the resolved graph, defined by a ../javadoc/org/gradle/api/artifacts/result/ResolutionResult.html[ResolutionResult].

The API provides flexible ways to access the resolved artifacts:

When you call a configuration’s getFiles(), Gradle selects artifacts based on the attributes used during graph resolution. However, the ArtifactView API is more flexible. It allows you to resolve artifacts from the graph with custom attributes.

Artifact views

An ArtifactView allows you to:

  1. Query artifacts with different attributes:

  2. Extract specific types of artifacts:

  3. Avoid side effects:

In the following example, a producer project creates a library with typical Java library variants (runtimeElements, apiElements). We also create a custom variant called apiProductionElements with the artifact production.jar and attribute org.gradle.category:production:

producer/build.gradle.kts

plugins {
    `java-library`
}

repositories {
    mavenCentral()
}

dependencies {
    // Define some dependencies here
}

// Define a task that produces a custom artifact
tasks.register<Jar>("createProductionArtifact") {
    archiveBaseName.set("production")
    from(sourceSets["main"].output)
    destinationDirectory.set(file("build/libs"))
}

configurations {
    // Define a custom configuration and extend from apiElements
    create("apiProductionElements") {
        extendsFrom(configurations.apiElements.get())
        outgoing.artifacts.clear()
        attributes {
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named("production"))
        }
        artifacts {
            add("apiProductionElements", tasks.named("createProductionArtifact"))
        }
    }
}

producer/build.gradle

plugins {
    id 'java-library'
}

repositories {
    mavenCentral()
}

dependencies {
    // Define some dependencies here
}

// Define a task that produces a custom artifact
tasks.register('createProductionArtifact', Jar) {
    archiveBaseName.set('production')
    from(sourceSets.main.output)
    destinationDirectory.set(file('build/libs'))
}

configurations {
    // Define a custom configuration and extend from apiElements
    apiProductionElements {
        extendsFrom(configurations.apiElements)
        attributes {
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category, 'production'))
        }
        artifacts {
            add('apiProductionElements', tasks.named('createProductionArtifact'))
        }
    }
}

We can view the available variants of this library as well as their corresponding artifacts and attributes with a custom task called checkProducerAttributes. Here is an abridged output showing the relevant variants of this library, along with their corresponding artifacts and attributes:

Configuration: apiElements
Attributes:
  - org.gradle.category -> library
  - org.gradle.usage -> java-api
  - org.gradle.libraryelements -> jar
  - org.gradle.dependency.bundling -> external
Artifacts:
  - producer.jar

Configuration: apiProductionElements
Attributes:
  - org.gradle.category -> production
Artifacts:
  - production.jar

Configuration: mainSourceElements
Attributes:
  - org.gradle.dependency.bundling -> external
  - org.gradle.category -> verification
  - org.gradle.verificationtype -> main-sources
Artifacts:
  - /src/main/resources
  - /src/main/java

Configuration: runtimeElements
Attributes:
  - org.gradle.category -> library
  - org.gradle.usage -> java-runtime
  - org.gradle.libraryelements -> jar
  - org.gradle.dependency.bundling -> external
Artifacts:
  - producer.jar

A Java application is a consumer of this Java library:

consumer/build.gradle.kts

plugins {
    application
}

repositories {
    mavenCentral()
}

// Declare the dependency on the producer project
dependencies {
    implementation(project(":producer")) // This references another subproject in the same build
}

consumer/build.gradle

plugins {
    id 'application'
}

repositories {
    mavenCentral()
}

// Declare the dependency on the producer project
dependencies {
    implementation project(':producer')
}

By default, the application, as the consumer, will consume the expected variant when it is run. We can verify this with another custom task called checkResolvedVariant that prints out the following:

RuntimeClasspath Configuration:
- Component: project :producer
    - Variant: runtimeElements
       - org.gradle.category -> library
       - org.gradle.usage -> java-runtime
       - org.gradle.libraryelements -> jar
       - org.gradle.dependency.bundling -> external
       - org.gradle.jvm.version -> 11
- Artifact: producer.jar

As expected, for the runtimeClasspath, the application consumes the runtimeElements variant of the library which is available as the artifact producer.jar. It uses the attributes org.gradle.category:library and org.gradle.usage:java-runtime to select this variant.

Now, let’s create an ArtifactView to select one of the other artifacts provided by the library. We do this by using an ArtifactView with the attribute org.gradle.category:classes so that instead of the jar file, we get the sources:

consumer/build.gradle.kts

tasks.register("artifactWithAttributeAndView") {
    val configuration = configurations.runtimeClasspath
    println("ArtifactView with attribute 'libraryelements = classes' for ${configuration.name}:")
    val artifactView = configuration.get().incoming.artifactView {
        attributes {
            attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements::class, "classes"))
        }
    }
    println("- Attributes:")
    artifactView.attributes.keySet().forEach { attribute ->
        val value = artifactView.attributes.getAttribute(attribute)
        println("  - ${attribute.name} = ${value}")
    }
    artifactView.artifacts.artifactFiles.files.forEach { file ->
        println("- Artifact: ${file.name}")
    }
}

tasks.register("artifactWithAttributeAndVariantReselectionView") {
    val configuration = configurations.runtimeClasspath
    println("ArtifactView with attribute 'category = production' for ${configuration.name}:")
    val artifactView = configuration.get().incoming.artifactView {
        withVariantReselection()
        attributes {
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category::class, "production"))
        }
    }
    println("- Attributes:")
    artifactView.attributes.keySet().forEach { attribute ->
        val value = artifactView.attributes.getAttribute(attribute)
        println("  - ${attribute.name} = ${value}")
    }
    artifactView.artifacts.artifactFiles.files.forEach { file ->
        println("- Artifact: ${file.name}")
    }
}

consumer/build.gradle

tasks.register('artifactWithAttributeAndView') {
    def configuration = configurations.runtimeClasspath
    println "ArtifactView with attribute 'libraryelements = classes' for ${configuration.name}:"
    def artifactView = configuration.incoming.artifactView {
        attributes {
            attribute(LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE, objects.named(LibraryElements, 'classes'))
        }
    }
    println "- Attributes:"
    artifactView.attributes.keySet().each { attribute ->
        def value = artifactView.attributes.getAttribute(attribute)
        println "  - ${attribute.name} = ${value}"
    }
    artifactView.artifacts.artifactFiles.files.each { file ->
        println "- Artifact: ${file.name}"
    }
}

tasks.register('artifactWithAttributeAndVariantReselectionView') {
    def configuration = configurations.runtimeClasspath
    println "ArtifactView with attribute 'category = production' for ${configuration.name}:"
    def artifactView = configuration.incoming.artifactView {
        withVariantReselection()
        attributes {
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category,'production'))
        }
    }
    println "- Attributes:"
    artifactView.attributes.keySet().each { attribute ->
        def value = artifactView.attributes.getAttribute(attribute)
        println "  - ${attribute.name} = ${value}"
    }
    artifactView.artifacts.artifactFiles.files.each { file ->
        println "- Artifact: ${file.name}"
    }
}

We run the task artifactWithAttributeAndView to see that we get the main artifact instead:

ArtifactView with attribute 'libraryelements = classes' for runtimeClasspath:
- Attributes:
  - org.gradle.libraryelements = classes
  - org.gradle.category = library
  - org.gradle.usage = java-runtime
  - org.gradle.dependency.bundling = external
  - org.gradle.jvm.environment = standard-jvm
- Artifact: main

Now, let’s create an ArtifactView to select our custom variant apiProductionElements by specifying the attribute org.gradle.category:production and forcing Gradle to reselect a new variant:

consumer/build.gradle.kts

tasks.register("artifactWithAttributeAndVariantReselectionView") {
    val configuration = configurations.runtimeClasspath
    println("ArtifactView with attribute 'category = production' for ${configuration.name}:")
    val artifactView = configuration.get().incoming.artifactView {
        withVariantReselection()
        attributes {
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category::class, "production"))
        }
    }
    println("- Attributes:")
    artifactView.attributes.keySet().forEach { attribute ->
        val value = artifactView.attributes.getAttribute(attribute)
        println("  - ${attribute.name} = ${value}")
    }
    artifactView.artifacts.artifactFiles.files.forEach { file ->
        println("- Artifact: ${file.name}")
    }
}

consumer/build.gradle

tasks.register('artifactWithAttributeAndVariantReselectionView') {
    def configuration = configurations.runtimeClasspath
    println "ArtifactView with attribute 'category = production' for ${configuration.name}:"
    def artifactView = configuration.incoming.artifactView {
        withVariantReselection()
        attributes {
            attribute(Category.CATEGORY_ATTRIBUTE, objects.named(Category,'production'))
        }
    }
    println "- Attributes:"
    artifactView.attributes.keySet().each { attribute ->
        def value = artifactView.attributes.getAttribute(attribute)
        println "  - ${attribute.name} = ${value}"
    }
    artifactView.artifacts.artifactFiles.files.each { file ->
        println "- Artifact: ${file.name}"
    }
}

As expected, the apiProductionElements variant is selected along with the production.jar artifact:

ArtifactView with attribute 'libraryelements = classes' for runtimeClasspath:
- Attributes:
  - org.gradle.libraryelements = classes
  - org.gradle.category = library
  - org.gradle.usage = java-runtime
  - org.gradle.dependency.bundling = external
  - org.gradle.jvm.environment = standard-jvm
- Artifact: main

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4