Skip to content

Commit 35cdfd0

Browse files
committed
2.4.0-1.11.1-1
1 parent d2b0163 commit 35cdfd0

9 files changed

Lines changed: 103 additions & 32 deletions

File tree

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## [2.4.0-1.11.1-1]
4+
5+
- Adds `composeuiviewcontroller.metadataPath` to pass the absolute path passed by the Gradle plugin. This is always correct regardless of the
6+
working directory at KSP execution time.
7+
38
## [2.4.0-1.11.1]
49

510
- Kotlin 2.4.0 🥳

CHANGELOG_PLUGIN.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# Changelog
22

3+
## [2.4.0-1.11.1-1]
4+
5+
- Compatible with 2.4.0-1.11.1-1
6+
7+
---
8+
39
## [2.4.0-1.11.1]
410

511
- Compatible with 2.4.0-1.11.1

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ KSP library and Gradle plugin for generating `ComposeUIViewController` and `UIVi
88

99
| [Version](https://plugins.gradle.org/plugin/io.github.guilhe.kmp.plugin-composeuiviewcontroller) | [Kotlin](https://github.com/JetBrains/kotlin/releases) | [KSP](https://github.com/Google/KSP/releases) | [Compose Multiplatform](https://github.com/JetBrains/compose-multiplatform/releases) | Xcode |
1010
|--------------------------------------------------------------------------------------------------|:------------------------------------------------------:|:---------------------------------------------:|:------------------------------------------------------------------------------------:|:------:|
11-
| 2.4.0-1.11.1 | 2.4.0 | 2.3.9 | 1.11.1 | 26.5.0 |
11+
| 2.4.0-1.11.1-1 | 2.4.0 | 2.3.9 | 1.11.1 | 26.5.0 |
1212

1313
[![Android Weekly](https://androidweekly.net/issues/issue-583/badge)](https://androidweekly.net/issues/issue-583) [![Featured in Kotlin Weekly - Issue #378](https://img.shields.io/badge/Featured_in_Kotlin_Weekly-Issue_%23378-7878b4)](https://mailchi.mp/kotlinweekly/kotlin-weekly-378) [![Featured in Kotlin Weekly - Issue #389](https://img.shields.io/badge/Featured_in_Kotlin_Weekly-Issue_%23389-7878b4)](https://mailchi.mp/kotlinweekly/kotlin-weekly-389) <a href="https://jetc.dev/issues/177.html"><img src="https://img.shields.io/badge/As_Seen_In-jetc.dev_Newsletter_Issue_%23177-blue?logo=Jetpack+Compose&amp;logoColor=white" alt="As Seen In - jetc.dev Newsletter Issue #177"></a> <a href="https://jetc.dev/issues/188.html"><img src="https://img.shields.io/badge/As_Seen_In-jetc.dev_Newsletter_Issue_%23188-blue?logo=Jetpack+Compose&amp;logoColor=white" alt="As Seen In - jetc.dev Newsletter Issue #188"></a>
1414

build-logic/conventions/src/main/kotlin/KmpComposeUIViewControllerPublishPlugin.kt

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,23 +35,23 @@ class KmpComposeUIViewControllerPublishPlugin : Plugin<Project> {
3535
project.findProperty("signingInMemoryKeyId") != null ||
3636
System.getenv("ORG_GRADLE_PROJECT_signingInMemoryKeyId") != null
3737

38-
if (!hasSigning) {
39-
project.logger.debug("\t> KmpComposeUIViewControllerPublishPlugin [${project.name}] - no signing configuration found, skipping publish setup.")
40-
return
38+
project.logger.debug("\t> KmpComposeUIViewControllerPublishPlugin [${project.name}] - hasSigning = $hasSigning")
39+
40+
if (hasSigning) {
41+
project.plugins.apply("signing")
42+
project.gradle.taskGraph.whenReady(object : Closure<Unit>(project) {
43+
fun doCall(graph: org.gradle.api.execution.TaskExecutionGraph) {
44+
val isMavenLocal = graph.allTasks.any { it.name == "publishToMavenLocal" || it.path.endsWith("publishToMavenLocal") }
45+
project.extensions.getByType(SigningExtension::class.java).isRequired = !isMavenLocal
46+
project.logger.debug("\t> KmpComposeUIViewControllerPublishPlugin [${project.name}] - isMavenLocal = $isMavenLocal")
47+
}
48+
})
4149
}
4250

43-
project.plugins.apply("signing")
44-
project.gradle.taskGraph.whenReady(object : Closure<Unit>(project) {
45-
fun doCall(graph: org.gradle.api.execution.TaskExecutionGraph) {
46-
val isMavenLocal = graph.allTasks.any { it.name == "publishToMavenLocal" || it.path.endsWith("publishToMavenLocal") }
47-
project.extensions.getByType(SigningExtension::class.java).isRequired = !isMavenLocal
48-
project.logger.debug("\t> KmpComposeUIViewControllerPublishPlugin [${project.name}] - isMavenLocal = $isMavenLocal")
49-
}
50-
})
5151
project.plugins.apply("com.vanniktech.maven.publish")
5252
project.extensions.getByType(MavenPublishBaseExtension::class.java).apply {
5353
publishToMavenCentral(automaticRelease = false)
54-
signAllPublications()
54+
if (hasSigning) signAllPublications()
5555
pom {
5656
name.set(LIB_NAME)
5757
description.set(LIB_DESCRIPTION)

build.gradle.kts

Lines changed: 60 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ buildscript {
1515

1616
allprojects {
1717
group = "com.github.guilhe.kmp"
18-
version = "2.4.0-1.11.1"
18+
version = "2.4.0-1.11.1-1"
1919
}
2020

2121
dependencies {
@@ -30,6 +30,14 @@ tasks.register("publishLibraryModules") {
3030
finalizedBy(":kmp-composeuiviewcontroller-ksp:publishToMavenCentral")
3131
}
3232

33+
tasks.register("publishLibraryModulesLocally") {
34+
description = "Publishes all library modules to the local Maven repository (~/.m2) for local testing (no signing required)"
35+
dependsOn(":kmp-composeuiviewcontroller-common:publishToMavenLocal")
36+
dependsOn(":kmp-composeuiviewcontroller-annotations:publishToMavenLocal")
37+
dependsOn(":kmp-composeuiviewcontroller-ksp:publishToMavenLocal")
38+
dependsOn(":kmp-composeuiviewcontroller-gradle-plugin:publishToMavenLocal")
39+
}
40+
3341
tasks.register("serveDokka") {
3442
description = "Serves the generated Dokka documentation on a local web server. Use -Pport=PORT to specify a custom port (default: 8080)."
3543
dependsOn("dokkaGenerate")
@@ -74,6 +82,9 @@ tasks.register("buildAllSamples") {
7482
?: throw GradleException("No available iOS Simulator found. Install a simulator runtime in Xcode.")
7583
}
7684

85+
data class BuildResult(val sample: String, val passed: Boolean, val reason: String? = null)
86+
val results = mutableListOf<BuildResult>()
87+
7788
for (sample in samples) {
7889
println("\n🔨 [$sample] Starting build...")
7990

@@ -92,18 +103,56 @@ tasks.register("buildAllSamples") {
92103
args.addAll(listOf("-sdk", "iphonesimulator"))
93104
}
94105

95-
val pb = ProcessBuilder(args)
96-
.directory(file(sample))
97-
.redirectErrorStream(true)
106+
try {
107+
val pb = ProcessBuilder(args)
108+
.directory(file(sample))
109+
.redirectErrorStream(true)
98110

99-
val process = pb.start()
100-
val reader = Thread { process.inputStream.bufferedReader().forEachLine { println("[$sample] $it") } }
101-
reader.start()
102-
val exitCode = process.waitFor()
103-
reader.join()
111+
val process = pb.start()
112+
val outputLines = mutableListOf<String>()
113+
val reader = Thread {
114+
process.inputStream.bufferedReader().forEachLine { line ->
115+
println("[$sample] $line")
116+
outputLines.add(line)
117+
}
118+
}
119+
reader.start()
120+
val exitCode = process.waitFor()
121+
reader.join()
122+
123+
if (exitCode != 0) {
124+
val errorLine = outputLines.lastOrNull { it.contains("error:", ignoreCase = true) }
125+
?: outputLines.lastOrNull { it.isNotBlank() }
126+
?: "exit code $exitCode"
127+
println("❌ [$sample] Build failed — continuing to next sample.")
128+
results.add(BuildResult(sample, false, errorLine.trim()))
129+
} else {
130+
println("✅ [$sample] Done!")
131+
results.add(BuildResult(sample, true))
132+
}
133+
} catch (e: Exception) {
134+
println("❌ [$sample] Exception during build — continuing to next sample.")
135+
results.add(BuildResult(sample, false, e.message ?: "Unknown exception"))
136+
}
137+
}
138+
139+
println("\n" + "=".repeat(60))
140+
println("📋 Build Summary")
141+
println("=".repeat(60))
142+
val passed = results.filter { it.passed }
143+
val failed = results.filter { !it.passed }
144+
if (passed.isNotEmpty()) {
145+
println("\n✅ Passed (${passed.size}):")
146+
passed.forEach { println("${it.sample}") }
147+
}
148+
if (failed.isNotEmpty()) {
149+
println("\n❌ Failed (${failed.size}):")
150+
failed.forEach { println("${it.sample}: ${it.reason}") }
151+
}
152+
println("\n" + "=".repeat(60))
104153

105-
if (exitCode != 0) throw GradleException("❌ [$sample] Build failed — stopping.")
106-
println("✅ [$sample] Done!")
154+
if (failed.isNotEmpty()) {
155+
throw GradleException("${failed.size} sample(s) failed to build. See summary above.")
107156
}
108157
}
109158
}

kmp-composeuiviewcontroller-gradle-plugin/build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ dependencies {
2727
testImplementation(libs.test.kotlin)
2828
}
2929

30-
version = "2.4.0-1.11.1"
30+
version = "2.4.0-1.11.1-1"
3131
group = "io.github.guilhe.kmp"
3232

3333
gradlePlugin {

kmp-composeuiviewcontroller-gradle-plugin/src/main/kotlin/com/github/guilhe/kmp/composeuiviewcontroller/gradle/Constants.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ let package = Package(
2222
)
2323
""".trimIndent()
2424

25-
internal const val VERSION_LIBRARY = "2.4.0-1.11.1"
25+
internal const val VERSION_LIBRARY = "2.4.0-1.11.1-1"
2626
internal const val LOG_TAG = "KmpComposeUIViewControllerPlugin"
2727
internal const val PLUGIN_KMP = "org.jetbrains.kotlin.multiplatform"
2828
internal const val PLUGIN_KSP = "com.google.devtools.ksp"
@@ -62,6 +62,7 @@ internal const val PARAM_SPM_MODULE = "spm_module_name"
6262
internal const val PARAM_IOS_DEPLOYMENT_TARGET = "ios_deployment_target"
6363
internal const val PARAM_SWIFT_TOOLS_VERSION = "swift_tools_version"
6464
internal const val KSP_ARG_METADATA_HASH = "composeuiviewcontroller.metadataHash"
65+
internal const val KSP_ARG_METADATA_PATH = "composeuiviewcontroller.metadataPath"
6566
internal const val ERROR_MISSING_KMP = "$LOG_TAG requires the Kotlin Multiplatform plugin to be applied."
6667
internal const val ERROR_MISSING_PACKAGE = "Could not determine project's package"
6768
internal const val ERROR_MISSING_FRAMEWORK_CONFIG = "No framework configuration found."

kmp-composeuiviewcontroller-gradle-plugin/src/main/kotlin/com/github/guilhe/kmp/composeuiviewcontroller/gradle/Plugin.kt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -327,7 +327,10 @@ public class KmpComposeUIViewControllerPlugin : Plugin<Project> {
327327
logger.info("\t> Registered $FILE_NAME_ARGS as input for task '${task.name}'")
328328
}
329329

330-
// KSP level
330+
// KSP level: pass the absolute path so the processor is independent of the working directory.
331+
// Relative path resolution fails when Gradle is invoked from a subdirectory (e.g. Cocoapods
332+
// invoking from iosApp/ instead of the project root).
333+
extensions.findByType(KspExtension::class.java)?.arg(KSP_ARG_METADATA_PATH, metadataFile.absolutePath)
331334
if (metadataFile.exists()) {
332335
val metadataHash = metadataFile.readText().hashCode().toString()
333336
extensions.findByType(KspExtension::class.java)?.arg(KSP_ARG_METADATA_HASH, metadataHash)

kmp-composeuiviewcontroller-ksp/src/main/kotlin/com/github/guilhe/kmp/composeuiviewcontroller/ksp/Processor.kt

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ import java.io.File
2121
import kotlinx.serialization.json.Json
2222

2323
public class ProcessorProvider : SymbolProcessorProvider {
24-
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = Processor(environment.codeGenerator, environment.logger)
24+
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor =
25+
Processor(environment.codeGenerator, environment.logger, environment.options)
2526
}
2627

2728
private data class TypeAliasInfo(
@@ -32,6 +33,7 @@ private data class TypeAliasInfo(
3233
internal class Processor(
3334
private val codeGenerator: CodeGenerator,
3435
private val logger: KSPLogger,
36+
private val options: Map<String, String> = emptyMap(),
3537
) : SymbolProcessor {
3638

3739
override fun process(resolver: Resolver): List<KSAnnotated> {
@@ -193,10 +195,15 @@ internal class Processor(
193195
}
194196

195197
private fun getFrameworkMetadataFromDisk(): List<ModuleMetadata> {
196-
val file = if (System.getProperty("user.dir").endsWith("Pods")) {
197-
File("../../build/$TEMP_FILES_FOLDER/$FILE_NAME_ARGS")
198-
} else {
199-
File("./build/$TEMP_FILES_FOLDER/$FILE_NAME_ARGS")
198+
// Prefer the absolute path passed by the Gradle plugin (composeuiviewcontroller.metadataPath).
199+
// This is always correct regardless of the working directory at KSP execution time.
200+
// Older plugin versions or Cocoapods setups (invoked from iosApp/ instead of the project root)
201+
// do not set this arg, so we fall back to the legacy relative path heuristic.
202+
val absolutePath = options["composeuiviewcontroller.metadataPath"]
203+
val file = when {
204+
!absolutePath.isNullOrBlank() -> File(absolutePath)
205+
System.getProperty("user.dir").endsWith("Pods") -> File("../../build/$TEMP_FILES_FOLDER/$FILE_NAME_ARGS")
206+
else -> File("./build/$TEMP_FILES_FOLDER/$FILE_NAME_ARGS")
200207
}
201208
val moduleMetadata = try {
202209
Json.decodeFromString<List<ModuleMetadata>>(file.readText())

0 commit comments

Comments
 (0)