diff --git a/compose/README.md b/compose/README.md index d75f649f..4ba19af8 100644 --- a/compose/README.md +++ b/compose/README.md @@ -63,3 +63,15 @@ Run tests for Web: ``` ./scripts/testWeb ``` + +## Multiplatform build + +```console +./scripts/downloadAndroidSdk +export COMPOSE_CUSTOM_VERSION=1.1.0-beta04 +./scripts/publishToMavenLocal -Pcompose.platforms=all +./scripts/publishGradlePluginToMavenLocal +./scripts/publishWebComponentsToMavenLocal +``` +`-Pcompose.platforms=all` could be replace with comma-separated list of platforms, such as `js,jvm,androidDebug,androidRelease,macosx64,uikitx64`. + diff --git a/compose/build.gradle.kts b/compose/build.gradle.kts index 53a9248a..03177b70 100644 --- a/compose/build.gradle.kts +++ b/compose/build.gradle.kts @@ -1,86 +1,106 @@ +import org.gradle.api.* import org.jetbrains.compose.internal.publishing.* plugins { signing } -val composeBuild = gradle.includedBuild("support") -fun Task.dependsOnComposeTask(name: String) = dependsOn(composeBuild.task(name)) +fun Task.dependsOnComposeTask(name: String) { + dependsOn(project.composeBuild?.task(name) ?: return) +} -val isOelPublication = project.findProperty("oel.publication") == "true" -val isWebExist = composeBuild.projectDir.resolve(".jbWebExistsMarker").exists() +open class ComposePublishingTask : AbstractComposePublishingTask() { + override fun dependsOnComposeTask(task: String) { + dependsOn(project.composeBuild?.task(task) ?: return) + } +} + +val composeProperties = ComposeProperties(project) +val isWebExist = + project.composeBuild?.run { projectDir.resolve(".jbWebExistsMarker").exists() } ?: false + +val mainComponents = + listOf( + ComposeComponent(":compose:animation:animation"), + ComposeComponent(":compose:animation:animation-core"), + ComposeComponent(":compose:animation:animation-graphics", supportedPlatforms = ComposePlatforms.JVM_BASED), + ComposeComponent(":compose:foundation:foundation"), + ComposeComponent(":compose:foundation:foundation-layout"), + ComposeComponent(":compose:material:material"), + ComposeComponent(":compose:material3:material3", supportedPlatforms = ComposePlatforms.JVM_BASED), + ComposeComponent(":compose:material:material-icons-core"), + ComposeComponent(":compose:material:material-ripple"), + ComposeComponent(":compose:runtime:runtime"), + ComposeComponent(":compose:runtime:runtime-saveable"), + ComposeComponent(":compose:ui:ui"), + ComposeComponent(":compose:ui:ui-geometry"), + ComposeComponent(":compose:ui:ui-graphics"), + ComposeComponent(":compose:ui:ui-test", supportedPlatforms = ComposePlatforms.JVM_BASED), + ComposeComponent(":compose:ui:ui-test-junit4", supportedPlatforms = ComposePlatforms.JVM_BASED), + ComposeComponent(":compose:ui:ui-text"), + ComposeComponent(":compose:ui:ui-tooling", supportedPlatforms = ComposePlatforms.JVM_BASED), + ComposeComponent(":compose:ui:ui-tooling-preview", supportedPlatforms = ComposePlatforms.JVM_BASED), + ComposeComponent(":compose:ui:ui-unit"), + ComposeComponent(":compose:ui:ui-util", supportedPlatforms = ComposePlatforms.ALL), + ) + +val iconsComponents = + listOf( + ComposeComponent(":compose:material:material-icons-extended", supportedPlatforms = ComposePlatforms.JVM_BASED), + ) + +fun ComposePublishingTask.mainPublications() { + publish(":compose:compiler:compiler", publications = listOf("Maven")) + publish(":compose:compiler:compiler-hosted", publications = listOf("Maven")) + publish( + ":compose:ui:ui-tooling-data", + onlyWithPlatforms = setOf(ComposePlatforms.AndroidRelease, ComposePlatforms.AndroidDebug), + publications = listOf("Maven") + ) + + publish( + ":compose:desktop:desktop", + onlyWithPlatforms = setOf(ComposePlatforms.Desktop), + publications = listOf( + "KotlinMultiplatform", + "Jvm", + "Jvmlinux-x64", + "Jvmlinux-arm64", + "Jvmmacos-x64", + "Jvmmacos-arm64", + "Jvmwindows-x64" + ) + ) + + mainComponents.forEach { publishMultiplatform(it) } +} + +fun ComposePublishingTask.iconsPublications() { + iconsComponents.forEach { publishMultiplatform(it) } +} // To show all projects which use `xxx` task, run: // ./gradlew -p frameworks/support help --task xxx +tasks.register("publishComposeJb", ComposePublishingTask::class) { + repository = "MavenRepository" + mainPublications() +} -tasks.register("publishComposeJb") { - dependsOnComposeTask(":compose:compiler:compiler:publishMavenPublicationToMavenRepository") - dependsOnComposeTask(":compose:compiler:compiler-hosted:publishMavenPublicationToMavenRepository") - dependsOnComposeTask(":compose:ui:ui-tooling-data:publishMavenPublicationToMavenRepository") - - dependsOnComposeTask(":compose:desktop:desktop:publishKotlinMultiplatformPublicationToMavenRepository") - dependsOnComposeTask(":compose:desktop:desktop:publishJvmPublicationToMavenRepository") - dependsOnComposeTask(":compose:desktop:desktop:publishJvmlinux-x64PublicationToMavenRepository") - dependsOnComposeTask(":compose:desktop:desktop:publishJvmlinux-arm64PublicationToMavenRepository") - dependsOnComposeTask(":compose:desktop:desktop:publishJvmmacos-x64PublicationToMavenRepository") - dependsOnComposeTask(":compose:desktop:desktop:publishJvmmacos-arm64PublicationToMavenRepository") - dependsOnComposeTask(":compose:desktop:desktop:publishJvmwindows-x64PublicationToMavenRepository") - - listOf( - ":compose:animation:animation", - ":compose:animation:animation-core", - ":compose:animation:animation-graphics", - ":compose:foundation:foundation", - ":compose:foundation:foundation-layout", - ":compose:material:material", - ":compose:material3:material3", - ":compose:material:material-icons-core", - ":compose:material:material-ripple", - ":compose:runtime:runtime", - ":compose:runtime:runtime-saveable", - ":compose:ui:ui", - ":compose:ui:ui-geometry", - ":compose:ui:ui-graphics", - ":compose:ui:ui-test", - ":compose:ui:ui-test-junit4", - ":compose:ui:ui-text", - ":compose:ui:ui-tooling", - ":compose:ui:ui-tooling-preview", - ":compose:ui:ui-unit", - ":compose:ui:ui-util", - ).forEach { - dependsOnComposeTask("$it:publishKotlinMultiplatformPublicationToMavenRepository") - dependsOnComposeTask("$it:publishDesktopPublicationToMavenRepository") - - if (!isOelPublication) { - dependsOnComposeTask("$it:publishAndroidDebugPublicationToMavenRepository") - dependsOnComposeTask("$it:publishAndroidReleasePublicationToMavenRepository") - } - } - - if (isWebExist) { - listOf( - ":compose:runtime:runtime", - ).forEach { - dependsOnComposeTask("$it:publishJsPublicationToMavenRepository") - } - } +tasks.register("publishComposeJbToMavenLocal", ComposePublishingTask::class) { + repository = "MavenLocal" + mainPublications() } // separate task that cannot be built in parallel (because it requires too much RAM). // should be run with "--max-workers=1" -tasks.register("publishComposeJbExtendedIcons") { - listOf( - ":compose:material:material-icons-extended", - ).forEach { - dependsOnComposeTask("$it:publishKotlinMultiplatformPublicationToMavenRepository") - dependsOnComposeTask("$it:publishDesktopPublicationToMavenRepository") +tasks.register("publishComposeJbExtendedIcons", ComposePublishingTask::class) { + repository = "MavenRepository" + iconsPublications() +} - if (!isOelPublication) { - dependsOnComposeTask("$it:publishAndroidDebugPublicationToMavenRepository") - dependsOnComposeTask("$it:publishAndroidReleasePublicationToMavenRepository") - } - } +tasks.register("publishComposeJbExtendedIconsToMavenLocal", ComposePublishingTask::class) { + repository = "MavenLocal" + iconsPublications() } tasks.register("testComposeJbDesktop") { diff --git a/compose/buildSrc/build.gradle.kts b/compose/buildSrc/build.gradle.kts new file mode 100644 index 00000000..33fcebe5 --- /dev/null +++ b/compose/buildSrc/build.gradle.kts @@ -0,0 +1,12 @@ +plugins { + `kotlin-dsl` +} + +repositories { + gradlePluginPortal() + mavenCentral() +} + +dependencies { + compileOnly(gradleApi()) +} diff --git a/compose/buildSrc/src/main/kotlin/AbstractComposePublishingTask.kt b/compose/buildSrc/src/main/kotlin/AbstractComposePublishingTask.kt new file mode 100644 index 00000000..0ab84c4a --- /dev/null +++ b/compose/buildSrc/src/main/kotlin/AbstractComposePublishingTask.kt @@ -0,0 +1,47 @@ +/* + * Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. + */ +import org.gradle.api.* +import org.gradle.api.tasks.Internal + +abstract class AbstractComposePublishingTask : DefaultTask() { + @get:Internal + lateinit var repository: String + + private val composeProperties by lazy { + ComposeProperties(project) + } + private val isOelPublication: Boolean by lazy { + composeProperties.isOelPublication + } + private val targetPlatforms: Set by lazy { + composeProperties.targetPlatforms + } + + abstract fun dependsOnComposeTask(task: String) + + fun publish(project: String, publications: Collection) { + for (publication in publications) { + dependsOnComposeTask("$project:publish${publication}PublicationTo$repository") + } + } + + fun publish(project: String, publications: Collection, onlyWithPlatforms: Set) { + if (onlyWithPlatforms.any { it in targetPlatforms }) { + publish(project, publications) + } + } + + fun publishMultiplatform(component: ComposeComponent) { + dependsOnComposeTask("${component.path}:publish${ComposePlatforms.KotlinMultiplatform.name}PublicationTo$repository") + + for (platform in targetPlatforms) { + if (platform !in component.supportedPlatforms) continue + + if (platform in ComposePlatforms.ANDROID && isOelPublication) continue + + dependsOnComposeTask("${component.path}:publish${platform.name}PublicationTo$repository") + } + } +} \ No newline at end of file diff --git a/compose/buildSrc/src/main/kotlin/ComposeComponent.kt b/compose/buildSrc/src/main/kotlin/ComposeComponent.kt new file mode 100644 index 00000000..752a99f0 --- /dev/null +++ b/compose/buildSrc/src/main/kotlin/ComposeComponent.kt @@ -0,0 +1,9 @@ +/* + * Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. + */ + +data class ComposeComponent( + val path: String, + val supportedPlatforms: Set = ComposePlatforms.ALL +) \ No newline at end of file diff --git a/compose/buildSrc/src/main/kotlin/ComposePlatforms.kt b/compose/buildSrc/src/main/kotlin/ComposePlatforms.kt new file mode 100644 index 00000000..e92a1464 --- /dev/null +++ b/compose/buildSrc/src/main/kotlin/ComposePlatforms.kt @@ -0,0 +1,66 @@ +/* + * Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. + */ + +import java.util.* + +enum class ComposePlatforms(vararg val alternativeNames: String) { + KotlinMultiplatform("Common"), + Desktop("Jvm"), + AndroidDebug("Android"), + AndroidRelease("Android"), + Js("Web"), + MacosX64("Macos"), + MacosArm64("Macos"), + UikitX64("UiKit"), + UikitArm64("UiKit"); + + fun matches(nameCandidate: String): Boolean = + listOf(name, *alternativeNames).any { it.equals(nameCandidate, ignoreCase = true) } + + companion object { + val ALL = EnumSet.allOf(ComposePlatforms::class.java) + + val JVM_BASED = EnumSet.of( + ComposePlatforms.Desktop, + ComposePlatforms.AndroidDebug, + ComposePlatforms.AndroidRelease + ) + + val ANDROID = EnumSet.of( + ComposePlatforms.AndroidDebug, + ComposePlatforms.AndroidRelease + ) + + /** + * Maps comma separated list of platforms into a set of [ComposePlatforms] + * The function is case- and whitespace-insensetive. + * + * Special value: all + */ + fun parse(platformsNames: String): Set { + val platforms = EnumSet.noneOf(ComposePlatforms::class.java) + val unknownNames = arrayListOf() + + for (name in platformsNames.split(",").map { it.trim() }) { + if (name.equals("all", ignoreCase = true)) { + return ALL + } + + val publication = ALL.firstOrNull { it.matches(name) } + if (publication != null) { + platforms.add(publication) + } else { + unknownNames.add(name) + } + } + + if (unknownNames.isNotEmpty()) { + error("Unknown platforms: ${unknownNames.joinToString(", ")}") + } + + return platforms + } + } +} diff --git a/compose/buildSrc/src/main/kotlin/ComposeProperties.kt b/compose/buildSrc/src/main/kotlin/ComposeProperties.kt new file mode 100644 index 00000000..737a9919 --- /dev/null +++ b/compose/buildSrc/src/main/kotlin/ComposeProperties.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. + */ + +import org.gradle.api.* + +class ComposeProperties(private val myProject: Project) { + val isOelPublication: Boolean + get() = myProject.findProperty("oel.publication") == "true" + + val targetPlatforms: Set + get() { + val requestedPlatforms = myProject.findProperty("compose.platforms")?.toString() ?: "jvm, android" + return ComposePlatforms.parse(requestedPlatforms) + } +} diff --git a/compose/buildSrc/src/main/kotlin/utils.kt b/compose/buildSrc/src/main/kotlin/utils.kt new file mode 100644 index 00000000..dca373cf --- /dev/null +++ b/compose/buildSrc/src/main/kotlin/utils.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2020-2021 JetBrains s.r.o. and respective authors and developers. + * Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file. + */ + +import org.gradle.api.Project +import org.gradle.api.initialization.IncludedBuild + +val isInIdea: Boolean + get() = System.getProperty("idea.active") == "true" + +val Project.composeBuild: IncludedBuild? + get() = if (isInIdea) null else gradle.includedBuild("support") diff --git a/compose/gradle/wrapper/gradle-wrapper.properties b/compose/gradle/wrapper/gradle-wrapper.properties index ffed3a25..e750102e 100644 --- a/compose/gradle/wrapper/gradle-wrapper.properties +++ b/compose/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/compose/scripts/publishExtendedIconsToMavenLocal b/compose/scripts/publishExtendedIconsToMavenLocal new file mode 100755 index 00000000..1113cdf0 --- /dev/null +++ b/compose/scripts/publishExtendedIconsToMavenLocal @@ -0,0 +1,8 @@ +#!/bin/bash + +cd "$(dirname "$0")" +. ./prepare + +pushd .. +./gradlew publishComposeJbExtendedIconsToMavenLocal $COMPOSE_DEFAULT_GRADLE_ARGS --max-workers=1 "$@" || exit 1 +popd diff --git a/compose/scripts/publishGradlePluginToMavenLocal b/compose/scripts/publishGradlePluginToMavenLocal new file mode 100755 index 00000000..c276666b --- /dev/null +++ b/compose/scripts/publishGradlePluginToMavenLocal @@ -0,0 +1,12 @@ +#!/bin/bash + +cd "$(dirname "$0")" + +if [[ -z "$COMPOSE_CUSTOM_VERSION" ]]; then + echo "Must provide COMPOSE_CUSTOM_VERSION in environment" 1>&2 + exit 1 +fi + +pushd ../../gradle-plugins +./gradlew publishToMavenLocal -Pcompose.version="$COMPOSE_CUSTOM_VERSION" -Pdeploy.version="$COMPOSE_CUSTOM_VERSION" -Pcompose.with.web=true || exit 1 +popd \ No newline at end of file diff --git a/compose/scripts/publishToMavenLocal b/compose/scripts/publishToMavenLocal new file mode 100755 index 00000000..551a69f7 --- /dev/null +++ b/compose/scripts/publishToMavenLocal @@ -0,0 +1,8 @@ +#!/bin/bash + +cd "$(dirname "$0")" +. ./prepare + +pushd .. +./gradlew publishComposeJbToMavenLocal $COMPOSE_DEFAULT_GRADLE_ARGS "$@" || exit 1 +popd \ No newline at end of file diff --git a/compose/scripts/publishWebComponentsToMavenLocal b/compose/scripts/publishWebComponentsToMavenLocal new file mode 100755 index 00000000..72c72ff9 --- /dev/null +++ b/compose/scripts/publishWebComponentsToMavenLocal @@ -0,0 +1,13 @@ +#!/bin/bash + +cd "$(dirname "$0")" + +if [[ -z "$COMPOSE_CUSTOM_VERSION" ]]; then + echo "Must provide COMPOSE_CUSTOM_VERSION in environment" 1>&2 + exit 1 +fi + +pushd ../../web +./gradlew publishToMavenLocal -PCOMPOSE_CORE_VERSION="$COMPOSE_CUSTOM_VERSION" -PCOMPOSE_WEB_VERSION="$COMPOSE_CUSTOM_VERSION" || exit 1 +popd + diff --git a/compose/settings.gradle.kts b/compose/settings.gradle.kts index f8bd21e4..1413a048 100644 --- a/compose/settings.gradle.kts +++ b/compose/settings.gradle.kts @@ -12,4 +12,6 @@ pluginManagement { } } -includeBuild("frameworks/support") \ No newline at end of file +if (System.getProperty("idea.active") != "true") { + includeBuild("frameworks/support") +}