Skip to content

Commit

Permalink
Exposed expression API and generics */? basic support
Browse files Browse the repository at this point in the history
  • Loading branch information
gmazzo committed Dec 28, 2023
1 parent c399096 commit 3ca4406
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 31 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ Designed for KTS scripts, with *experimental* support for Kotlin's **multi-platf
On your `build.gradle.kts` add:
```kotlin
plugins {
id("org.jetbrains.kotlin.jvm") version embeddedKotlinVersion
id("com.github.gmazzo.buildconfig") version <current version>
id("org.jetbrains.kotlin.jvm") version "<kotlin version>"
id("com.github.gmazzo.buildconfig") version "<current version>"
}

buildConfig {
Expand All @@ -25,9 +25,7 @@ buildConfig {
buildConfigField("FEATURE_ENABLED", true)
buildConfigField("MAGIC_NUMBERS", intArrayOf(1, 2, 3, 4))
buildConfigField("STRING_LIST", arrayOf("a", "b", "c"))
buildConfigField<Map<String, Int>>("MAP") {
expression("mapOf(\"a\" to 1, \"b\" to 2)")
}
buildConfigField<Map<String, Int>>("MAP", expression("mapOf(\"a\" to 1, \"b\" to 2)"))
buildConfigField("com.github.gmazzo.buildconfig.demos.kts.SomeData", "DATA", "SomeData(\"a\", 1)")

}
Expand Down Expand Up @@ -67,6 +65,7 @@ buildConfig {
buildConfigField(int[], "MAGIC_NUMBERS", [1, 2, 3])
buildConfigField('List<String>', "STRING_LIST", ["a", "b", "c"])
buildConfigField("java.util.Map<String, Integer>", "MAP", "java.util.Map.of(\"a\", 1, \"b\", 2)")
buildConfigField(Map.class, "GENERIC_MAP", expression("java.util.Map.of(\"a\", 1, \"b\", 2)"))
buildConfigField("com.github.gmazzo.buildconfig.demos.groovy.SomeData", "DATA", "new SomeData(\"a\", 1)")
}
```
Expand Down
2 changes: 2 additions & 0 deletions demo-project/groovy-gen-kotlin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ buildConfig {
"MAP_PROVIDER",
provider { "mapOf(\"a\" to 1, \"b\" to 2)" }
)
buildConfigField(Map.class, "MAP_GENERIC", expression("mapOf(\"a\" to 1, \"b\" to 2)"))
buildConfigField(Map.class, "MAP_GENERIC_PROVIDER", provider { expression("mapOf(\"a\" to 1, \"b\" to 2)") })
buildConfigField(
"com.github.gmazzo.buildconfig.demos.groovy.SomeData",
"DATA",
Expand Down
2 changes: 2 additions & 0 deletions demo-project/groovy/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,8 @@ buildConfig {
"MAP_PROVIDER",
provider { "java.util.Map.of(\"a\", 1, \"b\", 2)" }
)
buildConfigField(Map.class, "MAP_GENERIC", expression("java.util.Map.of(\"a\", 1, \"b\", 2)"))
buildConfigField(Map.class, "MAP_GENERIC_PROVIDER", provider { expression("java.util.Map.of(\"a\", 1, \"b\", 2)") })
buildConfigField(
"com.github.gmazzo.buildconfig.demos.groovy.SomeData",
"DATA",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,8 @@ public void testBooleans() {
public void testCustomTypes() {
assertEquals(Map.of("a", 1, "b", 2), BuildConfig.MAP);
assertEquals(Map.of("a", 1, "b", 2), BuildConfig.MAP_PROVIDER);
assertEquals(Map.of("a", 1, "b", 2), BuildConfig.MAP_GENERIC);
assertEquals(Map.of("a", 1, "b", 2), BuildConfig.MAP_GENERIC_PROVIDER);
assertEquals(new SomeData("a", 1), BuildConfig.DATA);
assertEquals(new SomeData("a", 1), BuildConfig.DATA_PROVIDER);
}
Expand Down
14 changes: 4 additions & 10 deletions demo-project/kts-gen-java/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -157,16 +157,10 @@ buildConfig {
buildConfigField("BOOLEAN_SET_PROVIDER", provider { setOf(true, null, false) })

// custom formats with expressions, including Map and custom types
buildConfigField(
"java.util.Map<String, Int>",
"MAP",
"java.util.Map.of(\"a\", 1, \"b\", 2)"
)
buildConfigField(
"java.util.Map<String, Int>",
"MAP_PROVIDER",
provider { "java.util.Map.of(\"a\", 1, \"b\", 2)" }
)
buildConfigField<Map<String, Int>>("MAP", expression("java.util.Map.of(\"a\", 1, \"b\", 2)"))
buildConfigField<Map<String, Int>>("MAP_PROVIDER", provider { expression("java.util.Map.of(\"a\", 1, \"b\", 2)") })
buildConfigField<Map<*, *>>("MAP_GENERIC", expression("java.util.Map.of(\"a\", 1, \"b\", 2)"))
buildConfigField<Map<*, *>>("MAP_GENERIC_PROVIDER", provider { expression("java.util.Map.of(\"a\", 1, \"b\", 2)") })
buildConfigField(
"com.github.gmazzo.buildconfig.demos.kts.SomeData",
"DATA",
Expand Down
10 changes: 4 additions & 6 deletions demo-project/kts/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -172,12 +172,10 @@ buildConfig {
buildConfigField("BOOLEAN_SET_PROVIDER", provider { setOf(true, null, false) })

// custom formats with expressions, including Map and custom types
buildConfigField<Map<String, Int>>("MAP") {
expression("mapOf(\"a\" to 1, \"b\" to 2)")
}
buildConfigField<Map<String, Int>>("MAP_PROVIDER") {
expression("mapOf(\"a\" to 1, \"b\" to 2)")
}
buildConfigField<Map<String, Int>>("MAP", expression("mapOf(\"a\" to 1, \"b\" to 2)"))
buildConfigField<Map<String, Int>>("MAP_PROVIDER", provider { expression("mapOf(\"a\" to 1, \"b\" to 2)") })
buildConfigField<Map<*, *>>("MAP_GENERIC", expression("mapOf(\"a\" to 1, \"b\" to 2)"))
buildConfigField<Map<*, *>>("MAP_GENERIC_PROVIDER", provider { expression("mapOf(\"a\" to 1, \"b\" to 2)") })
buildConfigField(
"com.github.gmazzo.buildconfig.demos.kts.SomeData",
"DATA",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,15 @@ interface BuildConfigClassSpec : Named {
it.value(castToType(value, type) as Serializable?)
}

fun buildConfigField(
type: Class<*>,
name: String,
expression: BuildConfigValue.Expression
) = buildConfigField(name) {
it.type(type)
it.value.value(expression)
}

/*
Because of erasure types on Groovy, this method is call for two use cases:
- when `buildConfigField('File', 'NAME', provider { 'File("aFile")' })` is called
Expand All @@ -87,7 +96,13 @@ interface BuildConfigClassSpec : Named {
) = buildConfigField(name) {
it.type(type)
it.value
.value(value.map { v -> if (v is String) BuildConfigValue.Expression(v) else BuildConfigValue.Literal(v) })
.value(value.map { v ->
when (v) {
is BuildConfigValue -> v
is String -> BuildConfigValue.Expression(v)
else -> BuildConfigValue.Literal(v)
}
})
.disallowChanges()
}

Expand All @@ -97,7 +112,17 @@ interface BuildConfigClassSpec : Named {
value: Provider<out Type>,
) = buildConfigField(name) {
it.type(type)
it.value(value.map { v -> castToType(v, type) as Serializable })
it.value.value(value.map { v ->
when (v) {
is BuildConfigValue -> v
is String -> when (type) {
String::class.java -> BuildConfigValue.Literal(v)
else -> BuildConfigValue.Expression(v)
}

else -> BuildConfigValue.Literal(castToType(v, type) as Serializable)
}
})
}

fun buildConfigField(
Expand All @@ -110,4 +135,7 @@ interface BuildConfigClassSpec : Named {
}
}

fun expression(expression: String) =
BuildConfigValue.Expression(expression)

}
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,32 @@ private val Type.genericName: String
else -> error("Unsupported type: $this")
}

private val Type.isArray get() = when (this) {
is Class<*> -> isArray
is GenericArrayType -> true
else -> false
}
private val Type.isArray
get() = when (this) {
is Class<*> -> isArray
is GenericArrayType -> true
else -> false
}

internal fun nameOf(type: Type): BuildConfigType = when(type) {
internal fun nameOf(type: Type): BuildConfigType = when (type) {
is Class<*> -> BuildConfigType(
className = type.genericName,
typeArguments = type.typeParameters.map { nameOf(it.genericDeclaration) },
typeArguments = type.typeParameters.map {
nameOf(checkNotNull(it.bounds.singleOrNull()) {
"Types with complex parameters bounds are not supported: $type"
})
},
nullable = false,
array = type.isArray
)

is ParameterizedType -> BuildConfigType(
className = type.rawType.genericName,
typeArguments = type.actualTypeArguments.map { nameOf(it) },
nullable = false,
array = false
)

is GenericArrayType -> BuildConfigType(
className = type.genericComponentType.genericName,
typeArguments = checkNotNull(type.genericComponentType as? ParameterizedType) {
Expand All @@ -68,6 +75,7 @@ internal fun nameOf(type: Type): BuildConfigType = when(type) {
nullable = false,
array = true
)

else -> error("Unsupported type: $type")
}

Expand All @@ -77,7 +85,7 @@ internal fun nameOf(type: KType): BuildConfigType {

return BuildConfigType(
className = type.javaType.genericName,
typeArguments = targetType.arguments.map { nameOf(it.type!!) },
typeArguments = targetType.arguments.map { it.type?.let(::nameOf) ?: nameOf("*") },
nullable = targetType.isMarkedNullable,
array = isArray
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import com.squareup.javapoet.MethodSpec
import com.squareup.javapoet.ParameterizedTypeName
import com.squareup.javapoet.TypeName
import com.squareup.javapoet.TypeSpec
import com.squareup.javapoet.WildcardTypeName
import org.gradle.api.logging.Logging
import org.gradle.api.tasks.Input
import javax.lang.model.element.Modifier
Expand All @@ -35,6 +36,7 @@ data class BuildConfigJavaGenerator(
"string" -> STRING
"list" -> LIST
"set" -> SET
"*", "?" -> WildcardTypeName.get(Object::class.java)
else -> ClassName.bestGuess(className)
}
if (typeArguments.isNotEmpty()) type = ParameterizedTypeName.get(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.SET
import com.squareup.kotlinpoet.SHORT
import com.squareup.kotlinpoet.SHORT_ARRAY
import com.squareup.kotlinpoet.STAR
import com.squareup.kotlinpoet.STRING
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.TypeSpec
Expand Down Expand Up @@ -105,6 +106,7 @@ data class BuildConfigKotlinGenerator(
"string" -> STRING
"list" -> LIST
"set" -> SET
"*", "?" -> STAR
else -> ClassName.bestGuess(kotlinClassName)
}
if (typeArguments.isNotEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.gradle.kotlin.dsl
import com.github.gmazzo.buildconfig.BuildConfigClassSpec
import com.github.gmazzo.buildconfig.BuildConfigDsl
import com.github.gmazzo.buildconfig.BuildConfigField
import com.github.gmazzo.buildconfig.BuildConfigValue
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectProvider
import org.gradle.api.provider.Provider
Expand Down Expand Up @@ -36,6 +37,26 @@ inline fun <reified Type : Serializable> BuildConfigClassSpec.buildConfigField(
it.value(value)
})

@BuildConfigDsl
@JvmName("buildConfigFieldExpression")
inline fun <reified Type : Any?> BuildConfigClassSpec.buildConfigField(
name: String,
expression: BuildConfigValue.Expression,
): NamedDomainObjectProvider<BuildConfigField> = buildConfigField(name, Action {
it.type(typeOf<Type>())
it.value.set(expression)
})

@BuildConfigDsl
@JvmName("buildConfigFieldExpression")
inline fun <reified Type : Any?> BuildConfigClassSpec.buildConfigField(
name: String,
expression: Provider<BuildConfigValue.Expression>,
): NamedDomainObjectProvider<BuildConfigField> = buildConfigField(name, Action {
it.type(typeOf<Type>())
it.value.set(expression)
})

@BuildConfigDsl
@JvmName("buildConfigFieldArray")
inline fun <reified Type : Serializable?> BuildConfigClassSpec.buildConfigField(
Expand Down

0 comments on commit 3ca4406

Please sign in to comment.