https://gradle.com/ logo
#community-support
Title
# community-support
a

Andrew Tasso

05/24/2023, 10:18 PM
I'm trying to figure out why, when declaring configurations and artifacts to be consumed in one sub-project, and consuming those artifacts in another project as dependencies, the tasks for the producing project are not being executed first. When executing
./gradlew build
the build task for the consuming project will saying that the zip file can't be find, (since it hasn't been created yet). What am I missing? Producing Project (A project with
java-application
applied named "Dummy")
Copy code
configurations {
		appDistribution {
			canBeConsumed = true
			canBeResolved = false
		}
	}

	artifacts {
		appDistribution(distZip)
	}
Consuming Project:
Copy code
configurations {
	bundledApps {
		canBeConsumed = false
		canBeResolved = true
	}
}

dependencies {
	bundledApps(project(path: ":Dummy", configuration: 'appDistribution'))
}

configurations.bundledApps.each { file -> 
	distributions.main.contents {
		from(zipTree(file)) {
			into "tools"
		}
	}
}
a

Adam

05/24/2023, 10:21 PM
try using
configurations.bundledApps.incoming.artifactFiles
to get the incoming files (or something similar - I often get muddled with area of Gradle)
a

Andrew Tasso

05/24/2023, 10:30 PM
@Adam Thanks for the tip. I was unfamiliar with that. I'm still getting the same error after using that method
Copy code
configurations.bundledApps.incoming.files.each { file -> 
	distributions.main.contents {
		from(zipTree(file)) {
			into "tools"
		}
	}
}
a

Adam

05/24/2023, 10:41 PM
possibly using
each {}
means Gradle loses the task dependency. Try using
incoming.resolvedArtifacts
(or something like that, you want one that returns a
Provider<>
), and you can unzip the files in a
map {}
, then pass the result into the distributions contents something like this:
Copy code
distributions.main.contents {
  from(configurations.bundledApps.incoming.resolvedArtifacts.map { files -> ... }) {
    into "tools"
  }
}
v

Vampire

05/24/2023, 11:42 PM
Or maybe better, use an artifact transform to do the unzipping.
a

Andrew Tasso

05/25/2023, 1:19 AM
@Adam I suspect you're onto something. I included this in the first
distributions
declaration and it builds in correct order
from(configurations.bundledApps.singleFile){ into "tools" }
@Vampire I looked into artifact transforms and I'm not quite following how I'd use it to unzip them.
v

Vampire

05/25/2023, 1:21 AM
The unzipping is even on of the examples in the documentation
And I also did it some years ago where I needed it
artifact transform is what you want
Then you also do not need to unpack the same archives again and again on every build
a

Andrew Tasso

05/25/2023, 6:30 PM
@Adam Digging into this a bit more seems to be revealing that
zipTree
is what's breaking task order resolution. The consuming task knows where the file should be based upon the output of that task. But Gradle is not executing that task first.
v

Vampire

05/25/2023, 6:57 PM
Use an artifact transform and it will work 😉
a

Andrew Tasso

05/25/2023, 7:00 PM
Do you have a suggestion for a built-in to do the unzipping?
v

Vampire

05/25/2023, 7:02 PM
Here a Kotlin variant with optionally stripping the top-level directory:
Copy code
abstract class Unzip : TransformAction<Parameters> {
    @get:Inject
    protected abstract val fileSystem: FileSystemOperations

    @get:Inject
    protected abstract val archive: ArchiveOperations

    @get:InputArtifact
    abstract val inputArtifact: Provider<FileSystemLocation>

    override fun transform(outputs: TransformOutputs) {
        val input = inputArtifact.get().asFile
        val output = outputs.dir(input.name)
        fileSystem.sync {
            from(archive.zipTree(input))
            into(output)
            if (parameters.stripTopLevelDirectory.getOrElse(false)) {
                eachFile {
                    val segments = relativePath.segments
                    relativePath = RelativePath(
                        relativePath.isFile,
                        *segments.sliceArray(1 until segments.size)
                    )
                }
            }
        }
    }

    interface Parameters : TransformParameters {
        @get:Optional
        @get:Input
        val stripTopLevelDirectory: Property<Boolean>
    }
}
a

Andrew Tasso

05/25/2023, 7:08 PM
Awesome. Thanks!
6 Views