Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support custom version or coordinates for Compose compiler #207

Merged
merged 1 commit into from
Jul 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ kotlin-test = { module = "org.jetbrains.kotlin:kotlin-test", version.ref = "kotl

kotlinx-coroutines-core = "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3"

androidx-compose-compiler = "androidx.compose.compiler:compiler:1.5.1"

compose-compiler = "org.jetbrains.compose.compiler:compiler:1.5.0"
compose-runtime = "org.jetbrains.compose.runtime:runtime:1.4.3"

Expand Down
2 changes: 0 additions & 2 deletions mosaic-gradle-plugin/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,6 @@ buildConfig {
}

packageName('com.jakewharton.mosaic.gradle')
buildConfigField("String", "composeCompilerGroupId", "\"${libs.compose.compiler.get().module.group}\"")
buildConfigField("String", "composeCompilerArtifactId", "\"${libs.compose.compiler.get().module.name}\"")
buildConfigField("String", "composeCompilerVersion", "\"${libs.compose.compiler.get().version}\"")
buildConfigField("String", "mosaicVersion", "\"${project.version}\"")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.jakewharton.mosaic.gradle

import org.gradle.api.provider.Property

interface MosaicExtension {
/**
* The version of the JetBrains Compose compiler to use, or a Maven coordinate triple of
* the custom Compose compiler to use.
*
* Example: using a custom version of the JetBrains Compose compiler
* ```kotlin
* redwood {
* kotlinCompilerPlugin.set("1.4.8")
* }
* ```
*
* Example: using a custom Maven coordinate for the Compose compiler
* ```kotlin
* redwood {
* kotlinCompilerPlugin.set("com.example:custom-compose-compiler:1.0.0")
* }
* ```
*/
val kotlinCompilerPlugin: Property<String>
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.jakewharton.mosaic.gradle

import javax.inject.Inject
import org.gradle.api.Project
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.JavaPlugin.API_CONFIGURATION_NAME
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
Expand All @@ -12,33 +15,28 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_MAIN_
import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption

class MosaicPlugin : KotlinCompilerPluginSupportPlugin {
override fun isApplicable(kotlinCompilation: KotlinCompilation<*>) = true

override fun getCompilerPluginId() = "com.jakewharton.mosaic"

override fun getPluginArtifact() = SubpluginArtifact(
composeCompilerGroupId,
composeCompilerArtifactId,
composeCompilerVersion,
)
private open class MosaicExtensionImpl
@Inject constructor(objectFactory: ObjectFactory) : MosaicExtension {
override val kotlinCompilerPlugin: Property<String> =
objectFactory.property(String::class.java)
.convention(composeCompilerVersion)
}

override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> {
if (kotlinCompilation.target.platformType == KotlinPlatformType.js) {
// This enables a workaround for Compose lambda generation to function correctly in JS.
// Note: We cannot use SubpluginOption to do this because it targets the Compose plugin.
kotlinCompilation.compilerOptions.options.freeCompilerArgs.addAll(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:generateDecoys=true",
)
}
private const val extensionName = "mosaic"

return kotlinCompilation.target.project.provider { emptyList() }
}
@Suppress("unused") // Used reflectively by Gradle.
class MosaicPlugin : KotlinCompilerPluginSupportPlugin {
private lateinit var extension: MosaicExtension

override fun apply(target: Project) {
super.apply(target)

extension = target.extensions.create(
MosaicExtension::class.java,
extensionName,
MosaicExtensionImpl::class.java,
)

if (target.isInternal() && target.path == ":mosaic-runtime") {
// Being lazy and using our own plugin to configure the Compose compiler on our runtime.
// Bail out because otherwise we create a circular dependency reference on ourselves!
Expand Down Expand Up @@ -69,6 +67,39 @@ class MosaicPlugin : KotlinCompilerPluginSupportPlugin {
}
}

override fun isApplicable(kotlinCompilation: KotlinCompilation<*>) = true

override fun getCompilerPluginId() = "com.jakewharton.mosaic"

override fun getPluginArtifact(): SubpluginArtifact {
val plugin = extension.kotlinCompilerPlugin.get()
val parts = plugin.split(":")
return when (parts.size) {
1 -> SubpluginArtifact("org.jetbrains.compose.compiler", "compiler", parts[0])
3 -> SubpluginArtifact(parts[0], parts[1], parts[2])
else -> error(
"""
|Illegal format of '$extensionName.${MosaicExtension::kotlinCompilerPlugin.name}' property.
|Expected format: either '<VERSION>' or '<GROUP_ID>:<ARTIFACT_ID>:<VERSION>'
|Actual value: '$plugin'
""".trimMargin(),
)
}
}

override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> {
if (kotlinCompilation.target.platformType == KotlinPlatformType.js) {
// This enables a workaround for Compose lambda generation to function correctly in JS.
// Note: We cannot use SubpluginOption to do this because it targets the Compose plugin.
kotlinCompilation.compilerOptions.options.freeCompilerArgs.addAll(
"-P",
"plugin:androidx.compose.compiler.plugins.kotlin:generateDecoys=true",
)
}

return kotlinCompilation.target.project.provider { emptyList() }
}

private fun Project.isInternal(): Boolean {
return properties["com.jakewharton.mosaic.internal"].toString() == "true"
}
Expand Down
2 changes: 1 addition & 1 deletion mosaic-gradle-plugin/src/test/fixture/counter/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
buildscript {
dependencies {
classpath libs.kotlin.gradlePlugin
classpath "com.jakewharton.mosaic:mosaic-gradle-plugin:${mosaicVersion}"
classpath "com.jakewharton.mosaic:mosaic-gradle-plugin:$mosaicVersion"
}
repositories {
maven {
Expand Down
7 changes: 7 additions & 0 deletions mosaic-gradle-plugin/src/test/fixture/counter/settings.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files('../../../../../gradle/libs.versions.toml'))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
buildscript {
dependencies {
classpath "com.jakewharton.mosaic:mosaic-gradle-plugin:$mosaicVersion"
classpath libs.kotlin.gradlePlugin
}

repositories {
maven {
url "file://${projectDir.absolutePath}/../../../../../build/testMaven"
}
mavenCentral()
}
}

apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'com.jakewharton.mosaic'

mosaic {
// Use the AndroidX Compose compiler instead of JetBrains Compose compiler.
kotlinCompilerPlugin = libs.androidx.compose.compiler.get().toString()
}

repositories {
maven {
url "file://${projectDir.absolutePath}/../../../../../build/testMaven"
}
mavenCentral()
google()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files('../../../../../gradle/libs.versions.toml'))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
buildscript {
dependencies {
classpath "com.jakewharton.mosaic:mosaic-gradle-plugin:$mosaicVersion"
classpath libs.kotlin.gradlePlugin
}

repositories {
maven {
url "file://${projectDir.absolutePath}/../../../../../build/testMaven"
}
mavenCentral()
google()
}
}

apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'com.jakewharton.mosaic'

mosaic {
kotlinCompilerPlugin = 'wrong:format'
}

repositories {
maven {
url "file://${projectDir.absolutePath}/../../../../../build/testMaven"
}
mavenCentral()
google()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files('../../../../../gradle/libs.versions.toml'))
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
buildscript {
ext.kotlinVersion = '1.8.20'

dependencies {
classpath "com.jakewharton.mosaic:mosaic-gradle-plugin:$mosaicVersion"
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
}

repositories {
maven {
url "file://${projectDir.absolutePath}/../../../../../build/testMaven"
}
mavenCentral()
google()
}
}

if (kotlinVersion == libs.kotlin.gradlePlugin.get().version) {
throw RuntimeException("This test requires a different version of Kotlin then the Mosaic build")
}

apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'com.jakewharton.mosaic'

mosaic {
// Use the JetBrains Compose compiler version for the version of Kotlin used by this project.
kotlinCompilerPlugin = '1.4.8'
}

repositories {
maven {
url "file://${projectDir.absolutePath}/../../../../../build/testMaven"
}
mavenCentral()
google()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
dependencyResolutionManagement {
versionCatalogs {
libs {
from(files('../../../../../gradle/libs.versions.toml'))
}
}
}
Original file line number Diff line number Diff line change
@@ -1,36 +1,45 @@
package com.jakewharton.mosaic.gradle

import com.google.common.truth.Truth.assertThat
import java.io.File
import org.gradle.testkit.runner.GradleRunner
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import org.junit.runners.Parameterized.Parameters
import java.io.File

@RunWith(Parameterized::class)
class FixtureTest(
private val fixtureName: String,
) {
companion object {
@JvmStatic
@Parameters(name = "{0}")
fun parameters() = listOf(
arrayOf("counter"),
class FixtureTest {
@Test fun counter() {
fixture("counter").build()
}

@Test fun customCompilerCoordinates() {
fixture("custom-compiler-coordinates").build()
}

@Test fun customCompilerInvalid() {
val result = fixture("custom-compiler-invalid").buildAndFail()
assertThat(result.output).contains(
"""
|Illegal format of 'mosaic.kotlinCompilerPlugin' property.
|Expected format: either '<VERSION>' or '<GROUP_ID>:<ARTIFACT_ID>:<VERSION>'
|Actual value: 'wrong:format'
""".trimMargin(),
)
}

private val fixturesDir = File("src/test/fixture")
private fun versionProperty() = "-PmosaicVersion=$mosaicVersion"
@Test fun customCompilerVersion() {
fixture("custom-compiler-version").build()
}

@Test fun todo() {
val fixtureDir = File(fixturesDir, fixtureName)
val gradleRoot = File(fixtureDir, "gradle").also { it.mkdir() }
File("../gradle").copyRecursively(File(gradleRoot.path), true)
private fun fixture(
name: String,
tasks: Array<String> = arrayOf("clean", "build"),
): GradleRunner {
val fixtureDir = File("src/test/fixture", name)
val gradleWrapper = File(fixtureDir, "gradle/wrapper").also { it.mkdirs() }
File("../gradle/wrapper").copyRecursively(File(gradleWrapper.path), true)

GradleRunner.create()
return GradleRunner.create()
.withProjectDir(fixtureDir)
.withArguments("clean", "build", "--stacktrace", versionProperty())
.withDebug(true) // Run in-process for speed.
.build()
.withArguments(*tasks, "--stacktrace", "-PmosaicVersion=$mosaicVersion")
.withDebug(true)
}
}