aboutsummaryrefslogtreecommitdiff
path: root/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt
diff options
context:
space:
mode:
Diffstat (limited to 'gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt')
-rw-r--r--gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt106
1 files changed, 106 insertions, 0 deletions
diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt
new file mode 100644
index 00000000..8932056c
--- /dev/null
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspConfigurations.kt
@@ -0,0 +1,106 @@
+package com.google.devtools.ksp.gradle
+
+import org.gradle.api.Project
+import org.gradle.api.artifacts.Configuration
+import org.jetbrains.kotlin.gradle.dsl.*
+import org.jetbrains.kotlin.gradle.plugin.*
+import java.util.*
+
+/**
+ * Creates and retrieves ksp-related configurations.
+ */
+class KspConfigurations(private val project: Project) {
+ companion object {
+ const val ROOT = "ksp"
+ }
+
+ // "ksp" configuration. In single-platform projects, it is applied to the "main" sourceSet.
+ // In multi-platform projects, it is applied to the "main" sourceSet of all targets.
+ private val rootMainConfiguration = project.configurations.create(ROOT)
+
+ // Stores all saved configurations for quick access.
+ private val configurations = mutableMapOf<KotlinSourceSet, Configuration>()
+
+ @OptIn(ExperimentalStdlibApi::class)
+ private fun addConfiguration(owner: KotlinSourceSet, parent: Configuration?, name: String): Configuration {
+ val configName = ROOT + name.replaceFirstChar { it.uppercase() }
+ val existingConfig = project.configurations.findByName(configName)
+ if (existingConfig != null && configName != ROOT) {
+ error("Unexpected duplicate configuration ($configName).")
+ }
+
+ val config = existingConfig ?: project.configurations.create(configName)
+ if (parent != null) config.extendsFrom(parent)
+ configurations[owner] = config
+ return config
+ }
+
+ init {
+ project.plugins.withType(KotlinBasePluginWrapper::class.java).configureEach {
+ // 1.6.0: decorateKotlinProject(project.kotlinExtension)
+ decorateKotlinProject(project.extensions.getByName("kotlin") as KotlinProjectExtension)
+ }
+ }
+
+ private fun decorateKotlinProject(kotlin: KotlinProjectExtension) {
+ when (kotlin) {
+ is KotlinMultiplatformExtension -> kotlin.targets.configureEach(::decorateKotlinTarget)
+ is KotlinSingleTargetExtension -> decorateKotlinTarget(kotlin.target)
+ }
+ }
+
+ private fun decorateKotlinTarget(target: KotlinTarget) {
+ if (target.platformType == KotlinPlatformType.androidJvm) {
+ /**
+ * TODO: Android might need special handling. Discuss. Tricky points:
+ * 1) KotlinSourceSets are defined in terms of AGP Variants - a resolved, compilable entity.
+ * Using them would be consistent with other targets and simple.
+ * 2) AGP AndroidSourceSets represent a hierarchy: we have "test", "debug", but also "testDebug"
+ * which depends on the other two. Not clear if this dependency should be reflected in the
+ * configurations.
+ * 3) Need to find a way to retrieve the correct configurations in applyToCompilation
+ */
+ Unit
+ } else {
+ // We could add target-specific configurations here (kspJvm, parent of kspJvmMain & kspJvmTest)
+ // but we decided that kspJvm should actually mean kspJvmMain, which in turn is not created.
+ target.compilations.configureEach { compilation ->
+ val isMain = compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME
+ compilation.kotlinSourceSets.forEach { sourceSet ->
+ val isDefault = sourceSet.name == compilation.defaultSourceSetName
+ decorateKotlinSourceSet(compilation, isMain, sourceSet, isDefault)
+ }
+ }
+ }
+ }
+
+ private fun decorateKotlinSourceSet(
+ compilation: KotlinCompilation<*>,
+ isMainCompilation: Boolean,
+ sourceSet: KotlinSourceSet,
+ isDefaultSourceSet: Boolean
+ ) {
+ val parent = if (isMainCompilation) rootMainConfiguration else null
+ if (isMainCompilation && isDefaultSourceSet) {
+ // Use target name instead of sourceSet name, to avoid creating "kspMain" or "kspJvmMain".
+ // Note: on single-platform, target name is conveniently set to "" so this resolves to "ksp".
+ addConfiguration(sourceSet, parent, compilation.target.name)
+ } else {
+ addConfiguration(sourceSet, parent, sourceSet.name)
+ }
+ }
+
+ /**
+ * Returns the user-facing configurations involved in the given compilation.
+ * We use [KotlinCompilation.kotlinSourceSets], not [KotlinCompilation.allKotlinSourceSets] for a few reasons:
+ * 1) consistency with how we created the configurations
+ * 2) all* can return sets belonging to other compilations. In this case the dependency should be tracked
+ * by Gradle at the task level, not by us through configurations.
+ * 3) all* can return user-defined sets belonging to no compilation, like intermediate source sets defined
+ * to share code between targets. They do not currently have their own ksp configuration.
+ */
+ fun find(compilation: KotlinCompilation<*>): Set<Configuration> {
+ val sourceSets = compilation.kotlinSourceSets
+ return sourceSets.mapNotNull { configurations[it] }.toSet()
+ }
+}