Reputation: 3088
I am trying to build my own extension function, which uses an extension method from C:/Users/<username>/.gradle/caches/7.3-20211011231002+0000/kotlin-dsl/accessors/5030f2917b46f065859e6c634449b97d/sources/org/gradle/kotlin/dsl/Accessors2oadk7let745pm8ahqypkqzlk.kt:63
- which seems to be something deeply internal.
In my buildSrc
subproject I want to try to add the following extension function
val org.gradle.api.Project.testSources
get() = sourceSets.getByName("test").output
Is there a way to resolve the extension functions defined in the Kotlin DSL (my overall goal is instead of writing project(":<name>").sourceSets["test"].output
to write project(":<name>").testSources
).
I do not really understand why all the extension methods are not available....
The build-gradle.kts of my buildSrc.
plugins {
`kotlin-dsl`
}
Repo (this will not build as one file is missing, which I want to keep private, but that shouldn't matter for this issue)
Upvotes: 4
Views: 3771
Reputation: 7139
You can share extension functions, or field extension, within a single project by simply defining them in .kt
files in ./buildSrc/src/main/kotlin/
. You can then import them into any of the project's build.gradle.kts
files.
For example, if you create ./buildSrc/src/main/kotlin/my/project/MyExtensions.kt
.kt
, not .kts
file.//MyExtensions.kt
package my.project
val org.gradle.api.Project.testSources
get() = sourceSets.getByName("test").output // compilation error...
But... that code won't work. Because it's in a .kt
file, not a .kts
, the Gradle magic won't load the Kotlin DSL sourceSets
accessor.
For tips on how to access Gradle objects without the Kotlin DSL accessors, looking at the Gradle Plugin development guide is best https://docs.gradle.org/current/userguide/custom_plugins.html.
You can also cmd/ctrl + left click
in the build.gradle.kts
files to see what the Kotlin DSL accessor is...
// auto-generated Kotlin DSL accessor
/**
* Retrieves the [sourceSets][org.gradle.api.tasks.SourceSetContainer] extension.
*/
val org.gradle.api.Project.`sourceSets`: org.gradle.api.tasks.SourceSetContainer get() =
(this as org.gradle.api.plugins.ExtensionAware).extensions.getByName("sourceSets") as org.gradle.api.tasks.SourceSetContainer
The auto generated code is a good start.
There's a few ways of accessing Gradle objects. Personally I'd prefer to retrieve the SourceSetContainer by type, not by string. And so here's how to fix your field extension.
package my.project
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.SourceSetOutput
import org.gradle.kotlin.dsl.findByType
val Project.testSources: SourceSetOutput?
get() = extensions
.findByType<SourceSetContainer>()
?.getByName("test")
?.output
Now in <root>/build.gradle.kts
you can import the extension, and use it as expected.
//build.gradle.kts
import my.project.testSources
project.testSources?.files?.forEach { file: File? ->
logger.lifecycle("my extension function found a testSources file $file")
}
You can also share functions with regular Gradle plugins. See https://docs.gradle.org/current/dsl/org.gradle.api.plugins.ExtensionAware.html. However I don't think defining extension functions is possible.
Upvotes: 8