Skip to content

Commit ec69848

Browse files
authored
Merge pull request #257 from thisisthepy/feat/compose-extended
Feat: switch Compose dependencies and plugins to org.thisisthepy.compose 1.11.1-ext.1
2 parents 860fbc8 + 914ed8a commit ec69848

13 files changed

Lines changed: 125 additions & 36 deletions

File tree

‎build.gradle.kts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ plugins {
44
alias(libs.plugins.android.application).apply(false)
55
alias(libs.plugins.android.library).apply(false)
66
alias(libs.plugins.jetpack.compose).apply(false)
7+
alias(libs.plugins.kotlin.native.desktop).apply(false)
78
alias(libs.plugins.compose.compiler).apply(false)
89
alias(libs.plugins.kotlin.multiplatform).apply(false)
910
alias(libs.plugins.kotlin.jvm).apply(false)

‎gradle.properties‎

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ kotlin.native.binary.sourceInfoType=libbacktrace
2121
#Compose
2222
org.jetbrains.compose.experimental.jscanvas.enabled=true
2323
org.jetbrains.compose.experimental.uikit.enabled=true
24+
# org.thisisthepy.compose:compose-gradle-plugin:1.11.1-ext.1's Maven Central POM marks
25+
# hot-reload-gradle-plugin as optional (shadow configuration), so Gradle does not place it on the
26+
# plugin classpath unless disabled or declared separately.
27+
org.jetbrains.compose.hot.reload.disable=true
2428

2529
# Python Build
2630
pythonVersion=3.15.0
@@ -37,9 +41,9 @@ org.gradle.java.installations.paths=/Volumes/macMini/toolchains/bellsoft-liberic
3741

3842
# compose-multiplatform-core-extended (#191, #249): the Compose modules a native-image build takes from
3943
# the fork instead of upstream, and where from. Read in one place, by the notebook E2E's native image;
40-
# the fork's coordinates and version line are changing (to 1.11.1-ext.N), and only these lines follow.
41-
composeExtended.version=1.11.1001
42-
# The group the fork publishes under, as a prefix of upstream's (the fork moves to org.thisisthepy.compose).
43-
composeExtended.groupPrefix=org.jetbrains.compose
44-
composeExtended.modules=org.jetbrains.compose.ui:ui,org.jetbrains.compose.ui:ui-desktop,org.jetbrains.compose.ui:ui-text,org.jetbrains.compose.ui:ui-text-desktop,org.jetbrains.compose.foundation:foundation,org.jetbrains.compose.foundation:foundation-desktop
45-
composeExtended.mavenLocal=true
44+
# the fork's coordinates and version line are 1.11.1-ext.N, and only these lines follow.
45+
composeExtended.version=1.11.1-ext.1
46+
# The group the fork publishes under, as a prefix of upstream's (org.thisisthepy.compose).
47+
composeExtended.groupPrefix=org.thisisthepy.compose
48+
composeExtended.modules=org.thisisthepy.compose.ui:ui,org.thisisthepy.compose.ui:ui-desktop,org.thisisthepy.compose.ui:ui-text,org.thisisthepy.compose.ui:ui-text-desktop,org.thisisthepy.compose.foundation:foundation,org.thisisthepy.compose.foundation:foundation-desktop
49+
composeExtended.mavenLocal=false

‎gradle/libs.versions.toml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@ androidx-appcompat = "1.7.0"
88
androidx-constraintlayout = "2.1.4"
99
androidx-core-ktx = "1.13.1"
1010
androidx-espresso-core = "3.6.1"
11-
androidx-lifecycle = "2.10.0"
1211
androidx-material = "1.12.0"
1312
androidx-test-junit = "1.2.1"
14-
compose-plugin = "1.11.1"
13+
androidx-lifecycle = "2.11.0-beta01"
14+
compose-plugin = "1.11.1-ext.1"
1515
# JetBrains stopped publishing material-icons with Compose after 1.7.3 (Maven Central: newest is 1.7.3);
1616
# it is the version Compose Multiplatform 1.11.x points to, resolved against 1.11.1's ui/ui-graphics.
1717
compose-material-icons = "1.7.3"
@@ -42,7 +42,8 @@ kotlinx-browser = { group = "org.jetbrains.kotlinx", name = "kotlinx-browser", v
4242
[plugins]
4343
android-application = { id = "com.android.application", version.ref = "agp" }
4444
android-library = { id = "com.android.library", version.ref = "agp" }
45-
jetpack-compose = { id = "org.jetbrains.compose", version.ref = "compose-plugin" }
45+
jetpack-compose = { id = "org.thisisthepy.compose", version.ref = "compose-plugin" }
46+
kotlin-native-desktop = { id = "org.thisisthepy.kotlin.native.desktop", version.ref = "compose-plugin" }
4647
compose-compiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
4748
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }
4849
graalvm-native = { id = "org.graalvm.buildtools.native", version.ref = "graalvm-buildtools" }

‎python-multiplatform-compose/fixtures/compose/build.gradle.kts‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,13 @@ kotlin {
5151
implementation(compose.material3)
5252
implementation(compose.ui)
5353
// `Icons.Default.Add` and friends (issue #37): the one place an `ImageVector` is built.
54-
implementation(libs.compose.material.icons.core)
54+
// `material-icons-core` stays at 1.7.3 under `org.jetbrains.compose.material`, so exclude
55+
// its transitive upstream `org.jetbrains.compose.{runtime,ui}` to avoid pulling a second
56+
// Compose copy (1.7.3) alongside `org.thisisthepy.compose.*`.
57+
implementation(libs.compose.material.icons.core.get().toString()) {
58+
exclude(group = "org.jetbrains.compose.runtime")
59+
exclude(group = "org.jetbrains.compose.ui")
60+
}
5561
implementation(compose.desktop.currentOs)
5662
}
5763
}

‎python-multiplatform-compose/fixtures/notebook-e2e/build.gradle.kts‎

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@ kotlin {
5757
implementation(compose.foundation)
5858
implementation(compose.material3)
5959
implementation(compose.ui)
60-
implementation(libs.compose.material.icons.core)
60+
implementation(libs.compose.material.icons.core.get().toString()) {
61+
exclude(group = "org.jetbrains.compose.runtime")
62+
exclude(group = "org.jetbrains.compose.ui")
63+
}
6164
implementation(compose.desktop.currentOs)
6265
}
6366
}
@@ -207,7 +210,7 @@ val composeExtendedVersion = providers.gradleProperty("composeExtended.version")
207210
// The fork's group prefix: `org.jetbrains.compose` (its old coordinates) or its own, e.g.
208211
// `org.thisisthepy.compose`; a module `org.jetbrains.compose.ui:ui-desktop` is then taken as
209212
// `<prefix>.ui:ui-desktop`.
210-
val composeExtendedGroupPrefix = providers.gradleProperty("composeExtended.groupPrefix").orNull ?: "org.jetbrains.compose"
213+
val composeExtendedGroupPrefix = providers.gradleProperty("composeExtended.groupPrefix").orNull ?: "org.thisisthepy.compose"
211214
val composeExtendedModules = providers.gradleProperty("composeExtended.modules").orNull
212215
?.split(',')?.map { it.trim() }?.filter { it.isNotEmpty() }?.toSet().orEmpty()
213216
// Where the fork's modules come from: this machine's mavenLocal (`composeExtended.mavenLocal`), or a
@@ -242,13 +245,21 @@ if (composeExtendedVersion != null && (composeExtendedMavenLocal || composeExten
242245
includeGroupAndSubgroups("com.google")
243246
}
244247
}
245-
mavenCentral()
248+
mavenCentral {
249+
metadataSources {
250+
gradleMetadata()
251+
mavenPom()
252+
}
253+
}
246254
}
247255
}
248256
val e2eNativeRuntime: Configuration = configurations.getByName("desktopTestRuntimeClasspath").copyRecursive().apply {
249257
resolutionStrategy.eachDependency {
250258
if (composeExtendedVersion != null && "${requested.group}:${requested.name}" in composeExtendedModules) {
251-
useTarget("${requested.group.replaceFirst("org.jetbrains.compose", composeExtendedGroupPrefix)}:${requested.name}:$composeExtendedVersion")
259+
val targetGroup = requested.group
260+
.replaceFirst("org.jetbrains.compose", composeExtendedGroupPrefix)
261+
.replaceFirst("org.thisisthepy.compose", composeExtendedGroupPrefix)
262+
useTarget("$targetGroup:${requested.name}:$composeExtendedVersion")
252263
because("compose-multiplatform-core-extended: an AWT-free main dispatcher for a native image (#249)")
253264
}
254265
}

‎python-multiplatform-gradle-plugin/fixtures/artifact/build.gradle.kts‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,15 +63,15 @@ kotlin {
6363
// Version pinned to the catalog's `compose-plugin`, which is what the rest of this
6464
// build resolves, so no second Compose version enters the cache.
6565
val composeVersion = libs.versions.compose.plugin.get()
66-
implementation("org.jetbrains.compose.ui:ui-desktop:$composeVersion")
67-
implementation("org.jetbrains.compose.ui:ui-unit-desktop:$composeVersion")
68-
implementation("org.jetbrains.compose.foundation:foundation-layout-desktop:$composeVersion")
66+
implementation("org.thisisthepy.compose.ui:ui-desktop:$composeVersion")
67+
implementation("org.thisisthepy.compose.ui:ui-unit-desktop:$composeVersion")
68+
implementation("org.thisisthepy.compose.foundation:foundation-layout-desktop:$composeVersion")
6969
// `Modifier.clickable` lives here rather than in `foundation-layout`, and it is the
7070
// acceptance criterion for a **non-composable** function-typed slot: an ordinary
7171
// function taking `onClick: () -> Unit`, so it needs no composition to call and yet
7272
// was unreachable for as long as a `kotlin.FunctionN` parameter was declined one
7373
// layer before the slot grammar was consulted (`ArtifactScanner.functionSlotOrNull`).
74-
implementation("org.jetbrains.compose.foundation:foundation-desktop:$composeVersion")
74+
implementation("org.thisisthepy.compose.foundation:foundation-desktop:$composeVersion")
7575
}
7676
}
7777
val desktopTest by getting {

‎python-multiplatform-gradle-plugin/src/main/kotlin/python/multiplatform/gradle/artifact/ArtifactScanner.kt‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -816,8 +816,23 @@ internal object ArtifactScanner {
816816
// of a @Composable function". Found by generating them and watching the fixture fail to
817817
// compile, which is also why the check reads the getter's own annotations rather than the
818818
// property's -- metadata does not carry them for a release build.
819-
val getterName = "get" + property.name.replaceFirstChar { it.uppercase() }
820-
if (declaringNode.methods.any { it.name == getterName && isComposable(it) }) return@mapNotNull null
819+
//
820+
// The same check declines `@Deprecated(level = HIDDEN)` properties (`ButtonDefaults.SmallButtonContentPadding`
821+
// in Material3 1.11.1-ext.1), whose accessor is `ACC_SYNTHETIC` and therefore unreachable from source.
822+
val getter = property.getterSignature?.let { signature ->
823+
declaringNode.methods.firstOrNull { it.name == signature.name && it.desc == signature.descriptor }
824+
}
825+
val field = property.fieldSignature?.let { signature ->
826+
declaringNode.fields.firstOrNull { it.name == signature.name && it.desc == signature.descriptor }
827+
}
828+
when {
829+
getter != null -> {
830+
if (!getter.access.hasFlag(Opcodes.ACC_PUBLIC) || getter.access.hasFlag(Opcodes.ACC_SYNTHETIC)) return@mapNotNull null
831+
if (isComposable(getter)) return@mapNotNull null
832+
}
833+
field != null && field.access.hasFlag(Opcodes.ACC_PUBLIC) && !field.access.hasFlag(Opcodes.ACC_SYNTHETIC) -> Unit
834+
else -> return@mapNotNull null
835+
}
821836
val returnModel = kotlinTypeModelOf(property.returnType, classpath) ?: return@mapNotNull null
822837
val returnType = resolveKotlinType(property.returnType, classpath, BoundaryDirection.RETURN)
823838
?: return@mapNotNull null

‎python-multiplatform-gradle-plugin/src/test/kotlin/python/multiplatform/gradle/artifact/ArtifactScannerTest.kt‎

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -558,8 +558,13 @@ class ArtifactScannerTest {
558558
).firstOrNull { it.isDirectory }
559559
if (gradleCaches == null) return // no local Gradle cache found at either known location
560560

561-
fun jarUnder(group: String, artifact: String): File? = gradleCaches.resolve(group).resolve(artifact)
562-
.walkTopDown().firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
561+
fun jarUnder(group: String, artifact: String): File? = listOf(
562+
group,
563+
group.replaceFirst("org.jetbrains.compose", "org.thisisthepy.compose"),
564+
).firstNotNullOfOrNull { g ->
565+
gradleCaches.resolve(g).resolve(artifact)
566+
.walkTopDown().firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
567+
}
563568

564569
val layoutJar = jarUnder("org.jetbrains.compose.foundation", "foundation-layout-desktop") ?: return
565570
val unitJar = jarUnder("org.jetbrains.compose.ui", "ui-unit-desktop") ?: return
@@ -701,8 +706,13 @@ class ArtifactScannerTest {
701706
).firstOrNull { it.isDirectory }
702707
if (gradleCaches == null) return // no local Gradle cache found at either known location
703708

704-
fun jarUnder(group: String, artifact: String): File? = gradleCaches.resolve(group).resolve(artifact)
705-
.walkTopDown().firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
709+
fun jarUnder(group: String, artifact: String): File? = listOf(
710+
group,
711+
group.replaceFirst("org.jetbrains.compose", "org.thisisthepy.compose"),
712+
).firstNotNullOfOrNull { g ->
713+
gradleCaches.resolve(g).resolve(artifact)
714+
.walkTopDown().firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
715+
}
706716

707717
val material3Jar = jarUnder("org.jetbrains.compose.material3", "material3-desktop") ?: return
708718
val uiTextJar = jarUnder("org.jetbrains.compose.ui", "ui-text-desktop") ?: return
@@ -758,8 +768,13 @@ class ArtifactScannerTest {
758768
).firstOrNull { it.isDirectory }
759769
if (gradleCaches == null) return // no local Gradle cache found at either known location
760770

761-
fun jarUnder(group: String, artifact: String): File? = gradleCaches.resolve(group).resolve(artifact)
762-
.walkTopDown().firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
771+
fun jarUnder(group: String, artifact: String): File? = listOf(
772+
group,
773+
group.replaceFirst("org.jetbrains.compose", "org.thisisthepy.compose"),
774+
).firstNotNullOfOrNull { g ->
775+
gradleCaches.resolve(g).resolve(artifact)
776+
.walkTopDown().firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
777+
}
763778

764779
val uiJar = jarUnder("org.jetbrains.compose.ui", "ui-desktop") ?: return
765780
val classpath = listOfNotNull(

‎python-multiplatform-gradle-plugin/src/test/kotlin/python/multiplatform/gradle/artifact/ComposableBindingTest.kt‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,13 @@ class ComposableBindingTest {
2929
File("/Volumes/macMini/caches/.gradle/caches/modules-2/files-2.1"),
3030
).firstOrNull { it.isDirectory }
3131

32-
private fun jarUnder(group: String, artifact: String): File? = caches?.resolve(group)?.resolve(artifact)
33-
?.walkTopDown()?.firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
32+
private fun jarUnder(group: String, artifact: String): File? = listOf(
33+
group,
34+
group.replaceFirst("org.jetbrains.compose", "org.thisisthepy.compose"),
35+
).firstNotNullOfOrNull { g ->
36+
caches?.resolve(g)?.resolve(artifact)
37+
?.walkTopDown()?.firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
38+
}
3439

3540
private val kotlinStdlibJar: File
3641
get() = File(Class.forName("kotlin.text.Regex").protectionDomain.codeSource.location.toURI())

‎python-multiplatform-gradle-plugin/src/test/kotlin/python/multiplatform/gradle/artifact/ComposableValueClassSlotTest.kt‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,13 @@ class ComposableValueClassSlotTest {
5151
File("/Volumes/macMini/caches/.gradle/caches/modules-2/files-2.1"),
5252
).firstOrNull { it.isDirectory }
5353

54-
private fun jarUnder(group: String, artifact: String): File? = caches?.resolve(group)?.resolve(artifact)
55-
?.walkTopDown()?.firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
54+
private fun jarUnder(group: String, artifact: String): File? = listOf(
55+
group,
56+
group.replaceFirst("org.jetbrains.compose", "org.thisisthepy.compose"),
57+
).firstNotNullOfOrNull { g ->
58+
caches?.resolve(g)?.resolve(artifact)
59+
?.walkTopDown()?.firstOrNull { it.isFile && it.name.endsWith(".jar") && "sources" !in it.name }
60+
}
5661

5762
private val kotlinStdlibJar: File
5863
get() = File(Class.forName("kotlin.text.Regex").protectionDomain.codeSource.location.toURI())

0 commit comments

Comments
 (0)