Skip to content

Commit

Permalink
Plugin version hotfix.
Browse files Browse the repository at this point in the history
  • Loading branch information
GuilhE committed Jun 27, 2024
1 parent 6067fd1 commit 1d9da3a
Show file tree
Hide file tree
Showing 9 changed files with 110 additions and 72 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
# Changelog
---
## [2.0.20-Beta1-1.6.11-BETA-1]

- Prepares Processor for Plugin 1.1.0 where it will be capable of checking for compilerArgs

---
## [2.0.20-Beta1-1.6.11-BETA]

Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG_PLUGIN.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# Changelog
---

## [1.0.1]

- Removes unique VERSION logic since KPS and Plugin will have different versions

---

## [1.0.0]

Hello world!
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ buildscript {

allprojects {
group = "com.github.guilhe.kmp"
version = "2.0.20-Beta1-1.6.11-BETA"
version = "2.0.20-Beta1-1.6.11-BETA-1"
}
3 changes: 0 additions & 3 deletions kmp-composeuiviewcontroller-gradle-plugin/Version.kt

This file was deleted.

26 changes: 1 addition & 25 deletions kmp-composeuiviewcontroller-gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ tasks.test {
useJUnitPlatform()
}

version = "1.0.0"
version = "1.0.1"
group = "io.github.guilhe.kmp"

gradlePlugin {
Expand All @@ -56,40 +56,16 @@ gradlePlugin {
}
}

/**
* The following configurations address the need for a unique source of truth regarding the library version within this module.
* Despite the version being initially defined in the root project's `build.gradle.kts` under the `allprojects` extension, direct access from this module is not feasible.
* To resolve this limitation, the code introduces a Gradle task (`copyVersionTemplate`) responsible for copying a `Version.kt` file from the project directory.
* It incorporates variable substitution to inject the specified `version` property into the file, storing it in a designated directory (`generated/kmp-composeuiviewcontroller-version/main`).
* By integrating this task into Kotlin compilation and JAR creation (`sourcesJar`), the approach ensures seamless inclusion of the versioned file in the main source set (`sourceSets`).
*
* It also provides `sourceSets` configurations for `resources` to make it possible to access and copy `exportToXcode.sh` file.
*/

sourceSets {
main {
java.srcDir(layout.buildDirectory.dir("generated/kmp-composeuiviewcontroller-version/main"))
resources.srcDir("src/main/resources")
}
}

private val copyVersionTemplate by tasks.registering(Copy::class) {
inputs.property("version", version)
from(layout.projectDirectory.file("Version.kt"))
into(layout.buildDirectory.dir("generated/kmp-composeuiviewcontroller-version/main"))
expand("version" to "$version")
filteringCharset = "UTF-8"
}

tasks.withType(Copy::class) {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

tasks.named("sourcesJar", Jar::class) {
dependsOn(copyVersionTemplate)
duplicatesStrategy = DuplicatesStrategy.INCLUDE
}

tasks.compileKotlin {
dependsOn(copyVersionTemplate)
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ import org.jetbrains.kotlin.konan.target.Family
import java.io.BufferedReader
import java.io.File

private const val VERSION = "2.0.20-Beta1-1.6.11-BETA-1"

public class KmpComposeUIViewControllerPlugin : Plugin<Project> {
private fun KotlinTarget.isKmpNativeCoroutinesTarget(): Boolean = this is KotlinNativeTarget && konanTarget.family == Family.IOS

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,11 @@ import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSTypeReference
import com.google.devtools.ksp.symbol.KSValueParameter

internal class Processor(private val codeGenerator: CodeGenerator, private val logger: KSPLogger) : SymbolProcessor {
internal class Processor(
private val codeGenerator: CodeGenerator,
private val logger: KSPLogger,
private val options: Map<String, String>
) : SymbolProcessor {

override fun process(resolver: Resolver): List<KSAnnotated> {
val candidates = resolver.getSymbolsWithAnnotation(composeUIViewControllerAnnotationName)
Expand All @@ -22,7 +26,7 @@ internal class Processor(private val codeGenerator: CodeGenerator, private val l

val trimmedCandidates = candidates.distinctBy { it.containingFile?.fileName }
for (node in trimmedCandidates) {
val frameworkName: String = getFrameworkNameFromAnnotations(node)
val frameworkBaseName: String = getFrameworkNameFromCompilerArgs() ?: getFrameworkNameFromAnnotations(node)
node.containingFile?.let { file ->
val packageName = file.packageName.asString()
for (composable in file.declarations.filterIsInstance<KSFunctionDeclaration>().filter {
Expand Down Expand Up @@ -60,15 +64,15 @@ internal class Processor(private val codeGenerator: CodeGenerator, private val l
createKotlinFileWithoutState(packageName, composable, makeParameters, parameters).also {
logger.info("${composable.name()}UIViewController created!")
}
createSwiftFileWithoutState(frameworkName, composable, makeParameters).also {
createSwiftFileWithoutState(frameworkBaseName, composable, makeParameters).also {
logger.info("${composable.name()}Representable created!")
}
} else {
val stateParameterName = stateParameter.name()
createKotlinFileWithState(packageName, composable, stateParameterName, stateParameter, makeParameters, parameters).also {
logger.info("${composable.name()}UIViewController created!")
}
createSwiftFileWithState(frameworkName, composable, stateParameterName, stateParameter, makeParameters).also {
createSwiftFileWithState(frameworkBaseName, composable, stateParameterName, stateParameter, makeParameters).also {
logger.info("${composable.name()}Representable created!")
}
}
Expand All @@ -78,6 +82,16 @@ internal class Processor(private val codeGenerator: CodeGenerator, private val l
return emptyList()
}

private fun getFrameworkNameFromCompilerArgs(): String? {
val name = options["frameworkBaseName"]
if (name != null) {
return name.ifEmpty {
throw IllegalArgumentException("@${composeUIViewControllerAnnotationName.name()} requires a non-null and non-empty value for $composeUIViewControllerAnnotationParameterName")
}
}
return name
}

private fun getFrameworkNameFromAnnotations(node: KSAnnotated): String {
val annotation = node.annotations.firstOrNull { it.shortName.asString() == composeUIViewControllerAnnotationName.name() }
if (annotation != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ import com.google.devtools.ksp.processing.SymbolProcessorProvider

public class ProcessorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return Processor(environment.codeGenerator, environment.logger)
return Processor(environment.codeGenerator, environment.logger, environment.options)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.github.guilhe.kmp.composeuiviewcontroller.ksp.composeUIViewController
import com.tschuchort.compiletesting.KotlinCompilation
import com.tschuchort.compiletesting.SourceFile
import com.tschuchort.compiletesting.SourceFile.Companion.kotlin
import com.tschuchort.compiletesting.kspArgs
import com.tschuchort.compiletesting.kspIncremental
import com.tschuchort.compiletesting.kspSourcesDir
import com.tschuchort.compiletesting.symbolProcessorProviders
Expand All @@ -26,14 +27,15 @@ class ProcessorTest {
@JvmField
var temporaryFolder: TemporaryFolder = TemporaryFolder()

private fun prepareCompilation(vararg sourceFiles: SourceFile): KotlinCompilation {
private fun prepareCompilation(vararg sourceFiles: SourceFile, args: Map<String, String> = emptyMap()): KotlinCompilation {
return KotlinCompilation().apply {
workingDir = temporaryFolder.root
inheritClassPath = true
symbolProcessorProviders = listOf(ProcessorProvider())
sources = sourceFiles.asList()
verbose = false
kspIncremental = false
kspArgs = args.toMutableMap()
}
}

Expand Down Expand Up @@ -63,6 +65,78 @@ class ProcessorTest {
)
}

@Test
fun `Empty frameworkName in @ComposeUIViewController throws IllegalStateException`() {
val code = """
package com.mycomposable.test
import $composeUIViewControllerAnnotationName
@ComposeUIViewController("")
@Composable
fun Screen(@ComposeUIViewControllerState state: ViewState) { }
""".trimIndent()
val compilation = prepareCompilation(kotlin("Screen.kt", code))
val result = compilation.compile()

assertEquals(result.exitCode, KotlinCompilation.ExitCode.COMPILATION_ERROR)
}

@Test
fun `Empty frameworkBaseName in CompilerArgs throws IllegalStateException`() {
val code = """
package com.mycomposable.test
import $composeUIViewControllerAnnotationName
@ComposeUIViewController
@Composable
fun Screen(@ComposeUIViewControllerState state: ViewState) { }
""".trimIndent()
val compilation = prepareCompilation(kotlin("Screen.kt", code), args = mapOf("frameworkBaseName" to ""))
val result = compilation.compile()

assertEquals(result.exitCode, KotlinCompilation.ExitCode.COMPILATION_ERROR)
}

@Test
fun `Default frameworkName in @ComposeUIViewController will have the value 'SharedComposables'`() {
val code = """
package com.mycomposable.test
import $composeUIViewControllerAnnotationName
@ComposeUIViewController
@Composable
fun Screen(@ComposeUIViewControllerState state: ViewState) { }
""".trimIndent()
val compilation = prepareCompilation(kotlin("Screen.kt", code))
val result = compilation.compile()

assertEquals(result.exitCode, KotlinCompilation.ExitCode.OK)
val generatedSwiftFiles = compilation.kspSourcesDir
.walkTopDown()
.filter { it.name == "ScreenUIViewControllerRepresentable.swift" }
assertContains(generatedSwiftFiles.first().readText(), "import SharedComposables")
}

@Test
fun `If frameworkBaseName is provided via compiler argument it will be used over default @ComposeUIViewController frameworkName value`() {
val code = """
package com.mycomposable.test
import $composeUIViewControllerAnnotationName
@ComposeUIViewController
@Composable
fun Screen(@ComposeUIViewControllerState state: ViewState) { }
""".trimIndent()
val compilation = prepareCompilation(kotlin("Screen.kt", code), args = mapOf("frameworkBaseName" to "MyFramework"))
val result = compilation.compile()

assertEquals(result.exitCode, KotlinCompilation.ExitCode.OK)
val generatedSwiftFiles = compilation.kspSourcesDir
.walkTopDown()
.filter { it.name == "ScreenUIViewControllerRepresentable.swift" }
assertContains(generatedSwiftFiles.first().readText(), "import MyFramework")
}

@Test
fun `Not using @ComposeUIViewControllerState will generate files without state`() {
val code = """
Expand Down Expand Up @@ -129,43 +203,7 @@ class ProcessorTest {
}

@Test
fun `Empty frameworkName in @ComposeUIViewController throws IllegalStateException`() {
val code = """
package com.mycomposable.test
import $composeUIViewControllerAnnotationName
@ComposeUIViewController("")
@Composable
fun Screen(@ComposeUIViewControllerState state: ViewState) { }
""".trimIndent()
val compilation = prepareCompilation(kotlin("Screen.kt", code))
val result = compilation.compile()

assertEquals(result.exitCode, KotlinCompilation.ExitCode.COMPILATION_ERROR)
}

@Test
fun `Default frameworkName in @ComposeUIViewController will have the value 'SharedComposables'`() {
val code = """
package com.mycomposable.test
import $composeUIViewControllerAnnotationName
@ComposeUIViewController
@Composable
fun Screen(@ComposeUIViewControllerState state: ViewState) { }
""".trimIndent()
val compilation = prepareCompilation(kotlin("Screen.kt", code))
val result = compilation.compile()

assertEquals(result.exitCode, KotlinCompilation.ExitCode.OK)
val generatedSwiftFiles = compilation.kspSourcesDir
.walkTopDown()
.filter { it.name == "ScreenUIViewControllerRepresentable.swift" }
assertContains(generatedSwiftFiles.first().readText(), "import SharedComposables")
}

@Test
fun `No more than one @ComposeUIViewControllerState is allowed`() {
fun `Only 1 @ComposeUIViewControllerState is allowed`() {
val code = """
package com.mycomposable.test
import $composeUIViewControllerAnnotationName
Expand Down

0 comments on commit 1d9da3a

Please sign in to comment.