Is it possible for a plugin to configure a gradle task for a single execution?

已回答
Hi.
I’m trying to build a plugin to generate Jetpack Compose compiler metrics with the click of a button in the IDE (among other things). So far, I’ve figured out adding the button part and being able to execute gradle commands on click of it.To do this, the project’s gradle setup must be configured appropriately, such as following:
// Root project's build.gradle file.
...
subprojects {
    tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
        kotlinOptions {
            // Trigger this with: ./gradlew assembleRelease -PenableComposeReports=true
            if (project.findProperty("enableComposeReports") == "true") {
                freeCompilerArgs += ["-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + rootProject.buildDir.absolutePath + "/compose_metrics/"]
                freeCompilerArgs += ["-P", "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + rootProject.buildDir.absolutePath + "/compose_metrics/"]
            }
        }
    }
}
And this can be triggered with ./gradlew assembleRelease -PenableComposeReports=true , which I’m able to do on click of a menu item in the IDE. However, I need the ability for the plugin to do this for arbitrary projects which may or may not have the above mentioned gradle setup.
  1. Is it possible for a plugin to configure a gradle task (like shown above) programmatically, for a single execution?
  2. Otherwise, is it possible to set Kotlin freeCompilerArgs via CLI during the gradle task execution?
0

To achieve this you can use Gradle init scripts. 
First take a look at the init script documentation: https://docs.gradle.org/current/userguide/init_scripts.html
Your init script can contain something like that:

allprojects {
    tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).all {
        kotlinOptions {
            // Trigger this with: ./gradlew assembleRelease -PenableComposeReports=true
            if (project.findProperty("enableComposeReports") == "true") {
                freeCompilerArgs += ["-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + rootProject.buildDir.absolutePath + "/compose_metrics/"]
                freeCompilerArgs += ["-P", "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + rootProject.buildDir.absolutePath + "/compose_metrics/"]
            }
        }
    }
}

Please note the usage of `.all()` vs `.configureEach()` on a collection. The former will be applied to any elements added to the collection in the future.

1

To inject the init script during a Gradle task execution, your plugin can implement following extension point

GradleProjectResolverExtension

while the interface is somewhat overloaded, you can inherit from class AbstractProjectResolverExtension and implement the only method you are interested in. At this point it is enhanceTaskProcessing. The last parameter is an init-script consumer, that allows your plugin to contribute to init-script that will be used to launch Gradle tasks. 

1

Thank you so much Nikita Skvortsov! You saved me so much time and headache. Your answer worked perfectly for me.

Sharing my work-in-progress code. So far, it's been working well for me, and I hope it might come in handy for someone else too.

// init.gradle
initscript {
repositories {
mavenCentral()
google()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.7.0")
classpath("com.android.tools.build:gradle:7.4.2")
}
}

allprojects {
afterEvaluate {
tasks.configureEach {
if (it.class.name.contains("org.jetbrains.kotlin.gradle.tasks.KotlinCompile")) {
kotlinOptions {
freeCompilerArgs += ["-P", "plugin:androidx.compose.compiler.plugins.kotlin:reportsDestination=" + rootProject.buildDir.absolutePath + "/reports/"]
freeCompilerArgs += ["-P", "plugin:androidx.compose.compiler.plugins.kotlin:metricsDestination=" + rootProject.buildDir.absolutePath + "/metrics/"]
}
}
}
}
}
// GradleInitScriptInjector.kt
import com.intellij.util.Consumer
import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension

public class GradleInitScriptInjector : AbstractProjectResolverExtension() {

override fun enhanceTaskProcessing(
taskNames: MutableList<String>,
jvmParametersSetup: String?,
initScriptConsumer: Consumer<String>
) {
val gradleInitScript: String = TODO() // Read init.gradle file as text or store that as a String
// Check conditions...
initScriptConsumer.consume(gradleInitScript)
}
}
<!--plugin.xml-->
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
    <projectResolve implementation="com.package.name.GradleInitScriptInjector"/> </extensions>

Thank you once again Nikita Skvortsov for taking time out and helping me with this!

0

Thank you for the follow up and for sharing your code for those who come after you )

0

请先登录再写评论。