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

name.remal.gradle_plugins.plugins.dependencies.filtered_dependencies.FilteredDependency.kt Maven / Gradle / Ivy

package name.remal.gradle_plugins.plugins.dependencies.filtered_dependencies

import name.remal.*
import name.remal.gradle_plugins.api.BuildTimeConstants.getStringProperty
import name.remal.gradle_plugins.dsl.extensions.autoFileTree
import org.gradle.api.Buildable
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.FileCollectionDependency
import org.gradle.api.artifacts.ModuleDependency
import org.gradle.api.artifacts.component.ComponentIdentifier
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.artifacts.dependencies.SelfResolvingDependencyInternal
import org.gradle.api.tasks.TaskDependency
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream
import java.nio.file.Files
import java.nio.file.Path
import java.util.jar.JarEntry
import java.util.jar.JarOutputStream

class FilteredDependency(
    private val delegate: Dependency,
    private val filter: DependencyFilter,
    private val cacheDir: File,
    private val project: Project
) : FileCollectionDependency, SelfResolvingDependencyInternal {

    private val includes: Set by lazy { filter.includes.toHashSet() }
    private val excludes: Set by lazy { filter.excludes.toHashSet() }
    private val configurerHash: String by lazy {
        sha256(ByteArrayOutputStream().also {
            ObjectOutputStream(it).use {
                it.writeObject(getStringProperty("version"))
                it.writeObject(includes)
                it.writeObject(excludes)
            }
        }.toByteArray())
    }

    private fun processResolvedFiles(files: Set): Set {
        return files.asSequence()
            .filter(File::exists)
            .map { file ->
                val cachedFile = File(cacheDir, "${file.nameWithoutExtension}/${file.hash}/$configurerHash/${file.nameWithoutExtension}.filtered.jar")
                if (cachedFile.exists()) return@map cachedFile

                JarOutputStream(cachedFile.createParentDirectories().outputStream()).use { jarOutputStream ->
                    project.autoFileTree(file)
                        .matching {
                            it.include(includes)
                            it.include("META-INF/MANIFEST.MF")
                            it.include("module-info.class")

                            it.exclude(excludes)
                            it.exclude("META-INF/*.SF")
                            it.exclude("META-INF/*.DSA")
                            it.exclude("META-INF/*.RSA")
                        }
                        .visit { details ->
                            if (details.isDirectory) {
                                val entry = JarEntry(details.path + "/")
                                entry.time = details.lastModified
                                jarOutputStream.putNextEntry(entry)
                            } else {
                                val entry = JarEntry(details.path)
                                entry.time = details.lastModified
                                jarOutputStream.putNextEntry(entry)
                                details.open().use { it.copyTo(jarOutputStream) }
                            }
                        }
                }
                return@map cachedFile
            }
            .toSet()
    }

    private val _transitiveFiles: Set by lazy {
        processResolvedFiles(
            project.configurations.detachedConfiguration(delegate).files
        )
    }

    private val _notTransitiveFiles: Set by lazy {
        processResolvedFiles(
            project.configurations.detachedConfiguration(delegate.copy()
                .also {
                    if (it is ModuleDependency) {
                        it.isTransitive = false
                    }
                }
            ).files
        )
    }

    override fun resolve(transitive: Boolean): Set {
        if (transitive) {
            return _transitiveFiles
        } else {
            return _notTransitiveFiles
        }
    }

    override fun resolve(): Set {
        return resolve(true)
    }


    override fun getFiles(): FileCollection {
        return project.files(resolve())
    }


    override fun copy(): Dependency {
        return FilteredDependency(
            delegate.copy(),
            DependencyFilter().also {
                it.includes.addAll(filter.includes)
                it.excludes.addAll(filter.excludes)
            },
            cacheDir,
            project
        ).also {
            it._reason = _reason
        }
    }

    override fun contentEquals(dependency: Dependency): Boolean {
        if (dependency !is FilteredDependency) return false
        if (delegate != dependency.delegate) return false
        if (filter != dependency.filter) return false
        if (cacheDir != dependency.cacheDir) return false
        if (project !== dependency.project) return false
        return true
    }

    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (other == null || other !is FilteredDependency) return false
        return contentEquals(other)
    }

    override fun hashCode(): Int {
        var result = delegate.hashCode()
        result = 31 * result + filter.hashCode()
        result = 31 * result + project.hashCode()
        return result
    }

    override fun getGroup(): String? = delegate.group

    override fun getName(): String = delegate.name

    override fun getVersion(): String? = delegate.version

    override fun getBuildDependencies(): TaskDependency {
        if (delegate is Buildable) {
            return delegate.buildDependencies
        }
        return TaskDependency { emptySet() }
    }


    override fun getTargetComponentId(): ComponentIdentifier? {
        return null
    }


    private var _reason: String? = null

    override fun because(reason: String?) {
        _reason = reason
    }

    override fun getReason(): String? {
        return _reason
    }


    private val File.hash: String
        get() {
            val digest = newSha256Digest()
            Files.walk(absoluteFile.toPath())
                .map { it.toAbsolutePath() }
                .filter(Path::isRegularFile)
                .distinct()
                .sorted()
                .forEach { it.newInputStream().use(digest::update) }
            return digest.digestHex()
        }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy