Separate podgen & podinstall tasks

^KT-54161 Verification Pending
This commit is contained in:
Artem Daugel-Dauge
2023-01-10 13:12:13 +01:00
committed by Space Team
parent f144f8b6d3
commit 8a34d1f430
6 changed files with 253 additions and 246 deletions
@@ -70,9 +70,10 @@ class CocoaPodsIT : BaseGradleIT() {
private val defaultPodRepo = "https://github.com/AFNetworking/AFNetworking"
private val defaultPodName = "AFNetworking"
private val defaultTarget = "IOS"
private val defaultFamily = "IOS"
private val defaultFamily = "ios"
private val defaultSDK = "iphonesimulator"
private val defaultPodGenTaskName = podGenFullTaskName()
private val defaultPodInstallSyntheticTaskName = ":podInstallSyntheticIos"
private val defaultBuildTaskName = podBuildFullTaskName()
private val defaultSetupBuildTaskName = podSetupBuildFullTaskName()
private val defaultCinteropTaskName = cinteropTaskName + defaultPodName + defaultTarget
@@ -245,7 +246,7 @@ class CocoaPodsIT : BaseGradleIT() {
}
@Test
fun testSyntheticProjectPodspecGeneration() {
fun testSyntheticProjectPodfileGeneration() {
val gradleProject = transformProjectWithPluginsDsl(cocoapodsSingleKtPod, gradleVersion)
gradleProject.gradleBuildScript().appendToCocoapodsBlock("""
ios.deploymentTarget = "14.1"
@@ -257,9 +258,11 @@ class CocoaPodsIT : BaseGradleIT() {
}
}
""".trimIndent())
gradleProject.build("podGenIOS", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
gradleProject.build("podInstallSyntheticIos", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
assertSuccessful()
val podfileText = gradleProject.projectDir.resolve("build/cocoapods/synthetic/IOS/Podfile").readText().trim()
assertTasksExecuted(":podGenIos")
val podfileText = gradleProject.projectDir.resolve("build/cocoapods/synthetic/ios/Podfile").readText().trim()
assertTrue(podfileText.contains("platform :ios, '14.1'"))
assertTrue(podfileText.contains("pod 'SSZipArchive'"))
assertTrue(podfileText.contains("pod 'AFNetworking', '~> 4.0.1'"))
@@ -270,6 +273,27 @@ class CocoaPodsIT : BaseGradleIT() {
}
}
@Test
fun testSyntheticProjectPodfilePostprocessing() {
project.gradleBuildScript().apply {
appendToCocoapodsBlock("""pod("AWSMobileClient", version = "2.29.1")""")
appendText("""
tasks.withType<org.jetbrains.kotlin.gradle.targets.native.tasks.PodGenTask>().configureEach {
doLast {
podfile.get().appendText("ENV['SWIFT_VERSION'] = '5'")
}
}
""".trimIndent())
}
project.build("podInstallSyntheticIos", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
assertSuccessful()
assertFileContains(path = "build/cocoapods/synthetic/ios/Podfile", "ENV['SWIFT_VERSION'] = '5'")
}
}
@Test
fun testPodDownloadGitNoTagNorCommit() {
doTestGit()
@@ -378,9 +402,10 @@ class CocoaPodsIT : BaseGradleIT() {
val tasks = listOf(
podspecTaskName,
defaultPodGenTaskName,
defaultPodInstallSyntheticTaskName,
defaultSetupBuildTaskName,
defaultBuildTaskName,
defaultCinteropTaskName
defaultCinteropTaskName,
)
with(project.gradleBuildScript()) {
addPod(defaultPodName, produceGitBlock(defaultPodRepo))
@@ -416,21 +441,21 @@ class CocoaPodsIT : BaseGradleIT() {
}
@Test
fun testPodGenInvalidatesUTD() {
fun testPodInstallInvalidatesUTD() {
with(project.gradleBuildScript()) {
addPod("AFNetworking")
}
hooks.addHook {
assertTasksExecuted(defaultPodGenTaskName)
assertTrue { fileInWorkingDir("build/cocoapods/synthetic/IOS/Pods/AFNetworking").deleteRecursively() }
assertTasksExecuted(defaultPodInstallSyntheticTaskName)
assertTrue { fileInWorkingDir("build/cocoapods/synthetic/ios/Pods/AFNetworking").deleteRecursively() }
}
project.testSynthetic(defaultPodGenTaskName)
project.testSynthetic(defaultPodInstallSyntheticTaskName)
hooks.rewriteHooks {
assertTasksExecuted(defaultPodGenTaskName)
assertTasksExecuted(defaultPodInstallSyntheticTaskName)
}
project.testSynthetic(defaultPodGenTaskName)
project.testSynthetic(defaultPodInstallSyntheticTaskName)
}
@Test
@@ -499,7 +524,7 @@ class CocoaPodsIT : BaseGradleIT() {
val anotherTarget = "MacosX64"
val anotherSdk = "macosx"
val anotherFamily = "OSX"
val anotherFamily = "macos"
with(project.gradleBuildScript()) {
appendToKotlinBlock(anotherTarget.replaceFirstChar { it.lowercase(Locale.getDefault()) } + "()")
}
@@ -10,22 +10,17 @@ import org.gradle.api.Action
import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectSet
import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency.PodLocation.*
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_FRAMEWORK_PREFIX
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBinary
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import org.jetbrains.kotlin.gradle.tasks.addArg
import org.jetbrains.kotlin.gradle.tasks.addArgs
import org.jetbrains.kotlin.gradle.utils.relativeToRoot
import org.jetbrains.kotlin.konan.target.HostManager
import java.io.File
import java.net.URI
import javax.inject.Inject
@Suppress("unused") // Public API
abstract class CocoapodsExtension @Inject constructor(private val project: Project) {
/**
* Configure version of the pod
@@ -62,7 +62,7 @@ internal class CocoapodsBuildDirs(val project: Project) {
val synthetic: File
get() = root.resolve("synthetic")
fun synthetic(family: Family) = synthetic.resolve(family.name)
fun synthetic(family: Family) = synthetic.resolve(family.platformLiteral)
val publish: File = root.resolve("publish")
@@ -72,11 +72,20 @@ internal class CocoapodsBuildDirs(val project: Project) {
internal fun String.asValidFrameworkName() = replace('-', '_')
internal val Family.platformLiteral: String
get() = when (this) {
Family.OSX -> "macos"
Family.IOS -> "ios"
Family.TVOS -> "tvos"
Family.WATCHOS -> "watchos"
else -> throw IllegalArgumentException("Bad family ${this.name}")
}
private val Family.toPodGenTaskName: String
get() = lowerCamelCaseName(
KotlinCocoapodsPlugin.POD_GEN_TASK_NAME,
name
)
get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_GEN_TASK_NAME, platformLiteral)
private val Family.toPodInstallSyntheticTaskName: String
get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_INSTALL_TASK_NAME, "synthetic", platformLiteral)
private fun String.toSetupBuildTaskName(pod: CocoapodsDependency): String = lowerCamelCaseName(
KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME,
@@ -451,23 +460,25 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
project: Project,
cocoapodsExtension: CocoapodsExtension
) {
val podspecTaskProvider = project.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java)
project.tasks.register(POD_INSTALL_TASK_NAME, PodInstallTask::class.java) {
it.group = TASK_GROUP
it.description = "Invokes `pod install` call within Podfile location directory"
it.podfile.set(cocoapodsExtension.podfile)
it.podspec.set(podspecTaskProvider.map { podspecTask -> podspecTask.outputFile })
it.frameworkName = cocoapodsExtension.podFrameworkName
it.dependsOn(podspecTaskProvider)
val podspecTaskProvider = project.tasks.named<PodspecTask>(POD_SPEC_TASK_NAME)
project.registerTask<PodInstallTask>(POD_INSTALL_TASK_NAME) { task ->
task.group = TASK_GROUP
task.description = "Invokes `pod install` call within Podfile location directory"
task.podfile.set(project.provider { cocoapodsExtension.podfile })
task.podspec.set(podspecTaskProvider.map { it.outputFile })
task.frameworkName.set(cocoapodsExtension.podFrameworkName)
task.specRepos.set(project.provider { cocoapodsExtension.specRepos })
task.pods.set(cocoapodsExtension.pods)
task.dependsOn(podspecTaskProvider)
}
}
private fun registerPodGenTask(
private fun registerSyntheticPodTasks(
project: Project, kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension
) {
val families = mutableSetOf<Family>()
val podspecTaskProvider = project.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java)
val podspecTaskProvider = project.tasks.named<PodspecTask>(POD_SPEC_TASK_NAME)
kotlinExtension.supportedTargets().all { target ->
val family = target.konanTarget.family
if (family in families) {
@@ -483,15 +494,23 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
else -> error("Unknown cocoapods platform: $family")
}
project.tasks.register(family.toPodGenTaskName, PodGenTask::class.java) {
it.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
it.podspec = podspecTaskProvider.map { task -> task.outputFile }
it.podName = project.provider { cocoapodsExtension.name }
it.useLibraries = project.provider { cocoapodsExtension.useLibraries }
it.specRepos = project.provider { cocoapodsExtension.specRepos }
it.family = family
it.platformSettings = platformSettings
it.pods.set(cocoapodsExtension.pods)
val podGenTask = project.registerTask<PodGenTask>(family.toPodGenTaskName) { task ->
task.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
task.podspec = podspecTaskProvider.map { it.outputFile }
task.podName = project.provider { cocoapodsExtension.name }
task.useLibraries = project.provider { cocoapodsExtension.useLibraries }
task.specRepos = project.provider { cocoapodsExtension.specRepos }
task.family = family
task.platformSettings = platformSettings
task.pods.set(cocoapodsExtension.pods)
}
project.registerTask<PodInstallSyntheticTask>(family.toPodInstallSyntheticTaskName) { task ->
task.description = "Invokes `pod install` for synthetic project"
task.podfile.set(podGenTask.map { it.podfile.get() })
task.family.set(family)
task.podName.set(cocoapodsExtension.name)
task.dependsOn(podGenTask)
}
}
}
@@ -520,15 +539,15 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
}
sdks += sdk
val podGenTaskProvider = project.tasks.named(target.konanTarget.family.toPodGenTaskName, PodGenTask::class.java)
project.tasks.register(sdk.toSetupBuildTaskName(pod), PodSetupBuildTask::class.java) {
it.group = TASK_GROUP
it.description = "Collect environment variables from .xcworkspace file"
it.pod = project.provider { pod }
it.sdk = project.provider { sdk }
it.podsXcodeProjDir = podGenTaskProvider.map { podGen -> podGen.podsXcodeProjDir.get() }
it.frameworkName = cocoapodsExtension.podFrameworkName
it.dependsOn(podGenTaskProvider)
val podInstallTask = project.tasks.named<PodInstallSyntheticTask>(target.konanTarget.family.toPodInstallSyntheticTaskName)
project.registerTask<PodSetupBuildTask>(sdk.toSetupBuildTaskName(pod)) { task ->
task.group = TASK_GROUP
task.description = "Collect environment variables from .xcworkspace file"
task.pod = project.provider { pod }
task.sdk = project.provider { sdk }
task.podsXcodeProjDir = podInstallTask.map { it.podsXcodeProjDirProvider.get() }
task.frameworkName = cocoapodsExtension.podFrameworkName
task.dependsOn(podInstallTask)
}
}
}
@@ -772,7 +791,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
injectPodspecExtensionToArtifacts(project, kotlinArtifactsExtension, cocoapodsExtension)
registerPodspecTask(project, cocoapodsExtension)
registerPodGenTask(project, kotlinExtension, cocoapodsExtension)
registerSyntheticPodTasks(project, kotlinExtension, cocoapodsExtension)
registerPodInstallTask(project, cocoapodsExtension)
registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension)
registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension)
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.gradle.targets.native.cocoapods
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.SpecRepos
@@ -20,8 +19,7 @@ class MissingSpecReposMessage(override val missingInfo: SpecRepos) : MissingInfo
}
class MissingCocoapodsMessage(
override val missingInfo: CocoapodsDependency,
private val project: Project
override val missingInfo: CocoapodsDependency
) : MissingInfoMessage<CocoapodsDependency> {
override val missingMessage: String
get() = "pod '${missingInfo.name}'${missingInfo.source?.let { ", ${it.getPodSourcePath()}" }.orEmpty()}"
@@ -8,46 +8,30 @@
package org.jetbrains.kotlin.gradle.targets.native.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.FileTree
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.gradle.api.tasks.Optional
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.*
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency.PodLocation.*
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
import org.jetbrains.kotlin.gradle.plugin.cocoapods.platformLiteral
import org.jetbrains.kotlin.gradle.targets.native.cocoapods.MissingCocoapodsMessage
import org.jetbrains.kotlin.gradle.targets.native.cocoapods.MissingSpecReposMessage
import org.jetbrains.kotlin.gradle.tasks.PodspecTask.Companion.retrievePods
import org.jetbrains.kotlin.gradle.tasks.PodspecTask.Companion.retrieveSpecRepos
import org.jetbrains.kotlin.gradle.utils.runCommand
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import java.io.File
import java.io.IOException
import java.io.Reader
import java.util.*
private val Family.platformLiteral: String
get() = when (this) {
Family.OSX -> "macos"
Family.IOS -> "ios"
Family.TVOS -> "tvos"
Family.WATCHOS -> "watchos"
else -> throw IllegalArgumentException("Bad family ${this.name}")
}
val CocoapodsDependency.schemeName: String
get() = name.split("/")[0]
/**
* The task takes the path to the Podfile and calls `pod install`
* to obtain sources or artifacts for the declared dependencies.
* This task is a part of CocoaPods integration infrastructure.
*/
open class CocoapodsTask : DefaultTask() {
init {
@@ -58,61 +42,164 @@ open class CocoapodsTask : DefaultTask() {
}
open class PodInstallTask : CocoapodsTask() {
/**
* The task takes the path to the Podfile and calls `pod install`
* to obtain sources or artifacts for the declared dependencies.
* This task is a part of CocoaPods integration infrastructure.
*/
abstract class AbstractPodInstallTask : CocoapodsTask() {
init {
onlyIf { podfile.isPresent }
}
@get:Internal
internal lateinit var frameworkName: Provider<String>
@get:Optional
@get:PathSensitive(PathSensitivity.ABSOLUTE)
@get:InputFile
internal val podfile = project.objects.property(File::class.java)
abstract val podfile: Property<File?>
@get:Optional
@get:PathSensitive(PathSensitivity.ABSOLUTE)
@get:InputFile
internal val podspec = project.objects.property(File::class.java)
protected val workingDir: Provider<File> = podfile.map { file: File? ->
requireNotNull(file) { "Task outputs shouldn't be queried if it's skipped" }.parentFile
}
@get:Optional
@get:OutputDirectory
internal val podsXcodeProjDirProvider: Provider<File>?
get() = podfile.orNull?.let {
project.provider { it.parentFile.resolve("Pods").resolve("Pods.xcodeproj") }
}
internal val podsDir: Provider<File> = workingDir.map { it.resolve("Pods") }
@get:Internal
internal val podsXcodeProjDirProvider: Provider<File> = podsDir.map { it.resolve("Pods.xcodeproj") }
@TaskAction
fun doPodInstall() {
podfile.orNull?.parentFile?.also { podfileDir ->
val podInstallCommand = listOf("pod", "install")
open fun doPodInstall() {
val podInstallCommand = listOf("pod", "install")
runCommand(podInstallCommand,
logger,
errorHandler = { returnCode, output, _ ->
CocoapodsErrorHandlingUtil.handlePodInstallError(
podInstallCommand.joinToString(" "),
returnCode,
output,
project,
frameworkName.get()
)
},
exceptionHandler = { e: IOException ->
CocoapodsErrorHandlingUtil.handle(e, podInstallCommand)
},
processConfiguration = {
directory(podfileDir)
})
runCommand(podInstallCommand,
logger,
errorHandler = ::handleError,
exceptionHandler = { e: IOException ->
CocoapodsErrorHandlingUtil.handle(e, podInstallCommand)
},
processConfiguration = {
directory(workingDir.get())
})
with(podsXcodeProjDirProvider) {
check(this != null && get().exists() && get().isDirectory) {
"The directory 'Pods/Pods.xcodeproj' was not created as a result of the `pod install` call."
}
with(podsXcodeProjDirProvider.get()) {
check(exists() && isDirectory) {
"The directory 'Pods/Pods.xcodeproj' was not created as a result of the `pod install` call."
}
}
}
abstract fun handleError(retCode: Int, error: String, process: Process): String?
}
abstract class PodInstallTask : AbstractPodInstallTask() {
@get:Optional
@get:InputFile
abstract val podspec: Property<File?>
@get:Input
abstract val frameworkName: Property<String>
@get:Nested
abstract val specRepos: Property<SpecRepos>
@get:Nested
abstract val pods: ListProperty<CocoapodsDependency>
override fun handleError(retCode: Int, error: String, process: Process): String? {
val specReposMessages = MissingSpecReposMessage(specRepos.get()).missingMessage
val cocoapodsMessages = pods.get().map { MissingCocoapodsMessage(it).missingMessage }
return listOfNotNull(
"'pod install' command failed with code $retCode.",
"Error message:",
error.lines().filter { it.isNotBlank() }.joinToString("\n"),
"""
| Please, check that podfile contains following lines in header:
| $specReposMessages
|
""".trimMargin(),
"""
| Please, check that each target depended on ${frameworkName.get()} contains following dependencies:
| ${cocoapodsMessages.joinToString("\n")}
|
""".trimMargin()
).joinToString("\n")
}
}
abstract class PodInstallSyntheticTask : AbstractPodInstallTask() {
@get:Input
abstract val family: Property<Family>
@get:Input
abstract val podName: Property<String>
@get:OutputDirectory
internal val syntheticXcodeProject: Provider<File> = workingDir.map { it.resolve("synthetic.xcodeproj") }
override fun doPodInstall() {
val projResource = "/cocoapods/project.pbxproj"
val projDestination = syntheticXcodeProject.get().resolve("project.pbxproj")
syntheticXcodeProject.get().mkdirs()
projDestination.outputStream().use { file ->
javaClass.getResourceAsStream(projResource)!!.use { resource ->
resource.copyTo(file)
}
}
super.doPodInstall()
}
override fun handleError(retCode: Int, error: String, process: Process): String? {
var message = """
|'pod install' command on the synthetic project failed with return code: $retCode
|
| Error: ${error.lines().filter { it.contains("[!]") }.joinToString("\n")}
|
""".trimMargin()
if (
error.contains("deployment target") ||
error.contains("no platform was specified") ||
error.contains(Regex("The platform of the target .+ is not compatible with `${podName.get()}"))
) {
message += """
|
| Possible reason: ${family.get().platformLiteral} deployment target is not configured
| Configure deployment_target for ALL targets as follows:
| cocoapods {
| ...
| ${family.get().platformLiteral}.deploymentTarget = "..."
| ...
| }
|
""".trimMargin()
return message
} else if (
error.contains("Unable to add a source with url") ||
error.contains("Couldn't determine repo name for URL") ||
error.contains("Unable to find a specification")
) {
message += """
|
| Possible reason: spec repos are not configured correctly.
| Ensure that spec repos are correctly configured for all private pod dependencies:
| cocoapods {
| specRepos {
| url("<private spec repo url>")
| }
| }
|
""".trimMargin()
return message
} else {
return null
}
}
}
/**
@@ -126,82 +213,39 @@ abstract class PodGenTask : CocoapodsTask() {
}
}
@get:PathSensitive(PathSensitivity.ABSOLUTE)
@get:InputFile
internal lateinit var podspec: Provider<File>
internal abstract val podspec: Property<File>
@get:Input
internal lateinit var podName: Provider<String>
internal abstract val podName: Property<String>
@get:Input
internal lateinit var useLibraries: Provider<Boolean>
internal abstract val useLibraries: Property<Boolean>
@get:Internal
lateinit var family: Family
@get:Input
internal abstract val family: Property<Family>
@get:Nested
internal lateinit var platformSettings: PodspecPlatformSettings
internal abstract val platformSettings: Property<PodspecPlatformSettings>
@get:Nested
internal lateinit var specRepos: Provider<SpecRepos>
internal abstract val specRepos: Property<SpecRepos>
@get:Nested
abstract val pods: ListProperty<CocoapodsDependency>
internal abstract val pods: ListProperty<CocoapodsDependency>
@get:OutputDirectory
internal val outputDir: Provider<File> = project.provider { project.cocoapodsBuildDirs.synthetic(family) }
@get:Internal
internal val podsXcodeProjDir: Provider<File> = outputDir.map { it.resolve("Pods").resolve("Pods.xcodeproj") }
@get:Internal
val podfile: Provider<File> = outputDir.map { it.resolve("Podfile") }
@get:OutputFile
val podfile: Provider<File> = family.map { project.cocoapodsBuildDirs.synthetic(it).resolve("Podfile") }
@TaskAction
fun generate() {
val syntheticDir = outputDir.get().apply { mkdirs() }
val specRepos = specRepos.get().getAll()
val projResource = "/cocoapods/project.pbxproj"
val projDestination = syntheticDir.resolve("synthetic.xcodeproj").resolve("project.pbxproj")
projDestination.parentFile.mkdirs()
projDestination.outputStream().use { file ->
javaClass.getResourceAsStream(projResource)!!.use { resource ->
resource.copyTo(file)
}
}
val podfile = this.podfile.get()
podfile.createNewFile()
val podfileContent = getPodfileContent(specRepos, family.platformLiteral)
val podfileContent = getPodfileContent(specRepos, family.get().platformLiteral)
podfile.writeText(podfileContent)
val podInstallCommand = listOf("pod", "install")
runCommand(
podInstallCommand,
project.logger,
exceptionHandler = { e: IOException ->
CocoapodsErrorHandlingUtil.handle(e, podInstallCommand)
},
errorHandler = { retCode, output, _ ->
CocoapodsErrorHandlingUtil.handlePodInstallSyntheticError(
podInstallCommand.joinToString(" "),
retCode,
output,
family,
podName.get()
)
},
processConfiguration = {
directory(syntheticDir)
})
val podsXcprojFile = podsXcodeProjDir.get()
check(podsXcprojFile.exists() && podsXcprojFile.isDirectory) {
"Synthetic project '${podsXcprojFile.path}' was not created."
}
}
private fun getPodfileContent(specRepos: Collection<String>, xcodeTarget: String) =
@@ -215,11 +259,12 @@ abstract class PodGenTask : CocoapodsTask() {
if (useLibraries.get().not()) {
appendLine("\tuse_frameworks!")
}
val deploymentTarget = platformSettings.deploymentTarget
val settings = platformSettings.get()
val deploymentTarget = settings.deploymentTarget
if (deploymentTarget != null) {
appendLine("\tplatform :${platformSettings.name}, '$deploymentTarget'")
appendLine("\tplatform :${settings.name}, '$deploymentTarget'")
} else {
appendLine("\tplatform :${platformSettings.name}")
appendLine("\tplatform :${settings.name}")
}
pods.get().mapNotNull {
buildString {
@@ -251,6 +296,7 @@ abstract class PodGenTask : CocoapodsTask() {
end
""".trimIndent()
)
appendLine()
}
}
@@ -403,6 +449,7 @@ data class PodBuildSettingsProperties(
fun readSettingsFromReader(reader: Reader): PodBuildSettingsProperties {
with(Properties()) {
@Suppress("BlockingMethodInNonBlockingContext") // It's ok to do blocking call here
load(reader)
return PodBuildSettingsProperties(
readProperty(BUILD_DIR),
@@ -448,79 +495,4 @@ private object CocoapodsErrorHandlingUtil {
}
}
fun handlePodInstallError(command: String, retCode: Int, error: String, project: Project, frameworkName: String): String {
val specReposMessages = retrieveSpecRepos(project)?.let { MissingSpecReposMessage(it).missingMessage }
val cocoapodsMessages = retrievePods(project)?.map { MissingCocoapodsMessage(it, project).missingMessage }
return listOfNotNull(
"'pod install' command failed with code $retCode.",
"Full command: $command",
"Error message:",
error.lines().filter { it.isNotBlank() }.joinToString("\n"),
specReposMessages?.let {
"""
| Please, check that podfile contains following lines in header:
| $it
|
""".trimMargin()
},
cocoapodsMessages?.let {
"""
| Please, check that each target depended on $frameworkName contains following dependencies:
| ${it.joinToString("\n")}
|
""".trimMargin()
}
).joinToString("\n")
}
fun handlePodInstallSyntheticError(command: String, retCode: Int, error: String, family: Family, podName: String): String? {
var message = """
|'pod install' command on the synthetic project failed with return code: $retCode
|
| Full command: $command
|
| Error: ${error.lines().filter { it.contains("[!]") }.joinToString("\n")}
|
""".trimMargin()
if (
error.contains("deployment target") ||
error.contains("no platform was specified") ||
error.contains(Regex("The platform of the target .+ is not compatible with `$podName"))
) {
message += """
|
| Possible reason: ${family.name.toLowerCaseAsciiOnly()} deployment target is not configured
| Configure deployment_target for ALL targets as follows:
| cocoapods {
| ...
| ${family.name.toLowerCaseAsciiOnly()}.deploymentTarget = "..."
| ...
| }
|
""".trimMargin()
return message
} else if (
error.contains("Unable to add a source with url") ||
error.contains("Couldn't determine repo name for URL") ||
error.contains("Unable to find a specification")
) {
message += """
|
| Possible reason: spec repos are not configured correctly.
| Ensure that spec repos are correctly configured for all private pod dependencies:
| cocoapods {
| specRepos {
| url("<private spec repo url>")
| }
| }
|
""".trimMargin()
return message
}
return null
}
}
@@ -221,8 +221,6 @@ open class PodspecTask : DefaultTask() {
else project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podfile != null
|| (project.parent?.let { hasPodfileOwnOrParent(it) } ?: false)
internal fun retrieveSpecRepos(project: Project): SpecRepos? = project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.specRepos
internal fun retrievePods(project: Project): List<CocoapodsDependency>? = project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podsAsTaskInput
}
}