Browse Source

Turn off Compose resources sync when third party resources plugins ar… (#3469)

* Turn off Compose resources sync when third party resources plugins are used

* Fix Gradle 7.x test kit check
pull/3506/head
Alexey Tsvetkov 1 year ago committed by GitHub
parent
commit
44376fdf85
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 21
      gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/uikit/internal/resources/configureSyncIosResources.kt
  2. 89
      gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/GradlePluginTest.kt
  3. 7
      gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/utils/TestProject.kt
  4. 2
      gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/utils/TestProjects.kt
  5. 7
      gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/utils/assertUtils.kt
  6. 53
      gradle-plugins/compose/src/test/test-projects/misc/iosMokoResources/build.gradle
  7. 1
      gradle-plugins/compose/src/test/test-projects/misc/iosMokoResources/gradle.properties
  8. 13
      gradle-plugins/compose/src/test/test-projects/misc/iosMokoResources/settings.gradle
  9. 10
      gradle-plugins/compose/src/test/test-projects/misc/iosMokoResources/src/commonMain/kotlin/App.kt
  10. 48
      gradle-plugins/compose/src/test/test-projects/misc/iosResources/build.gradle
  11. 1
      gradle-plugins/compose/src/test/test-projects/misc/iosResources/gradle.properties
  12. 12
      gradle-plugins/compose/src/test/test-projects/misc/iosResources/settings.gradle
  13. 38
      gradle-plugins/compose/src/test/test-projects/misc/iosResources/src/commonMain/kotlin/App.kt
  14. 36
      gradle-plugins/compose/src/test/test-projects/misc/iosResources/src/commonMain/resources/compose-multiplatform.xml

21
gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/uikit/internal/resources/configureSyncIosResources.kt

@ -23,8 +23,27 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import java.io.File import java.io.File
private val incompatiblePlugins = listOf(
"dev.icerock.mobile.multiplatform-resources",
"io.github.skeptick.libres",
)
internal fun Project.configureSyncTask(mppExt: KotlinMultiplatformExtension) { internal fun Project.configureSyncTask(mppExt: KotlinMultiplatformExtension) {
if (!IosGradleProperties.syncResources(providers).get()) return fun reportSyncIsDisabled(reason: String) {
logger.info("Compose Multiplatform resource management for iOS is disabled: $reason")
}
if (!IosGradleProperties.syncResources(providers).get()) {
reportSyncIsDisabled("'${IosGradleProperties.SYNC_RESOURCES_PROPERTY}' value is 'false'")
return
}
for (incompatiblePluginId in incompatiblePlugins) {
if (project.plugins.hasPlugin(incompatiblePluginId)) {
reportSyncIsDisabled("resource management is not compatible with '$incompatiblePluginId'")
return
}
}
with (SyncIosResourcesContext(project, mppExt)) { with (SyncIosResourcesContext(project, mppExt)) {
configureSyncResourcesTasks() configureSyncResourcesTasks()

89
gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/tests/integration/GradlePluginTest.kt

@ -8,7 +8,10 @@ package org.jetbrains.compose.test.tests.integration
import org.jetbrains.compose.desktop.ui.tooling.preview.rpc.PreviewLogger import org.jetbrains.compose.desktop.ui.tooling.preview.rpc.PreviewLogger
import org.jetbrains.compose.desktop.ui.tooling.preview.rpc.RemoteConnection import org.jetbrains.compose.desktop.ui.tooling.preview.rpc.RemoteConnection
import org.jetbrains.compose.desktop.ui.tooling.preview.rpc.receiveConfigFromGradle import org.jetbrains.compose.desktop.ui.tooling.preview.rpc.receiveConfigFromGradle
import org.jetbrains.compose.internal.utils.OS
import org.jetbrains.compose.internal.utils.currentOS
import org.jetbrains.compose.test.utils.* import org.jetbrains.compose.test.utils.*
import org.junit.jupiter.api.Assumptions
import java.net.ServerSocket import java.net.ServerSocket
import java.net.Socket import java.net.Socket
@ -17,8 +20,94 @@ import java.util.concurrent.atomic.AtomicBoolean
import java.util.concurrent.atomic.AtomicInteger import java.util.concurrent.atomic.AtomicInteger
import kotlin.concurrent.thread import kotlin.concurrent.thread
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import java.io.File
class GradlePluginTest : GradlePluginTestBase() { class GradlePluginTest : GradlePluginTestBase() {
private data class IosTestEnv(
val targetBuildDir: File,
val appDir: File,
val envVars: Map<String, String>
)
enum class IosPlatform(val id: String) {
SIMULATOR("iphonesimulator"), IOS("iphoneos")
}
enum class IosArch(val id: String) {
X64("x86_64"), ARM64("arm64")
}
enum class IosBuildConfiguration(val id: String) {
DEBUG("Debug"), RELEASE("Release")
}
private fun iosTestEnv(
platform: IosPlatform = IosPlatform.SIMULATOR,
arch: IosArch = IosArch.X64,
configuration: IosBuildConfiguration = IosBuildConfiguration.DEBUG
): IosTestEnv {
val targetBuildDir = testWorkDir.resolve("build/ios/${configuration.id}-${platform.id}").apply { mkdirs() }
val appDir = targetBuildDir.resolve("App.app").apply { mkdirs() }
val envVars = mapOf(
"PLATFORM_NAME" to platform.id,
"ARCHS" to arch.id,
"BUILT_PRODUCTS_DIR" to targetBuildDir.canonicalPath,
"CONTENTS_FOLDER_PATH" to appDir.name,
)
return IosTestEnv(
targetBuildDir = targetBuildDir,
appDir = appDir,
envVars = envVars
)
}
@Test
fun iosResources() {
Assumptions.assumeTrue(currentOS == OS.MacOS)
val iosTestEnv = iosTestEnv()
val testEnv = defaultTestEnvironment.copy(
// for some reason configuration cache + test kit + custom vars does not work
useGradleConfigurationCache = false,
additionalEnvVars = iosTestEnv.envVars
)
with(testProject(TestProjects.iosResources, testEnv)) {
gradle(":embedAndSignAppleFrameworkForXcode", "--dry-run").checks {
// This test is not intended to actually run embedAndSignAppleFrameworkForXcode.
// Instead, it should check that embedAndSign depends on syncComposeResources using dry run
check.taskSkipped(":syncComposeResourcesForIos")
check.taskSkipped(":embedAndSignAppleFrameworkForXcode")
}
gradle(":syncComposeResourcesForIos").checks {
check.taskSuccessful(":syncComposeResourcesForIos")
iosTestEnv.appDir.resolve("compose-resources/compose-multiplatform.xml").checkExists()
}
}
}
@Test
fun iosMokoResources() {
Assumptions.assumeTrue(currentOS == OS.MacOS)
val iosTestEnv = iosTestEnv()
val testEnv = defaultTestEnvironment.copy(
// for some reason configuration cache + test kit + custom vars does not work
useGradleConfigurationCache = false,
additionalEnvVars = iosTestEnv.envVars
)
with(testProject(TestProjects.iosMokoResources, testEnv)) {
gradle(
":embedAndSignAppleFrameworkForXcode",
":copyFrameworkResourcesToApp",
"--dry-run",
"--info"
).checks {
// This test is not intended to actually run embedAndSignAppleFrameworkForXcode.
// Instead, it should check that the sync disables itself.
check.logContains("Compose Multiplatform resource management for iOS is disabled")
check.logDoesntContain(":syncComposeResourcesForIos")
}
}
}
@Test @Test
fun skikoWasm() = with( fun skikoWasm() = with(
testProject( testProject(

7
gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/utils/TestProject.kt

@ -16,16 +16,19 @@ data class TestEnvironment(
val workingDir: File, val workingDir: File,
val kotlinVersion: String = TestKotlinVersions.Default, val kotlinVersion: String = TestKotlinVersions.Default,
val composeGradlePluginVersion: String = TestProperties.composeGradlePluginVersion, val composeGradlePluginVersion: String = TestProperties.composeGradlePluginVersion,
val mokoResourcesPluginVersion: String = "0.23.0",
val composeCompilerPlugin: String? = null, val composeCompilerPlugin: String? = null,
val composeCompilerArgs: String? = null, val composeCompilerArgs: String? = null,
val composeVerbose: Boolean = true, val composeVerbose: Boolean = true,
val useGradleConfigurationCache: Boolean = TestProperties.gradleConfigurationCache, val useGradleConfigurationCache: Boolean = TestProperties.gradleConfigurationCache,
val additionalEnvVars: Map<String, String> = mapOf()
) { ) {
private val placeholders = linkedMapOf( private val placeholders = linkedMapOf(
"COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER" to composeGradlePluginVersion, "COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER" to composeGradlePluginVersion,
"KOTLIN_VERSION_PLACEHOLDER" to kotlinVersion, "KOTLIN_VERSION_PLACEHOLDER" to kotlinVersion,
"COMPOSE_COMPILER_PLUGIN_PLACEHOLDER" to composeCompilerPlugin, "COMPOSE_COMPILER_PLUGIN_PLACEHOLDER" to composeCompilerPlugin,
"COMPOSE_COMPILER_PLUGIN_ARGS_PLACEHOLDER" to composeCompilerArgs, "COMPOSE_COMPILER_PLUGIN_ARGS_PLACEHOLDER" to composeCompilerArgs,
"MOKO_RESOURCES_PLUGIN_VERSION_PLACEHOLDER" to mokoResourcesPluginVersion,
) )
fun replacePlaceholdersInFile(file: File) { fun replacePlaceholdersInFile(file: File) {
@ -121,6 +124,10 @@ class TestProject(
withGradleVersion(TestProperties.gradleVersionForTests) withGradleVersion(TestProperties.gradleVersionForTests)
withProjectDir(testEnvironment.workingDir) withProjectDir(testEnvironment.workingDir)
withArguments(allArgs) withArguments(allArgs)
if (testEnvironment.additionalEnvVars.isNotEmpty()) {
val newEnv = HashMap(System.getenv() + testEnvironment.additionalEnvVars)
withEnvironment(newEnv)
}
forwardOutput() forwardOutput()
} }
} }

2
gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/utils/TestProjects.kt

@ -24,4 +24,6 @@ object TestProjects {
const val jsMpp = "misc/jsMpp" const val jsMpp = "misc/jsMpp"
const val skikoWasm = "misc/skikoWasm" const val skikoWasm = "misc/skikoWasm"
const val jvmPreview = "misc/jvmPreview" const val jvmPreview = "misc/jvmPreview"
const val iosResources = "misc/iosResources"
const val iosMokoResources = "misc/iosMokoResources"
} }

7
gradle-plugins/compose/src/test/kotlin/org/jetbrains/compose/test/utils/assertUtils.kt

@ -53,6 +53,13 @@ internal class BuildResultChecks(private val result: BuildResult) {
taskOutcome(task, TaskOutcome.FROM_CACHE) taskOutcome(task, TaskOutcome.FROM_CACHE)
} }
fun taskSkipped(task: String) {
// task outcome for skipped task is null in Gradle 7.x
if (result.task(task)?.outcome != null) {
taskOutcome(task, TaskOutcome.SKIPPED)
}
}
private fun taskOutcome(task: String, expectedOutcome: TaskOutcome) { private fun taskOutcome(task: String, expectedOutcome: TaskOutcome) {
val actualOutcome = result.task(task)?.outcome val actualOutcome = result.task(task)?.outcome
if (actualOutcome != expectedOutcome) { if (actualOutcome != expectedOutcome) {

53
gradle-plugins/compose/src/test/test-projects/misc/iosMokoResources/build.gradle

@ -0,0 +1,53 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.compose"
id "dev.icerock.mobile.multiplatform-resources"
}
kotlin {
iosX64 {
binaries.framework {
baseName = "shared"
isStatic = true
}
}
iosArm64 {
binaries.framework {
baseName = "shared"
isStatic = true
}
}
iosSimulatorArm64 {
binaries.framework {
baseName = "shared"
isStatic = true
}
}
sourceSets {
def commonMain = named("commonMain") {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation("dev.icerock.moko:resources-compose:MOKO_RESOURCES_PLUGIN_VERSION_PLACEHOLDER") // for compose multiplatform
}
}
def iosMain = create("iosMain") {
dependsOn(commonMain.get())
}
named("iosX64Main") {
dependsOn(iosMain)
}
named("iosArm64Main") {
dependsOn(iosMain)
}
named("iosSimulatorArm64Main") {
dependsOn(iosMain)
}
}
}
multiplatformResources {
multiplatformResourcesPackage = "org.example"
}

1
gradle-plugins/compose/src/test/test-projects/misc/iosMokoResources/gradle.properties

@ -0,0 +1 @@
org.jetbrains.compose.experimental.uikit.enabled=true

13
gradle-plugins/compose/src/test/test-projects/misc/iosMokoResources/settings.gradle

@ -0,0 +1,13 @@
pluginManagement {
plugins {
id 'org.jetbrains.kotlin.multiplatform' version 'KOTLIN_VERSION_PLACEHOLDER'
id 'org.jetbrains.compose' version 'COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER'
id 'dev.icerock.mobile.multiplatform-resources' version 'MOKO_RESOURCES_PLUGIN_VERSION_PLACEHOLDER'
}
repositories {
mavenLocal()
gradlePluginPortal()
maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
}
}
rootProject.name = "iosResources"

10
gradle-plugins/compose/src/test/test-projects/misc/iosMokoResources/src/commonMain/kotlin/App.kt

@ -0,0 +1,10 @@
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
@Composable
fun App() {
MaterialTheme {
Text("Hello, World!")
}
}

48
gradle-plugins/compose/src/test/test-projects/misc/iosResources/build.gradle

@ -0,0 +1,48 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.compose"
}
kotlin {
iosX64 {
binaries.framework {
baseName = "shared"
isStatic = true
}
}
iosArm64 {
binaries.framework {
baseName = "shared"
isStatic = true
}
}
iosSimulatorArm64 {
binaries.framework {
baseName = "shared"
isStatic = true
}
}
sourceSets {
def commonMain = named("commonMain") {
dependencies {
implementation(compose.runtime)
implementation(compose.foundation)
implementation(compose.material)
implementation(compose.components.resources)
}
}
def iosMain = create("iosMain") {
dependsOn(commonMain.get())
}
named("iosX64Main") {
dependsOn(iosMain)
}
named("iosArm64Main") {
dependsOn(iosMain)
}
named("iosSimulatorArm64Main") {
dependsOn(iosMain)
}
}
}

1
gradle-plugins/compose/src/test/test-projects/misc/iosResources/gradle.properties

@ -0,0 +1 @@
org.jetbrains.compose.experimental.uikit.enabled=true

12
gradle-plugins/compose/src/test/test-projects/misc/iosResources/settings.gradle

@ -0,0 +1,12 @@
pluginManagement {
plugins {
id 'org.jetbrains.kotlin.multiplatform' version 'KOTLIN_VERSION_PLACEHOLDER'
id 'org.jetbrains.compose' version 'COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER'
}
repositories {
mavenLocal()
gradlePluginPortal()
maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
}
}
rootProject.name = "iosResources"

38
gradle-plugins/compose/src/test/test-projects/misc/iosResources/src/commonMain/kotlin/App.kt

@ -0,0 +1,38 @@
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
@OptIn(ExperimentalResourceApi::class)
@Composable
fun App() {
MaterialTheme {
var greetingText by remember { mutableStateOf("Hello, World!") }
var showImage by remember { mutableStateOf(false) }
Column(Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Button(onClick = {
showImage = !showImage
}) {
Text(greetingText)
}
AnimatedVisibility(showImage) {
Image(
painterResource("compose-multiplatform.xml"),
null
)
}
}
}
}

36
gradle-plugins/compose/src/test/test-projects/misc/iosResources/src/commonMain/resources/compose-multiplatform.xml

@ -0,0 +1,36 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="600dp"
android:height="600dp"
android:viewportWidth="600"
android:viewportHeight="600">
<path
android:pathData="M301.21,418.53C300.97,418.54 300.73,418.56 300.49,418.56C297.09,418.59 293.74,417.72 290.79,416.05L222.6,377.54C220.63,376.43 219,374.82 217.85,372.88C216.7,370.94 216.09,368.73 216.07,366.47L216.07,288.16C216.06,287.32 216.09,286.49 216.17,285.67C216.38,283.54 216.91,281.5 217.71,279.6L199.29,268.27L177.74,256.19C175.72,260.43 174.73,265.23 174.78,270.22L174.79,387.05C174.85,393.89 178.57,400.2 184.53,403.56L286.26,461.02C290.67,463.51 295.66,464.8 300.73,464.76C300.91,464.76 301.09,464.74 301.27,464.74C301.24,449.84 301.22,439.23 301.22,439.23L301.21,418.53Z"
android:fillColor="#041619"
android:fillType="nonZero"/>
<path
android:pathData="M409.45,242.91L312.64,188.23C303.64,183.15 292.58,183.26 283.68,188.51L187.92,245C183.31,247.73 179.93,251.62 177.75,256.17L177.74,256.19L199.29,268.27L217.71,279.6C217.83,279.32 217.92,279.02 218.05,278.74C218.24,278.36 218.43,277.98 218.64,277.62C219.06,276.88 219.52,276.18 220.04,275.51C221.37,273.8 223.01,272.35 224.87,271.25L289.06,233.39C290.42,232.59 291.87,231.96 293.39,231.51C295.53,230.87 297.77,230.6 300,230.72C302.98,230.88 305.88,231.73 308.47,233.2L373.37,269.85C375.54,271.08 377.49,272.68 379.13,274.57C379.68,275.19 380.18,275.85 380.65,276.53C380.86,276.84 381.05,277.15 381.24,277.47L397.79,266.39L420.34,252.93L420.31,252.88C417.55,248.8 413.77,245.35 409.45,242.91Z"
android:fillColor="#37BF6E"
android:fillType="nonZero"/>
<path
android:pathData="M381.24,277.47C381.51,277.92 381.77,278.38 382.01,278.84C382.21,279.24 382.39,279.65 382.57,280.06C382.91,280.88 383.19,281.73 383.41,282.59C383.74,283.88 383.92,285.21 383.93,286.57L383.93,361.1C383.96,363.95 383.35,366.77 382.16,369.36C381.93,369.86 381.69,370.35 381.42,370.83C379.75,373.79 377.32,376.27 374.39,378L310.2,415.87C307.47,417.48 304.38,418.39 301.21,418.53L301.22,439.23C301.22,439.23 301.24,449.84 301.27,464.74C306.1,464.61 310.91,463.3 315.21,460.75L410.98,404.25C419.88,399 425.31,389.37 425.22,379.03L425.22,267.85C425.17,262.48 423.34,257.34 420.34,252.93L397.79,266.39L381.24,277.47Z"
android:fillColor="#3870B2"
android:fillType="nonZero"/>
<path
android:pathData="M177.75,256.17C179.93,251.62 183.31,247.73 187.92,245L283.68,188.51C292.58,183.26 303.64,183.15 312.64,188.23L409.45,242.91C413.77,245.35 417.55,248.8 420.31,252.88L420.34,252.93L498.59,206.19C494.03,199.46 487.79,193.78 480.67,189.75L320.86,99.49C306.01,91.1 287.75,91.27 273.07,99.95L114.99,193.2C107.39,197.69 101.81,204.11 98.21,211.63L177.74,256.19L177.75,256.17ZM301.27,464.74C301.09,464.74 300.91,464.76 300.73,464.76C295.66,464.8 290.67,463.51 286.26,461.02L184.53,403.56C178.57,400.2 174.85,393.89 174.79,387.05L174.78,270.22C174.73,265.23 175.72,260.43 177.74,256.19L98.21,211.63C94.86,218.63 93.23,226.58 93.31,234.82L93.31,427.67C93.42,438.97 99.54,449.37 109.4,454.92L277.31,549.77C284.6,553.88 292.84,556.01 301.2,555.94L301.2,555.8C301.39,543.78 301.33,495.26 301.27,464.74Z"
android:strokeWidth="10"
android:fillColor="#00000000"
android:strokeColor="#083042"
android:fillType="nonZero"/>
<path
android:pathData="M498.59,206.19L420.34,252.93C423.34,257.34 425.17,262.48 425.22,267.85L425.22,379.03C425.31,389.37 419.88,399 410.98,404.25L315.21,460.75C310.91,463.3 306.1,464.61 301.27,464.74C301.33,495.26 301.39,543.78 301.2,555.8L301.2,555.94C309.48,555.87 317.74,553.68 325.11,549.32L483.18,456.06C497.87,447.39 506.85,431.49 506.69,414.43L506.69,230.91C506.6,222.02 503.57,213.5 498.59,206.19Z"
android:strokeWidth="10"
android:fillColor="#00000000"
android:strokeColor="#083042"
android:fillType="nonZero"/>
<path
android:pathData="M301.2,555.94C292.84,556.01 284.6,553.88 277.31,549.76L109.4,454.92C99.54,449.37 93.42,438.97 93.31,427.67L93.31,234.82C93.23,226.58 94.86,218.63 98.21,211.63C101.81,204.11 107.39,197.69 114.99,193.2L273.07,99.95C287.75,91.27 306.01,91.1 320.86,99.49L480.67,189.75C487.79,193.78 494.03,199.46 498.59,206.19C503.57,213.5 506.6,222.02 506.69,230.91L506.69,414.43C506.85,431.49 497.87,447.39 483.18,456.06L325.11,549.32C317.74,553.68 309.48,555.87 301.2,555.94Z"
android:strokeWidth="10"
android:fillColor="#00000000"
android:strokeColor="#083042"
android:fillType="nonZero"/>
</vector>
Loading…
Cancel
Save