Skip to content

Commit

Permalink
Merge pull request #9 from yshrsmz/issue/8-flavor
Browse files Browse the repository at this point in the history
Issue/8 flavor support
  • Loading branch information
yshrsmz authored Feb 8, 2019
2 parents 6780a2a + 83ecc23 commit 636bbd4
Show file tree
Hide file tree
Showing 23 changed files with 833 additions and 58 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,5 @@ playground.xcworkspace
.DS_Store

secret.properties
!.idea/codeStyles/*
!.idea/codeStyles/*
!.idea/dictionaries/dic.xml
9 changes: 9 additions & 0 deletions .idea/dictionaries/dic.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions CHANGELOGS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Change Log
Version 0.3.0 *(WIP)*
---

- Support build flavor ([#8](https://github.com/yshrsmz/BuildKonfig/issues/8))
- TBD


Expand Down
82 changes: 81 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,37 @@ BuildKonfig
BuildConfig for Kotlin Multiplatform Project.
It currently supports embedding values from gradle file.

## Table Of Contents

- [Motivation](#motivation)
- [Usage](#usage)
- [Requirements](#requirements)
- [Gradle Configuration](#gradle-configuration)
- [Product Flavor?](#product-flavor)
- [Overwriting Values](#overwriting-values)
- [Supported Types](#supported-types)

<a name="motivation"/>

## Motivation

Passing values from Android/iOS or any other platform code should work, but it's a hassle.
Setting up Android to read values from properties and add those into BuildConfig, and do the equivalent in iOS?
Rather I'd like to do it once.


## Usege
<a name="usage"/>

## Usage

<a name="requirements"/>

### Requirements

- Kotlin **1.3.20** or later
- Kotlin Multiplatform Project

<a name="gradle-configuration"/>

### Gradle Configuration

Expand Down Expand Up @@ -102,6 +119,69 @@ internal actual object BuildKonfig {
}
```

<a name="product-flavor"/>

### Product Flavor?

Yes(sort of).
Kotlin Multiplatform Project does not support product flavor. Kotlin/Native part of the project has release/debug distinction, but it's not global.
So we made some workaround to mimick product flavor capability of Android.

Specify default flavor in your `gradle.properties`

```properties
# ROOT_DIR/gradle.properties
buildkonfig.flavor=dev
```

```gradle
// ./mpp_project/build.gradle
buildkonfig {
packageName = 'com.example.app'
// default config is required
defaultConfigs {
buildConfigField 'STRING', 'name', 'value'
}
defaultConfigs("dev") {
buildConfigField 'STRING', 'name', 'devValue'
}
targetConfigs {
android {
buildConfigField 'STRING', 'name2', 'value2'
}
ios {
buildConfigField 'STRING', 'name', 'valueIos'
}
}
targetConfigs("dev") {
ios {
buildConfigField 'STRING', 'name', 'devValueIos'
}
}
}
```

In a development phase you can change value in `gradle.properties` as you like.
In CI environment, you can pass value via CLI `$ ./gradlew build -Pbuildkonfig.flavor=release`


<a name="overwriting-values"/>

### Overwriting Values

If you configure same field across multiple defaultConfigs and targetConfigs, flavored targetConfigs is the strongest.

Lefter the stronger.
```
Flavored TargetConfig > TargetConfig > Flavored DefaultConfig > DefaultConfig
```


<a name="supported-types"/>

## Supported Types

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ import com.codingfeline.buildkonfig.compiler.generator.BuildKonfigCompiler
import java.io.File

class BuildKonfigEnvironment(
val data: BuildKonfigData
private val data: BuildKonfigData
) {

sealed class CompilationStatus {
class Success : CompilationStatus()
object Success : CompilationStatus()
class Failure(val errors: List<String>) : CompilationStatus()
}

Expand Down Expand Up @@ -39,7 +39,7 @@ class BuildKonfigEnvironment(
}

return if (errors.isEmpty()) {
CompilationStatus.Success()
CompilationStatus.Success
} else {
CompilationStatus.Failure(errors)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@ package com.codingfeline.buildkonfig.compiler
import java.io.Serializable

open class TargetConfig(val name: String) : Serializable {
var flavor: String = ""
val fieldSpecs = mutableMapOf<String, FieldSpec>()
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,60 @@ package com.codingfeline.buildkonfig.gradle
import groovy.lang.Closure
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project

open class BuildKonfigExtension(
private val project: Project
) {

private val configFactory = TargetConfigFactory(project.objects, project.logger)

open class BuildKonfigExtension {
var packageName: String? = null
var defaultConfigs: TargetConfigDsl? = null
var targetConfigs: NamedDomainObjectContainer<TargetConfigDsl>? = null

val defaultConfigs = mutableMapOf<String, TargetConfigDsl>()
val targetConfigs = mutableMapOf<String, NamedDomainObjectContainer<TargetConfigDsl>>()

@Suppress("unused")
fun defaultConfigs(config: Action<TargetConfigDsl>) {
defaultConfigs?.let { config.execute(it) }
defaultConfigs.computeIfAbsent("") { createNewTargetConfig() }
.let {
config.execute(it)
it.flavor = ""
}
}

@Suppress("unused")
fun defaultConfigs(flavor: String, config: Action<TargetConfigDsl>) {
defaultConfigs.computeIfAbsent(flavor) { createNewTargetConfig() }
.let {
config.execute(it)
it.flavor = flavor
}
}

@Suppress("unused")
fun targetConfigs(config: Closure<*>) {
this.targetConfigs?.configure(config)
targetConfigs.computeIfAbsent("") { createTargetConfigContainer() }
.configure(config)
.forEach { it.flavor = "" }
}

@Suppress("unused")
fun targetConfigs(flavor: String, config: Closure<*>) {
targetConfigs.computeIfAbsent(flavor) { createTargetConfigContainer() }
.configure(config)
.forEach { it.flavor = flavor }
}

private fun createNewTargetConfig(): TargetConfigDsl {
return project.objects.newInstance(
TargetConfigDsl::class.java,
"defaults",
project.logger
)
}

private fun createTargetConfigContainer(): NamedDomainObjectContainer<TargetConfigDsl> {
return project.container(TargetConfigDsl::class.java, configFactory)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,7 @@ open class BuildKonfigPlugin : Plugin<Project> {
}
}

val objectFactory = target.objects

val extension = target.extensions.create("buildkonfig", BuildKonfigExtension::class.java)

val logger = target.logger

extension.defaultConfigs = objectFactory.newInstance(TargetConfigDsl::class.java, "defaults", logger)
extension.targetConfigs = target.container(
TargetConfigDsl::class.java,
PlatformConfigFactory(objectFactory, logger)
)
val extension = target.extensions.create("buildkonfig", BuildKonfigExtension::class.java, target)

target.afterEvaluate {
if (!isMultiplatform) {
Expand Down Expand Up @@ -72,7 +62,7 @@ open class BuildKonfigPlugin : Plugin<Project> {

project.afterEvaluate { p ->

val mainTask = p.tasks.register("generateBuildKonfig", BuildKonfigTask::class.java) {
val task = p.tasks.register("generateBuildKonfig", BuildKonfigTask::class.java) {
it.packageName = requireNotNull(extension.packageName) { "packageName must be provided" }
it.commonOutputDirectory = commonOutputDirectory
it.outputDirectories = outputDirectoryMap
Expand All @@ -84,17 +74,17 @@ open class BuildKonfigPlugin : Plugin<Project> {

p.extensions.getByType(KotlinMultiplatformExtension::class.java).targets.forEach { target ->
target.compilations.forEach { compilationUnit ->
if (compilationUnit is KotlinNativeCompilation) {

compilationUnit.target.binaries.forEach { binary ->
p.tasks.named(binary.linkTaskName).configure { it.dependsOn(mainTask) }
when (compilationUnit) {
is KotlinNativeCompilation -> {
compilationUnit.target.binaries.forEach { binary ->
p.tasks.named(binary.linkTaskName).configure { it.dependsOn(task) }
}
}
} else if (compilationUnit is KotlinJvmAndroidCompilation) {

p.tasks.named(compilationUnit.compileKotlinTaskName).configure { it.dependsOn(mainTask) }
} else {

p.tasks.named(compilationUnit.compileKotlinTaskName).configure { it.dependsOn(mainTask) }
is KotlinJvmAndroidCompilation -> {
p.tasks.named(compilationUnit.compileKotlinTaskName)
.configure { it.dependsOn(task) }
}
else -> p.tasks.named(compilationUnit.compileKotlinTaskName).configure { it.dependsOn(task) }
}
}
}
Expand Down
Loading

0 comments on commit 636bbd4

Please sign in to comment.