From 48b52e459a5ea2ea6bf9a1b75d3155fd3ffa20d4 Mon Sep 17 00:00:00 2001 From: Igor Demin Date: Thu, 18 Feb 2021 10:02:48 +0300 Subject: [PATCH] Gradle plugin. Replace 'androidx.compose' artifacts by 'org.jetbrains.compose' artifacts. Fixes https://github.com/JetBrains/compose-jb/issues/272 --- gradle-plugins/buildSrc/build.gradle.kts | 2 + .../kotlin/printAllAndroidxReplacements.kt | 66 +++++++++++++++++++ gradle-plugins/compose/build.gradle.kts | 4 ++ .../org/jetbrains/compose/ComposePlugin.kt | 53 ++++++++++++++- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 5 files changed, 124 insertions(+), 3 deletions(-) create mode 100644 gradle-plugins/buildSrc/src/main/kotlin/printAllAndroidxReplacements.kt diff --git a/gradle-plugins/buildSrc/build.gradle.kts b/gradle-plugins/buildSrc/build.gradle.kts index 5afd954c56..6a9f0c17b9 100644 --- a/gradle-plugins/buildSrc/build.gradle.kts +++ b/gradle-plugins/buildSrc/build.gradle.kts @@ -9,4 +9,6 @@ repositories { dependencies { compileOnly(gradleApi()) implementation(kotlin("stdlib")) + implementation("io.ktor:ktor-client-core:1.5.1") + implementation("io.ktor:ktor-client-cio:1.5.1") } diff --git a/gradle-plugins/buildSrc/src/main/kotlin/printAllAndroidxReplacements.kt b/gradle-plugins/buildSrc/src/main/kotlin/printAllAndroidxReplacements.kt new file mode 100644 index 0000000000..9155bd0b71 --- /dev/null +++ b/gradle-plugins/buildSrc/src/main/kotlin/printAllAndroidxReplacements.kt @@ -0,0 +1,66 @@ +import io.ktor.client.* +import io.ktor.client.request.* +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.collect +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.flow.map +import kotlinx.coroutines.runBlocking + +private const val libsRepo = "https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jetbrains/compose/" +private const val version = "0.3.0-build154" +private val exceptions = listOf( + "desktop:desktop", + "compose-full", + "compose-gradle-plugin" +) + +fun printAllAndroidxReplacements() = runBlocking { + HttpClient().use { client -> + client + .allRecursiveFolders(libsRepo) + .map { it.removePrefix(libsRepo).removeSuffix("/") } + .filter { it.endsWith(version) } + .map { it.removeSuffix(version).removeSuffix("/") } + .map { it.replace("/", ":") } + .filter { !it.endsWith("-android") } + .filter { !it.endsWith("-android-debug") } + .filter { !it.endsWith("-android-release") } + .filter { !it.endsWith("-metadata") } + .filter { !it.endsWith("-desktop") } + .filter { !it.contains("-jvm") } + .filter { !exceptions.contains(it) } + .collect { + require(isMavenCoordsValid(it)) { + "module name isn't valid: $it" + } + println("it.replaceAndroidx(\"androidx.compose.$it\", \"org.jetbrains.compose.$it\")") + } + } +} + +private fun isMavenCoordsValid(coords: String) = coords.count { it == ':' } == 1 + +private fun HttpClient.allRecursiveFolders( + url: String +): Flow = flow { + require(url.endsWith("/")) + val response = get(url) + val folders = parseFolders(response) + for (folder in folders) { + emit("$url$folder/") + } + for (folder in folders.filter(String::isMavenPart)) { + allRecursiveFolders("$url$folder/").collect(::emit) + } +} + +private fun parseFolders( + htmlResponse: String +): Sequence = Regex("title=\"(.*?)\"") + .findAll(htmlResponse) + .map { it.groupValues[1] } + .filter { it.endsWith("/") && it != "../" } + .map { it.removeSuffix("/") } + +private fun String.isMavenPart() = all { it.isLetterOrDigit() || it == '-' } \ No newline at end of file diff --git a/gradle-plugins/compose/build.gradle.kts b/gradle-plugins/compose/build.gradle.kts index aa0464735e..ef6081cceb 100644 --- a/gradle-plugins/compose/build.gradle.kts +++ b/gradle-plugins/compose/build.gradle.kts @@ -100,4 +100,8 @@ fun Test.configureTest(gradleVersion: String) { tasks.named("check") { dependsOn(testMinGradleVersion) +} + +task("printAllAndroidxReplacements") { + doLast { printAllAndroidxReplacements() } } \ No newline at end of file diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt index ab9f4d0d55..3c1d07b065 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/ComposePlugin.kt @@ -4,6 +4,7 @@ package org.jetbrains.compose import org.gradle.api.Plugin import org.gradle.api.Project +import org.gradle.api.artifacts.dsl.ComponentModuleMetadataHandler import org.gradle.api.artifacts.dsl.DependencyHandler import org.gradle.api.plugins.ExtensionAware import org.jetbrains.compose.desktop.DesktopExtension @@ -37,11 +38,59 @@ class ComposePlugin : Plugin { } project.dependencies.add( - "kotlinCompilerPluginClasspath", - "org.jetbrains.compose.compiler:compiler:$composeVersion" + "kotlinCompilerPluginClasspath", + "org.jetbrains.compose.compiler:compiler:$composeVersion" ) } + fun ComponentModuleMetadataHandler.replaceAndroidx(original: String, replacement: String) { + module(original) { + it.replacedBy(replacement, "org.jetbrains.compose isn't compatible with androidx.compose, because it is the same library published with different maven coordinates") + } + } + + project.dependencies.modules { + // Replace 'androidx.compose' artifacts by 'org.jetbrains.compose' artifacts. + // It is needed, because 'org.jetbrains.compose' artifacts are the same artifacts as 'androidx.compose' + // (but with different version). + // And Gradle will throw an error when it cannot determine which class from which artifact should it use. + // + // Note that we don't provide a configuration parameter to disable dependency replacement, + // because without replacement, gradle will fail anyway because classpath contains two incompatible artifacts. + // + // We should define all replacements, even for transient dependencies. + // For example, a library can depend on androidx.compose.foundation:foundation-layout + // + // List of all org.jetbrains.compose libraries is here: + // https://maven.pkg.jetbrains.space/public/p/compose/dev/org/jetbrains/compose/ + // + // (use ./gradle printAllAndroidxReplacements to know what dependencies should be here) + // + // It is temporarily solution until we will be publishing all MPP artifacts in Google Maven repository. + // Or align versions with androidx artifacts and point MPP-android artifacts to androidx artifacts (is it possible?) + + it.replaceAndroidx("androidx.compose.animation:animation", "org.jetbrains.compose.animation:animation") + it.replaceAndroidx("androidx.compose.animation:animation-core", "org.jetbrains.compose.animation:animation-core") + it.replaceAndroidx("androidx.compose.compiler:compiler", "org.jetbrains.compose.compiler:compiler") + it.replaceAndroidx("androidx.compose.compiler:compiler-hosted", "org.jetbrains.compose.compiler:compiler-hosted") + it.replaceAndroidx("androidx.compose.foundation:foundation", "org.jetbrains.compose.foundation:foundation") + it.replaceAndroidx("androidx.compose.foundation:foundation-layout", "org.jetbrains.compose.foundation:foundation-layout") + it.replaceAndroidx("androidx.compose.material:material", "org.jetbrains.compose.material:material") + it.replaceAndroidx("androidx.compose.material:material-icons-core", "org.jetbrains.compose.material:material-icons-core") + it.replaceAndroidx("androidx.compose.material:material-icons-extended", "org.jetbrains.compose.material:material-icons-extended") + it.replaceAndroidx("androidx.compose.material:material-ripple", "org.jetbrains.compose.material:material-ripple") + it.replaceAndroidx("androidx.compose.runtime:runtime", "org.jetbrains.compose.runtime:runtime") + it.replaceAndroidx("androidx.compose.runtime:runtime-saveable", "org.jetbrains.compose.runtime:runtime-saveable") + it.replaceAndroidx("androidx.compose.ui:ui", "org.jetbrains.compose.ui:ui") + it.replaceAndroidx("androidx.compose.ui:ui-geometry", "org.jetbrains.compose.ui:ui-geometry") + it.replaceAndroidx("androidx.compose.ui:ui-graphics", "org.jetbrains.compose.ui:ui-graphics") + it.replaceAndroidx("androidx.compose.ui:ui-test", "org.jetbrains.compose.ui:ui-test") + it.replaceAndroidx("androidx.compose.ui:ui-test-junit4", "org.jetbrains.compose.ui:ui-test-junit4") + it.replaceAndroidx("androidx.compose.ui:ui-text", "org.jetbrains.compose.ui:ui-text") + it.replaceAndroidx("androidx.compose.ui:ui-unit", "org.jetbrains.compose.ui:ui-unit") + it.replaceAndroidx("androidx.compose.ui:ui-util", "org.jetbrains.compose.ui:ui-util") + } + project.tasks.withType(KotlinCompile::class.java) { it.kotlinOptions.apply { jvmTarget = "1.8".takeIf { jvmTarget.toDouble() < 1.8 } ?: jvmTarget diff --git a/gradle-plugins/gradle/wrapper/gradle-wrapper.properties b/gradle-plugins/gradle/wrapper/gradle-wrapper.properties index 622ab64a3c..25d3265315 100644 --- a/gradle-plugins/gradle/wrapper/gradle-wrapper.properties +++ b/gradle-plugins/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists