Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Different ways to apply plugins ? (Gradle Kotlin DSL)

Trying to migrate this one project's build to GSK. We have this in Groovy:

allprojects {
    apply plugin: 'java'
...
    sourceSets {
        ...
    }
    sourceCompatibility = ...
}

So while figuring out how to access the plugin convention in Kotlin, I found out that:

allprojects {
    plugins {
        java apply true
    }
    ...
    println("Project $name, plugins: ${plugins}") // empty list
    val java = the<JavaPluginConvention>() // throws exception
}

but if you do it like this:

allprojects {
    apply {
        plugin(JavaPlugin::class.java)
    }
}

plugin is applied and convention becomes accessible

WTH?

like image 291
bruto Avatar asked Jan 16 '18 21:01

bruto


1 Answers

This issue isn't specific to Kotlin, and is due to a race condition. While the script is being evaluated, it may not have added the plugin to the classpath yet. This is one of many reasons why the plugins block was created, as it's specifically evaluated prior to the rest of the scripts evaluation during a buildscript phase. That said however, this special treatment is only done if this block is at the top of the script, and not when it's within a subprojects or allprojects block, as those blocks are technically arbitrary and are evaluated later to ensure the buildscript is idempotent. In your case, you are just moving up the race by placing it in allprojects block, and are getting lucky.

When dealing with multi-project builds, this is problematic, however if possible, the best is to declare the plugin in the plugins block with the apply false constrained syntax to add it to your build's classpath in the buildscript phase. You will then be able to apply the plugin later via the plugin's id during script evaluation (version isn't necessary, as it's used for fetching the dependency only).

An example:

plugins {
    id("org.gradle.sample.hello") version "1.0.0" apply false
}

subprojects {
    apply(plugin = "org.gradle.sample.hello")
}

The Gradle User Guide does a great job at explaining how these should be used, and the balance you will need to consider in multi-module projects.

Due to the nature of how some plugins are written, there may be cases where other issues will arise, but if plugin authors are following best practice guidelines, you'll be fine.

like image 172
aweigold Avatar answered Oct 02 '22 04:10

aweigold