diff --git a/gradle-plugins/build.gradle.kts b/gradle-plugins/build.gradle.kts index 07dd7273b7..6ad3a2b4d5 100644 --- a/gradle-plugins/build.gradle.kts +++ b/gradle-plugins/build.gradle.kts @@ -48,28 +48,36 @@ subprojects { } afterEvaluate { - mavenPublicationConfig?.let { mavenPublicationConfig -> - configurePublication(mavenPublicationConfig) + val publicationConfig = mavenPublicationConfig + val gradlePluginConfig = gradlePluginConfig - gradlePluginConfig?.let { gradlePluginConfig -> - configureGradlePlugin(mavenPublicationConfig, gradlePluginConfig) + if (publicationConfig != null) { + if (gradlePluginConfig != null) { + // pluginMaven is a default publication created by java-gradle-plugin + // https://github.com/gradle/gradle/issues/10384 + configureMavenPublication("pluginMaven", publicationConfig) + configureGradlePlugin(publicationConfig, gradlePluginConfig) + } else { + configureMavenPublication("maven", publicationConfig) { + from(components["java"]) + } } } } } -fun Project.configurePublication( - publicationConfig: MavenPublicationConfigExtension +fun Project.configureMavenPublication( + publicationName: String, + config: MavenPublicationConfigExtension, + customize: MavenPublication.() -> Unit = {} ) { // maven publication for plugin configureIfExists { - // pluginMaven is a default publication created by java-gradle-plugin - // https://github.com/gradle/gradle/issues/10384 - publications.create("pluginMaven") { - artifactId = publicationConfig.artifactId + publications.create(publicationName) { + artifactId = config.artifactId pom { - name.set(publicationConfig.displayName) - description.set(publicationConfig.description) + name.set(config.displayName) + description.set(config.description) url.set(BuildProperties.website) licenses { license { @@ -78,6 +86,8 @@ fun Project.configurePublication( } } } + + customize() } } } diff --git a/gradle-plugins/compose-preview-runtime/build.gradle.kts b/gradle-plugins/compose-preview-runtime/build.gradle.kts new file mode 100644 index 0000000000..cc9b75cee3 --- /dev/null +++ b/gradle-plugins/compose-preview-runtime/build.gradle.kts @@ -0,0 +1,14 @@ +plugins { + kotlin("jvm") + id("maven-publish") +} + +mavenPublicationConfig { + displayName = "Compose Desktop Preview Runtime" + description = "Runtime helpers for Compose Desktop Preview" + artifactId = "compose-preview-runtime-desktop" +} + +dependencies { + compileOnly("org.jetbrains.kotlin:kotlin-stdlib") +} \ No newline at end of file diff --git a/gradle-plugins/compose-preview-runtime/src/main/kotlin/org/jetbrains/compose/desktop/preview/runtime/ComposePreviewRunner.kt b/gradle-plugins/compose-preview-runtime/src/main/kotlin/org/jetbrains/compose/desktop/preview/runtime/ComposePreviewRunner.kt new file mode 100644 index 0000000000..a2760c6e02 --- /dev/null +++ b/gradle-plugins/compose-preview-runtime/src/main/kotlin/org/jetbrains/compose/desktop/preview/runtime/ComposePreviewRunner.kt @@ -0,0 +1,40 @@ +/* + * 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. + */ + +package org.jetbrains.compose.desktop.preview.runtime + +import kotlin.reflect.KProperty1 + +class ComposePreviewRunner { + companion object { + private const val PREVIEW_ANNOTATION_FQ_NAME = "androidx.compose.ui.tooling.desktop.preview.Preview" + + @JvmStatic + fun main(args: Array) { + val classLoader = ComposePreviewRunner::class.java.classLoader + + val previewFqName = args[0] + val previewClassFqName = previewFqName.substringBeforeLast(".") + val previewMethodName = previewFqName.substringAfterLast(".") + val previewClass = classLoader.loadClass(previewClassFqName) + val previewMethod = previewClass.methods.find { it.name == previewMethodName } + ?: error("Could not find method '$previewMethodName' in class '${previewClass.canonicalName}'") + + val content = previewMethod.invoke(previewClass) + val previewAnnotation = previewMethod.annotations.find { it.annotationClass.qualifiedName == PREVIEW_ANNOTATION_FQ_NAME } + ?: error("Could not find '$PREVIEW_ANNOTATION_FQ_NAME' annotation on '$previewClassFqName#$previewMethodName'") + val environmentKClassProperty = previewAnnotation.annotationClass.members.find { it is KProperty1<*, *> && it.name == "environment" } + as KProperty1> + val environmentClass = environmentKClassProperty.get(previewAnnotation) + val previewEnvironment = environmentClass + .getDeclaredConstructor() + .newInstance() + val showMethod = previewEnvironment.javaClass + .methods.find { it.name == "show" } + ?: error("Could not find 'show' in class '${environmentClass.canonicalName}'") + showMethod.invoke(previewEnvironment, content) + } + } +} \ 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 db6b5e7e31..d36f513956 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 @@ -15,6 +15,7 @@ import org.gradle.api.plugins.ExtensionAware import org.jetbrains.compose.desktop.DesktopExtension import org.jetbrains.compose.desktop.application.internal.configureApplicationImpl import org.jetbrains.compose.desktop.application.internal.currentTarget +import org.jetbrains.compose.desktop.preview.internal.initializePreview import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler import org.jetbrains.kotlin.gradle.tasks.KotlinCompile @@ -35,6 +36,8 @@ class ComposePlugin : Plugin { } } + project.initializePreview() + project.pluginManager.apply(ComposeCompilerKotlinSupportPlugin::class.java) project.afterEvaluate { diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureApplication.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureApplication.kt index 51fba7f82c..55c6da6f39 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureApplication.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/application/internal/configureApplication.kt @@ -17,6 +17,8 @@ import org.jetbrains.compose.desktop.application.dsl.Application import org.jetbrains.compose.desktop.application.dsl.TargetFormat import org.jetbrains.compose.desktop.application.internal.validation.validatePackageVersions import org.jetbrains.compose.desktop.application.tasks.* +import org.jetbrains.compose.desktop.preview.internal.configureRunPreviewTask +import org.jetbrains.compose.desktop.preview.tasks.AbstractRunComposePreviewTask import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType import java.io.File @@ -155,6 +157,10 @@ internal fun Project.configurePackagingTasks(apps: Collection) { val run = project.tasks.composeTask(taskName("run", app)) { configureRunTask(app) } + + val runPreview = project.tasks.composeTask("runComposeDesktopPreview") { + configureRunPreviewTask(app) + } } } @@ -327,7 +333,7 @@ private fun File.isZipOrJar() = name.endsWith(".jar", ignoreCase = true) || name.endsWith(".zip", ignoreCase = true) -private fun Application.javaHomeOrDefault(): String = +internal fun Application.javaHomeOrDefault(): String = javaHome ?: System.getProperty("java.home") private inline fun TaskContainer.composeTask( diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/preview/internal/configurePreview.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/preview/internal/configurePreview.kt new file mode 100644 index 0000000000..583871478e --- /dev/null +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/preview/internal/configurePreview.kt @@ -0,0 +1,26 @@ +package org.jetbrains.compose.desktop.preview.internal + +import org.gradle.api.Project +import org.jetbrains.compose.composeVersion +import org.jetbrains.compose.desktop.application.dsl.Application +import org.jetbrains.compose.desktop.application.internal.javaHomeOrDefault +import org.jetbrains.compose.desktop.application.internal.provider +import org.jetbrains.compose.desktop.preview.tasks.AbstractRunComposePreviewTask + +internal const val PREVIEW_RUNTIME_CLASSPATH_CONFIGURATION = "composeDesktopPreviewRuntimeClasspath" +private val COMPOSE_PREVIEW_RUNTIME_DEPENDENCY = "org.jetbrains.compose:compose-preview-runtime-desktop:$composeVersion" + +fun Project.initializePreview() { + configurations.create(PREVIEW_RUNTIME_CLASSPATH_CONFIGURATION).defaultDependencies { deps -> + deps.add(dependencies.create(COMPOSE_PREVIEW_RUNTIME_DEPENDENCY)) + } +} + +internal fun AbstractRunComposePreviewTask.configureRunPreviewTask(app: Application) { + app._configurationSource?.let { configSource -> + dependsOn(configSource.jarTaskName) + classpath = configSource.runtimeClasspath(project) + javaHome.set(provider { app.javaHomeOrDefault() }) + jvmArgs.set(provider { app.jvmArgs }) + } +} \ No newline at end of file diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/preview/tasks/AbstractRunComposePreviewTask.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/preview/tasks/AbstractRunComposePreviewTask.kt new file mode 100644 index 0000000000..723d76d698 --- /dev/null +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/desktop/preview/tasks/AbstractRunComposePreviewTask.kt @@ -0,0 +1,39 @@ +package org.jetbrains.compose.desktop.preview.tasks + +import org.gradle.api.file.FileCollection +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property +import org.gradle.api.tasks.* +import org.jetbrains.compose.desktop.application.internal.javaExecutable +import org.jetbrains.compose.desktop.application.internal.notNullProperty +import org.jetbrains.compose.desktop.preview.internal.PREVIEW_RUNTIME_CLASSPATH_CONFIGURATION +import org.jetbrains.compose.desktop.tasks.AbstractComposeDesktopTask + +abstract class AbstractRunComposePreviewTask : AbstractComposeDesktopTask() { + @get:InputFiles + internal lateinit var classpath: FileCollection + + @get:InputFiles + internal val previewRuntimeClasspath: FileCollection + get() = project.configurations.getByName(PREVIEW_RUNTIME_CLASSPATH_CONFIGURATION) + + @get:Internal + internal val javaHome: Property = objects.notNullProperty().apply { + set(providers.systemProperty("java.home")) + } + + @get:Input + @get:Optional + internal val jvmArgs: ListProperty = objects.listProperty(String::class.java) + + @TaskAction + fun run() { + val target = project.findProperty("compose.desktop.preview.target") as String + execOperations.javaexec { javaExec -> + javaExec.executable = javaExecutable(javaHome.get()) + javaExec.main = "org.jetbrains.compose.desktop.preview.runtime.ComposePreviewRunner" + javaExec.classpath = previewRuntimeClasspath + classpath + javaExec.args = listOf(target) + } + } +} \ No newline at end of file diff --git a/gradle-plugins/settings.gradle.kts b/gradle-plugins/settings.gradle.kts index 198979339b..7650bcf52d 100644 --- a/gradle-plugins/settings.gradle.kts +++ b/gradle-plugins/settings.gradle.kts @@ -5,4 +5,5 @@ pluginManagement { } } -include(":compose") \ No newline at end of file +include(":compose") +include(":compose-preview-runtime") \ No newline at end of file