Use unzipped dependency in tasks across multiple projects

Hi there,

I wrote a plugin to execute a native executable in multiple subprojects. The native executable is extracted from a ZIP archive into the build-directory of the project. I now have the problem that this ZIP is unpacked in every project the plugin is applied to which takes a lot of time and resources, since the ZIP archive is about 100MB. Is there a proper way to only extract the ZIP archive once into a central directory wihtout having overlapping task outputs?

Here is a rough draft of what the plugin does:

val binaries by configurations.creating {
    isCanBeConsumed = false
    isCanBeResolved = true
}

dependencies {
    binaries("org.example:binaries:1.0.0+build.1337") {
        artifact {
            extension = "zip"
        }
    }
}

val unzipBinaryExecutable by tasks.registering(Sync::class) {
    from(zipTree(binaries))
    into(project.layout.buildDirectory.dir("extracted-binaries"))
}

val executeBinary by tasks.registering {
    inputs.files(unzipBinaryExecutable)
    doLast {
        // do stuff with
    }
}

// some more complex configuration

Thanks for your help
Daniel

If you do not use a sync task, but instead an artifact transform to do the unzipping, it should reuse the unpack result if possible.

Thanks, that did the trick. I now just use a simple transformer to do the unzipping:

import org.gradle.api.artifacts.transform.CacheableTransform
import org.gradle.api.artifacts.transform.InputArtifact
import org.gradle.api.artifacts.transform.TransformAction
import org.gradle.api.artifacts.transform.TransformOutputs
import org.gradle.api.artifacts.transform.TransformParameters
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.kotlin.dsl.support.unzipTo

@CacheableTransform
abstract class UnzipTransformer : TransformAction<TransformParameters.None> {

    @get:InputArtifact
    @get:PathSensitive(PathSensitivity.NAME_ONLY)
    abstract val inputArtifact: Provider<FileSystemLocation>

    override fun transform(outputs: TransformOutputs) {
        unzipTo(outputs.dir("unzipped-${inputArtifact.get().asFile.nameWithoutExtension}"), inputArtifact.get().asFile)
    }
}

The transformer can then transform jar to unzipped-jar

import org.gradle.api.artifacts.type.ArtifactTypeDefinition

private companion object {
    const val UNZIPPED_ARTIFACT_TYPE = ""unzipped-jar"
}

val binaries by configurations.creating {
    isCanBeResolved = true
    isCanBeConsumed = false
    attributes.attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, UNZIPPED_ARTIFACT_TYPE)
}

dependencies.registerTransform(UnzipTransformer::class) {
    it.from.attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, ArtifactTypeDefinition.JAR_TYPE)
    it.to.attribute(ArtifactTypeDefinition.ARTIFACT_TYPE_ATTRIBUTE, UNZIPPED_ARTIFACT_TYPE)
}

val executeBinary by tasks.registering {
    inputs.files(binaries)
    doLast {
       // binaries.singleFile.path now points to the directory containing the unzipped files
    }
}

But be aware the unzipTo is not public API!