Separate podgen & podinstall tasks
^KT-54161 Verification Pending
This commit is contained in:
committed by
Space Team
parent
f144f8b6d3
commit
8a34d1f430
+37
-12
@@ -70,9 +70,10 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
private val defaultPodRepo = "https://github.com/AFNetworking/AFNetworking"
|
private val defaultPodRepo = "https://github.com/AFNetworking/AFNetworking"
|
||||||
private val defaultPodName = "AFNetworking"
|
private val defaultPodName = "AFNetworking"
|
||||||
private val defaultTarget = "IOS"
|
private val defaultTarget = "IOS"
|
||||||
private val defaultFamily = "IOS"
|
private val defaultFamily = "ios"
|
||||||
private val defaultSDK = "iphonesimulator"
|
private val defaultSDK = "iphonesimulator"
|
||||||
private val defaultPodGenTaskName = podGenFullTaskName()
|
private val defaultPodGenTaskName = podGenFullTaskName()
|
||||||
|
private val defaultPodInstallSyntheticTaskName = ":podInstallSyntheticIos"
|
||||||
private val defaultBuildTaskName = podBuildFullTaskName()
|
private val defaultBuildTaskName = podBuildFullTaskName()
|
||||||
private val defaultSetupBuildTaskName = podSetupBuildFullTaskName()
|
private val defaultSetupBuildTaskName = podSetupBuildFullTaskName()
|
||||||
private val defaultCinteropTaskName = cinteropTaskName + defaultPodName + defaultTarget
|
private val defaultCinteropTaskName = cinteropTaskName + defaultPodName + defaultTarget
|
||||||
@@ -245,7 +246,7 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testSyntheticProjectPodspecGeneration() {
|
fun testSyntheticProjectPodfileGeneration() {
|
||||||
val gradleProject = transformProjectWithPluginsDsl(cocoapodsSingleKtPod, gradleVersion)
|
val gradleProject = transformProjectWithPluginsDsl(cocoapodsSingleKtPod, gradleVersion)
|
||||||
gradleProject.gradleBuildScript().appendToCocoapodsBlock("""
|
gradleProject.gradleBuildScript().appendToCocoapodsBlock("""
|
||||||
ios.deploymentTarget = "14.1"
|
ios.deploymentTarget = "14.1"
|
||||||
@@ -257,9 +258,11 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
""".trimIndent())
|
""".trimIndent())
|
||||||
gradleProject.build("podGenIOS", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
gradleProject.build("podInstallSyntheticIos", "-Pkotlin.native.cocoapods.generate.wrapper=true") {
|
||||||
assertSuccessful()
|
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("platform :ios, '14.1'"))
|
||||||
assertTrue(podfileText.contains("pod 'SSZipArchive'"))
|
assertTrue(podfileText.contains("pod 'SSZipArchive'"))
|
||||||
assertTrue(podfileText.contains("pod 'AFNetworking', '~> 4.0.1'"))
|
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
|
@Test
|
||||||
fun testPodDownloadGitNoTagNorCommit() {
|
fun testPodDownloadGitNoTagNorCommit() {
|
||||||
doTestGit()
|
doTestGit()
|
||||||
@@ -378,9 +402,10 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
val tasks = listOf(
|
val tasks = listOf(
|
||||||
podspecTaskName,
|
podspecTaskName,
|
||||||
defaultPodGenTaskName,
|
defaultPodGenTaskName,
|
||||||
|
defaultPodInstallSyntheticTaskName,
|
||||||
defaultSetupBuildTaskName,
|
defaultSetupBuildTaskName,
|
||||||
defaultBuildTaskName,
|
defaultBuildTaskName,
|
||||||
defaultCinteropTaskName
|
defaultCinteropTaskName,
|
||||||
)
|
)
|
||||||
with(project.gradleBuildScript()) {
|
with(project.gradleBuildScript()) {
|
||||||
addPod(defaultPodName, produceGitBlock(defaultPodRepo))
|
addPod(defaultPodName, produceGitBlock(defaultPodRepo))
|
||||||
@@ -416,21 +441,21 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testPodGenInvalidatesUTD() {
|
fun testPodInstallInvalidatesUTD() {
|
||||||
with(project.gradleBuildScript()) {
|
with(project.gradleBuildScript()) {
|
||||||
addPod("AFNetworking")
|
addPod("AFNetworking")
|
||||||
}
|
}
|
||||||
|
|
||||||
hooks.addHook {
|
hooks.addHook {
|
||||||
assertTasksExecuted(defaultPodGenTaskName)
|
assertTasksExecuted(defaultPodInstallSyntheticTaskName)
|
||||||
assertTrue { fileInWorkingDir("build/cocoapods/synthetic/IOS/Pods/AFNetworking").deleteRecursively() }
|
assertTrue { fileInWorkingDir("build/cocoapods/synthetic/ios/Pods/AFNetworking").deleteRecursively() }
|
||||||
}
|
}
|
||||||
project.testSynthetic(defaultPodGenTaskName)
|
project.testSynthetic(defaultPodInstallSyntheticTaskName)
|
||||||
|
|
||||||
hooks.rewriteHooks {
|
hooks.rewriteHooks {
|
||||||
assertTasksExecuted(defaultPodGenTaskName)
|
assertTasksExecuted(defaultPodInstallSyntheticTaskName)
|
||||||
}
|
}
|
||||||
project.testSynthetic(defaultPodGenTaskName)
|
project.testSynthetic(defaultPodInstallSyntheticTaskName)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -499,7 +524,7 @@ class CocoaPodsIT : BaseGradleIT() {
|
|||||||
|
|
||||||
val anotherTarget = "MacosX64"
|
val anotherTarget = "MacosX64"
|
||||||
val anotherSdk = "macosx"
|
val anotherSdk = "macosx"
|
||||||
val anotherFamily = "OSX"
|
val anotherFamily = "macos"
|
||||||
with(project.gradleBuildScript()) {
|
with(project.gradleBuildScript()) {
|
||||||
appendToKotlinBlock(anotherTarget.replaceFirstChar { it.lowercase(Locale.getDefault()) } + "()")
|
appendToKotlinBlock(anotherTarget.replaceFirstChar { it.lowercase(Locale.getDefault()) } + "()")
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-6
@@ -10,22 +10,17 @@ import org.gradle.api.Action
|
|||||||
import org.gradle.api.Named
|
import org.gradle.api.Named
|
||||||
import org.gradle.api.NamedDomainObjectSet
|
import org.gradle.api.NamedDomainObjectSet
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.provider.Provider
|
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency.PodLocation.*
|
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.cocoapods.KotlinCocoapodsPlugin.Companion.POD_FRAMEWORK_PREFIX
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
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.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.io.File
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@Suppress("unused") // Public API
|
||||||
abstract class CocoapodsExtension @Inject constructor(private val project: Project) {
|
abstract class CocoapodsExtension @Inject constructor(private val project: Project) {
|
||||||
/**
|
/**
|
||||||
* Configure version of the pod
|
* Configure version of the pod
|
||||||
|
|||||||
+53
-34
@@ -62,7 +62,7 @@ internal class CocoapodsBuildDirs(val project: Project) {
|
|||||||
val synthetic: File
|
val synthetic: File
|
||||||
get() = root.resolve("synthetic")
|
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")
|
val publish: File = root.resolve("publish")
|
||||||
|
|
||||||
@@ -72,11 +72,20 @@ internal class CocoapodsBuildDirs(val project: Project) {
|
|||||||
|
|
||||||
internal fun String.asValidFrameworkName() = replace('-', '_')
|
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
|
private val Family.toPodGenTaskName: String
|
||||||
get() = lowerCamelCaseName(
|
get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_GEN_TASK_NAME, platformLiteral)
|
||||||
KotlinCocoapodsPlugin.POD_GEN_TASK_NAME,
|
|
||||||
name
|
private val Family.toPodInstallSyntheticTaskName: String
|
||||||
)
|
get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_INSTALL_TASK_NAME, "synthetic", platformLiteral)
|
||||||
|
|
||||||
private fun String.toSetupBuildTaskName(pod: CocoapodsDependency): String = lowerCamelCaseName(
|
private fun String.toSetupBuildTaskName(pod: CocoapodsDependency): String = lowerCamelCaseName(
|
||||||
KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME,
|
KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME,
|
||||||
@@ -451,23 +460,25 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
project: Project,
|
project: Project,
|
||||||
cocoapodsExtension: CocoapodsExtension
|
cocoapodsExtension: CocoapodsExtension
|
||||||
) {
|
) {
|
||||||
val podspecTaskProvider = project.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java)
|
val podspecTaskProvider = project.tasks.named<PodspecTask>(POD_SPEC_TASK_NAME)
|
||||||
project.tasks.register(POD_INSTALL_TASK_NAME, PodInstallTask::class.java) {
|
project.registerTask<PodInstallTask>(POD_INSTALL_TASK_NAME) { task ->
|
||||||
it.group = TASK_GROUP
|
task.group = TASK_GROUP
|
||||||
it.description = "Invokes `pod install` call within Podfile location directory"
|
task.description = "Invokes `pod install` call within Podfile location directory"
|
||||||
it.podfile.set(cocoapodsExtension.podfile)
|
task.podfile.set(project.provider { cocoapodsExtension.podfile })
|
||||||
it.podspec.set(podspecTaskProvider.map { podspecTask -> podspecTask.outputFile })
|
task.podspec.set(podspecTaskProvider.map { it.outputFile })
|
||||||
it.frameworkName = cocoapodsExtension.podFrameworkName
|
task.frameworkName.set(cocoapodsExtension.podFrameworkName)
|
||||||
it.dependsOn(podspecTaskProvider)
|
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
|
project: Project, kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension
|
||||||
) {
|
) {
|
||||||
val families = mutableSetOf<Family>()
|
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 ->
|
kotlinExtension.supportedTargets().all { target ->
|
||||||
val family = target.konanTarget.family
|
val family = target.konanTarget.family
|
||||||
if (family in families) {
|
if (family in families) {
|
||||||
@@ -483,15 +494,23 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
else -> error("Unknown cocoapods platform: $family")
|
else -> error("Unknown cocoapods platform: $family")
|
||||||
}
|
}
|
||||||
|
|
||||||
project.tasks.register(family.toPodGenTaskName, PodGenTask::class.java) {
|
val podGenTask = project.registerTask<PodGenTask>(family.toPodGenTaskName) { task ->
|
||||||
it.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
|
task.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies"
|
||||||
it.podspec = podspecTaskProvider.map { task -> task.outputFile }
|
task.podspec = podspecTaskProvider.map { it.outputFile }
|
||||||
it.podName = project.provider { cocoapodsExtension.name }
|
task.podName = project.provider { cocoapodsExtension.name }
|
||||||
it.useLibraries = project.provider { cocoapodsExtension.useLibraries }
|
task.useLibraries = project.provider { cocoapodsExtension.useLibraries }
|
||||||
it.specRepos = project.provider { cocoapodsExtension.specRepos }
|
task.specRepos = project.provider { cocoapodsExtension.specRepos }
|
||||||
it.family = family
|
task.family = family
|
||||||
it.platformSettings = platformSettings
|
task.platformSettings = platformSettings
|
||||||
it.pods.set(cocoapodsExtension.pods)
|
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
|
sdks += sdk
|
||||||
|
|
||||||
val podGenTaskProvider = project.tasks.named(target.konanTarget.family.toPodGenTaskName, PodGenTask::class.java)
|
val podInstallTask = project.tasks.named<PodInstallSyntheticTask>(target.konanTarget.family.toPodInstallSyntheticTaskName)
|
||||||
project.tasks.register(sdk.toSetupBuildTaskName(pod), PodSetupBuildTask::class.java) {
|
project.registerTask<PodSetupBuildTask>(sdk.toSetupBuildTaskName(pod)) { task ->
|
||||||
it.group = TASK_GROUP
|
task.group = TASK_GROUP
|
||||||
it.description = "Collect environment variables from .xcworkspace file"
|
task.description = "Collect environment variables from .xcworkspace file"
|
||||||
it.pod = project.provider { pod }
|
task.pod = project.provider { pod }
|
||||||
it.sdk = project.provider { sdk }
|
task.sdk = project.provider { sdk }
|
||||||
it.podsXcodeProjDir = podGenTaskProvider.map { podGen -> podGen.podsXcodeProjDir.get() }
|
task.podsXcodeProjDir = podInstallTask.map { it.podsXcodeProjDirProvider.get() }
|
||||||
it.frameworkName = cocoapodsExtension.podFrameworkName
|
task.frameworkName = cocoapodsExtension.podFrameworkName
|
||||||
it.dependsOn(podGenTaskProvider)
|
task.dependsOn(podInstallTask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -772,7 +791,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
|||||||
injectPodspecExtensionToArtifacts(project, kotlinArtifactsExtension, cocoapodsExtension)
|
injectPodspecExtensionToArtifacts(project, kotlinArtifactsExtension, cocoapodsExtension)
|
||||||
registerPodspecTask(project, cocoapodsExtension)
|
registerPodspecTask(project, cocoapodsExtension)
|
||||||
|
|
||||||
registerPodGenTask(project, kotlinExtension, cocoapodsExtension)
|
registerSyntheticPodTasks(project, kotlinExtension, cocoapodsExtension)
|
||||||
registerPodInstallTask(project, cocoapodsExtension)
|
registerPodInstallTask(project, cocoapodsExtension)
|
||||||
registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
||||||
registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension)
|
||||||
|
|||||||
+1
-3
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.native.cocoapods
|
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.CocoapodsDependency
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.SpecRepos
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.SpecRepos
|
||||||
|
|
||||||
@@ -20,8 +19,7 @@ class MissingSpecReposMessage(override val missingInfo: SpecRepos) : MissingInfo
|
|||||||
}
|
}
|
||||||
|
|
||||||
class MissingCocoapodsMessage(
|
class MissingCocoapodsMessage(
|
||||||
override val missingInfo: CocoapodsDependency,
|
override val missingInfo: CocoapodsDependency
|
||||||
private val project: Project
|
|
||||||
) : MissingInfoMessage<CocoapodsDependency> {
|
) : MissingInfoMessage<CocoapodsDependency> {
|
||||||
override val missingMessage: String
|
override val missingMessage: String
|
||||||
get() = "pod '${missingInfo.name}'${missingInfo.source?.let { ", ${it.getPodSourcePath()}" }.orEmpty()}"
|
get() = "pod '${missingInfo.name}'${missingInfo.source?.let { ", ${it.getPodSourcePath()}" }.orEmpty()}"
|
||||||
|
|||||||
+161
-189
@@ -8,46 +8,30 @@
|
|||||||
package org.jetbrains.kotlin.gradle.targets.native.tasks
|
package org.jetbrains.kotlin.gradle.targets.native.tasks
|
||||||
|
|
||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.api.file.FileCollection
|
import org.gradle.api.file.FileCollection
|
||||||
import org.gradle.api.file.FileTree
|
import org.gradle.api.file.FileTree
|
||||||
import org.gradle.api.provider.ListProperty
|
import org.gradle.api.provider.ListProperty
|
||||||
|
import org.gradle.api.provider.Property
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
import org.gradle.api.tasks.Optional
|
import org.gradle.api.tasks.Optional
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.*
|
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.CocoapodsExtension.CocoapodsDependency.PodLocation.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
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.MissingCocoapodsMessage
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.cocoapods.MissingSpecReposMessage
|
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.gradle.utils.runCommand
|
||||||
import org.jetbrains.kotlin.konan.target.Family
|
import org.jetbrains.kotlin.konan.target.Family
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.io.Reader
|
import java.io.Reader
|
||||||
import java.util.*
|
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
|
val CocoapodsDependency.schemeName: String
|
||||||
get() = name.split("/")[0]
|
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() {
|
open class CocoapodsTask : DefaultTask() {
|
||||||
init {
|
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 {
|
init {
|
||||||
onlyIf { podfile.isPresent }
|
onlyIf { podfile.isPresent }
|
||||||
}
|
}
|
||||||
|
|
||||||
@get:Internal
|
|
||||||
internal lateinit var frameworkName: Provider<String>
|
|
||||||
|
|
||||||
@get:Optional
|
@get:Optional
|
||||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
|
||||||
@get:InputFile
|
@get:InputFile
|
||||||
internal val podfile = project.objects.property(File::class.java)
|
abstract val podfile: Property<File?>
|
||||||
|
|
||||||
@get:Optional
|
protected val workingDir: Provider<File> = podfile.map { file: File? ->
|
||||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
requireNotNull(file) { "Task outputs shouldn't be queried if it's skipped" }.parentFile
|
||||||
@get:InputFile
|
}
|
||||||
internal val podspec = project.objects.property(File::class.java)
|
|
||||||
|
|
||||||
@get:Optional
|
|
||||||
@get:OutputDirectory
|
@get:OutputDirectory
|
||||||
internal val podsXcodeProjDirProvider: Provider<File>?
|
internal val podsDir: Provider<File> = workingDir.map { it.resolve("Pods") }
|
||||||
get() = podfile.orNull?.let {
|
|
||||||
project.provider { it.parentFile.resolve("Pods").resolve("Pods.xcodeproj") }
|
@get:Internal
|
||||||
}
|
internal val podsXcodeProjDirProvider: Provider<File> = podsDir.map { it.resolve("Pods.xcodeproj") }
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun doPodInstall() {
|
open fun doPodInstall() {
|
||||||
podfile.orNull?.parentFile?.also { podfileDir ->
|
val podInstallCommand = listOf("pod", "install")
|
||||||
val podInstallCommand = listOf("pod", "install")
|
|
||||||
|
|
||||||
runCommand(podInstallCommand,
|
runCommand(podInstallCommand,
|
||||||
logger,
|
logger,
|
||||||
errorHandler = { returnCode, output, _ ->
|
errorHandler = ::handleError,
|
||||||
CocoapodsErrorHandlingUtil.handlePodInstallError(
|
exceptionHandler = { e: IOException ->
|
||||||
podInstallCommand.joinToString(" "),
|
CocoapodsErrorHandlingUtil.handle(e, podInstallCommand)
|
||||||
returnCode,
|
},
|
||||||
output,
|
processConfiguration = {
|
||||||
project,
|
directory(workingDir.get())
|
||||||
frameworkName.get()
|
})
|
||||||
)
|
|
||||||
},
|
|
||||||
exceptionHandler = { e: IOException ->
|
|
||||||
CocoapodsErrorHandlingUtil.handle(e, podInstallCommand)
|
|
||||||
},
|
|
||||||
processConfiguration = {
|
|
||||||
directory(podfileDir)
|
|
||||||
})
|
|
||||||
|
|
||||||
with(podsXcodeProjDirProvider) {
|
with(podsXcodeProjDirProvider.get()) {
|
||||||
check(this != null && get().exists() && get().isDirectory) {
|
check(exists() && isDirectory) {
|
||||||
"The directory 'Pods/Pods.xcodeproj' was not created as a result of the `pod install` call."
|
"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
|
@get:InputFile
|
||||||
internal lateinit var podspec: Provider<File>
|
internal abstract val podspec: Property<File>
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
internal lateinit var podName: Provider<String>
|
internal abstract val podName: Property<String>
|
||||||
|
|
||||||
@get:Input
|
@get:Input
|
||||||
internal lateinit var useLibraries: Provider<Boolean>
|
internal abstract val useLibraries: Property<Boolean>
|
||||||
|
|
||||||
@get:Internal
|
@get:Input
|
||||||
lateinit var family: Family
|
internal abstract val family: Property<Family>
|
||||||
|
|
||||||
@get:Nested
|
@get:Nested
|
||||||
internal lateinit var platformSettings: PodspecPlatformSettings
|
internal abstract val platformSettings: Property<PodspecPlatformSettings>
|
||||||
|
|
||||||
@get:Nested
|
@get:Nested
|
||||||
internal lateinit var specRepos: Provider<SpecRepos>
|
internal abstract val specRepos: Property<SpecRepos>
|
||||||
|
|
||||||
@get:Nested
|
@get:Nested
|
||||||
abstract val pods: ListProperty<CocoapodsDependency>
|
internal abstract val pods: ListProperty<CocoapodsDependency>
|
||||||
|
|
||||||
@get:OutputDirectory
|
@get:OutputFile
|
||||||
internal val outputDir: Provider<File> = project.provider { project.cocoapodsBuildDirs.synthetic(family) }
|
val podfile: Provider<File> = family.map { project.cocoapodsBuildDirs.synthetic(it).resolve("Podfile") }
|
||||||
|
|
||||||
@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") }
|
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
fun generate() {
|
fun generate() {
|
||||||
val syntheticDir = outputDir.get().apply { mkdirs() }
|
|
||||||
val specRepos = specRepos.get().getAll()
|
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()
|
val podfile = this.podfile.get()
|
||||||
podfile.createNewFile()
|
podfile.createNewFile()
|
||||||
|
|
||||||
val podfileContent = getPodfileContent(specRepos, family.platformLiteral)
|
val podfileContent = getPodfileContent(specRepos, family.get().platformLiteral)
|
||||||
podfile.writeText(podfileContent)
|
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) =
|
private fun getPodfileContent(specRepos: Collection<String>, xcodeTarget: String) =
|
||||||
@@ -215,11 +259,12 @@ abstract class PodGenTask : CocoapodsTask() {
|
|||||||
if (useLibraries.get().not()) {
|
if (useLibraries.get().not()) {
|
||||||
appendLine("\tuse_frameworks!")
|
appendLine("\tuse_frameworks!")
|
||||||
}
|
}
|
||||||
val deploymentTarget = platformSettings.deploymentTarget
|
val settings = platformSettings.get()
|
||||||
|
val deploymentTarget = settings.deploymentTarget
|
||||||
if (deploymentTarget != null) {
|
if (deploymentTarget != null) {
|
||||||
appendLine("\tplatform :${platformSettings.name}, '$deploymentTarget'")
|
appendLine("\tplatform :${settings.name}, '$deploymentTarget'")
|
||||||
} else {
|
} else {
|
||||||
appendLine("\tplatform :${platformSettings.name}")
|
appendLine("\tplatform :${settings.name}")
|
||||||
}
|
}
|
||||||
pods.get().mapNotNull {
|
pods.get().mapNotNull {
|
||||||
buildString {
|
buildString {
|
||||||
@@ -251,6 +296,7 @@ abstract class PodGenTask : CocoapodsTask() {
|
|||||||
end
|
end
|
||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
)
|
)
|
||||||
|
appendLine()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,6 +449,7 @@ data class PodBuildSettingsProperties(
|
|||||||
|
|
||||||
fun readSettingsFromReader(reader: Reader): PodBuildSettingsProperties {
|
fun readSettingsFromReader(reader: Reader): PodBuildSettingsProperties {
|
||||||
with(Properties()) {
|
with(Properties()) {
|
||||||
|
@Suppress("BlockingMethodInNonBlockingContext") // It's ok to do blocking call here
|
||||||
load(reader)
|
load(reader)
|
||||||
return PodBuildSettingsProperties(
|
return PodBuildSettingsProperties(
|
||||||
readProperty(BUILD_DIR),
|
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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
-2
@@ -221,8 +221,6 @@ open class PodspecTask : DefaultTask() {
|
|||||||
else project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podfile != null
|
else project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podfile != null
|
||||||
|| (project.parent?.let { hasPodfileOwnOrParent(it) } ?: false)
|
|| (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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user