From f8e3907dfb34d571814440dd30391196fadcb738 Mon Sep 17 00:00:00 2001 From: David Herman Date: Sun, 10 Mar 2024 18:04:38 -0700 Subject: [PATCH] Add `excludedSources` to the KSP extension This new property allows users to create a Gradle task that generates Kotlin code, which can then get excluded by KSP's processing step. This can help avoid circular Gradle dependency issues, such as in the case where KSP generates an intermediate file (like a resource) which a Gradle plugin then consumes and uses to generate its own Kotlin source. Without this change, KSP would want to rerun when the new source got generated, which upsets Gradle because it already ran. The following is one example of using the `excludedSources` property: ```kotlin val generateCodeTask = tasks.register("generateCodeTask") { val outputDir = project.layout.buildDirectory.dir("generated/src") outputs.dir(outputDir) doLast { /* ... generate code into outputDir ... */ } } ksp.excludedSources.from(generateCodeTask) kotlin { sourceSets.main { kotlin.srcDir(generateCodeTask) } } ``` Bug #1791 Co-authored-by: David Herman Co-authored-by: Dennis Tsar <45399002+DennisTsar@users.noreply.github.com> --- .../kotlin/com/google/devtools/ksp/gradle/KspAATask.kt | 9 +++++++-- .../com/google/devtools/ksp/gradle/KspExtension.kt | 7 ++++++- .../com/google/devtools/ksp/gradle/KspSubplugin.kt | 7 +++++-- 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt index 2508eff853..bf97755051 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt @@ -166,16 +166,21 @@ abstract class KspAATask @Inject constructor( cfg.moduleName.value(kotlinCompilation.defaultSourceSet.name) val kotlinOutputDir = KspGradleSubplugin.getKspKotlinOutputDir(project, sourceSetName, target) val javaOutputDir = KspGradleSubplugin.getKspJavaOutputDir(project, sourceSetName, target) + val filteredTasks = + kspExtension.excludedSources.buildDependencies.getDependencies(null).map { it.name } kotlinCompilation.allKotlinSourceSetsObservable.forAll { sourceSet -> val filtered = sourceSet.kotlin.srcDirs.filter { - !kotlinOutputDir.isParentOf(it) && !javaOutputDir.isParentOf(it) + !kotlinOutputDir.isParentOf(it) && !javaOutputDir.isParentOf(it) && + it !in kspExtension.excludedSources }.map { // @SkipWhenEmpty doesn't work well with File. project.objects.fileTree().from(it) } cfg.sourceRoots.from(filtered) cfg.javaSourceRoots.from(filtered) - kspAATask.dependsOn(sourceSet.kotlin.nonSelfDeps(kspTaskName)) + kspAATask.dependsOn( + sourceSet.kotlin.nonSelfDeps(kspTaskName).filter { it.name !in filteredTasks } + ) } if (kotlinCompilation is KotlinCommonCompilation) { cfg.commonSourceRoots.from(kotlinCompilation.defaultSourceSet.kotlin) diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt index 9beac05d36..495afb31ce 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspExtension.kt @@ -18,13 +18,18 @@ package com.google.devtools.ksp.gradle import org.gradle.api.GradleException +import org.gradle.api.file.ConfigurableFileCollection import org.gradle.process.CommandLineArgumentProvider -open class KspExtension { +abstract class KspExtension { internal val apOptions = mutableMapOf() internal val commandLineArgumentProviders = mutableListOf() internal val excludedProcessors = mutableSetOf() + // Specify sources that should be excluded from KSP. + // If you have a task that generates sources, you can call `ksp.excludedSources.from(task)`. + abstract val excludedSources: ConfigurableFileCollection + open val arguments: Map get() = apOptions.toMap() open fun arg(k: String, v: String) { diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt index 4a88fe1b16..1fd16c76e3 100644 --- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt +++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspSubplugin.kt @@ -318,13 +318,16 @@ class KspGradleSubplugin @Inject internal constructor(private val registry: Tool ) } } else { + val filteredTasks = + kspExtension.excludedSources.buildDependencies.getDependencies(null).map { it.name } kotlinCompilation.allKotlinSourceSetsObservable.forAll { sourceSet -> kspTask.setSource( sourceSet.kotlin.srcDirs.filter { - !kotlinOutputDir.isParentOf(it) && !javaOutputDir.isParentOf(it) + !kotlinOutputDir.isParentOf(it) && !javaOutputDir.isParentOf(it) && + it !in kspExtension.excludedSources } ) - kspTask.dependsOn(sourceSet.kotlin.nonSelfDeps(kspTaskName)) + kspTask.dependsOn(sourceSet.kotlin.nonSelfDeps(kspTaskName).filter { it.name !in filteredTasks }) } }