Skip to content

Commit

Permalink
Support dependencies between sqldelight modules (#1229)
Browse files Browse the repository at this point in the history
  • Loading branch information
Alec Strong committed Feb 24, 2019
1 parent 221128f commit bf56253
Show file tree
Hide file tree
Showing 16 changed files with 545 additions and 23 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -12,3 +12,4 @@ sqldelight-gradle-plugin/src/test/integration/gradle
sqldelight-gradle-plugin/src/test/integration-android/gradle
sqldelight-gradle-plugin/src/test/integration-android-library/gradle
sqldelight-gradle-plugin/src/test/integration-multiplatform/gradle
sqldelight-gradle-plugin/src/test/multi-module/gradle
Expand Up @@ -24,25 +24,66 @@ class SqlDelightDatabase(
get() = File(project.buildDir, "sqldelight/$name")

private val sources by lazy { sources() }
private val dependencies = mutableListOf<SqlDelightDatabase>()

private var recursionGuard = false

fun methodMissing(name: String, args: Any): Any {
return (project as GroovyObject).invokeMethod(name, args)
}

fun dependency(dependencyProject: Project) {
dependencyProject.afterEvaluate {
val dependency = dependencyProject.extensions.findByType(SqlDelightExtension::class.java)
?: throw IllegalStateException("Cannot depend on a module with no sqldelight plugin.")
dependencies.add(dependency.databases.singleOrNull { it.name == name }
?: throw IllegalStateException("No database named $name in $dependencyProject"))
}
}

internal fun getProperties(): SqlDelightDatabaseProperties {
val packageName = requireNotNull(packageName) { "property packageName must be provided" }

return SqlDelightDatabaseProperties(
packageName = packageName,
compilationUnits = sources.map { source ->
return@map SqlDelightCompilationUnit(
name = source.name,
sourceFolders = relativeSourceFolders(source)
)
},
outputDirectory = outputDirectory.toRelativeString(project.projectDir),
className = name
)
if (recursionGuard) {
throw IllegalStateException("Found a circular dependency in $project with database $name")
}
recursionGuard = true

try {
return SqlDelightDatabaseProperties(
packageName = packageName,
compilationUnits = sources.map { source ->
return@map SqlDelightCompilationUnit(
name = source.name,
sourceFolders = sourceFolders(source)
)
},
outputDirectory = outputDirectory.toRelativeString(project.projectDir),
className = name
)
} finally {
recursionGuard = false
}
}

private fun sourceFolders(source: Source): List<String> {
val sourceFolders = sourceFolders ?: listOf("sqldelight")

val relativeSourceFolders = sourceFolders.flatMap { folder ->
source.sourceSets.map { "src/$it/$folder" }
}

return relativeSourceFolders + dependencies.flatMap { dependency ->
val dependencySource = source.closestMatch(dependency.sources)
?: return@flatMap emptyList<String>()
val compilationUnit = dependency.getProperties().compilationUnits
.single { it.name == dependencySource.name }

return@flatMap compilationUnit.sourceFolders.map {
val folder = File(dependency.project.projectDir, it)
return@map project.relativePath(folder)
}
}
}

internal fun registerTasks() {
Expand All @@ -67,7 +108,7 @@ class SqlDelightDatabase(
// Add the source dependency on the generated code.
source.sourceDirectorySet.srcDir(outputDirectory.toRelativeString(project.projectDir))

val sourceFiles = project.files(*relativeSourceFolders(source).map(::File).toTypedArray())
val sourceFiles = project.files(*sourceFolders(source).map(::File).toTypedArray())

// Register the sqldelight generating task.
val task = project.tasks.register("generate${source.name.capitalize()}${name}Interface", SqlDelightTask::class.java) {
Expand All @@ -89,14 +130,6 @@ class SqlDelightDatabase(
}
}

private fun relativeSourceFolders(source: Source): List<String> {
val sourceFolders = sourceFolders ?: listOf("sqldelight")

return sourceFolders.flatMap { folder ->
source.sourceSets.map { "src/$it/$folder" }
}
}

private fun addMigrationTasks(
sourceSet: Collection<File>,
source: Source
Expand Down
Expand Up @@ -13,7 +13,11 @@ import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTargetPreset
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.konan.target.KonanTarget

/**
* @return A list of source roots and their dependencies.
Expand Down Expand Up @@ -44,6 +48,7 @@ internal fun SqlDelightDatabase.sources(): List<Source> {
// Kotlin project.
val sourceSets = project.property("sourceSets") as SourceSetContainer
return listOf(Source(
type = KotlinPlatformType.jvm,
name = "main",
sourceSets = listOf("main"),
sourceDirectorySet = sourceSets.getByName("main").kotlin!!,
Expand Down Expand Up @@ -72,7 +77,10 @@ private fun KotlinMultiplatformExtension.sources(): List<Source> {
return@mapNotNull null
}
Source(
type = target.platformType,
konanTarget = (target as? KotlinNativeTarget)?.konanTarget,
name = "${target.name}${compilation.name.capitalize()}",
variantName = (compilation as? KotlinJvmAndroidCompilation)?.name,
sourceDirectorySet = compilation.defaultSourceSet.kotlin,
sourceSets = compilation.allKotlinSourceSets.map { it.name },
registerTaskDependency = { task ->
Expand All @@ -96,7 +104,9 @@ private fun BaseExtension.sources(project: Project): List<Source> {

return variants.map { variant ->
Source(
type = KotlinPlatformType.androidJvm,
name = variant.name,
variantName = variant.name,
sourceDirectorySet = sourceSets[variant.name]
?: throw IllegalStateException("Couldnt find ${variant.name} in $sourceSets"),
sourceSets = variant.sourceSets.map { it.name },
Expand All @@ -107,8 +117,24 @@ private fun BaseExtension.sources(project: Project): List<Source> {
}
}
internal data class Source(
val type: KotlinPlatformType,
val konanTarget: KonanTarget? = null,
val sourceDirectorySet: SourceDirectorySet,
val name: String,
val variantName: String? = null,
val sourceSets: List<String>,
val registerTaskDependency: (TaskProvider<SqlDelightTask>) -> Unit
)
) {
fun closestMatch(sources: Collection<Source>): Source? {
var matches = sources.filter {
type == it.type || (type == KotlinPlatformType.androidJvm && it.type == KotlinPlatformType.jvm )
}
if (matches.size <= 1) return matches.singleOrNull()

// Multiplatform native matched or android variants matched.
matches = matches.filter {
konanTarget == it.konanTarget && variantName == it.variantName
}
return matches.singleOrNull()
}
}
3 changes: 1 addition & 2 deletions sqldelight-gradle-plugin/src/test/integration/build.gradle
Expand Up @@ -22,6 +22,5 @@ dependencies {
implementation deps.kotlin.stdlib.jdk
implementation deps.sqliteJdbc
implementation "com.squareup.sqldelight:sqlite-driver:${com.squareup.sqldelight.VersionKt.VERSION}"
// TODO why don't these work when specified as androidTestImplementation?
compile deps.truth
implementation deps.truth
}

0 comments on commit bf56253

Please sign in to comment.