Closed ninrod closed 5 years ago
You can see a potential way to solve this problem here:
I created a script that I could apply from either context and then call a function that that script exports.
https://github.com/gradle/kotlin-dsl/issues/821#issue-314655076
@JLLeitschuh that's so hacky. So I understand that there is no support yet for code reuse when using the buildSrc strategy, yes?
This is the only way I've figured out where I can reuse code in my buildSrc/build.gradle.kts
, buildSrc/settings.gradle.kts
, build.gradle.kts
, & settings.gradle.kts
file.
The problem is that you can't use code in your buildSrc
project in your buildSrc/build.gradle.kts
or your buildSrc/settings.gradle.kts
.
I agree, I wish there was a better solution, but I haven't thought of anything better and I've been using this solution for over 2 years now.
Any better solutions would be welcome.
I understand. I did not quite grasp the workaround though. Do you have a repo somewhere where this strategy is working? for reference purpouses?
problem I'm having is this:
..e-experiment ➜ make
gradle build
> Configure project :buildSrc
buildSrc: we are using jcenter for plugins
buildSrc: we are using jcenter for plugins
> Configure project :
e: /home/ninrod/code/sources/kotlin-dsl-gradle-experiment/build.gradle.kts:16:13: Unresolved reference: doWeHaveToUseArtifactory
FAILURE: Build failed with an exception.
* Where:
Build file '/home/ninrod/code/sources/kotlin-dsl-gradle-experiment/build.gradle.kts' line: 16
* What went wrong:
Script compilation error:
Line 16: if (doWeHaveToUseArtifactory()) {
^ Unresolved reference: doWeHaveToUseArtifactory
1 error
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.
* Get more help at https://help.gradle.org
Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
Use '--warning-mode all' to show the individual deprecation warnings.
See https://docs.gradle.org/5.1.1/userguide/command_line_interface.html#sec:command_line_warnings
BUILD FAILED in 0s
makefile:4: recipe for target 'build' failed
make: *** [build] Error 1
...e-experiment ➜
the functions.gradle.kts file is define like this:
import java.io.File
//the hack below was stolen from @JLLeitschuh.
//source: https://github.com/gradle/kotlin-dsl/issues/821#issue-314655076
// BEGIN HACK --------------------------
/**
* Makes it so that this script can be called with `this` as both a
* [KotlinBuildScript] & [KotlinSettingsScript] by providing an adapter
* to the two things that `this` could be.
*/
fun <R> callBasedOnContext(
ifBuildScript: KotlinBuildScript.() -> R,
ifSettingsScript: KotlinSettingsScript.() -> R
): R {
/*
* A bit of a hack to get around a compiler error when trying to do
* `is KotlinBuildScript` and `is KotlinSettingsScript`.
*/
val kotlinProjectClass: KClass<*> = KotlinBuildScript::class
val kotlinSettingsClass: KClass<*> = KotlinSettingsScript::class
return when {
kotlinProjectClass.isInstance(this) -> (this as KotlinBuildScript).ifBuildScript()
kotlinSettingsClass.isInstance(this) -> (this as KotlinSettingsScript).ifSettingsScript()
else -> throw AssertionError("$this is not being applied to a supported type.")
}
}
val extra: ExtraPropertiesExtension by lazy {
callBasedOnContext(
ifBuildScript = { extra },
ifSettingsScript = { (settings as ExtensionAware).extra }
)
}
fun hasPropertyHelper(propertyName: String): Boolean {
return callBasedOnContext(
ifBuildScript = { hasProperty(propertyName) },
ifSettingsScript = { (settings as ExtensionAware).extra.properties.containsKey(propertyName) }
)
}
fun propertyHelper(propertyName: String): Any? {
return callBasedOnContext(
ifBuildScript = { property(propertyName) },
ifSettingsScript = { (settings as ExtensionAware).extra.properties[propertyName] }
)
}
// HACK ENDED -------------------
// my stuff
fun hello(): String = "hello, world!"
fun doWeHaveToUseArtifactory(): Boolean {
val centos = File("/etc/centos-release").exists()
val workbench = File("/etc/hostname").readText().trim() == "workbench"
return centos && workbench
}
// trying to "export" the function. does not work"
extra["doWeHaveToUseArtifactory"] = this::doWeHaveToUseArtifactory
my build.gradle.kts file is importing the functions.gradle.kts file like so:
import org.gradle.jvm.tasks.Jar
apply {
from("functions.gradle.kts")
}
buildscript {
// sadly, we have to import our values inside buildscript because this block does not get anything from outside
val artifactory_gradle: String by project
val kotlin_version: String by project
repositories {
// BUG HERE: I have to use the full qualified name of the doWeHaveToUseArtifactory
// because the buildScript block does not respect the top level defined imports!
if (doWeHaveToUseArtifactory()) {
println("configuring artifactory for plugin repos")
maven {
url = uri(artifactory_gradle)
}
} else {
println("we are using jcenter for plugins")
maven {
url = uri("https://plugins.gradle.org/m2/")
}
jcenter()
}
}
dependencies {
// BUG HERE: I have to use the full qualified name of the doWeHaveToUseArtifactory
// because the buildScript block does not respect the top level defined imports!
if (org.ninrod.backend.build.doWeHaveToUseArtifactory()) {
println("we are going to add the classpath of the org.jfrog.buildinfo plugin")
classpath("org.jfrog.buildinfo:build-info-extractor-gradle:4.9.0")
}
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
}
}
if (doWeHaveToUseArtifactory()) {
apply(plugin = "com.jfrog.artifactory")
}
apply(plugin = "kotlin")
plugins {
application
}
application {
mainClassName = "org.ninrod.backend.EntrypointKt"
version = "0.0.1"
}
configure<JavaPluginConvention> {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
repositories {
val artifactory = "http://artifactory/artifactory/gradle"
if (doWeHaveToUseArtifactory()) {
maven {
url = uri(artifactory)
}
} else {
println("we are using jcenter for plugins")
maven {
url = uri("https://plugins.gradle.org/m2/")
}
jcenter()
}
}
dependencies {
// this block fetches properties from gradle.properties
val kotlin_version: String by project
val exposed_version: String by project
val junit5_version: String by project
val postgresql_driver_version: String by project
// kotlin
compile("org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version")
compile("org.jetbrains.kotlin:kotlin-reflect:$kotlin_version")
// db
compile("org.jetbrains.exposed:exposed:$exposed_version")
compile("org.jetbrains.exposed:spring-transaction:$exposed_version")
compile("org.postgresql:postgresql:$postgresql_driver_version")
// tests
testCompile("org.junit.jupiter:junit-jupiter-api:$junit5_version")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:$junit5_version")
}
tasks {
"jar"(Jar::class) {
baseName = project.name
manifest {
attributes["Main-Class"] = application.mainClassName
}
from( configurations.runtime.get().map { if (it.isDirectory) it else zipTree(it) })
}
val dumpTest by creating {
println("CONFIGURATION PHASE!!!")
println(hello())
println("temos que usar artifactory? " + doWeHaveToUseArtifactory())
doLast {
println("EXECUTION PHASE!!!")
}
}
}
Gradle is working as intended wrt the original issue description:
buildSrc/build.gradle.kts
cannot resolve references defined inbuildSrc/src
This is a chicken and egg problem. buildSrc/build.gradle.kts
contains the build logic that describes how to build the code from buildSrc/src
, so it cannot depend on what gets built.
Trying to work around that using some dynamic construct won't make things easy.
Now, if you want to share code type-safely between your "buildSrc
build logic"' and "buildSrc
sources" you need to extract that code into something new. That new thing is another build, either via a published artifact or a Gradle included build. The recent webinar on the Kotlin DSL will provide some answers, also see Integrating Separate Gradle build in the user guide.
Please use the Gradle forums for support questions https://discuss.gradle.org/
Now, if you want to share code type-safely between your "buildSrc build logic"' and "buildSrc sources" you need to extract that code into something new. That new thing is another build, either via a published artifact or a Gradle included build. The recent webinar on the Kotlin DSL will provide some answers, also see Integrating Separate Gradle build in the user guide.
I tried it but sadly got error message “Cannot include build ‘dependenciesDigest’ in build ‘buildSrc’. This is not supported yet.”. I’m using Gradle version 5.4.1
Expected Behavior
The user should be able to reference objects and functions defined in his buildSrc/src/main/kotlin directory.
Current Behavior
I have a working kotlin dsl gradle build: kotlin-dsl-gradle-experiment
I've written a function in my buildSrc/src/main/kotlin/test.kt file as follows:
I'd love to use that function inside my buildSrc/build.gradle.kts instead of duplicating myself in every kotlin dsl block:
Context
this affects all kotlin-dsl users that have to configure interesting/complex behaviour and have to resort to logic which should be reusable.
These actions does not work:
Steps to Reproduce (for bugs)
simply clone the kotlin-dsl-gradle-experiment and verify the behaviour:
Your Environment
Gradle 5.1.1
Build time: 2019-01-10 23:05:02 UTC Revision: 3c9abb645fb83932c44e8610642393ad62116807
Kotlin DSL: 1.1.1 Kotlin: 1.3.11 Groovy: 2.5.4 Ant: Apache Ant(TM) version 1.9.13 compiled on July 10 2018 JVM: 1.8.0_192 (Oracle Corporation 25.192-b12) OS: Linux 4.9.87-linuxkit-aufs amd64