How do I set the sourceSets within task in gradle ...
# gradle
h
How do I set the sourceSets within task in gradle (I'm converting a groovy to kotlin script). See thread details.
In here we are creating a
specDirName
from the filename (jar). We use this for the extracted location and we use it to set it on the classpath (sourceSets). I'm struggling to find a way to modify the sourceSets within the configurations loop in my kotlin script file.
Copy code
tasks.register('extractApis') {
    configurations.spec.each { file ->
        def specDirName = file.toString().split("\\" + file.separator).find { it.matches("^[a-z\\-]*-(specs|api)\$") }
        copy {
            from zipTree(file)
            into "$buildDir/extracted/$specDirName"
        }
        sourceSets.main.java.srcDirs += "$buildDir/generated/$specDirName/src/main/java"
        sourceSets.main.resources.srcDirs += "$buildDir/generated/$specDirName/src/main/resources"
    }
}
v
Which part are you struggling with?
h
Cant do sourcesets within configurations loop block.
I’ll share the kotlin variant I have so far in a bit (15 min). Out for lunch now
v
Actually, you should not do it like that anyway, no matter whether Groovy DSL or Kotlin DSL. If you have tasks that generate code or resources, you should not hard-code paths to their outputs. Instead the tasks should properly declare their outputs and then you configure the whole task as
srcDir
, then you also automatically get the needed task dependencies in all tasks that try to access the sources or resources like compilation tasks, source jar tasks, static code analysis tasks, and so on, without the need to declare manual `dependsOn`s which are practically always bad practice unless a lifecycle task is on the left-hand side.
And additionally, you do the work for
extractApis
in its configuration phase, instead of its execution phase. That means whenever the task is configured, the work is right away done, whether the task is going to executed or not, and in the configuration phase.
And besides that, the paths you configure as
srcDir
also do not match the path where you extract into.
h
This is the script I've converted until now which seems to do the same:
Copy code
configurations.create("openApiSpec") {
    isCanBeResolved = true
    isCanBeConsumed = false
}

tasks {
    register("extractApis") {
        configurations.getByName("openApiSpec").forEach {
            val specDirName = Regex("^[a-z\\-]*-(specs|api)").find(it.name)?.value
            copy {
                from(zipTree(it))
                into(layout.buildDirectory.dir("extracted/$specDirName"))
            }

        }
    }
}
Didn't manage to get that regex completely as the groovy one (missing that last part
\$
ending part, but seems to give the same result for the dirName. There might be more Jars on the classpath (openApiSpec) which needs to be extracted in a separate (own dir). And have those directory on the source path. I'm not sure how to break this in separate tasks as we can add multiple jar files in the openApiSpec configuration.
v
(missing that last part
\$
ending part
Just use
$
should be the same then.
But other than that, most of what I said above is still true, like doing when configuring and so on
a
Gradle lets you use functions even though you shouldn't. It makes it really difficult to use a lot of the time :( • using
forEach {}
means that Gradle will eagerly fetch the dependencies • using
zipTree
and
copy {}
actually uses
Project.zipTree
, which will break configuration cache (which isn't hugely important if you don't have it enabled, but it sets off alarm bells for me) • doing copy operations immediately, instead of in a task action (e.g. in a
doLast {}
or
doFirst {}
block) is 'allowed', but it means that the task you've written actually doesn't do anything. Did you try adapting the task I shared yesterday? It should work better https://kotlinlang.slack.com/archives/C19FD9681/p1693314919620089?thread_ts=1693308712.410899&cid=C19FD9681
v
which will break configuration cache
It will not, because he does this during configuration time, which is of course bad in itself as desribed above 🙂
h
When adding
$
at the end I get null for the value.
v
Because
File.name
should include the extension if I'm not wrong, but should be the same for Groovy
h
I've shared that code with a collegue and he came up with this groovy script which is being used by other teams. So I thought of rewriting it in kotlin script. I'll try to see which part I can add together. In the one from yesterday I thought it doesn't support multiple jars but maybe it does, in the last step does a mapping.
a
it'll support multiple jars for sure 👍
h
The File.name is
xxxx-specs-1.2.3.jar
Copy code
val specDirName = Regex("^[a-z\\-]*-(specs|api)$").find("xxx-specs-1.2.3.jar")?.value
this 👆 gives a null for specDirName.
v
Of course.
$
means end of string, but your string continues with
-1.2.3.jar
Your Groovy version does not match on the filename. It splits the whole path in a weird way and searches for some sub-path that matches the regex, hoping that the jar is in a directory where the artifact name is an intermediate directory.
1