[Gradle][tests] Install cocoapods in MPP plugin tests

This commit is contained in:
Ilya Matveev
2021-04-19 21:53:21 +07:00
committed by TeamCityServer
parent 2d0dbf9729
commit aa9ff3d6bb
2 changed files with 128 additions and 2 deletions
@@ -207,6 +207,11 @@ tasks.withType<Test> {
systemProperty("kotlinVersion", rootProject.extra["kotlinVersion"] as String) systemProperty("kotlinVersion", rootProject.extra["kotlinVersion"] as String)
systemProperty("runnerGradleVersion", gradle.gradleVersion) systemProperty("runnerGradleVersion", gradle.gradleVersion)
val installCocoapods = project.findProperty("installCocoapods") as String?
if (installCocoapods != null) {
systemProperty("installCocoapods", installCocoapods)
}
val jdk9Provider = project.getToolchainLauncherFor(JdkMajorVersion.JDK_9).map { it.metadata.installationPath.asFile.absolutePath } val jdk9Provider = project.getToolchainLauncherFor(JdkMajorVersion.JDK_9).map { it.metadata.installationPath.asFile.absolutePath }
val jdk10Provider = project.getToolchainLauncherFor(JdkMajorVersion.JDK_10).map { it.metadata.installationPath.asFile.absolutePath } val jdk10Provider = project.getToolchainLauncherFor(JdkMajorVersion.JDK_10).map { it.metadata.installationPath.asFile.absolutePath }
val jdk11Provider = project.getToolchainLauncherFor(JdkMajorVersion.JDK_11).map { it.metadata.installationPath.asFile.absolutePath } val jdk11Provider = project.getToolchainLauncherFor(JdkMajorVersion.JDK_11).map { it.metadata.installationPath.asFile.absolutePath }
@@ -20,11 +20,14 @@ import org.jetbrains.kotlin.gradle.transformProjectWithPluginsDsl
import org.jetbrains.kotlin.gradle.util.modify import org.jetbrains.kotlin.gradle.util.modify
import org.jetbrains.kotlin.gradle.util.runProcess import org.jetbrains.kotlin.gradle.util.runProcess
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
import org.junit.AfterClass
import org.junit.Assume.assumeTrue import org.junit.Assume.assumeTrue
import org.junit.Before import org.junit.Before
import org.junit.BeforeClass import org.junit.BeforeClass
import org.junit.Test import org.junit.Test
import java.io.File import java.io.File
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertTrue import kotlin.test.assertTrue
@@ -46,6 +49,9 @@ class CocoaPodsIT : BaseGradleIT() {
// We use Kotlin DSL. Earlier Gradle versions fail at accessors codegen. // We use Kotlin DSL. Earlier Gradle versions fail at accessors codegen.
private val gradleVersion = GradleVersionRequired.FOR_MPP_SUPPORT private val gradleVersion = GradleVersionRequired.FOR_MPP_SUPPORT
override fun defaultBuildOptions(): BuildOptions =
super.defaultBuildOptions().copy(customEnvironmentVariables = mapOf("PATH" to getPathEnv()))
val PODFILE_IMPORT_DIRECTIVE_PLACEHOLDER = "<import_mode_directive>" val PODFILE_IMPORT_DIRECTIVE_PLACEHOLDER = "<import_mode_directive>"
private val cocoapodsSingleKtPod = "native-cocoapods-single" private val cocoapodsSingleKtPod = "native-cocoapods-single"
@@ -764,7 +770,8 @@ class CocoaPodsIT : BaseGradleIT() {
hooks.addHook { hooks.addHook {
// Check that a built universal framework includes both device and simulator architectures. // Check that a built universal framework includes both device and simulator architectures.
val framework = fileInWorkingDir("build/cocoapods/framework/cocoapods.framework/cocoapods") val framework = fileInWorkingDir("build/cocoapods/framework/cocoapods.framework/cocoapods")
with(runProcess(listOf("file", framework.absolutePath), projectDir)) { val env = mapOf("PATH" to getPathEnv())
with(runProcess(listOf("file", framework.absolutePath), projectDir, environmentVariables = env)) {
assertTrue(isSuccessful) assertTrue(isSuccessful)
assertTrue(output.contains("\\(for architecture x86_64\\):\\s+current ar archive".toRegex())) assertTrue(output.contains("\\(for architecture x86_64\\):\\s+current ar archive".toRegex()))
assertTrue(output.contains("\\(for architecture arm64\\):\\s+current ar archive".toRegex())) assertTrue(output.contains("\\(for architecture arm64\\):\\s+current ar archive".toRegex()))
@@ -943,7 +950,6 @@ class CocoaPodsIT : BaseGradleIT() {
taskName: String, taskName: String,
vararg args: String vararg args: String
) { ) {
assumeTrue(KotlinCocoapodsPlugin.isAvailableToProduceSynthetic)
testWithWrapper(taskName, *args) testWithWrapper(taskName, *args)
} }
@@ -1214,6 +1220,7 @@ class CocoaPodsIT : BaseGradleIT() {
) { ) {
val process = ProcessBuilder(command, *args).apply { val process = ProcessBuilder(command, *args).apply {
directory(workingDir) directory(workingDir)
environment()["PATH"] = getPathEnv()
if (inheritIO) { if (inheritIO) {
inheritIO() inheritIO()
} }
@@ -1391,5 +1398,119 @@ class CocoaPodsIT : BaseGradleIT() {
fun assumeItsMac() { fun assumeItsMac() {
assumeTrue(HostManager.hostIsMac) assumeTrue(HostManager.hostIsMac)
} }
@BeforeClass
@JvmStatic
fun installPodGen() {
if (cocoapodsInstallationRequired) {
if (cocoapodsInstallationAllowed) {
WorkaroundForXcode12_3.apply()
gem("install", "--user-install", "cocoapods", "cocoapods-generate")
cocoapodsInstallationPath = File(getGemUserInstallationPath()).resolve("bin")
} else {
fail(
"""
Running CocoaPods integration tests requires cocoapods and cocoapods-generate to be installed.
Please install them manually:
gem install cocoapods cocoapods-generate
Or re-run the tests with the 'installCocoapods=true' Gradle property.
""".trimIndent()
)
}
}
}
@AfterClass
@JvmStatic
fun uninstallPodGen() {
// Do not remove CocoaPods if we didn't install it.
if (cocoapodsInstallationRequired && cocoapodsInstallationAllowed) {
val packagesToRemove = gem("list", "--no-versions").lineSequence().filter {
it.startsWith("cocoapods")
}.toList()
try {
gem("uninstall", "--user-install", "-x", *packagesToRemove.toTypedArray())
} finally {
WorkaroundForXcode12_3.dispose()
}
}
}
private val cocoapodsInstallationRequired: Boolean = !isCocoapodsInstalled()
private val cocoapodsInstallationAllowed: Boolean = System.getProperty("installCocoapods").toBoolean()
private var cocoapodsInstallationPath: File? = null
private fun getPathEnv(): String {
val oldPath = System.getenv("PATH")
return cocoapodsInstallationPath?.let {
it.absolutePath + File.pathSeparator + oldPath
} ?: oldPath
}
private fun isCocoapodsInstalled(): Boolean {
val installed = gem("list", "--no-versions").lines()
return "cocoapods-generate" in installed && "cocoapods" in installed
}
private fun getGemUserInstallationPath(): String {
val installationDirLine = gem("environment").lineSequence().first {
it.contains("USER INSTALLATION DIRECTORY:")
}
return installationDirLine.substringAfter("USER INSTALLATION DIRECTORY:").trim()
}
private fun gem(vararg args: String): String {
val process = ProcessBuilder("gem", *args).start()
val finished = process.waitFor(30, TimeUnit.MINUTES)
val output = process.inputStream.use { it.reader().readText() }
check(finished && process.exitValue() == 0) {
if (!finished) {
process.destroyForcibly()
}
val argsString = args.joinToString(separator = " ")
val errors = process.errorStream.use { it.reader().readText() }
println("'gem $argsString' stdout:\n$errors")
println("'gem $argsString' stderr:\n$output")
if (finished) {
"Process 'gem $argsString' exited with error code ${process.exitValue()}. See log for details."
} else {
"Process 'gem $argsString ' killed by timeout. See log for details"
}
}
return output
}
// Workaround the issue with Ruby paths for Xcode 12.3.
// See: https://github.com/CocoaPods/CocoaPods/issues/10286#issuecomment-750403566
private object WorkaroundForXcode12_3 {
private val xcodeRubyRoot = File(
"/Applications/Xcode.app/Contents/Developer/Platforms/" +
"MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library" +
"/Frameworks/Ruby.framework/Versions/2.6/usr/include/ruby-2.6.0"
)
private val original = xcodeRubyRoot.resolve("universal-darwin20").toPath()
private var link: Path? = null
fun apply() {
val linkFile = xcodeRubyRoot.resolve("universal-darwin19")
if (!linkFile.exists() && Files.exists(original)) {
Files.createSymbolicLink(linkFile.toPath(), original)
linkFile.deleteOnExit()
link = linkFile.toPath()
}
}
fun dispose() {
link?.let { link ->
// We created the link, so now we should delete it.
if (Files.isSymbolicLink(link) && Files.readSymbolicLink(link) == original) {
Files.delete(link)
}
}
}
}
} }
} }