All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.gradle.utils.LazyResolvedConfiguration.kt Maven / Gradle / Ivy

There is a newer version: 2.1.0-RC
Show newest version
/*
 * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
 * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
 */

package org.jetbrains.kotlin.gradle.utils

import org.gradle.api.artifacts.ArtifactCollection
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.ResolveException
import org.gradle.api.artifacts.ResolvedConfiguration
import org.gradle.api.artifacts.component.ComponentIdentifier
import org.gradle.api.artifacts.result.*
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.tooling.core.withClosure

/**
 * Represents a Gradle Configuration that was resolved after configuration time.
 * But still can be accessed during Configuration time, triggering configuration resolution
 *
 * Serializable to configuration cache. So it can be stored in task state and be accessed during execution time.
 *
 * Has similar API as non-configuration cache friendly Gradle's [ResolvedConfiguration]
 */
internal class LazyResolvedConfiguration private constructor(
    private val resolvedComponentsRootProvider: Lazy,
    private val artifactCollection: ArtifactCollection,
    private val configurationName: String,
) {
    /**
     * Creates [LazyResolvedConfiguration] from given [configuration].
     */
    constructor(configuration: Configuration, configureArtifactViewAttributes: (AttributeContainer) -> Unit = {}) : this(
        // Calling resolutionResult doesn't actually trigger resolution. But accessing its root ResolvedComponentResult
        // via ResolutionResult::root does. ResolutionResult can't be serialised for Configuration Cache
        // but ResolvedComponentResult can. Wrapping it in `lazy` makes it resolve upon serialisation.
        resolvedComponentsRootProvider = configuration.incoming.resolutionResult.let { rr -> lazy { rr.root } },
        artifactCollection = configuration.lazyArtifactCollection(configureArtifactViewAttributes),
        configurationName = configuration.name
    )

    val files: FileCollection get() = artifactCollection.artifactFiles

    val root by resolvedComponentsRootProvider

    val resolvedArtifacts: Set get() = artifactCollection.artifacts

    val resolutionFailures: Collection get() = artifactCollection.failures

    private val artifactsByComponentId by TransientLazy { resolvedArtifacts.groupBy { it.id.componentIdentifier } }

    val allDependencies: Set by TransientLazy {
        root.dependencies.withClosure {
            if (it is ResolvedDependencyResult) it.selected.dependencies
            else emptyList()
        }
    }

    internal val allResolvedDependencies: Set by TransientLazy {
        allDependencies.filterIsInstance().toSet()
    }

    fun getArtifacts(dependency: ResolvedDependencyResult): List {
        val componentId = dependency.resolvedVariant.lastExternalVariantOrSelf().owner
        return artifactsByComponentId[componentId] ?: emptyList()
    }

    fun getArtifacts(component: ResolvedComponentResult): List {
        val componentIds = component.variants.map { it.lastExternalVariantOrSelf().owner }
        return componentIds.flatMap { artifactsByComponentId[it].orEmpty() }
    }

    fun getArtifacts(componentId: ComponentIdentifier): List = artifactsByComponentId[componentId].orEmpty()

    override fun toString(): String = "LazyResolvedConfiguration(configuration='$configurationName')"
}

private fun Configuration.lazyArtifactCollection(configureAttributes: AttributeContainer.() -> Unit): ArtifactCollection =
    incoming.artifactView { view ->
        view.isLenient = true
        configureAttributes.invoke(view.attributes)
    }.artifacts

internal tailrec fun ResolvedVariantResult.lastExternalVariantOrSelf(): ResolvedVariantResult {
    return if (externalVariant.isPresent) externalVariant.get().lastExternalVariantOrSelf() else this
}

/**
 * Same as [LazyResolvedConfiguration.getArtifacts] except it returns null for cases when dependency is resolved
 * but artifact is not available. For example when host-specific part of the library is not yet published
 */
internal fun LazyResolvedConfiguration.dependencyArtifactsOrNull(dependency: ResolvedDependencyResult): List? =
    try {
        getArtifacts(dependency)
    } catch (_: ResolveException) {
        null
    }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy