forked from cashapp/sqldelight
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SourceRoots.kt
148 lines (136 loc) · 4.91 KB
/
SourceRoots.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package app.cash.sqldelight.gradle.kotlin
import app.cash.sqldelight.gradle.SqlDelightDatabase
import com.android.build.gradle.AppExtension
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.LibraryExtension
import com.android.build.gradle.api.BaseVariant
import org.gradle.api.DomainObjectSet
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskContainer
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinJsProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import java.io.File
/**
* @return A list of source roots and their dependencies.
*
* Examples:
* Multiplatform Environment. Ios target labeled "ios".
* -> iosMain deps [commonMain]
*
* Android environment. internal, production, release, debug variants.
* -> internalDebug deps [internal, debug, main]
* -> internalRelease deps [internal, release, main]
* -> productionDebug deps [production, debug, main]
* -> productionRelease deps [production, release, main]
*
* Multiplatform environment with android target (oh boy)
*/
internal fun SqlDelightDatabase.sources(project: Project): List<Source> {
// Multiplatform project.
project.extensions.findByType(KotlinMultiplatformExtension::class.java)?.let {
return it.sources()
}
// kotlin.js only projects
project.extensions.findByType(KotlinJsProjectExtension::class.java)?.let {
return it.sources()
}
// Android project.
project.extensions.findByName("android")?.let {
return (it as BaseExtension).sources(project)
}
// Kotlin project.
val sourceSets = project.extensions.getByName("sourceSets") as SourceSetContainer
return listOf(
Source(
type = KotlinPlatformType.jvm,
name = "main",
sourceSets = listOf("main"),
sourceDirectorySet = sourceSets.getByName("main").kotlin ?: project.objects.sourceDirectorySet("empty", "Empty kotlin source set"),
),
)
}
private fun KotlinJsProjectExtension.sources(): List<Source> {
return listOf(
Source(
type = KotlinPlatformType.js,
name = "main",
sourceDirectorySet = sourceSets.getByName("main").kotlin,
sourceSets = listOf("main"),
),
)
}
private fun KotlinMultiplatformExtension.sources(): List<Source> {
// For multiplatform we only support SQLDelight in commonMain - to support other source sets
// we would need to generate expect/actual SQLDelight code which at least right now doesn't
// seem like there is a use case for. However this code is capable of running on any Target type.
return listOf(
Source(
type = KotlinPlatformType.common,
nativePresetName = null,
name = "commonMain",
variantName = "commonMain",
sourceDirectorySet = sourceSets.getByName("commonMain").kotlin,
sourceSets = listOf("commonMain"),
),
)
}
private fun BaseExtension.sources(project: Project): List<Source> {
val variants: DomainObjectSet<out BaseVariant> = when (this) {
is AppExtension -> applicationVariants
is LibraryExtension -> libraryVariants
else -> throw IllegalStateException("Unknown Android plugin $this")
}
val sourceSets = sourceSets
.associate { sourceSet ->
sourceSet.name to sourceSet.kotlinSourceDirectorySet
}
return variants.map { variant ->
Source(
type = KotlinPlatformType.androidJvm,
name = variant.name,
variantName = variant.name,
sourceDirectorySet = sourceSets[variant.name]
?: project.objects.sourceDirectorySet(variant.name, "Empty kotlin source set"),
sourceSets = variant.sourceSets.map { it.name },
registerGeneratedDirectory = { outputDirectoryProvider ->
variant.addJavaSourceFoldersToModel(outputDirectoryProvider.get())
},
)
}
}
private fun TaskContainer.namedOrNull(
taskName: String,
): TaskProvider<Task>? {
return try {
named(taskName)
} catch (_: Exception) {
null
}
}
internal data class Source(
val type: KotlinPlatformType,
val nativePresetName: String? = null,
val sourceDirectorySet: SourceDirectorySet,
val name: String,
val variantName: String? = null,
val sourceSets: List<String>,
val registerGeneratedDirectory: ((Provider<File>) -> Unit)? = null,
) {
fun closestMatch(sources: Collection<Source>): Source? {
var matches = sources.filter {
type == it.type || (type == KotlinPlatformType.androidJvm && it.type == KotlinPlatformType.jvm) || it.type == KotlinPlatformType.common
}
if (matches.size <= 1) return matches.singleOrNull()
// Multiplatform native matched or android variants matched.
matches = matches.filter {
nativePresetName == it.nativePresetName && variantName == it.variantName
}
return matches.singleOrNull()
}
}