From c638043aeeb33596fbfef40b0361f2dbb39b6364 Mon Sep 17 00:00:00 2001 From: Yaroslav Chernyshev Date: Fri, 19 Jun 2020 17:56:02 +0300 Subject: [PATCH] [Gradle, CocoaPods] Improved CocoaPods Integration features with tests --- .../cocoapods/KotlinCocoaPodsModelResolver.kt | 6 +- .../src/KotlinCocoaPodsModelBuilder.kt | 3 +- idea/resources/META-INF/gradle-java.xml | 1 + idea/resources/META-INF/gradle-java.xml.201 | 1 + .../jetbrains/kotlin/gradle/BaseGradleIT.kt | 24 + .../jetbrains/kotlin/gradle/CocoaPodsIT.kt | 488 +++++++++++++----- .../new-mpp-cocoapods-multiple/.gitignore | 9 + .../build.gradle.kts | 6 +- .../ios-app/Podfile | 10 + .../ios-app/ios-app.xcodeproj/project.pbxproj | 0 .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../ios-app/ios-app/AppDelegate.swift | 0 .../AppIcon.appiconset/Contents.json | 0 .../ios-app/Assets.xcassets/Contents.json | 0 .../Base.lproj/LaunchScreen.storyboard | 0 .../ios-app/Base.lproj/Main.storyboard | 0 .../ios-app/ios-app/Info.plist | 0 .../ios-app/ios-app/ViewController.swift | 13 + .../kotlin-library/build.gradle.kts | 27 + .../kotlin-library/gradle.properties | 2 + .../kotlin-library/src/iosMain/kotlin/a.kt} | 0 .../pod_dependency/pod_dependency.podspec | 0 .../pod_dependency/src/foo.h | 0 .../pod_dependency/src/foo.m | 0 .../second-library/build.gradle.kts | 25 + .../second-library/gradle.properties | 2 + .../second-library/src/iosMain/kotlin/B.kt | 1 + .../settings.gradle | 14 + .../subspec_dependency/src/baz.h | 0 .../subspec_dependency/src/baz.m | 0 .../subspec_dependency.podspec | 0 .../.gitignore | 0 .../new-mpp-cocoapods-single/build.gradle.kts | 25 + .../ios-app/Podfile | 0 .../ios-app/ios-app.xcodeproj/project.pbxproj | 341 ++++++++++++ .../contents.xcworkspacedata} | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../ios-app/ios-app/AppDelegate.swift | 34 ++ .../AppIcon.appiconset/Contents.json | 98 ++++ .../ios-app/Assets.xcassets/Contents.json | 6 + .../Base.lproj/LaunchScreen.storyboard | 25 + .../ios-app/Base.lproj/Main.storyboard | 24 + .../ios-app/ios-app/Info.plist | 45 ++ .../ios-app/ios-app/ViewController.swift | 0 .../kotlin-library/build.gradle.kts | 27 + .../kotlin-library/gradle.properties | 0 .../kotlin-library/src/iosMain/kotlin/A.kt | 10 + .../pod_dependency/pod_dependency.podspec | 11 + .../pod_dependency/src/foo.h | 3 + .../pod_dependency/src/foo.m | 5 + .../settings.gradle | 0 .../subspec_dependency/src/baz.h | 3 + .../subspec_dependency/src/baz.m | 5 + .../subspec_dependency.podspec | 15 + .../native/cocoapods/CocoapodsExtension.kt | 54 +- .../native/cocoapods/KotlinCocoapodsPlugin.kt | 150 ++++-- .../native/tasks/AdvancedCocoapodsTasks.kt | 293 ++++++----- .../targets/native/tasks/CocoapodsTasks.kt | 59 ++- 59 files changed, 1535 insertions(+), 338 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/.gitignore rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods/kotlin-library => new-mpp-cocoapods-multiple}/build.gradle.kts (70%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/Podfile rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app.xcodeproj/project.pbxproj (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app/AppDelegate.swift (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app/Assets.xcassets/Contents.json (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app/Base.lproj/Main.storyboard (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/ios-app/ios-app/Info.plist (100%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/ViewController.swift create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/build.gradle.kts create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/gradle.properties rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods/kotlin-library/src/iosMain/kotlin/A.kt => new-mpp-cocoapods-multiple/kotlin-library/src/iosMain/kotlin/a.kt} (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/pod_dependency/pod_dependency.podspec (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/pod_dependency/src/foo.h (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/pod_dependency/src/foo.m (100%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/build.gradle.kts create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/gradle.properties create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/src/iosMain/kotlin/B.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/settings.gradle rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/subspec_dependency/src/baz.h (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/subspec_dependency/src/baz.m (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-multiple}/subspec_dependency/subspec_dependency.podspec (100%) rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-single}/.gitignore (100%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/build.gradle.kts rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-single}/ios-app/Podfile (100%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.pbxproj rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods/build.gradle.kts => new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata} (100%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/AppDelegate.swift create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Assets.xcassets/Contents.json create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Base.lproj/Main.storyboard create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Info.plist rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-single}/ios-app/ios-app/ViewController.swift (100%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/build.gradle.kts rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-single}/kotlin-library/gradle.properties (100%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/src/iosMain/kotlin/A.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/pod_dependency.podspec create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/src/foo.h create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/src/foo.m rename libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/{new-mpp-cocoapods => new-mpp-cocoapods-single}/settings.gradle (100%) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/src/baz.h create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/src/baz.m create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/subspec_dependency.podspec diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/cocoapods/KotlinCocoaPodsModelResolver.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/cocoapods/KotlinCocoaPodsModelResolver.kt index 7853746a00b..da6aec50f69 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/cocoapods/KotlinCocoaPodsModelResolver.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/cocoapods/KotlinCocoaPodsModelResolver.kt @@ -11,6 +11,11 @@ import org.jetbrains.plugins.gradle.model.ProjectImportModelProvider import org.jetbrains.plugins.gradle.service.project.AbstractProjectResolverExtension class KotlinCocoaPodsModelResolver : AbstractProjectResolverExtension() { + override fun requiresTaskRunning(): Boolean = true + + override fun getToolingExtensionsClasses(): Set> { + return setOf(EnablePodImportTask::class.java) + } override fun getProjectsLoadedModelProvider(): ProjectImportModelProvider { return ClassSetProjectImportModelProvider( @@ -18,7 +23,6 @@ class KotlinCocoaPodsModelResolver : AbstractProjectResolverExtension() { ) } - override fun requiresTaskRunning(): Boolean = true } diff --git a/idea/kotlin-gradle-tooling/src/KotlinCocoaPodsModelBuilder.kt b/idea/kotlin-gradle-tooling/src/KotlinCocoaPodsModelBuilder.kt index d33c732ce20..a4db914fb8a 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinCocoaPodsModelBuilder.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinCocoaPodsModelBuilder.kt @@ -21,7 +21,8 @@ class KotlinCocoaPodsModelBuilder : AbstractModelBuilderService() { override fun buildAll(modelName: String, project: Project, context: ModelBuilderContext): Any? { val startParameter = project.gradle.startParameter - val taskNames = startParameter.taskNames + val taskNames = mutableListOf() + taskNames.addAll(startParameter.taskNames) if (project.tasks.findByPath(POD_IMPORT_TASK_NAME) != null && POD_IMPORT_TASK_NAME !in taskNames) { taskNames.add(POD_IMPORT_TASK_NAME) diff --git a/idea/resources/META-INF/gradle-java.xml b/idea/resources/META-INF/gradle-java.xml index c1255e052cb..c0b25a55d59 100644 --- a/idea/resources/META-INF/gradle-java.xml +++ b/idea/resources/META-INF/gradle-java.xml @@ -15,6 +15,7 @@ + diff --git a/idea/resources/META-INF/gradle-java.xml.201 b/idea/resources/META-INF/gradle-java.xml.201 index fdaf593d3c1..5ecfbfc77dd 100644 --- a/idea/resources/META-INF/gradle-java.xml.201 +++ b/idea/resources/META-INF/gradle-java.xml.201 @@ -11,6 +11,7 @@ + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt index bb636fdaeea..b1352578220 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/BaseGradleIT.kt @@ -479,6 +479,12 @@ abstract class BaseGradleIT { } } + fun CompiledProject.assertTasksExecutedByPrefix(taskPrefixes: Iterable) { + for (prefix in taskPrefixes) { + assertContainsRegex("(Executing actions for task|Executing task) '$prefix\\w*'".toRegex()) + } + } + fun CompiledProject.assertTasksExecuted(vararg tasks: String) { assertTasksExecuted(tasks.toList()) } @@ -521,6 +527,18 @@ abstract class BaseGradleIT { } } + fun CompiledProject.assertTasksRegisteredByPrefix(taskPrefixes: Iterable) { + for (prefix in taskPrefixes) { + assertContainsRegex("'Register task $prefix\\w*'".toRegex()) + } + } + + fun CompiledProject.assertTasksNotRegisteredByPrefix(taskPrefixes: Iterable) { + for (prefix in taskPrefixes) { + assertNotContains("'Register task $prefix\\w*'".toRegex()) + } + } + fun CompiledProject.assertTasksNotRealized(vararg tasks: String) { for (task in tasks) { assertNotContains("'Realize task $task'") @@ -538,6 +556,12 @@ abstract class BaseGradleIT { } } + fun CompiledProject.assertTasksSkippedByPrefix(taskPrefixes: Iterable) { + for (prefix in taskPrefixes) { + assertContainsRegex("Skipping task '$prefix\\w*'".toRegex()) + } + } + fun CompiledProject.getOutputForTask(taskName: String): String { @Language("RegExp") val taskOutputRegex = """ diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CocoaPodsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CocoaPodsIT.kt index 810bf1c72f6..3bff7b0e588 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CocoaPodsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CocoaPodsIT.kt @@ -5,6 +5,10 @@ package org.jetbrains.kotlin.gradle +import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin +import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_BUILD_DEPENDENCIES_TASK_NAME +import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_GEN_TASK_NAME +import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_SETUP_BUILD_TASK_NAME import org.jetbrains.kotlin.gradle.util.modify import org.jetbrains.kotlin.konan.target.HostManager import org.junit.Assume.assumeTrue @@ -19,124 +23,241 @@ class CocoaPodsIT : BaseGradleIT() { override val defaultGradleVersion: GradleVersionRequired get() = GradleVersionRequired.FOR_MPP_SUPPORT + // We use Kotlin DSL. Earlier Gradle versions fail at accessors codegen. - val gradleVersion = GradleVersionRequired.None + val gradleVersion = GradleVersionRequired.FOR_MPP_SUPPORT val PODFILE_IMPORT_DIRECTIVE_PLACEHOLDER = "" - @Test - fun testPodspec() = doTestPodspec() + val cocoapodsSingleKtPod = "new-mpp-cocoapods-single" + val cocoapodsMultipleKtPods = "new-mpp-cocoapods-multiple" @Test - fun testPodspecCustomFrameworkName() = doTestPodspec("MultiPlatformLibrary") + fun testPodspecSingle() = doTestPodspec( + cocoapodsSingleKtPod, + mapOf("kotlin-library" to null), + mapOf("kotlin-library" to kotlinLibraryPodspecContent()) + ) - private fun doTestPodspec(frameworkName: String? = null) { + @Test + fun testPodspecCustomFrameworkNameSingle() = doTestPodspec( + cocoapodsSingleKtPod, + mapOf("kotlin-library" to "MultiplatformLibrary"), + mapOf("kotlin-library" to kotlinLibraryPodspecContent("MultiplatformLibrary")) + ) + + @Test + fun testXcodeUseFrameworksSingle() = doTestXcode( + cocoapodsSingleKtPod, + ImportMode.FRAMEWORKS, + "ios-app", mapOf("kotlin-library" to null) + ) + + @Test + fun testXcodeUseFrameworksWithCustomFrameworkNameSingle() = doTestXcode( + cocoapodsSingleKtPod, + ImportMode.FRAMEWORKS, + "ios-app", + mapOf("kotlin-library" to "MultiplatformLibrary") + ) + + @Test + fun testXcodeUseModularHeadersSingle() = doTestXcode( + cocoapodsSingleKtPod, + ImportMode.MODULAR_HEADERS, + "ios-app", + mapOf("kotlin-library" to null) + ) + + @Test + fun testXcodeUseModularHeadersWithCustomFrameworkNameSingle() = doTestXcode( + cocoapodsSingleKtPod, + ImportMode.MODULAR_HEADERS, + "ios-app", + mapOf("kotlin-library" to "MultiplatformLibrary") + ) + + @Test + fun testPodImportUseFrameworksSingle() = doTestPodImport( + cocoapodsSingleKtPod, + "ios-app", + ImportMode.FRAMEWORKS, + listOf("kotlin-library") + ) + + @Test + fun testPodImportUseModularHeadersSingle() = + doTestPodImport( + cocoapodsSingleKtPod, + "ios-app", + ImportMode.MODULAR_HEADERS, + listOf("kotlin-library") + ) + + @Test + fun testPodspecMupltiple() = doTestPodspec( + cocoapodsMultipleKtPods, + mapOf("kotlin-library" to null, "second-library" to null), + mapOf("kotlin-library" to kotlinLibraryPodspecContent(), "second-library" to secondLibraryPodspecContent()), + ) + + @Test + fun testPodspecCustomFrameworkNameMupltiple() = doTestPodspec( + cocoapodsMultipleKtPods, + mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary"), + mapOf( + "kotlin-library" to kotlinLibraryPodspecContent("FirstMultiplatformLibrary"), + "second-library" to secondLibraryPodspecContent("SecondMultiplatformLibrary") + ) + ) + + @Test + fun testXcodeUseFrameworksMupltiple() = doTestXcode( + cocoapodsMultipleKtPods, + ImportMode.FRAMEWORKS, + "ios-app", + mapOf("kotlin-library" to null, "second-library" to null) + ) + + @Test + fun testXcodeUseFrameworksWithCustomFrameworkNameMupltiple() = doTestXcode( + cocoapodsMultipleKtPods, + ImportMode.FRAMEWORKS, + "ios-app", + mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary") + ) + + @Test + fun testXcodeUseModularHeadersMupltiple() = doTestXcode( + cocoapodsMultipleKtPods, + ImportMode.MODULAR_HEADERS, + "ios-app", + mapOf("kotlin-library" to null, "second-library" to null) + ) + + @Test + fun testXcodeUseModularHeadersWithCustomFrameworkNameMupltiple() = doTestXcode( + cocoapodsMultipleKtPods, + ImportMode.MODULAR_HEADERS, + "ios-app", + mapOf("kotlin-library" to "FirstMultiplatformLibrary", "second-library" to "SecondMultiplatformLibrary") + ) + + @Test + fun testPodImportUseFrameworksMupltiple() = doTestPodImport( + cocoapodsMultipleKtPods, + "ios-app", + ImportMode.FRAMEWORKS, + listOf("kotlin-library", "second-library") + ) + + @Test + fun testPodImportUseModularHeadersMupltiple() = + doTestPodImport( + cocoapodsMultipleKtPods, + "ios-app", + ImportMode.MODULAR_HEADERS, + listOf("kotlin-library", "second-library") + ) + + private fun doTestPodspec( + projectName: String, + subprojectsToFrameworkNamesMap: Map, + subprojectsToPodspecContentMap: Map + ) { assumeTrue(HostManager.hostIsMac) - val gradleProject = transformProjectWithPluginsDsl("new-mpp-cocoapods", gradleVersion) + val gradleProject = transformProjectWithPluginsDsl(projectName, gradleVersion) - // Check that the podspec task fails if there is no Gradle wrapper in the project. - gradleProject.build(":kotlin-library:podspec") { - assertFailed() - assertContains("The Gradle wrapper is required to run the build from Xcode.") - assertContains( - "Please run the same command with `-Pkotlin.native.cocoapods.generate.wrapper=true` " + - "or run the `:wrapper` task to generate the wrapper manually." - ) + gradleProject.build(":podspec") { + assertSuccessful() + assertTasksSkipped(":podspec") + assertNoSuchFile("cocoapods.podspec") } - // Check that we can generate the wrapper along with the podspec if the corresponding property specified - gradleProject.build(":kotlin-library:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") { + for ((subproject, frameworkName) in subprojectsToFrameworkNamesMap) { + frameworkName?.also { + gradleProject.gradleBuildScript(subproject).appendText( + """ + |kotlin { + | cocoapods { + | frameworkName = "$frameworkName" + | } + |} + """.trimMargin() + ) + } + + // Check that we can generate the wrapper along with the podspec if the corresponding property specified + gradleProject.build(":$subproject:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") { + assertSuccessful() + assertTasksExecuted(":$subproject:podspec") + + // Check that the podspec file is correctly generated. + val podspecFileName = "$subproject/${subproject.validFrameworkName}.podspec" + + + + assertFileExists(podspecFileName) + val actualPodspecContentWithoutBlankLines = fileInWorkingDir(podspecFileName).readText() + .lineSequence() + .filter { it.isNotBlank() } + .joinToString("\n") + + assertEquals(subprojectsToPodspecContentMap[subproject], actualPodspecContentWithoutBlankLines) + } + } + } + + private fun doTestPodImport( + projectName: String, + iosAppLocation: String, + mode: ImportMode, + subprojects: List + ) { + assumeTrue(HostManager.hostIsMac) + assumeTrue(KotlinCocoapodsPlugin.isAvailableToProduceSynthetic()) + + val gradleProject = transformProjectWithPluginsDsl(projectName, gradleVersion) + with(gradleProject) { + preparePodfile(iosAppLocation, mode) + podImportAsserts() + subprojects.forEach { podImportAsserts(it) } + } + } + + private fun BaseGradleIT.Project.podImportAsserts(subproject: String? = null) { + val buildScriptText = gradleBuildScript(subproject).readText() + val taskPrefix = subproject?.let { ":$it" } ?: "" + val podImport = "podImport" + val podspec = "podspec" + val podInstall = "podInstall" + + build("$taskPrefix:$podImport", "-Pkotlin.native.cocoapods.generate.wrapper=true") { assertSuccessful() - assertTasksExecuted(":kotlin-library:podspec", ":wrapper") - assertFileExists("gradlew") - // Check that the podspec file is correctly generated. - val podspecFileName = "kotlin-library/kotlin_library.podspec" + if ("noPodspec()" in buildScriptText) { + assertTasksSkipped("$taskPrefix:$podspec") + } + if ("podfile" in buildScriptText) { + assertTasksExecuted("$taskPrefix:$podInstall") + } else { + assertTasksSkipped("$taskPrefix:$podInstall") + } + assertTasksRegisteredByPrefix(listOf("$taskPrefix:$POD_GEN_TASK_NAME")) + if (buildScriptText.matches("pod\\(.*\\)".toRegex())) { + assertTasksExecutedByPrefix(listOf("$taskPrefix:$POD_GEN_TASK_NAME")) + } - frameworkName?.let { - fileInWorkingDir(podspecFileName).modify { - it.replace("build/cocoapods/framework/kotlin_library.framework", "build/cocoapods/framework/$frameworkName.framework") + with(listOf(POD_SETUP_BUILD_TASK_NAME, POD_BUILD_DEPENDENCIES_TASK_NAME).map { "$taskPrefix:$it" }) { + if (buildScriptText.matches("pod\\(.*\\)".toRegex())) { + assertTasksRegisteredByPrefix(this) + assertTasksExecutedByPrefix(this) } } - - val expectedPodspecContent = """ - Pod::Spec.new do |spec| - spec.name = 'kotlin_library' - spec.version = '1.0' - spec.homepage = 'https://github.com/JetBrains/kotlin' - spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" } - spec.authors = '' - spec.license = '' - spec.summary = 'CocoaPods test library' - - spec.static_framework = true - spec.vendored_frameworks = "build/cocoapods/framework/${frameworkName ?: "kotlin_library"}.framework" - spec.libraries = "c++" - spec.module_name = "#{spec.name}_umbrella" - - spec.dependency 'pod_dependency', '1.0' - spec.dependency 'subspec_dependency/Core', '1.0' - - spec.pod_target_xcconfig = { - 'KOTLIN_TARGET[sdk=iphonesimulator*]' => 'ios_x64', - 'KOTLIN_TARGET[sdk=iphoneos*]' => 'ios_arm', - 'KOTLIN_TARGET[sdk=watchsimulator*]' => 'watchos_x86', - 'KOTLIN_TARGET[sdk=watchos*]' => 'watchos_arm', - 'KOTLIN_TARGET[sdk=appletvsimulator*]' => 'tvos_x64', - 'KOTLIN_TARGET[sdk=appletvos*]' => 'tvos_arm64', - 'KOTLIN_TARGET[sdk=macosx*]' => 'macos_x64' - } - - spec.script_phases = [ - { - :name => 'Build kotlin_library', - :execution_position => :before_compile, - :shell_path => '/bin/sh', - :script => <<-SCRIPT - set -ev - REPO_ROOT="${'$'}PODS_TARGET_SRCROOT" - "${'$'}REPO_ROOT/../gradlew" -p "${'$'}REPO_ROOT" :kotlin-library:syncFramework \ - -Pkotlin.native.cocoapods.target=${'$'}KOTLIN_TARGET \ - -Pkotlin.native.cocoapods.configuration=${'$'}CONFIGURATION \ - -Pkotlin.native.cocoapods.cflags="${'$'}OTHER_CFLAGS" \ - -Pkotlin.native.cocoapods.paths.headers="${'$'}HEADER_SEARCH_PATHS" \ - -Pkotlin.native.cocoapods.paths.frameworks="${'$'}FRAMEWORK_SEARCH_PATHS" - SCRIPT - } - ] - end - """.trimIndent() - - assertFileExists(podspecFileName) - assertEquals(expectedPodspecContent, fileInWorkingDir(podspecFileName).readText()) } } - @Test - fun testInterop() { - assumeTrue(HostManager.hostIsMac) - val gradleProject = transformProjectWithPluginsDsl("new-mpp-cocoapods", gradleVersion) - with(gradleProject) { - // Check that a project with CocoaPods interop fails to be built from command line. - build(":kotlin-library:build") { - assertFailed() - assertContains("Cannot perform cinterop processing for module pod_dependency: cannot determine headers location.") - } - - // Check that a project without CocoaPods interop can be built from command line. - gradleBuildScript("kotlin-library").modify { - it.replace("""pod("pod_dependency", "1.0")""", "").replace("""pod("subspec_dependency/Core", "1.0")""", "") - } - projectDir.resolve("kotlin-library/src/iosMain/kotlin/A.kt").modify { - it.replace("import cocoapods.pod_dependency.*", "").replace("println(foo())", "") - .replace("import cocoapods.subspec_dependency.*", "").replace("println(baz())", "") - } - build(":kotlin-library:linkReleaseFrameworkIOS") { - assertSuccessful() - } - } - } private enum class ImportMode(val directive: String) { FRAMEWORKS("use_frameworks!"), @@ -177,40 +298,47 @@ class CocoaPodsIT : BaseGradleIT() { CommandResult(process.exitValue(), stdOut, stdErr).block() } - private fun doTestXcode(mode: ImportMode, isCustomFrameworkName: Boolean) { + private fun doTestXcode( + projectName: String, + mode: ImportMode, + iosAppLocation: String, + subprojectsToFrameworkNamesMap: Map + ) { assumeTrue(HostManager.hostIsMac) - val gradleProject = transformProjectWithPluginsDsl("new-mpp-cocoapods", gradleVersion) + val gradleProject = transformProjectWithPluginsDsl(projectName, gradleVersion) with(gradleProject) { setupWorkingDir() - // Add property with custom framework name - if (isCustomFrameworkName) { - gradleBuildScript("kotlin-library").appendText( - """ - kotlin { - cocoapods { - frameworkName = "MultiPlatformLibrary" + for ((subproject, frameworkName) in subprojectsToFrameworkNamesMap) { + + // Add property with custom framework name + frameworkName?.also { name -> + gradleBuildScript(subproject).appendText( + """ + kotlin { + cocoapods { + frameworkName = "$name" + } + } + """.trimIndent() + ) + + // Change swift sources import + val iosAppDir = projectDir.resolve(iosAppLocation) + iosAppDir.resolve("ios-app/ViewController.swift").modify { + it.replace("import ${subproject.validFrameworkName}", "import $name") } } - """.trimIndent() - ) - // Change swift sources import - val iosAppDir = projectDir.resolve("ios-app") - iosAppDir.resolve("ios-app/ViewController.swift").modify { - it.replace("import kotlin_library", "import MultiPlatformLibrary") + + // Generate podspec. + gradleProject.build(":$subproject:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") { + assertSuccessful() } - } - - // Generate podspec. - gradleProject.build(":kotlin-library:podspec", "-Pkotlin.native.cocoapods.generate.wrapper=true") { - assertSuccessful() - } - - val iosAppDir = projectDir.resolve("ios-app") + val iosAppDir = projectDir.resolve(iosAppLocation) // Set import mode for Podfile. iosAppDir.resolve("Podfile").modify { @@ -218,17 +346,8 @@ class CocoaPodsIT : BaseGradleIT() { } // Install pods. - runCommand(iosAppDir, "pod", "install") { - assertEquals( - 0, exitCode, """ - |Exit code mismatch for `pod install`. - |stdout: - |$stdOut - | - |stderr: - |$stdErr - """.trimMargin() - ) + gradleProject.build(":podInstall", "-Pkotlin.native.cocoapods.generate.wrapper=true") { + assertSuccessful() } // Run Xcode build. @@ -237,8 +356,8 @@ class CocoaPodsIT : BaseGradleIT() { "-sdk", "iphonesimulator", "-arch", "arm64", "-configuration", "Release", - "-workspace", "ios-app.xcworkspace", - "-scheme", "ios-app", + "-workspace", "${iosAppDir.name}.xcworkspace", + "-scheme", iosAppDir.name, inheritIO = true // Xcode doesn't finish the process if the PIPE redirect is used. ) { assertEquals( @@ -255,13 +374,102 @@ class CocoaPodsIT : BaseGradleIT() { } } - @Test - fun testXcodeUseFrameworks() = doTestXcode(ImportMode.FRAMEWORKS, false) + private fun Project.preparePodfile(iosAppLocation: String, mode: ImportMode) { + val iosAppDir = projectDir.resolve(iosAppLocation) - @Test - fun testXcodeUseModularHeaders() = doTestXcode(ImportMode.MODULAR_HEADERS, false) + // Set import mode for Podfile. + iosAppDir.resolve("Podfile").modify { + it.replace(PODFILE_IMPORT_DIRECTIVE_PLACEHOLDER, mode.directive) + } + } - @Test - fun testXcodeWithCustomFrameworkName() = doTestXcode(ImportMode.FRAMEWORKS, true) + private val String.validFrameworkName: String + get() = replace('-', '_') + + private fun kotlinLibraryPodspecContent(frameworkName: String? = null) = """ + Pod::Spec.new do |spec| + spec.name = 'kotlin_library' + spec.version = '1.0' + spec.homepage = 'https://github.com/JetBrains/kotlin' + spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" } + spec.authors = '' + spec.license = '' + spec.summary = 'CocoaPods test library' + spec.static_framework = true + spec.vendored_frameworks = "build/cocoapods/framework/${frameworkName ?: "kotlin_library"}.framework" + spec.libraries = "c++" + spec.module_name = "#{spec.name}_umbrella" + spec.dependency 'pod_dependency', '1.0' + spec.dependency 'subspec_dependency/Core', '1.0' + spec.pod_target_xcconfig = { + 'KOTLIN_TARGET[sdk=iphonesimulator*]' => 'ios_x64', + 'KOTLIN_TARGET[sdk=iphoneos*]' => 'ios_arm', + 'KOTLIN_TARGET[sdk=watchsimulator*]' => 'watchos_x86', + 'KOTLIN_TARGET[sdk=watchos*]' => 'watchos_arm', + 'KOTLIN_TARGET[sdk=appletvsimulator*]' => 'tvos_x64', + 'KOTLIN_TARGET[sdk=appletvos*]' => 'tvos_arm64', + 'KOTLIN_TARGET[sdk=macosx*]' => 'macos_x64' + } + spec.script_phases = [ + { + :name => 'Build kotlin_library', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + set -ev + REPO_ROOT="${'$'}PODS_TARGET_SRCROOT" + "${'$'}REPO_ROOT/../gradlew" -p "${'$'}REPO_ROOT" :kotlin-library:syncFramework \ + -Pkotlin.native.cocoapods.target=${'$'}KOTLIN_TARGET \ + -Pkotlin.native.cocoapods.configuration=${'$'}CONFIGURATION \ + -Pkotlin.native.cocoapods.cflags="${'$'}OTHER_CFLAGS" \ + -Pkotlin.native.cocoapods.paths.headers="${'$'}HEADER_SEARCH_PATHS" \ + -Pkotlin.native.cocoapods.paths.frameworks="${'$'}FRAMEWORK_SEARCH_PATHS" + SCRIPT + } + ] + end + """.trimIndent() + + private fun secondLibraryPodspecContent(frameworkName: String? = null) = """ + Pod::Spec.new do |spec| + spec.name = 'second_library' + spec.version = '1.0' + spec.homepage = 'https://github.com/JetBrains/kotlin' + spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" } + spec.authors = '' + spec.license = '' + spec.summary = 'CocoaPods test library' + spec.static_framework = true + spec.vendored_frameworks = "build/cocoapods/framework/${frameworkName ?: "second_library"}.framework" + spec.libraries = "c++" + spec.module_name = "#{spec.name}_umbrella" + spec.pod_target_xcconfig = { + 'KOTLIN_TARGET[sdk=iphonesimulator*]' => 'ios_x64', + 'KOTLIN_TARGET[sdk=iphoneos*]' => 'ios_arm', + 'KOTLIN_TARGET[sdk=watchsimulator*]' => 'watchos_x86', + 'KOTLIN_TARGET[sdk=watchos*]' => 'watchos_arm', + 'KOTLIN_TARGET[sdk=appletvsimulator*]' => 'tvos_x64', + 'KOTLIN_TARGET[sdk=appletvos*]' => 'tvos_arm64', + 'KOTLIN_TARGET[sdk=macosx*]' => 'macos_x64' + } + spec.script_phases = [ + { + :name => 'Build second_library', + :execution_position => :before_compile, + :shell_path => '/bin/sh', + :script => <<-SCRIPT + set -ev + REPO_ROOT="${'$'}PODS_TARGET_SRCROOT" + "${'$'}REPO_ROOT/../gradlew" -p "${'$'}REPO_ROOT" :second-library:syncFramework \ + -Pkotlin.native.cocoapods.target=${'$'}KOTLIN_TARGET \ + -Pkotlin.native.cocoapods.configuration=${'$'}CONFIGURATION \ + -Pkotlin.native.cocoapods.cflags="${'$'}OTHER_CFLAGS" \ + -Pkotlin.native.cocoapods.paths.headers="${'$'}HEADER_SEARCH_PATHS" \ + -Pkotlin.native.cocoapods.paths.frameworks="${'$'}FRAMEWORK_SEARCH_PATHS" + SCRIPT + } + ] + end + """.trimIndent() } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/.gitignore b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/.gitignore new file mode 100644 index 00000000000..da5776f5847 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/.gitignore @@ -0,0 +1,9 @@ +ios-app/Pods +Podfile.lock +kotlin-library/kotlin_library.podspec +second-library/second_library.podspec +ios-app/ios-app.xcodeproj/xcuserdata +ios-app/ios-app.xcworkspace/xcuserdata +ios-app/ios-app.xcodeproj/project.xcworkspace/xcuserdata +ios-app/ios-app.xcworkspace/contents.xcworkspacedata +ios-app/ios-app.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/kotlin-library/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/build.gradle.kts similarity index 70% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/kotlin-library/build.gradle.kts rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/build.gradle.kts index 38e62ac03d2..e4a80c9f0ae 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/kotlin-library/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/build.gradle.kts @@ -19,9 +19,7 @@ kotlin { iosX64("iOS") cocoapods { - summary = "CocoaPods test library" - homepage = "https://github.com/JetBrains/kotlin" - pod("pod_dependency", "1.0") - pod("subspec_dependency/Core", "1.0") + noPodspec() + podfile = projectDir.resolve("ios-app/Podfile") } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/Podfile b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/Podfile new file mode 100644 index 00000000000..559b656ebdc --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/Podfile @@ -0,0 +1,10 @@ + + +platform :ios, '9.0' + +target 'ios-app' do + pod 'pod_dependency', :path => '../pod_dependency' + pod 'subspec_dependency', :path => '../subspec_dependency' + pod 'kotlin_library', :path => '../kotlin-library' + pod 'second_library', :path => '../second-library' +end \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app.xcodeproj/project.pbxproj b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app.xcodeproj/project.pbxproj similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app.xcodeproj/project.pbxproj rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app.xcodeproj/project.pbxproj diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/AppDelegate.swift b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/AppDelegate.swift similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/AppDelegate.swift rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/AppDelegate.swift diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Assets.xcassets/Contents.json b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Assets.xcassets/Contents.json similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Assets.xcassets/Contents.json rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Assets.xcassets/Contents.json diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Base.lproj/Main.storyboard b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Base.lproj/Main.storyboard similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Base.lproj/Main.storyboard rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Base.lproj/Main.storyboard diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Info.plist b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Info.plist similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/Info.plist rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/Info.plist diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/ViewController.swift b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/ViewController.swift new file mode 100644 index 00000000000..1666b29d0d3 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/ios-app/ios-app/ViewController.swift @@ -0,0 +1,13 @@ +import UIKit +import kotlin_library +import second_library + +class ViewController: UIViewController { + override func viewDidLoad() { + super.viewDidLoad() + AKt.bar() + AKt.bazz() + BKt.secondBar() + // Do any additional setup after loading the view. + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/build.gradle.kts new file mode 100644 index 00000000000..cd7e5bc51cd --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + id("org.jetbrains.kotlin.multiplatform") + id("org.jetbrains.kotlin.native.cocoapods") +} + +group = "com.example" +version = "1.0" + +repositories { + mavenLocal() + jcenter() + maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") } +} + +group = "org.jetbrains.kotlin.sample.native" +version = "1.0" + +kotlin { + iosX64("iOS") + + cocoapods { + summary = "CocoaPods test library" + homepage = "https://github.com/JetBrains/kotlin" + pod("pod_dependency", "1.0", projectDir.resolve("../pod_dependency/pod_dependency.podspec")) + pod("subspec_dependency/Core", "1.0", projectDir.resolve("../subspec_dependency/subspec_dependency.podspec")) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/gradle.properties new file mode 100644 index 00000000000..e9cc339258a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/gradle.properties @@ -0,0 +1,2 @@ +kotlin.native.disableCompilerDaemon=true +kotlin.native.cacheKind=none \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/kotlin-library/src/iosMain/kotlin/A.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/src/iosMain/kotlin/a.kt similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/kotlin-library/src/iosMain/kotlin/A.kt rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/kotlin-library/src/iosMain/kotlin/a.kt diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/pod_dependency/pod_dependency.podspec b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/pod_dependency/pod_dependency.podspec similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/pod_dependency/pod_dependency.podspec rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/pod_dependency/pod_dependency.podspec diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/pod_dependency/src/foo.h b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/pod_dependency/src/foo.h similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/pod_dependency/src/foo.h rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/pod_dependency/src/foo.h diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/pod_dependency/src/foo.m b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/pod_dependency/src/foo.m similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/pod_dependency/src/foo.m rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/pod_dependency/src/foo.m diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/build.gradle.kts new file mode 100644 index 00000000000..6454fc6a4f7 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("org.jetbrains.kotlin.multiplatform") + id("org.jetbrains.kotlin.native.cocoapods") +} + +group = "com.example" +version = "1.0" + +repositories { + mavenLocal() + jcenter() + maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") } +} + +group = "org.jetbrains.kotlin.sample.native" +version = "1.0" + +kotlin { + iosX64("iOS") + + cocoapods { + summary = "CocoaPods test library" + homepage = "https://github.com/JetBrains/kotlin" + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/gradle.properties new file mode 100644 index 00000000000..e9cc339258a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/gradle.properties @@ -0,0 +1,2 @@ +kotlin.native.disableCompilerDaemon=true +kotlin.native.cacheKind=none \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/src/iosMain/kotlin/B.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/src/iosMain/kotlin/B.kt new file mode 100644 index 00000000000..53697ebc387 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/second-library/src/iosMain/kotlin/B.kt @@ -0,0 +1 @@ +fun secondBar() {} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/settings.gradle new file mode 100644 index 00000000000..aba309f9fc0 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/settings.gradle @@ -0,0 +1,14 @@ +pluginManagement { + repositories { + mavenLocal() + jcenter() + gradlePluginPortal() + } +} + +enableFeaturePreview('GRADLE_METADATA') + +// We move the actual library in a subproject to test accessing gradle wrapper from Xcode. +rootProject.name = "cocoapods" +include 'kotlin-library' +include 'second-library' \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/subspec_dependency/src/baz.h b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/subspec_dependency/src/baz.h similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/subspec_dependency/src/baz.h rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/subspec_dependency/src/baz.h diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/subspec_dependency/src/baz.m b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/subspec_dependency/src/baz.m similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/subspec_dependency/src/baz.m rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/subspec_dependency/src/baz.m diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/subspec_dependency/subspec_dependency.podspec b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/subspec_dependency/subspec_dependency.podspec similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/subspec_dependency/subspec_dependency.podspec rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-multiple/subspec_dependency/subspec_dependency.podspec diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/.gitignore b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/.gitignore similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/.gitignore rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/.gitignore diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/build.gradle.kts new file mode 100644 index 00000000000..e4a80c9f0ae --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + id("org.jetbrains.kotlin.multiplatform").version("") + id("org.jetbrains.kotlin.native.cocoapods").version("") +} + +group = "com.example" +version = "1.0" + +repositories { + mavenLocal() + jcenter() + maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") } +} + +group = "org.jetbrains.kotlin.sample.native" +version = "1.0" + +kotlin { + iosX64("iOS") + + cocoapods { + noPodspec() + podfile = projectDir.resolve("ios-app/Podfile") + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/Podfile b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/Podfile similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/Podfile rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/Podfile diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.pbxproj b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.pbxproj new file mode 100644 index 00000000000..3bf1d8a690a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.pbxproj @@ -0,0 +1,341 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + 2C4835762268863D00C928E6 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C4835752268863D00C928E6 /* AppDelegate.swift */; }; + 2C4835782268863D00C928E6 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2C4835772268863D00C928E6 /* ViewController.swift */; }; + 2C48357B2268863D00C928E6 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C4835792268863D00C928E6 /* Main.storyboard */; }; + 2C48357D2268863E00C928E6 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 2C48357C2268863E00C928E6 /* Assets.xcassets */; }; + 2C4835802268863E00C928E6 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 2C48357E2268863E00C928E6 /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 2C4835722268863D00C928E6 /* ios-app.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ios-app.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 2C4835752268863D00C928E6 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 2C4835772268863D00C928E6 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 2C48357A2268863D00C928E6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 2C48357C2268863E00C928E6 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 2C48357F2268863E00C928E6 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 2C4835812268863E00C928E6 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 2C48356F2268863D00C928E6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 2C4835692268863D00C928E6 = { + isa = PBXGroup; + children = ( + 2C4835742268863D00C928E6 /* ios-app */, + 2C4835732268863D00C928E6 /* Products */, + ); + sourceTree = ""; + }; + 2C4835732268863D00C928E6 /* Products */ = { + isa = PBXGroup; + children = ( + 2C4835722268863D00C928E6 /* ios-app.app */, + ); + name = Products; + sourceTree = ""; + }; + 2C4835742268863D00C928E6 /* ios-app */ = { + isa = PBXGroup; + children = ( + 2C4835752268863D00C928E6 /* AppDelegate.swift */, + 2C4835772268863D00C928E6 /* ViewController.swift */, + 2C4835792268863D00C928E6 /* Main.storyboard */, + 2C48357C2268863E00C928E6 /* Assets.xcassets */, + 2C48357E2268863E00C928E6 /* LaunchScreen.storyboard */, + 2C4835812268863E00C928E6 /* Info.plist */, + ); + path = "ios-app"; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 2C4835712268863D00C928E6 /* ios-app */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2C4835842268863E00C928E6 /* Build configuration list for PBXNativeTarget "ios-app" */; + buildPhases = ( + 2C48356E2268863D00C928E6 /* Sources */, + 2C48356F2268863D00C928E6 /* Frameworks */, + 2C4835702268863D00C928E6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "ios-app"; + productName = "ios-app"; + productReference = 2C4835722268863D00C928E6 /* ios-app.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 2C48356A2268863D00C928E6 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1020; + LastUpgradeCheck = 1020; + ORGANIZATIONNAME = jetbrains; + TargetAttributes = { + 2C4835712268863D00C928E6 = { + CreatedOnToolsVersion = 10.2; + }; + }; + }; + buildConfigurationList = 2C48356D2268863D00C928E6 /* Build configuration list for PBXProject "ios-app" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 2C4835692268863D00C928E6; + productRefGroup = 2C4835732268863D00C928E6 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 2C4835712268863D00C928E6 /* ios-app */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 2C4835702268863D00C928E6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C4835802268863E00C928E6 /* LaunchScreen.storyboard in Resources */, + 2C48357D2268863E00C928E6 /* Assets.xcassets in Resources */, + 2C48357B2268863D00C928E6 /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 2C48356E2268863D00C928E6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2C4835782268863D00C928E6 /* ViewController.swift in Sources */, + 2C4835762268863D00C928E6 /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 2C4835792268863D00C928E6 /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 2C48357A2268863D00C928E6 /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 2C48357E2268863E00C928E6 /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 2C48357F2268863E00C928E6 /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 2C4835822268863E00C928E6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 2C4835832268863E00C928E6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + CODE_SIGN_IDENTITY = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 2C4835852268863E00C928E6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = "ios-app/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.konan.ios-app"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 2C4835862268863E00C928E6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + INFOPLIST_FILE = "ios-app/Info.plist"; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = "org.jetbrains.konan.ios-app"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 2C48356D2268863D00C928E6 /* Build configuration list for PBXProject "ios-app" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2C4835822268863E00C928E6 /* Debug */, + 2C4835832268863E00C928E6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 2C4835842268863E00C928E6 /* Build configuration list for PBXNativeTarget "ios-app" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2C4835852268863E00C928E6 /* Debug */, + 2C4835862268863E00C928E6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 2C48356A2268863D00C928E6 /* Project object */; +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/build.gradle.kts rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.xcworkspace/contents.xcworkspacedata diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 00000000000..18d981003d6 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/AppDelegate.swift b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/AppDelegate.swift new file mode 100644 index 00000000000..f02afea65bf --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/AppDelegate.swift @@ -0,0 +1,34 @@ +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 00000000000..dfc5acac601 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images": [ + { + "idiom": "iphone", + "size": "20x20", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "20x20", + "scale": "3x" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "29x29", + "scale": "3x" + }, + { + "idiom": "iphone", + "size": "40x40", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "40x40", + "scale": "3x" + }, + { + "idiom": "iphone", + "size": "60x60", + "scale": "2x" + }, + { + "idiom": "iphone", + "size": "60x60", + "scale": "3x" + }, + { + "idiom": "ipad", + "size": "20x20", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "20x20", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "29x29", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "29x29", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "40x40", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "40x40", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "76x76", + "scale": "1x" + }, + { + "idiom": "ipad", + "size": "76x76", + "scale": "2x" + }, + { + "idiom": "ipad", + "size": "83.5x83.5", + "scale": "2x" + }, + { + "idiom": "ios-marketing", + "size": "1024x1024", + "scale": "1x" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Assets.xcassets/Contents.json b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Assets.xcassets/Contents.json new file mode 100644 index 00000000000..121dee67a67 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 00000000000..bfa36129419 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Base.lproj/Main.storyboard b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Base.lproj/Main.storyboard new file mode 100644 index 00000000000..f1bcf38400d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Base.lproj/Main.storyboard @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Info.plist b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Info.plist new file mode 100644 index 00000000000..16be3b68112 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/ViewController.swift b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/ViewController.swift similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/ios-app/ios-app/ViewController.swift rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/ios-app/ios-app/ViewController.swift diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/build.gradle.kts new file mode 100644 index 00000000000..cd7e5bc51cd --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/build.gradle.kts @@ -0,0 +1,27 @@ +plugins { + id("org.jetbrains.kotlin.multiplatform") + id("org.jetbrains.kotlin.native.cocoapods") +} + +group = "com.example" +version = "1.0" + +repositories { + mavenLocal() + jcenter() + maven { setUrl("https://dl.bintray.com/kotlin/kotlinx.html/") } +} + +group = "org.jetbrains.kotlin.sample.native" +version = "1.0" + +kotlin { + iosX64("iOS") + + cocoapods { + summary = "CocoaPods test library" + homepage = "https://github.com/JetBrains/kotlin" + pod("pod_dependency", "1.0", projectDir.resolve("../pod_dependency/pod_dependency.podspec")) + pod("subspec_dependency/Core", "1.0", projectDir.resolve("../subspec_dependency/subspec_dependency.podspec")) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/kotlin-library/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/gradle.properties similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/kotlin-library/gradle.properties rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/gradle.properties diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/src/iosMain/kotlin/A.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/src/iosMain/kotlin/A.kt new file mode 100644 index 00000000000..2577991a64f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/kotlin-library/src/iosMain/kotlin/A.kt @@ -0,0 +1,10 @@ +import cocoapods.pod_dependency.* +import cocoapods.subspec_dependency.* + +fun bar() { + println(foo()) +} + +fun bazz() { + println(baz()) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/pod_dependency.podspec b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/pod_dependency.podspec new file mode 100644 index 00000000000..e1f4ce85ff6 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/pod_dependency.podspec @@ -0,0 +1,11 @@ +Pod::Spec.new do |spec| + spec.name = 'pod_dependency' + spec.version = '1.0' + spec.homepage = 'foo' + spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" } + spec.authors = '' + spec.license = '' + spec.summary = 'foo' + spec.source_files = 'src/*' + spec.public_header_files = 'src/*.h' +end \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/src/foo.h b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/src/foo.h new file mode 100644 index 00000000000..77feebff9db --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/src/foo.h @@ -0,0 +1,3 @@ +#import + +NSString* foo(void); \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/src/foo.m b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/src/foo.m new file mode 100644 index 00000000000..5912a3d87b6 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/pod_dependency/src/foo.m @@ -0,0 +1,5 @@ +#include "foo.h" + +NSString* foo() { + return @"Foo"; +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/settings.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/settings.gradle similarity index 100% rename from libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods/settings.gradle rename to libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/settings.gradle diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/src/baz.h b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/src/baz.h new file mode 100644 index 00000000000..27e21fcd4e8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/src/baz.h @@ -0,0 +1,3 @@ +#import + +NSString* baz(void); \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/src/baz.m b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/src/baz.m new file mode 100644 index 00000000000..88de68533ba --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/src/baz.m @@ -0,0 +1,5 @@ +#include "baz.h" + +NSString* baz() { + return @"Baz"; +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/subspec_dependency.podspec b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/subspec_dependency.podspec new file mode 100644 index 00000000000..343c53ccc09 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-cocoapods-single/subspec_dependency/subspec_dependency.podspec @@ -0,0 +1,15 @@ +Pod::Spec.new do |spec| + spec.name = 'subspec_dependency' + spec.version = '1.0' + spec.homepage = 'baz' + spec.source = { :git => "Not Published", :tag => "Cocoapods/#{spec.name}/#{spec.version}" } + spec.authors = '' + spec.license = '' + spec.summary = 'baz' + spec.default_subspec = 'Core' + + spec.subspec 'Core' do |core| + core.source_files = "src/*" + core.public_header_files = "src/*.h" + end +end \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsExtension.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsExtension.kt index cfe63fd8ea2..78b66d1ef38 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsExtension.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/CocoapodsExtension.kt @@ -17,17 +17,6 @@ open class CocoapodsExtension(private val project: Project) { val version: String get() = project.version.toString() - @Optional - @InputFile - var podfile: File? = null - - /** - * Configure path to the Podfile. - */ - fun podfile(path: String) { - podfile = project.file(path) - } - /** * Configure authors of the pod built from this project. */ @@ -35,6 +24,23 @@ open class CocoapodsExtension(private val project: Project) { @Input var authors: String? = null + /** + * Configure existing file `Podfile`. + */ + @Optional + @InputFile + var podfile: File? = null + + @get:Input + internal var needPodspec: Boolean = true + + /** + * Setup plugin not to produce podspec file for cocoapods section + */ + fun noPodspec() { + needPodspec = false + } + /** * Configure license of the pod built from this project. */ @@ -56,6 +62,18 @@ open class CocoapodsExtension(private val project: Project) { @Input var homepage: String? = null + @Nested + val ios: PodspecPlatformSettings = PodspecPlatformSettings("ios") + + @Nested + val osx: PodspecPlatformSettings = PodspecPlatformSettings("osx") + + @Nested + val tvos: PodspecPlatformSettings = PodspecPlatformSettings("tvos") + + @Nested + val watchos: PodspecPlatformSettings = PodspecPlatformSettings("watchos") + /** * Configure framework name of the pod built from this project. */ @@ -81,17 +99,27 @@ open class CocoapodsExtension(private val project: Project) { * Add a CocoaPods dependency to the pod built from this project. */ @JvmOverloads - fun pod(name: String, version: String? = null, moduleName: String = name.split("/")[0]) { + fun pod(name: String, version: String? = null, podspec: File? = null, moduleName: String = name.split("/")[0]) { check(_pods.findByName(name) == null) { "Project already has a CocoaPods dependency with name $name" } - _pods.add(CocoapodsDependency(name, version, moduleName)) + _pods.add(CocoapodsDependency(name, version, podspec, moduleName)) } data class CocoapodsDependency( private val name: String, @get:Optional @get:Input val version: String?, + @get:Optional @get:InputFile val podspec: File?, @get:Input val moduleName: String ) : Named { @Input override fun getName(): String = name } + + data class PodspecPlatformSettings( + private val name: String, + @get:Optional @get:Input var deploymentTarget: String? = null + ) : Named { + + @Input + override fun getName(): String = name + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt index d566ffb1909..c7b973d7051 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/cocoapods/KotlinCocoapodsPlugin.kt @@ -12,23 +12,23 @@ import org.gradle.api.Task import org.gradle.api.provider.Provider import org.gradle.api.tasks.Sync import org.gradle.api.tasks.TaskProvider +import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.addExtension import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget import org.jetbrains.kotlin.gradle.plugin.whenEvaluated -import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildSettingsProperties -import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildTask -import org.jetbrains.kotlin.gradle.targets.native.tasks.PodInstallTask -import org.jetbrains.kotlin.gradle.targets.native.tasks.PodSetupBuildTask -import org.jetbrains.kotlin.gradle.tasks.* +import org.jetbrains.kotlin.gradle.targets.native.tasks.* +import org.jetbrains.kotlin.gradle.tasks.DefFileTask +import org.jetbrains.kotlin.gradle.tasks.DummyFrameworkTask +import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask +import org.jetbrains.kotlin.gradle.tasks.PodspecTask import org.jetbrains.kotlin.gradle.utils.asValidTaskName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget import java.io.File -import java.io.FileInputStream internal val Project.cocoapodsBuildDirs: CocoapodsBuildDirs get() = CocoapodsBuildDirs(this) @@ -43,17 +43,35 @@ internal class CocoapodsBuildDirs(val project: Project) { val defs: File get() = root.resolve("defs") + val buildSettings: File + get() = root.resolve("buildSettings") + + private val synthetic: File + get() = root.resolve("synthetic") + + fun synthetic(kotlinNativeTarget: KotlinNativeTarget) = synthetic.resolve(kotlinNativeTarget.name) + fun fatFramework(buildType: String) = root.resolve("fat-frameworks/${buildType.toLowerCase()}") } internal fun String.asValidFrameworkName() = replace('-', '_') -internal val KotlinNativeTarget.toBuildSetupTaskName: String - get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME, disambiguationClassifier) +private val KotlinNativeTarget.toPodGenTaskName: String + get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_GEN_TASK_NAME, disambiguationClassifier) -internal val KotlinNativeTarget.toBuildDependenciesTaskName: String - get() = lowerCamelCaseName(KotlinCocoapodsPlugin.POD_BUILD_DEPENDENCIES_TASK_NAME, disambiguationClassifier) +private val KotlinNativeTarget.toSetupBuildTaskName: String + get() = lowerCamelCaseName( + KotlinCocoapodsPlugin.POD_SETUP_BUILD_TASK_NAME, + disambiguationClassifier + ) + + +private val KotlinNativeTarget.toBuildDependenciesTaskName: String + get() = lowerCamelCaseName( + KotlinCocoapodsPlugin.POD_BUILD_DEPENDENCIES_TASK_NAME, + disambiguationClassifier + ) open class KotlinCocoapodsPlugin : Plugin { @@ -181,7 +199,8 @@ open class KotlinCocoapodsPlugin : Plugin { moduleNames.add(pod.moduleName) val defTask = project.registerTask( - lowerCamelCaseName("generateDef", pod.moduleName).asValidTaskName()) { + lowerCamelCaseName("generateDef", pod.moduleName).asValidTaskName() + ) { it.pod = pod it.description = "Generates a def file for CocoaPods dependencies with module ${pod.moduleName}" // This task is an implementation detail so we don't add it in any group @@ -199,7 +218,11 @@ open class KotlinCocoapodsPlugin : Plugin { interop.packageName = "cocoapods.${pod.moduleName}" - if (project.findProperty(TARGET_PROPERTY) == null && project.findProperty(CONFIGURATION_PROPERTY) == null) { + if (//TODO ychernyshev improve first check + isAvailableToProduceSynthetic() + && project.findProperty(TARGET_PROPERTY) == null + && project.findProperty(CONFIGURATION_PROPERTY) == null + ) { val podBuildTaskProvider = project.tasks.named(target.toBuildDependenciesTaskName, PodBuildTask::class.java) interopTask.inputs.file(podBuildTaskProvider.get().buildSettingsFileProvider) interopTask.dependsOn(podBuildTaskProvider) @@ -221,24 +244,28 @@ open class KotlinCocoapodsPlugin : Plugin { // Since we cannot expand the configuration phase of interop tasks // receiving the required environment variables happens on execution phase. // TODO This needs to be fixed to improve UP-TO-DATE checks. - if (project.findProperty(TARGET_PROPERTY) == null && project.findProperty(CONFIGURATION_PROPERTY) == null) { + if (// TODO ychernyshev improve first check + isAvailableToProduceSynthetic() + && project.findProperty(TARGET_PROPERTY) == null + && project.findProperty(CONFIGURATION_PROPERTY) == null + ) { val podBuildTaskProvider = project.tasks.named(target.toBuildDependenciesTaskName, PodBuildTask::class.java) val buildSettings = podBuildTaskProvider.get().buildSettingsFileProvider.get() - ?.inputStream() - ?.use { + .inputStream() + .use { PodBuildSettingsProperties.readSettingsFromStream(it) } - buildSettings?.cflags?.let { args -> + buildSettings.cflags?.let { args -> // Xcode quotes around paths with spaces. // Here and below we need to split such paths taking this into account. interop.compilerOpts.addAll(args.splitQuotedArgs()) } - buildSettings?.headerPaths?.let { args -> + buildSettings.headerPaths?.let { args -> interop.compilerOpts.addAll(args.splitQuotedArgs().map { "-I$it" }) } - buildSettings?.frameworkPaths?.let { args -> + buildSettings.frameworkPaths?.let { args -> interop.compilerOpts.addAll(args.splitQuotedArgs().map { "-F$it" }) } } @@ -253,7 +280,7 @@ open class KotlinCocoapodsPlugin : Plugin { cocoapodsExtension: CocoapodsExtension ) { project.tasks.register(DUMMY_FRAMEWORK_TASK_NAME, DummyFrameworkTask::class.java) { - it.settings = cocoapodsExtension + it.cocoapodsExtension = cocoapodsExtension } } @@ -279,14 +306,34 @@ open class KotlinCocoapodsPlugin : Plugin { 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.cocoapodsExtension = cocoapodsExtension - it.dependsOn(podspecTaskProvider) + //TODO avoid subproject task management here + project.allprojects.map { it.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java) } + .forEach { podspecTaskProvider -> + podspecTaskProvider.get().takeIf { task -> task.cocoapodsExtension.needPodspec } + ?.also { task -> it.inputs.file(task.outputFileProvider) } + it.dependsOn(podspecTaskProvider) + } + } + } + + private fun registerPodGenTask( + project: Project, kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension + ) { + + val podspecTaskProvider = project.tasks.named(POD_SPEC_TASK_NAME, PodspecTask::class.java) + + kotlinExtension.supportedTargets().all { target -> + project.tasks.register(target.toPodGenTaskName, PodGenTask::class.java) { + it.description = "Сreates a synthetic Xcode project to retrieve CocoaPods dependencies" + it.podspecProvider = podspecTaskProvider.get().outputFileProvider + it.kotlinNativeTarget = target + it.cocoapodsExtension = cocoapodsExtension + it.dependsOn(podspecTaskProvider) + } } } @@ -296,16 +343,16 @@ open class KotlinCocoapodsPlugin : Plugin { cocoapodsExtension: CocoapodsExtension ) { - val podInstallTaskProvider = project.tasks.named(POD_INSTALL_TASK_NAME, PodInstallTask::class.java) - kotlinExtension.supportedTargets().all { target -> - project.tasks.register(target.toBuildSetupTaskName, PodSetupBuildTask::class.java) { + + project.tasks.register(target.toSetupBuildTaskName, PodSetupBuildTask::class.java) { it.group = TASK_GROUP - it.kotlinNativeTarget = target it.description = "Collect environment variables from .xcworkspace file" it.cocoapodsExtension = cocoapodsExtension - it.podsXcodeProjDirProvider = podInstallTaskProvider.get().podsXcodeProjDirProvider - it.dependsOn(podInstallTaskProvider) + it.kotlinNativeTarget = target + val podGenTaskProvider = project.tasks.named(target.toPodGenTaskName, PodGenTask::class.java) + it.podsXcodeProjDirProvider = podGenTaskProvider.get().podsXcodeProjDirProvider + it.dependsOn(podGenTaskProvider) } } } @@ -318,15 +365,15 @@ open class KotlinCocoapodsPlugin : Plugin { kotlinExtension.supportedTargets().all { target -> - val podSetupBuildTaskProvider = project.tasks.named(target.toBuildSetupTaskName, PodSetupBuildTask::class.java) + val podSetupBuildTaskProvider = project.tasks.named(target.toSetupBuildTaskName, PodSetupBuildTask::class.java) project.tasks.register(target.toBuildDependenciesTaskName, PodBuildTask::class.java) { it.group = TASK_GROUP it.description = "Calls `xcodebuild` on xcworkspace for the pod scheme" it.kotlinNativeTarget = target it.cocoapodsExtension = cocoapodsExtension - it.podsXcodeProjDirProvider = (podSetupBuildTaskProvider.get()).podsXcodeProjDirProvider - it.buildSettingsFileProvider = (podSetupBuildTaskProvider.get()).buildSettingsFileProvider + it.podsXcodeProjDirProvider = podSetupBuildTaskProvider.get().podsXcodeProjDirProvider + it.buildSettingsFileProvider = podSetupBuildTaskProvider.get().buildSettingsFileProvider it.dependsOn(podSetupBuildTaskProvider) } } @@ -337,9 +384,11 @@ open class KotlinCocoapodsPlugin : Plugin { kotlinExtension: KotlinMultiplatformExtension ) { + val podInstallTaskProvider = project.tasks.named(POD_INSTALL_TASK_NAME, PodInstallTask::class.java) project.tasks.register(POD_IMPORT_TASK_NAME) { it.group = TASK_GROUP it.description = "Called on Gradle sync, depends on Cinterop tasks for every used pod" + it.dependsOn(podInstallTaskProvider) kotlinExtension.supportedTargets().all { target -> target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).cinterops.all { interop -> @@ -347,7 +396,6 @@ open class KotlinCocoapodsPlugin : Plugin { it.dependsOn(interopTaskProvider) } } - } } @@ -356,27 +404,40 @@ open class KotlinCocoapodsPlugin : Plugin { pluginManager.withPlugin("kotlin-multiplatform") { val kotlinExtension = project.multiplatformExtension val cocoapodsExtension = CocoapodsExtension(this) - - kotlinExtension.addExtension(EXTENSION_NAME, cocoapodsExtension) + kotlinExtension.addExtension(COCOAPODS_EXTENSION_NAME, cocoapodsExtension) createDefaultFrameworks(kotlinExtension, cocoapodsExtension) registerDummyFrameworkTask(project, cocoapodsExtension) createSyncTask(project, kotlinExtension) registerPodspecTask(project, cocoapodsExtension) - registerPodInstallTask(project, cocoapodsExtension) - registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension) - registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension) - registerPodImportTask(project, kotlinExtension) + if (isAvailableToProduceSynthetic()) { + registerPodGenTask(project, kotlinExtension, cocoapodsExtension) + registerPodInstallTask(project, cocoapodsExtension) + registerPodSetupBuildTasks(project, kotlinExtension, cocoapodsExtension) + registerPodBuildTasks(project, kotlinExtension, cocoapodsExtension) + registerPodImportTask(project, kotlinExtension) + } else { + logger.quiet( + """ + To take advantage of the new functionality for Cocoapods Integration like synchronizing with the Xcode project + and supporting dependencies on pods, please install the `cocoapods-generate` plugin for CocoaPods + by calling `gem install cocoapods-generate` in terminal. + + More details are available by https://github.com/square/cocoapods-generate + """.trimIndent() + ) + } createInterops(project, kotlinExtension, cocoapodsExtension) } } companion object { - const val EXTENSION_NAME = "cocoapods" + const val COCOAPODS_EXTENSION_NAME = "cocoapods" const val TASK_GROUP = "CocoaPods" const val SYNC_TASK_NAME = "syncFramework" const val POD_SPEC_TASK_NAME = "podspec" const val DUMMY_FRAMEWORK_TASK_NAME = "generateDummyFramework" const val POD_INSTALL_TASK_NAME = "podInstall" + const val POD_GEN_TASK_NAME = "podGen" const val POD_SETUP_BUILD_TASK_NAME = "podSetupBuild" const val POD_BUILD_DEPENDENCIES_TASK_NAME = "podBuildDependencies" const val POD_IMPORT_TASK_NAME = "podImport" @@ -396,5 +457,14 @@ open class KotlinCocoapodsPlugin : Plugin { // so we should generate a fat framework with arm32 and arm64 binaries. const val KOTLIN_TARGET_FOR_IOS_DEVICE = "ios_arm" const val KOTLIN_TARGET_FOR_WATCHOS_DEVICE = "watchos_arm" + + fun isAvailableToProduceSynthetic(): Boolean { + val gemListProcess = ProcessBuilder("gem", "list").start() + val gemListRetCode = gemListProcess.waitFor() + val gemListOutput = gemListProcess.inputStream.use { + it.reader().readText() + } + return gemListRetCode == 0 && gemListOutput.contains("cocoapods-generate") + } } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/AdvancedCocoapodsTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/AdvancedCocoapodsTasks.kt index 32881ae9cfe..95e7e0d15a8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/AdvancedCocoapodsTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/AdvancedCocoapodsTasks.kt @@ -12,150 +12,229 @@ import org.gradle.api.tasks.Optional import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget -import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildTask.Companion.toValidSDK +import org.jetbrains.kotlin.konan.target.Family import org.jetbrains.kotlin.konan.target.KonanTarget import java.io.File import java.io.FileInputStream import java.io.InputStream -import java.math.BigInteger -import java.security.MessageDigest import java.util.* -abstract class AdvancedCocoapodsTask : DefaultTask() { - @get:Nested - lateinit var cocoapodsExtension: CocoapodsExtension +internal val KotlinNativeTarget.toBuildSettingsFileName: String + get() = "build-settings-$disambiguationClassifier.properties" - @TaskAction - fun commonInvoke() { - podfileCheck(cocoapodsExtension) - specificInvoke() +internal val KotlinNativeTarget.toValidSDK: String + get() = when (konanTarget) { + KonanTarget.IOS_X64 -> "iphonesimulator" + KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> "iphoneos" + KonanTarget.WATCHOS_X86, KonanTarget.WATCHOS_X64 -> "watchsimulator" + KonanTarget.WATCHOS_ARM32, KonanTarget.WATCHOS_ARM64 -> "watchos" + KonanTarget.TVOS_X64 -> "appletvsimulator" + KonanTarget.TVOS_ARM64 -> "appletvos" + KonanTarget.MACOS_X64 -> "macosx" + else -> throw IllegalArgumentException("Bad target ${konanTarget.name}.") } - abstract fun specificInvoke() - - private fun podfileCheck(cocoapodsExtension: CocoapodsExtension) { - check(cocoapodsExtension.podfile != null) { - "Execution of task '$name' requires the path to the Podfile. Specify it in the file ${project.buildFile.absolutePath}." - } +internal val KotlinNativeTarget.platformLiteral: String + get() = when (konanTarget.family) { + Family.OSX -> "macos" + Family.IOS -> "ios" + Family.TVOS -> "tvos" + Family.WATCHOS -> "watchos" + else -> throw IllegalArgumentException("Unsupported native target '${konanTarget.name}'") } -} - /** * 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 PodInstallTask : AdvancedCocoapodsTask() { - - @get:InputFile - @get:Optional - internal val podfileProvider: Provider = project.provider { cocoapodsExtension.podfile } - - @get:OutputDirectory - @get:Optional - internal val podsXcodeProjDirProvider: Provider = project.provider { - cocoapodsExtension.podfile - ?.parentFile - ?.resolve("Pods") - ?.resolve("Pods.xcodeproj") +open class PodInstallTask : DefaultTask() { + init { + onlyIf { cocoapodsExtension?.podfile != null } } - override fun specificInvoke() { - val podfileDir = podfileProvider.get()!!.parentFile - val podInstallProcess = ProcessBuilder("pod", "install").apply { - directory(podfileDir) - inheritIO() - }.start() - val podInstallRetCode = podInstallProcess.waitFor() - check(podInstallRetCode == 0) { "Unable to run 'pod install', return code $podInstallRetCode" } + @get:Optional + @get:Nested + internal var cocoapodsExtension: CocoapodsExtension? = null - val podsXcprojFile = podsXcodeProjDirProvider.get() - check(podsXcprojFile != null && podsXcprojFile.exists() && podsXcprojFile.isDirectory) { - "The directory 'Pods/Pods.xcodeproj' was not created as a result of the `pod install` call." + @get:Optional + @get:OutputDirectory + internal val podsXcodeProjDirProvider: Provider? + get() = cocoapodsExtension?.podfile?.let { + project.provider { it.parentFile.resolve("Pods").resolve("Pods.xcodeproj") } + } + + + @TaskAction + fun doPodInstall() { + cocoapodsExtension?.podfile?.parentFile?.also { podfileDir -> + val podInstallProcess = ProcessBuilder("pod", "install").apply { + directory(podfileDir) + }.start() + val podInstallRetCode = podInstallProcess.waitFor() + val podInstallOutput = podInstallProcess.inputStream.use { it.reader().readText() } + + check(podInstallRetCode == 0) { + listOf( + "Executing of 'pod install' failed with code $podInstallRetCode.", + "Error message:", + podInstallOutput + ).joinToString("\n") + } + 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." + } + } } } } -open class PodSetupBuildTask : AdvancedCocoapodsTask() { +abstract class CocoapodsWithSyntheticTask : DefaultTask() { + init { + onlyIf { + cocoapodsExtension.pods.isNotEmpty() + } + } + + @get:Nested + internal lateinit var cocoapodsExtension: CocoapodsExtension +} + +/** + * The task takes the path to the .podspec file and calls `pod gen` + * to create synthetic xcode project and workspace. + */ +open class PodGenTask : CocoapodsWithSyntheticTask() { + + @get:InputFile + internal lateinit var podspecProvider: Provider + + @Internal + lateinit var kotlinNativeTarget: KotlinNativeTarget + + @get:OutputDirectory + internal val podsXcodeProjDirProvider: Provider + get() = project.provider { + project.cocoapodsBuildDirs.synthetic(kotlinNativeTarget) + .resolve(podspecProvider.get().nameWithoutExtension) + .resolve("Pods") + .resolve("Pods.xcodeproj") + } + + @TaskAction + fun generate() { + val podspecDir = podspecProvider.get().parentFile + val localPodspecPaths = cocoapodsExtension.pods.mapNotNull { it.podspec?.parentFile?.absolutePath } + + val podGenProcessArgs = listOfNotNull( + "pod", "gen", + "--platforms=${kotlinNativeTarget.platformLiteral}", + "--gen-directory=${project.cocoapodsBuildDirs.synthetic(kotlinNativeTarget).absolutePath}", + localPodspecPaths.takeIf { it.isNotEmpty() }?.joinToString(separator = ",")?.let { "--local-sources=$it" }, + podspecProvider.get().name + ) + + val podGenProcess = ProcessBuilder(podGenProcessArgs).apply { + directory(podspecDir) + }.start() + val podGenRetCode = podGenProcess.waitFor() + val outputText = podGenProcess.inputStream.use { it.reader().readText() } + + check(podGenRetCode == 0) { + listOfNotNull( + "Executing of '${podGenProcessArgs.joinToString(" ")}' failed with code $podGenRetCode and message:", + outputText, + outputText.takeIf { + it.contains("deployment target") + || it.contains("requested platforms: [\"${kotlinNativeTarget.platformLiteral}\"]") + }?.let { + """ + Tip: try to configure deployment_target for ALL targets as follows: + cocoapods { + ... + ${kotlinNativeTarget.konanTarget.family.name.toLowerCase()}.deploymentTarget = "..." + ... + } + """.trimIndent() + } + ).joinToString("\n") + } + + val podsXcprojFile = podsXcodeProjDirProvider.get() + check(podsXcprojFile.exists() && podsXcprojFile.isDirectory) { + "The directory '${podsXcprojFile.path}' was not created as a result of the `pod gen` call." + } + } +} + + +open class PodSetupBuildTask : CocoapodsWithSyntheticTask() { + @get:InputDirectory - @get:Optional - internal lateinit var podsXcodeProjDirProvider: Provider + internal lateinit var podsXcodeProjDirProvider: Provider @Internal lateinit var kotlinNativeTarget: KotlinNativeTarget @get:OutputFile - @get:Optional - internal val buildSettingsFileProvider: Provider = - project.provider { - project - .cocoapodsBuildDirs - .root - .resolve("buildSettings") - .resolve(kotlinNativeTarget.toBuildSettingsFileName) - } + internal val buildSettingsFileProvider: Provider = project.provider { + project.cocoapodsBuildDirs + .buildSettings + .resolve(kotlinNativeTarget.toBuildSettingsFileName) + } - override fun specificInvoke() { + @TaskAction + fun setupBuild() { val podsXcodeProjDir = podsXcodeProjDirProvider.get() val buildSettingsReceivingCommand = listOf( "xcodebuild", "-showBuildSettings", - "-project", podsXcodeProjDir!!.name, + "-project", podsXcodeProjDir.name, "-scheme", cocoapodsExtension.frameworkName, "-sdk", kotlinNativeTarget.toValidSDK ) val buildSettingsProcess = ProcessBuilder(buildSettingsReceivingCommand) .apply { - directory(podsXcodeProjDir!!.parentFile) + directory(podsXcodeProjDir.parentFile) }.start() val buildSettingsRetCode = buildSettingsProcess.waitFor() check(buildSettingsRetCode == 0) { - "Unable to run '${buildSettingsReceivingCommand.joinToString(" ")}' return code $buildSettingsRetCode" + listOf( + "Executing of '${buildSettingsReceivingCommand.joinToString(" ")}' failed with code $buildSettingsRetCode and message:", + buildSettingsProcess.errorStream.use { it.reader().readText() } + ).joinToString("\n") } - val stdOut = buildSettingsProcess.inputStream val buildSettingsProperties = PodBuildSettingsProperties.readSettingsFromStream(stdOut) - buildSettingsProperties.writeSettings(buildSettingsFileProvider.get()!!) - } - - companion object { - private val KotlinNativeTarget.toBuildSettingsFileName: String - get() = "build-settings-$disambiguationClassifier.properties" + buildSettingsFileProvider.get().let { buildSettingsProperties.writeSettings(it) } } } /** * The task compiles external cocoa pods sources. */ -open class PodBuildTask : AdvancedCocoapodsTask() { +open class PodBuildTask : CocoapodsWithSyntheticTask() { + @get:InputDirectory - @get:Optional - internal lateinit var podsXcodeProjDirProvider: Provider + internal lateinit var podsXcodeProjDirProvider: Provider @get:InputFile - @get:Optional - internal lateinit var buildSettingsFileProvider: Provider + internal lateinit var buildSettingsFileProvider: Provider @Internal lateinit var kotlinNativeTarget: KotlinNativeTarget - @get:OutputFile @get:Optional - internal val buildDirHashFileProvider: Provider = - project.provider { - project - .cocoapodsBuildDirs - .root - .resolve("buildDirHashSums") - .resolve(kotlinNativeTarget.toBuildDirHashSumFileName) - } + @get:OutputDirectory + internal var buildDirProvider: Provider? = null - override fun specificInvoke() { + @TaskAction + fun buildDependencies() { val podBuildSettings = PodBuildSettingsProperties.readSettingsFromStream( FileInputStream(buildSettingsFileProvider.get()) ) @@ -166,7 +245,7 @@ open class PodBuildTask : AdvancedCocoapodsTask() { val podXcodeBuildCommand = listOf( "xcodebuild", - "-project", podsXcodeProjDir!!.name, + "-project", podsXcodeProjDir.name, "-scheme", it.moduleName, "-sdk", kotlinNativeTarget.toValidSDK, "-configuration", podBuildSettings.configuration @@ -174,59 +253,19 @@ open class PodBuildTask : AdvancedCocoapodsTask() { val podBuildProcess = ProcessBuilder(podXcodeBuildCommand) .apply { - directory(podsXcodeProjDir!!.parentFile) + directory(podsXcodeProjDir.parentFile) inheritIO() }.start() val podBuildRetCode = podBuildProcess.waitFor() check(podBuildRetCode == 0) { - "Unable to run '${podXcodeBuildCommand.joinToString(" ")}' return code $podBuildRetCode" + listOf( + "Executing of '${podXcodeBuildCommand.joinToString(" ")}' failed with code $podBuildRetCode and message:", + podBuildProcess.errorStream.use { it.reader().readText() } + ).joinToString("\n") } } - val buildDirHashSumFile = buildDirHashFileProvider.get()!! - buildDirHashSumFile!!.parentFile.mkdirs() - buildDirHashSumFile!!.createNewFile() - check(buildDirHashSumFile!!.exists()) { - "Unable to create file ${buildDirHashSumFile.toRelativeString(project.projectDir)}!" - } - - buildDirHashSumFile.writeText(getFileChecksumStr(project.file(podBuildSettings.buildDir))) - } - - companion object { - - private fun getFileChecksumStr(file: File): String { - val digest = MessageDigest.getInstance("SHA-1") - file.walkTopDown().forEach { - val byteArray = ByteArray(1024) - var bytesCount = 0 - if (it.isFile) { - val inputStream = it.inputStream() - while (inputStream.read(byteArray).also { bt -> bytesCount = bt } != -1) { - digest.update(byteArray, 0, bytesCount) - } - } - } - val buildDirHashSumStr = BigInteger(1, digest.digest()).toString(16).padStart(32, '0') - return buildDirHashSumStr - } - - internal val KotlinNativeTarget.toBuildDirHashSumFileName: String - get() = "build-dir-hash-$disambiguationClassifier.txt" - - internal val KotlinNativeTarget.toValidSDK: String - get() { - return when (konanTarget) { - KonanTarget.IOS_X64 -> "iphonesimulator" - KonanTarget.IOS_ARM32, KonanTarget.IOS_ARM64 -> "iphoneos" - KonanTarget.WATCHOS_X86, KonanTarget.WATCHOS_X64 -> "watchsimulator" - KonanTarget.WATCHOS_ARM32, KonanTarget.WATCHOS_ARM64 -> "watchos" - KonanTarget.TVOS_X64 -> "appletvsimulator" - KonanTarget.TVOS_ARM64 -> "appletvos" - KonanTarget.MACOS_X64 -> "macos" - else -> throw Error("Bad target ${konanTarget.name}") - } - } + buildDirProvider = project.provider { project.file(podBuildSettings.buildDir) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CocoapodsTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CocoapodsTasks.kt index 1d84c32163c..6580616b5a4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CocoapodsTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CocoapodsTasks.kt @@ -7,11 +7,16 @@ package org.jetbrains.kotlin.gradle.tasks import org.gradle.api.DefaultTask +import org.gradle.api.Project +import org.gradle.api.plugins.ExtensionAware import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.gradle.api.tasks.wrapper.Wrapper +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin +import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.COCOAPODS_EXTENSION_NAME import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.GENERATE_WRAPPER_PROPERTY import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.KOTLIN_TARGET_FOR_IOS_DEVICE import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.KOTLIN_TARGET_FOR_WATCHOS_DEVICE @@ -29,13 +34,19 @@ open class PodspecTask : DefaultTask() { private val specName = project.name.asValidFrameworkName() @get:OutputFile - internal val outputFileProvider: Provider = project.provider { project.file("$specName.podspec") } + internal val outputFileProvider: Provider + get() = project.provider { project.file("$specName.podspec") } @get:Nested internal lateinit var cocoapodsExtension: CocoapodsExtension + init { + onlyIf { cocoapodsExtension.needPodspec } + } + @TaskAction fun generate() { + val frameworkDir = project.cocoapodsBuildDirs.framework.relativeTo(outputFileProvider.get().parentFile).path val dependencies = cocoapodsExtension.pods.map { pod -> val versionSuffix = if (pod.version != null) ", '${pod.version}'" else "" @@ -56,6 +67,13 @@ open class PodspecTask : DefaultTask() { val gradleCommand = "\$REPO_ROOT/${gradleWrapper!!.toRelativeString(project.projectDir)}" val syncTask = "${project.path}:$SYNC_TASK_NAME" + val deploymentTargets = run { + with(cocoapodsExtension) { + listOf(ios, osx, tvos, watchos).filter { it.deploymentTarget != null }.joinToString("\n") { + "| spec.${it.name}.deployment_target = '${it.deploymentTarget}'" + } + } + } with(outputFileProvider.get()) { writeText( @@ -74,6 +92,8 @@ open class PodspecTask : DefaultTask() { | spec.libraries = "c++" | spec.module_name = "#{spec.name}_umbrella" | + $deploymentTargets + | $dependencies | | spec.pod_target_xcconfig = { @@ -93,7 +113,7 @@ open class PodspecTask : DefaultTask() { | :shell_path => '/bin/sh', | :script => <<-SCRIPT | set -ev - | REPO_ROOT="${'$'}PODS_TARGET_SRCROOT/" + | REPO_ROOT="${'$'}PODS_TARGET_SRCROOT" | "$gradleCommand" -p "${'$'}REPO_ROOT" $syncTask \ | -P${KotlinCocoapodsPlugin.TARGET_PROPERTY}=${'$'}KOTLIN_TARGET \ | -P${KotlinCocoapodsPlugin.CONFIGURATION_PROPERTY}=${'$'}CONFIGURATION \ @@ -107,17 +127,30 @@ open class PodspecTask : DefaultTask() { """.trimMargin() ) - logger.quiet( - """ - Generated a podspec file at: ${absolutePath}. - To include it in your Xcode project, add the following dependency snippet in your Podfile: + if (hasPodfileOwnOrParent(project)) { + logger.quiet( + """ + Generated a podspec file at: ${absolutePath}. + To include it in your Xcode project, check that the following dependency snippet exists in your Podfile: - pod '$specName', :path => '${parentFile.absolutePath}' + pod '$specName', :path => '${parentFile.absolutePath}' """.trimIndent() - ) + ) + } + } } + + companion object { + private val KotlinMultiplatformExtension?.cocoapodsExtensionOrNull: CocoapodsExtension? + get() = (this as? ExtensionAware)?.extensions?.findByName(COCOAPODS_EXTENSION_NAME) as? CocoapodsExtension + + private fun hasPodfileOwnOrParent(project: Project): Boolean = + if (project.rootProject == project) project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podfile != null + else project.multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podfile != null + || (project.parent?.let { hasPodfileOwnOrParent(it) } ?: false) + } } @@ -137,10 +170,10 @@ open class DummyFrameworkTask : DefaultTask() { val destinationDir = project.cocoapodsBuildDirs.framework @Input - val frameworkNameProvider: Provider = project.provider { settings.frameworkName } + val frameworkNameProvider: Provider = project.provider { cocoapodsExtension.frameworkName } @get:Nested - internal lateinit var settings: CocoapodsExtension + internal lateinit var cocoapodsExtension: CocoapodsExtension private val frameworkDir: File get() = destinationDir.resolve("${frameworkNameProvider.get()}.framework") @@ -157,8 +190,10 @@ open class DummyFrameworkTask : DefaultTask() { private fun copyTextResource(from: String, to: File, transform: (String) -> String = { it }) { to.parentFile.mkdirs() to.printWriter().use { file -> - javaClass.getResourceAsStream(from).reader().forEachLine { - file.println(transform(it)) + javaClass.getResourceAsStream(from).use { + it.reader().forEachLine { str -> + file.println(transform(str)) + } } } }