[MPP] Run pod install through env to prevent ProcessBuilder from missing
PATH modifications ^KT-60394
This commit is contained in:
committed by
Space Team
parent
78fa93d75c
commit
6edfda0204
+80
-6
@@ -554,18 +554,18 @@ class CocoaPodsIT : KGPBaseTest() {
|
||||
@DisplayName("Cinterop commonization on")
|
||||
@GradleTest
|
||||
fun testCinteropCommonizationOn(gradleVersion: GradleVersion) {
|
||||
testCinteropCommonizationExecutes(gradleVersion, buildArguments=arrayOf("-Pkotlin.mpp.enableCInteropCommonization=true"))
|
||||
testCinteropCommonizationExecutes(gradleVersion, buildArguments = arrayOf("-Pkotlin.mpp.enableCInteropCommonization=true"))
|
||||
}
|
||||
|
||||
@DisplayName("Cinterop commonization unspecified")
|
||||
@GradleTest
|
||||
fun testCinteropCommonizationUnspecified(gradleVersion: GradleVersion) {
|
||||
testCinteropCommonizationExecutes(gradleVersion, buildArguments=emptyArray())
|
||||
testCinteropCommonizationExecutes(gradleVersion, buildArguments = emptyArray())
|
||||
}
|
||||
|
||||
private fun testCinteropCommonizationExecutes(
|
||||
gradleVersion: GradleVersion,
|
||||
buildArguments: Array<String>
|
||||
buildArguments: Array<String>,
|
||||
) {
|
||||
nativeProjectWithCocoapodsAndIosAppPodFile(cocoapodsCommonizationProjectName, gradleVersion) {
|
||||
buildWithCocoapodsWrapper(":commonize", *buildArguments) {
|
||||
@@ -875,18 +875,92 @@ class CocoaPodsIT : KGPBaseTest() {
|
||||
}
|
||||
}
|
||||
|
||||
private val maybeCocoaPodsIsNotInstalledError = "Possible reason: CocoaPods is not installed"
|
||||
private val maybePodfileIsIncorrectError = "Please, check that podfile contains following lines in header"
|
||||
|
||||
@DisplayName("Pod install emits correct error when pod binary is not present in PATH")
|
||||
@GradleTest
|
||||
fun testPodInstallErrorWithoutCocoaPodsInPATH(gradleVersion: GradleVersion) {
|
||||
val pathWithoutCocoapods = "/bin:/usr/bin"
|
||||
nativeProjectWithCocoapodsAndIosAppPodFile(
|
||||
gradleVersion = gradleVersion,
|
||||
environmentVariables = EnvironmentalVariables(
|
||||
mapOf("PATH" to pathWithoutCocoapods)
|
||||
)
|
||||
) {
|
||||
buildGradleKts.addCocoapodsBlock(
|
||||
"""
|
||||
podfile = project.file("ios-app/Podfile")
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
buildAndFailWithCocoapodsWrapper(
|
||||
podInstallTaskName,
|
||||
) {
|
||||
assertOutputDoesNotContain(maybePodfileIsIncorrectError)
|
||||
assertOutputContains(maybeCocoaPodsIsNotInstalledError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("Pod install emits other errors when pod install runs, but fails later")
|
||||
@GradleTest
|
||||
fun testOtherPodInstallErrors(gradleVersion: GradleVersion) {
|
||||
nativeProjectWithCocoapodsAndIosAppPodFile(
|
||||
gradleVersion = gradleVersion
|
||||
) {
|
||||
buildGradleKts.addCocoapodsBlock(
|
||||
"""
|
||||
podfile = project.file("ios-app/Podfile")
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
projectPath.resolve("ios-app/Podfile").append(
|
||||
"""
|
||||
raise "Dead"
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
buildAndFailWithCocoapodsWrapper(
|
||||
podInstallTaskName,
|
||||
) {
|
||||
assertOutputContains(maybePodfileIsIncorrectError)
|
||||
assertOutputDoesNotContain(maybeCocoaPodsIsNotInstalledError)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestProject.buildAndFailWithCocoapodsWrapper(
|
||||
vararg buildArguments: String,
|
||||
assertions: BuildResult.() -> Unit = {},
|
||||
) = buildWithCocoapodsWrapperUsing { buildOptions ->
|
||||
buildAndFail(
|
||||
*buildArguments,
|
||||
buildOptions = buildOptions,
|
||||
assertions = assertions,
|
||||
)
|
||||
}
|
||||
|
||||
private fun TestProject.buildWithCocoapodsWrapper(
|
||||
vararg buildArguments: String,
|
||||
assertions: BuildResult.() -> Unit = {},
|
||||
) = buildWithCocoapodsWrapperUsing { buildOptions ->
|
||||
build(
|
||||
*buildArguments,
|
||||
buildOptions = buildOptions,
|
||||
assertions = assertions,
|
||||
)
|
||||
}
|
||||
|
||||
private fun TestProject.buildWithCocoapodsWrapperUsing(
|
||||
builder: TestProject.(BuildOptions) -> Unit,
|
||||
) {
|
||||
val buildOptions = this.buildOptions.copy(
|
||||
nativeOptions = this.buildOptions.nativeOptions.copy(
|
||||
cocoapodsGenerateWrapper = true
|
||||
)
|
||||
)
|
||||
build(*buildArguments, buildOptions = buildOptions) {
|
||||
assertions()
|
||||
}
|
||||
builder(buildOptions)
|
||||
}
|
||||
|
||||
private fun TestProject.addPodToPodfile(iosAppLocation: String, pod: String) {
|
||||
|
||||
+1
-1
@@ -256,7 +256,7 @@ private fun TestProject.manualPodInstall(taskPrefix: String, iosAppPath: Path) {
|
||||
build("$taskPrefix:$DUMMY_FRAMEWORK_TASK_NAME", buildOptions = buildOptions)
|
||||
|
||||
runProcess(
|
||||
cmd = listOf("pod", "install"),
|
||||
cmd = listOf("env", "pod", "install"),
|
||||
environmentVariables = environmentVariables.environmentalVariables,
|
||||
workingDir = iosAppPath.toFile(),
|
||||
)
|
||||
|
||||
+2
-1
@@ -196,13 +196,14 @@ fun KGPBaseTest.nativeProjectWithCocoapodsAndIosAppPodFile(
|
||||
projectName: String = templateProjectName,
|
||||
gradleVersion: GradleVersion,
|
||||
buildOptions: BuildOptions = this.defaultBuildOptions,
|
||||
environmentVariables: EnvironmentalVariables = EnvironmentalVariables(cocoaPodsEnvironmentVariables()),
|
||||
projectBlock: TestProject.() -> Unit = {},
|
||||
) {
|
||||
nativeProject(
|
||||
projectName,
|
||||
gradleVersion,
|
||||
buildOptions = buildOptions,
|
||||
environmentVariables = EnvironmentalVariables(cocoaPodsEnvironmentVariables())
|
||||
environmentVariables = environmentVariables,
|
||||
) {
|
||||
preparePodfile("ios-app", ImportMode.FRAMEWORKS)
|
||||
projectBlock()
|
||||
|
||||
+15
-18
@@ -42,14 +42,14 @@ abstract class AbstractPodInstallTask : CocoapodsTask() {
|
||||
|
||||
@TaskAction
|
||||
open fun doPodInstall() {
|
||||
val podInstallCommand = listOf("pod", "install")
|
||||
// env is used here to work around the JVM PATH caching when spawning a child process with custom environment, i.e. LC_ALL
|
||||
// The caching causes the ProcessBuilder to ignore changes in the PATH that may occur on incremental runs of the Gradle daemon
|
||||
// KT-60394
|
||||
val podInstallCommand = listOf("env", "pod", "install")
|
||||
|
||||
runCommand(podInstallCommand,
|
||||
logger,
|
||||
errorHandler = ::handleError,
|
||||
exceptionHandler = { e: IOException ->
|
||||
CocoapodsErrorHandlingUtil.handle(e, podInstallCommand)
|
||||
},
|
||||
errorHandler = { retCode, output, process -> sharedHandleError(podInstallCommand, retCode, output, process) },
|
||||
processConfiguration = {
|
||||
directory(workingDir.get())
|
||||
// CocoaPods requires to be run with Unicode external encoding
|
||||
@@ -63,17 +63,14 @@ abstract class AbstractPodInstallTask : CocoapodsTask() {
|
||||
}
|
||||
}
|
||||
|
||||
abstract fun handleError(retCode: Int, error: String, process: Process): String?
|
||||
}
|
||||
|
||||
private object CocoapodsErrorHandlingUtil {
|
||||
fun handle(e: IOException, command: List<String>) {
|
||||
if (e.message?.contains("No such file or directory") == true) {
|
||||
val message = """
|
||||
|'${command.take(2).joinToString(" ")}' command failed with an exception:
|
||||
| ${e.message}
|
||||
private fun sharedHandleError(podInstallCommand: List<String>, retCode: Int, error: String, process: Process): String? {
|
||||
return if (error.contains("No such file or directory")) {
|
||||
val command = podInstallCommand.joinToString(" ")
|
||||
"""
|
||||
|'$command' command failed with an exception:
|
||||
| $error
|
||||
|
|
||||
| Full command: ${command.joinToString(" ")}
|
||||
| Full command: $command
|
||||
|
|
||||
| Possible reason: CocoaPods is not installed
|
||||
| Please check that CocoaPods v1.10 or above is installed.
|
||||
@@ -83,10 +80,10 @@ private object CocoapodsErrorHandlingUtil {
|
||||
| To install CocoaPods execute 'sudo gem install cocoapods'
|
||||
|
|
||||
""".trimMargin()
|
||||
throw IllegalStateException(message)
|
||||
} else {
|
||||
throw e
|
||||
handleError(retCode, error, process)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
abstract fun handleError(retCode: Int, error: String, process: Process): String?
|
||||
}
|
||||
+3
-14
@@ -13,22 +13,11 @@ internal fun runCommand(
|
||||
command: List<String>,
|
||||
logger: Logger? = null,
|
||||
errorHandler: ((retCode: Int, output: String, process: Process) -> String?)? = null,
|
||||
exceptionHandler: ((ex: IOException) -> Unit)? = null,
|
||||
processConfiguration: ProcessBuilder.() -> Unit = { }
|
||||
): String {
|
||||
var process: Process? = null
|
||||
try {
|
||||
process = ProcessBuilder(command)
|
||||
.apply {
|
||||
this.processConfiguration()
|
||||
}.start()
|
||||
} catch (e: IOException) {
|
||||
if (exceptionHandler != null) exceptionHandler(e) else throw e
|
||||
}
|
||||
|
||||
if (process == null) {
|
||||
throw IllegalStateException("Failed to run command ${command.joinToString(" ")}")
|
||||
}
|
||||
val process = ProcessBuilder(command).apply {
|
||||
this.processConfiguration()
|
||||
}.start()
|
||||
|
||||
var inputText = ""
|
||||
var errorText = ""
|
||||
|
||||
Reference in New Issue
Block a user