From 00ed07afb13182df9d1f002c2a2d181e5a3f0487 Mon Sep 17 00:00:00 2001 From: Oleksandr Karpovich Date: Thu, 19 Oct 2023 13:37:32 +0200 Subject: [PATCH] Add a better error message when we fail to execute SyncComposeResourcesForIosTask Reason: Since Xcode 15, there is a new default setting: `ENABLE_USER_SCRIPT_SANDBOXING = YES` SyncComposeResourcesForIosTask fails to work with it right now. --- .../resources/configureSyncIosResources.kt | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/uikit/internal/resources/configureSyncIosResources.kt b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/uikit/internal/resources/configureSyncIosResources.kt index ae0a430a088..030e99eaebd 100644 --- a/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/uikit/internal/resources/configureSyncIosResources.kt +++ b/gradle-plugins/compose/src/main/kotlin/org/jetbrains/compose/experimental/uikit/internal/resources/configureSyncIosResources.kt @@ -7,12 +7,15 @@ package org.jetbrains.compose.experimental.uikit.internal.resources import org.gradle.api.Project import org.gradle.api.file.Directory +import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskContainer +import org.gradle.api.tasks.TaskAction import org.jetbrains.compose.experimental.uikit.internal.utils.IosGradleProperties import org.jetbrains.compose.experimental.uikit.internal.utils.asIosNativeTargetOrNull import org.jetbrains.compose.experimental.uikit.internal.utils.cocoapodsExt import org.jetbrains.compose.experimental.uikit.internal.utils.withCocoapodsPlugin +import org.jetbrains.compose.experimental.uikit.tasks.AbstractComposeIosTask import org.jetbrains.compose.experimental.uikit.tasks.SyncComposeResourcesForIosTask import org.jetbrains.compose.internal.utils.joinLowerCamelCase import org.jetbrains.compose.internal.utils.new @@ -111,13 +114,56 @@ private fun SyncIosResourcesContext.configureCocoapodsResourcesAttribute() { } } +/** + * Since Xcode 15, there is a new default setting: `ENABLE_USER_SCRIPT_SANDBOXING = YES` + * It's set in project.pbxproj + * + * SyncComposeResourcesForIosTask fails to work with it right now. + * + * Gradle attempts to create an output folder for SyncComposeResourcesForIosTask on our behalf, + * so we can't handle an exception when it occurs. Therefore, we make SyncComposeResourcesForIosTask + * depend on CheckCanAccessComposeResourcesDirectory, where we test the possibility to run file operations + * in the corresponding folder. + */ +internal abstract class CheckCanAccessComposeResourcesDirectory : AbstractComposeIosTask() { + init { + outputs.upToDateWhen { false } + } + + val path: Property = objects.directoryProperty() + + @TaskAction + fun run() { + try { + val testFile = File(path.get().asFile, "testAccess.txt") + testFile.writeText("testAccess") + testFile.delete() + } catch (t: Throwable) { + logger.error(""" + |Failed to sync compose resources! + |Please make sure ENABLE_USER_SCRIPT_SANDBOXING is set to 'NO' in 'project.pbxproj' + |""".trimMargin()) + throw IllegalStateException( + "Sandbox environment detected. Is 'ENABLE_USER_SCRIPT_SANDBOXING' set to 'YES'?", + t + ) + } + } +} + private fun SyncIosResourcesContext.configureSyncResourcesTasks() { val lazyTasksDependencies = LazyTasksDependencyConfigurator(project.tasks) configureEachIosFramework { framework -> val frameworkClassifier = framework.namePrefix.uppercaseFirstChar() val syncResourcesTaskName = "sync${frameworkClassifier}ComposeResourcesForIos" + val checkSyncResourcesTaskName = "checkCanSync${frameworkClassifier}ComposeResourcesForIos" + val syncDir = syncDirFor(framework) + val checkAccessTask = framework.project.tasks.registerOrConfigure(checkSyncResourcesTaskName) { + path.set(syncDir) + } val syncTask = framework.project.tasks.registerOrConfigure(syncResourcesTaskName) { - outputDir.set(syncDirFor(framework)) + dependsOn(checkAccessTask) + outputDir.set(syncDir) iosTargets.add(iosTargetResourcesProvider(framework)) } with (lazyTasksDependencies) {