This message was deleted.
# configuration-cache
s
This message was deleted.
v
Can you maybe show how you would do it with a configure task, to make it clear what you actually try to achieve?
1
r
Copy code
val configureStripProguard: Task by tasks.register("configureStripProguard") {
    dependsOn(getRuntimeClasses)
    notCompatibleWithConfigurationCache("configures another task")

    doLast {
        // Configure the stripProguard task to copy from the proguard jar and exclude the runtime classes: see below
        stripProguard.apply {
            from(zipTree(proguardJarFile)) {
                exclude(getRuntimeClasses.get().classes)
            }
        }
    }
}
This is my current configure task, getRuntimeClasses is another task that simply gets a list of all the classes on the runtime classpath
if it matters:
Copy code
/**
 * A task which returns a list of the paths of every class in every JAR in the given set of files
 */
abstract class GetClassesInClasspath : DefaultTask() {
    @get:InputFiles
    @get:CompileClasspath
    abstract val inputFiles: ConfigurableFileCollection

    @Internal
    lateinit var classes: Set<String>

    @TaskAction
    fun writeClasses() {
        classes = inputFiles
            .flatMap { jar ->
                JarFile(jar).entries().asSequence()
                    .map { it.name }
                    .filter { it.endsWith(".class") && it != "module-info.class" }
            }
            .toSortedSet()
    }
}

/**
 * Get the list of all the class files on the runtime classpath (aka, libraries that are *not* shaded)
 */
val getRuntimeClasses: TaskProvider<GetClassesInClasspath> = tasks.register<GetClassesInClasspath>("getRuntimeClasses") {
    inputFiles.from(configurations.runtimeClasspath)
}
v
Actually, the whole
GetClassesInClasspath
is not really idiomatic. You should not set a task property that you then read in another task. If you need to transport information like that, you should probably use a shared build service. And also it might easily break, as a classpath can also contain directories, not only jar files. And a classpath might even contain non-existent entries in the Java world. (not fully sure if this could happen within Gradle right now) Actually, anytime you need to do a
dependsOn
manually (except with a lifecycle task on the left-hand side) you have a code smell and most probably do something in a non-optimal way. Without having tried, I guess you should do the filename gathering in a shared build service that you then use in the exclude spec. And the exclude spec can be a closure / lambda so that it is not evaluated at configuration time immediately, but only when needed. Not fully your use-case, but this for example is CC-safe:
Copy code
tasks.jar {
    val runtimeClasspath: FileCollection = configurations.runtimeClasspath.get()
    exclude { runtimeClasspath.files.contains(it.file) }
}
r
I'm aware the
GetClassesInClasspath
is a little fragile but it works for my purposes, unless you have a convenient other suggestion. But it's not too important. To make your bottom suggestion work, I need to modify it a bit, but calling this method for every single file in the jar is pretty ridiculous. I will look into a shared build service.
Copy code
fun classes() = configurations.runtimeClasspath.get()
        .flatMap { jar ->
            JarFile(jar).entries().asSequence()
                .map { it.name }
                .filter { it.endsWith(".class") && it != "module-info.class" }
        }
        .toSortedSet()

    from(zipTree(proguardJarFile)) {
        exclude { classes().contains(it.name) }
    }
Ah, actually, I just realized I can use the kotlin lazy {} for this
v
but calling this method for every single file in the jar is pretty ridiculous
Exactly, that's why I not suggested to do it like that, just to give you a general idea about CC-safety. 😉 You could maybe use a
val classes by lazy { ... }
then it will only be calculated once, but I'm not sure right now whether that will be CC-safe.
r
Configuration cache doesn't complain about lazy {} with a warning, at any rate
👌 1
using lazy {} and the exclude predicate feels pretty weird but it does the trick. Thanks so much for the help
👌 1
v
Not weird at all imho 🙂
If you want it less Kotlin-y and more Gradle-y, then use the shared build service instead of the lazy. But that imposes a bit more boilerplate you don't really need in this case. 🙂
r
I guess I find it weird because the only reason it works is that the exclude predicate is run at execution time (obvious in hindsight, but maybe not at first glance)
Personally, it would make a lot more sense to me if we had a
FileSystemOperations#jar
method that we could call instead
Update: the Kotlin lazy actually doesn't really work. It stops my build from crashing because the configurations gets resolved too early (hurray?) but it still gets resolved too early because gradle tries to serialize the lazy object, and this can cause an issue if the classpath contains jars that haven't been generated yet (need to be generated by a task)
I'm not actually sure how build service will fix this either, since I would need the build service to run AFTER the tasks to generate the jars on the classpath are run
v
The lazy value is serialized to CC. But the build service "result" not, just it's configuration. It should run only when needed at execution time. If you want to make triple sure you could make the build service with max concurrency 1 and define the jar producing task as also using that service. But that should really be unnecessary and if so, should not be done.