[Gradle] Configuration cache support in CocoaPods plugin and Apple frameworks tasks
^KT-54362 Verification Pending Merge-request: KT-MR-9947
This commit is contained in:
committed by
Space Team
parent
457837a255
commit
b1faee5ec6
-48
@@ -9,7 +9,6 @@ import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.report.BuildReportType
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.nio.file.Path
|
||||
@@ -79,53 +78,6 @@ class ConfigurationCacheIT : AbstractConfigurationCacheIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@NativeGradlePluginTests
|
||||
@DisplayName("works with native tasks in complex project")
|
||||
@GradleTestVersions(
|
||||
minVersion = TestVersions.Gradle.G_7_4,
|
||||
additionalVersions = [TestVersions.Gradle.G_7_6],
|
||||
maxVersion = TestVersions.Gradle.G_8_1
|
||||
)
|
||||
@GradleTest
|
||||
fun testNativeTasks(gradleVersion: GradleVersion) {
|
||||
val expectedTasks = mutableListOf(
|
||||
":lib:cinteropMyCinteropLinuxX64",
|
||||
":lib:commonizeCInterop",
|
||||
":lib:compileKotlinLinuxX64",
|
||||
":lib:linkExecutableDebugExecutableLinuxX64",
|
||||
":lib:linkSharedDebugSharedLinuxX64",
|
||||
":lib:linkStaticDebugStaticLinuxX64",
|
||||
":lib:linkDebugTestLinuxX64",
|
||||
)
|
||||
|
||||
if (HostManager.hostIsMac) {
|
||||
expectedTasks += listOf(
|
||||
":lib:cinteropMyCinteropIosX64",
|
||||
":lib:compileKotlinIosX64",
|
||||
":lib:assembleMyframeDebugFrameworkIosArm64",
|
||||
":lib:assembleMyfatframeDebugFatFramework",
|
||||
":lib:assembleLibDebugXCFramework",
|
||||
":lib:compileTestKotlinIosX64",
|
||||
":lib:linkDebugTestIosX64",
|
||||
":lib:transformCommonMainDependenciesMetadata",
|
||||
":lib:transformCommonMainCInteropDependenciesMetadata",
|
||||
":lib:linkDebugFrameworkIosArm64",
|
||||
":lib:linkDebugFrameworkIosX64",
|
||||
":lib:linkDebugFrameworkIosFat",
|
||||
":lib:linkReleaseFrameworkIosArm64",
|
||||
":lib:linkReleaseFrameworkIosX64",
|
||||
":lib:linkReleaseFrameworkIosFat",
|
||||
)
|
||||
}
|
||||
|
||||
project("native-configuration-cache", gradleVersion) {
|
||||
testConfigurationCacheOf(
|
||||
"build",
|
||||
executedTaskNames = expectedTasks,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@NativeGradlePluginTests
|
||||
@DisplayName("works with commonizer")
|
||||
@GradleTestVersions(
|
||||
|
||||
+92
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.condition.OS
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.nio.file.Path
|
||||
|
||||
@DisplayName("Configuration cache tests that can be run on MacOS")
|
||||
@NativeGradlePluginTests
|
||||
@OsCondition(supportedOn = [OS.LINUX, OS.MAC, OS.WINDOWS], enabledOnCI = [OS.LINUX, OS.MAC, OS.WINDOWS])
|
||||
class MacosCapableConfigurationCacheIT : AbstractConfigurationCacheIT() {
|
||||
|
||||
@DisplayName("works with native tasks in complex project")
|
||||
@GradleTestVersions(
|
||||
minVersion = TestVersions.Gradle.G_7_4,
|
||||
additionalVersions = [TestVersions.Gradle.G_7_6],
|
||||
maxVersion = TestVersions.Gradle.G_8_1
|
||||
)
|
||||
@GradleTest
|
||||
fun testNativeTasks(gradleVersion: GradleVersion) {
|
||||
val expectedTasks = mutableListOf(
|
||||
":lib:cinteropMyCinteropLinuxX64",
|
||||
":lib:commonizeCInterop",
|
||||
":lib:compileKotlinLinuxX64",
|
||||
":lib:linkExecutableDebugExecutableLinuxX64",
|
||||
":lib:linkSharedDebugSharedLinuxX64",
|
||||
":lib:linkStaticDebugStaticLinuxX64",
|
||||
":lib:linkDebugTestLinuxX64",
|
||||
)
|
||||
|
||||
if (HostManager.hostIsMac) {
|
||||
expectedTasks += listOf(
|
||||
":lib:cinteropMyCinteropIosX64",
|
||||
":lib:compileKotlinIosX64",
|
||||
":lib:assembleMyframeDebugFrameworkIosArm64",
|
||||
":lib:assembleMyfatframeDebugFatFramework",
|
||||
":lib:assembleLibDebugXCFramework",
|
||||
":lib:compileTestKotlinIosX64",
|
||||
":lib:linkDebugTestIosX64",
|
||||
":lib:transformCommonMainDependenciesMetadata",
|
||||
":lib:transformCommonMainCInteropDependenciesMetadata",
|
||||
":lib:linkDebugFrameworkIosArm64",
|
||||
":lib:linkDebugFrameworkIosX64",
|
||||
":lib:linkDebugFrameworkIosFat",
|
||||
":lib:linkReleaseFrameworkIosArm64",
|
||||
":lib:linkReleaseFrameworkIosX64",
|
||||
":lib:linkReleaseFrameworkIosFat",
|
||||
)
|
||||
}
|
||||
|
||||
project("native-configuration-cache", gradleVersion) {
|
||||
testConfigurationCacheOf(
|
||||
"build",
|
||||
executedTaskNames = expectedTasks,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@DisplayName("works with apple framework embedding and signing")
|
||||
@OsCondition(supportedOn = [OS.MAC], enabledOnCI = [OS.MAC])
|
||||
@GradleTestVersions(
|
||||
minVersion = TestVersions.Gradle.G_7_4,
|
||||
additionalVersions = [TestVersions.Gradle.G_7_6],
|
||||
maxVersion = TestVersions.Gradle.G_8_1,
|
||||
)
|
||||
@GradleTest
|
||||
fun testAppleFrameworkTasks(gradleVersion: GradleVersion, @TempDir targetBuildDir: Path) {
|
||||
project(
|
||||
projectName = "sharedAppleFramework",
|
||||
gradleVersion = gradleVersion,
|
||||
environmentVariables = EnvironmentalVariables(
|
||||
"CONFIGURATION" to "Debug",
|
||||
"SDK_NAME" to "iphoneos",
|
||||
"ARCHS" to "arm64",
|
||||
"EXPANDED_CODE_SIGN_IDENTITY" to "-",
|
||||
"TARGET_BUILD_DIR" to targetBuildDir.toString(),
|
||||
"FRAMEWORKS_FOLDER_PATH" to "testFrameworksDir"
|
||||
),
|
||||
) {
|
||||
testConfigurationCacheOf(":shared:embedAndSignAppleFrameworkForXcode")
|
||||
}
|
||||
}
|
||||
}
|
||||
+36
-143
@@ -12,56 +12,44 @@ import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.gradle.util.replaceText
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.condition.OS
|
||||
import org.junit.jupiter.api.io.TempDir
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.absolutePathString
|
||||
import kotlin.io.path.appendText
|
||||
|
||||
@OsCondition(supportedOn = [OS.MAC], enabledOnCI = [OS.MAC])
|
||||
@DisplayName("Tests for K/N with Apple Framework")
|
||||
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_70)
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_0)
|
||||
@NativeGradlePluginTests
|
||||
class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Assembling AppleFrameworkForXcode tasks for IosArm64")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_0)
|
||||
@GradleTest
|
||||
fun shouldAssembleAppleFrameworkForXcodeForIosArm64(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildJdk = jdkProvider.location,
|
||||
buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
buildOptions = defaultBuildOptions,
|
||||
environmentVariables = EnvironmentalVariables(
|
||||
"CONFIGURATION" to "debug",
|
||||
"SDK_NAME" to "iphoneos123",
|
||||
"ARCHS" to "arm64",
|
||||
"TARGET_BUILD_DIR" to "no use",
|
||||
"FRAMEWORKS_FOLDER_PATH" to "no use"
|
||||
),
|
||||
) {
|
||||
val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
"CONFIGURATION" to "debug",
|
||||
"SDK_NAME" to "iphoneos123",
|
||||
"ARCHS" to "arm64",
|
||||
"TARGET_BUILD_DIR" to "no use",
|
||||
"FRAMEWORKS_FOLDER_PATH" to "no use"
|
||||
)
|
||||
)
|
||||
|
||||
build(
|
||||
"assembleDebugAppleFrameworkForXcodeIosArm64",
|
||||
environmentVariables = environmentVariables,
|
||||
) {
|
||||
build("assembleDebugAppleFrameworkForXcodeIosArm64") {
|
||||
assertTasksExecuted(":shared:assembleDebugAppleFrameworkForXcodeIosArm64")
|
||||
assertDirectoryInProjectExists("shared/build/xcode-frameworks/debug/iphoneos123/sdk.framework")
|
||||
assertDirectoryInProjectExists("shared/build/xcode-frameworks/debug/iphoneos123/sdk.framework.dSYM")
|
||||
}
|
||||
|
||||
build(
|
||||
"assembleCustomDebugAppleFrameworkForXcodeIosArm64",
|
||||
environmentVariables = environmentVariables
|
||||
) {
|
||||
build("assembleCustomDebugAppleFrameworkForXcodeIosArm64") {
|
||||
assertTasksExecuted(":shared:assembleCustomDebugAppleFrameworkForXcodeIosArm64")
|
||||
assertDirectoryInProjectExists("shared/build/xcode-frameworks/debug/iphoneos123/lib.framework")
|
||||
assertDirectoryInProjectExists("shared/build/xcode-frameworks/debug/iphoneos123/lib.framework.dSYM")
|
||||
@@ -71,21 +59,15 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Assembling fat AppleFrameworkForXcode tasks for Arm64 and X64 simulators")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_0)
|
||||
@GradleTest
|
||||
fun shouldAssembleAppleFrameworkForXcodeForArm64AndX64Simulators(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildJdk = jdkProvider.location,
|
||||
buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
buildOptions = defaultBuildOptions
|
||||
) {
|
||||
val environmentVariables = mapOf(
|
||||
"CONFIGURATION" to "Release",
|
||||
@@ -106,57 +88,42 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("MacOS framework has symlinks")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleAndroidTest
|
||||
@GradleTest
|
||||
fun shouldCheckThatMacOSFrameworkHasSymlinks(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
@TempDir testBuildDir: Path,
|
||||
) {
|
||||
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildJdk = jdkProvider.location,
|
||||
buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
) {
|
||||
val environmentVariables = mapOf(
|
||||
"CONFIGURATION" to "debug",
|
||||
"SDK_NAME" to "macosx",
|
||||
"ARCHS" to "x86_64",
|
||||
"EXPANDED_CODE_SIGN_IDENTITY" to "-",
|
||||
"TARGET_BUILD_DIR" to projectPath.absolutePathString(),
|
||||
"TARGET_BUILD_DIR" to testBuildDir.toString(),
|
||||
"FRAMEWORKS_FOLDER_PATH" to "build/xcode-derived"
|
||||
)
|
||||
build(":shared:embedAndSignAppleFrameworkForXcode", environmentVariables = EnvironmentalVariables(environmentVariables)) {
|
||||
assertTasksExecuted(":shared:assembleDebugAppleFrameworkForXcodeMacosX64")
|
||||
assertSymlinkInProjectExists("shared/build/xcode-frameworks/debug/macosx/sdk.framework/Headers")
|
||||
assertSymlinkInProjectExists("build/xcode-derived/sdk.framework/Headers")
|
||||
assertSymlinkExists(testBuildDir.resolve("build/xcode-derived/sdk.framework/Headers"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("EmbedAnsSign executes normally when signing is disabled")
|
||||
@DisplayName("embedAndSign executes normally when signing is disabled")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleAndroidTest
|
||||
@GradleTest
|
||||
fun testEmbedAnsSignExecutionWithoutSigning(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildJdk = jdkProvider.location,
|
||||
buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
) {
|
||||
val environmentVariables = mapOf(
|
||||
"CONFIGURATION" to "debug",
|
||||
@@ -172,19 +139,12 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
}
|
||||
|
||||
@DisplayName("embedAndSignAppleFrameworkForXcode fail")
|
||||
@GradleAndroidTest
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleTest
|
||||
fun shouldFailWithExecutingEmbedAndSignAppleFrameworkForXcode(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
nativeProject("sharedAppleFramework", gradleVersion, buildJdk = jdkProvider.location) {
|
||||
buildAndFail(
|
||||
":shared:embedAndSignAppleFrameworkForXcode",
|
||||
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion)
|
||||
) {
|
||||
nativeProject("sharedAppleFramework", gradleVersion) {
|
||||
buildAndFail(":shared:embedAndSignAppleFrameworkForXcode") {
|
||||
assertOutputContains("Please run the embedAndSignAppleFrameworkForXcode task from Xcode")
|
||||
}
|
||||
}
|
||||
@@ -192,28 +152,21 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Registered tasks with Xcode environment for Debug IosArm64 configuration")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_0)
|
||||
@GradleTest
|
||||
fun shouldCheckAllRegisteredTasksWithXcodeEnvironmentForDebugIosArm64(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
@TempDir testBuildDir: Path,
|
||||
) {
|
||||
val buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildJdk = jdkProvider.location,
|
||||
buildOptions = buildOptions
|
||||
) {
|
||||
val environmentVariables = mapOf(
|
||||
"CONFIGURATION" to "Debug",
|
||||
"SDK_NAME" to "iphoneos",
|
||||
"ARCHS" to "arm64",
|
||||
"EXPANDED_CODE_SIGN_IDENTITY" to "-",
|
||||
"TARGET_BUILD_DIR" to "testBuildDir",
|
||||
"TARGET_BUILD_DIR" to testBuildDir.toString(),
|
||||
"FRAMEWORKS_FOLDER_PATH" to "testFrameworksDir"
|
||||
)
|
||||
buildAndAssertAllTasks(
|
||||
@@ -236,22 +189,13 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("embedAndSignAppleFrameworkForXcode was registered without required Xcode environments")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleTest
|
||||
fun shouldCheckEmbedAndSignAppleFrameworkForXcodeDoesNotRequireXcodeEnv(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
val buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildJdk = jdkProvider.location,
|
||||
buildOptions = buildOptions
|
||||
) {
|
||||
val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
@@ -289,21 +233,15 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Static framework for Arm64 is built but is not embedded")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_0)
|
||||
@GradleTest
|
||||
fun shouldCheckThatStaticFrameworkForArm64IsBuildAndNotEmbedded(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildJdk = jdkProvider.location,
|
||||
buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
buildOptions = defaultBuildOptions
|
||||
) {
|
||||
val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
@@ -333,22 +271,13 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Configuration errors reported to Xcode when embedAndSign task requested")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleAndroidTest
|
||||
@GradleTest
|
||||
fun shouldReportConfErrorsToXcodeWhenRequestedByEmbedAndSign(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
val buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildJdk = jdkProvider.location,
|
||||
buildOptions = buildOptions
|
||||
) {
|
||||
val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
@@ -378,22 +307,13 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Compilation errors reported to Xcode when embedAndSign task requested")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleTest
|
||||
fun shouldReportCompilationErrorsToXcodeWhenRequestedByEmbedAndSign(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
val buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildOptions = buildOptions,
|
||||
buildJdk = jdkProvider.location
|
||||
) {
|
||||
val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
@@ -417,22 +337,13 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Compilation errors printed with Gradle-style when any other task requested")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleTest
|
||||
fun shouldPrintCompilationErrorsWithGradleStyle(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
val buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildOptions = buildOptions,
|
||||
buildJdk = jdkProvider.location
|
||||
) {
|
||||
val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
@@ -456,22 +367,13 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Compilation errors printed with Xcode-style with explicit option")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleTest
|
||||
fun shouldPrintCompilationErrorsWithXcodeStyle(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
val buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildOptions = buildOptions,
|
||||
buildJdk = jdkProvider.location
|
||||
) {
|
||||
val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
@@ -499,22 +401,13 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Compilation errors reported to Xcode when embedAndSign task requested and compiler runs in a separate process")
|
||||
@OptIn(EnvironmentalVariablesOverride::class)
|
||||
@GradleAndroidTest
|
||||
// We need to use Gradle 7.2 here because of the issue https://github.com/gradle/gradle/issues/13957
|
||||
@GradleTestVersions(minVersion = TestVersions.Gradle.G_7_2)
|
||||
@GradleTest
|
||||
fun shouldReportErrorsToXcodeWhenEmbedAndSignRequestedAndDisableCompilerDaemon(
|
||||
gradleVersion: GradleVersion,
|
||||
agpVersion: String,
|
||||
jdkProvider: JdkVersions.ProvidedJdk,
|
||||
) {
|
||||
val buildOptions = defaultBuildOptions.copy(
|
||||
androidVersion = agpVersion
|
||||
)
|
||||
nativeProject(
|
||||
"sharedAppleFramework",
|
||||
gradleVersion,
|
||||
buildOptions = buildOptions,
|
||||
buildJdk = jdkProvider.location
|
||||
) {
|
||||
val environmentVariables = EnvironmentalVariables(
|
||||
mapOf(
|
||||
@@ -585,7 +478,7 @@ class AppleFrameworkIT : KGPBaseTest() {
|
||||
assertContainsVariant("mainDynamicReleaseFrameworkIos")
|
||||
}
|
||||
|
||||
// NB: '0' is required at the end since dependency is added with custom attribute and it creates new configuration
|
||||
// NB: '0' is required at the end since dependency is added with custom attribute, and it creates new configuration
|
||||
build(*dependencyInsight("iosAppIosX64DebugImplementation0"), "-PmultipleFrameworks") {
|
||||
assertContainsVariant("mainStaticDebugFrameworkIos")
|
||||
}
|
||||
|
||||
+69
-4
@@ -14,6 +14,8 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Compan
|
||||
import org.jetbrains.kotlin.gradle.testbase.ImportMode
|
||||
import org.jetbrains.kotlin.gradle.testbase.cocoaPodsEnvironmentVariables
|
||||
import org.jetbrains.kotlin.gradle.testbase.ensureCocoapodsInstalled
|
||||
import org.jetbrains.kotlin.gradle.testbase.TestVersions.Gradle.G_8_1
|
||||
import org.jetbrains.kotlin.gradle.transformProjectWithPluginsDsl
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import org.jetbrains.kotlin.gradle.util.runProcess
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
@@ -25,10 +27,7 @@ import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.zip.ZipFile
|
||||
import kotlin.test.assertContains
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
import kotlin.test.*
|
||||
|
||||
class CocoaPodsIT : BaseGradleIT() {
|
||||
|
||||
@@ -809,6 +808,72 @@ class CocoaPodsIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore // will be fixed in the next step
|
||||
fun `test configuration cache works in a complex scenario with Gradle 8_1`() {
|
||||
project = transformProjectWithPluginsDsl(templateProjectName, GradleVersionRequired.Exact(G_8_1)).apply {
|
||||
preparePodfile("ios-app", ImportMode.FRAMEWORKS)
|
||||
}
|
||||
`test configuration cache works in a complex scenario`()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test configuration cache works in a complex scenario`() {
|
||||
project.gradleBuildScript().appendToCocoapodsBlock("""pod("Base64", version = "1.1.2")""")
|
||||
|
||||
val tasks = arrayOf(
|
||||
":podspec",
|
||||
":podImport",
|
||||
":podPublishDebugXCFramework",
|
||||
":podPublishReleaseXCFramework",
|
||||
":syncFramework",
|
||||
)
|
||||
|
||||
val executableTasks = listOf(
|
||||
":podspec",
|
||||
":podPublishDebugXCFramework",
|
||||
":podPublishReleaseXCFramework",
|
||||
":linkPodDebugFrameworkIOS",
|
||||
)
|
||||
|
||||
fun build(vararg tasks: String, check: CompiledProject.() -> Unit) {
|
||||
project.build(
|
||||
*tasks,
|
||||
"-Pkotlin.native.cocoapods.generate.wrapper=true",
|
||||
"-Pkotlin.native.cocoapods.platform=iphonesimulator",
|
||||
"-Pkotlin.native.cocoapods.archs=x86_64",
|
||||
"-Pkotlin.native.cocoapods.configuration=Debug",
|
||||
options = defaultBuildOptions().copy(configurationCache = true),
|
||||
check = check,
|
||||
)
|
||||
}
|
||||
|
||||
build(*tasks) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(executableTasks)
|
||||
|
||||
assertContains("Calculating task graph as no configuration cache is available for tasks")
|
||||
|
||||
assertContains("Configuration cache entry stored.")
|
||||
}
|
||||
|
||||
build("clean") {
|
||||
assertSuccessful()
|
||||
}
|
||||
|
||||
build(*tasks) {
|
||||
assertSuccessful()
|
||||
|
||||
assertContains("Reusing configuration cache.")
|
||||
}
|
||||
|
||||
build(*tasks) {
|
||||
assertSuccessful()
|
||||
|
||||
assertTasksUpToDate(executableTasks)
|
||||
}
|
||||
}
|
||||
|
||||
// test configuration phase
|
||||
|
||||
private class CustomHooks {
|
||||
|
||||
-6
@@ -7,12 +7,6 @@ package org.jetbrains.kotlin.gradle.testbase
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.jetbrains.kotlin.gradle.BaseGradleIT
|
||||
import java.net.URI
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.ExperimentalPathApi
|
||||
import kotlin.io.path.exists
|
||||
import kotlin.io.path.name
|
||||
import kotlin.test.fail
|
||||
|
||||
/**
|
||||
* Tests whether configuration cache for the tasks specified by [buildArguments] works on simple scenario when project is built twice non-incrementally.
|
||||
|
||||
+3
-1
@@ -312,7 +312,9 @@ open class GradleProject(
|
||||
}
|
||||
|
||||
@JvmInline
|
||||
value class EnvironmentalVariables @EnvironmentalVariablesOverride constructor(val environmentalVariables: Map<String, String> = emptyMap())
|
||||
value class EnvironmentalVariables @EnvironmentalVariablesOverride constructor(val environmentalVariables: Map<String, String> = emptyMap()) {
|
||||
@EnvironmentalVariablesOverride constructor(vararg environmentVariables: Pair<String, String>) : this(mapOf(*environmentVariables))
|
||||
}
|
||||
|
||||
@RequiresOptIn("Environmental variables override may lead to interference of parallel builds and breaks Gradle tests debugging")
|
||||
annotation class EnvironmentalVariablesOverride
|
||||
|
||||
+14
-6
@@ -38,9 +38,10 @@ fun TestProject.makeSnapshotTo(destinationPath: String) {
|
||||
dest.resolve("run.sh").run {
|
||||
writeText(
|
||||
"""
|
||||
#!/usr/bin/env sh
|
||||
./gradlew ${buildOptions.toArguments(gradleVersion).joinToString(separator = " ")} ${'$'}@
|
||||
""".trimIndent()
|
||||
|#!/usr/bin/env sh
|
||||
|${formatEnvironmentForScript(envCommand = "export")}
|
||||
|./gradlew ${buildOptions.toArguments(gradleVersion).joinToString(separator = " ")} ${'$'}@
|
||||
|""".trimMargin()
|
||||
)
|
||||
|
||||
setPosixFilePermissions(
|
||||
@@ -55,9 +56,10 @@ fun TestProject.makeSnapshotTo(destinationPath: String) {
|
||||
dest.resolve("run.bat").run {
|
||||
writeText(
|
||||
"""
|
||||
@rem Executing Gradle build
|
||||
gradlew.bat ${buildOptions.toArguments(gradleVersion).joinToString(separator = " ")} %*
|
||||
""".trimIndent()
|
||||
|@rem Executing Gradle build
|
||||
|${formatEnvironmentForScript(envCommand = "set")}
|
||||
|gradlew.bat ${buildOptions.toArguments(gradleVersion).joinToString(separator = " ")} %*
|
||||
|""".trimMargin()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -80,6 +82,12 @@ fun TestProject.makeSnapshotTo(destinationPath: String) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun TestProject.formatEnvironmentForScript(envCommand: String): String {
|
||||
return environmentVariables.environmentalVariables.asSequence().joinToString(separator = "\n|") { (key, value) ->
|
||||
"$envCommand $key=\"$value\""
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Configures the JVM memory settings for the Gradle project.
|
||||
|
||||
-1
@@ -7,7 +7,6 @@ buildscript {
|
||||
}
|
||||
dependencies {
|
||||
classpath(kotlin("gradle-plugin:${property("kotlin_version")}"))
|
||||
classpath("com.android.tools.build:gradle:${property("android_tools_version")}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-11
@@ -1,10 +1,9 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
id("com.android.library")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
android()
|
||||
jvm()
|
||||
|
||||
val macosX64 = macosX64()
|
||||
val iosX64 = iosX64()
|
||||
@@ -35,12 +34,3 @@ kotlin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion(30)
|
||||
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
|
||||
defaultConfig {
|
||||
minSdkVersion(21)
|
||||
targetSdkVersion(30)
|
||||
}
|
||||
}
|
||||
|
||||
-2
@@ -1,2 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="com.github.jetbrains.myapplication" />
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
package com.github.jetbrains.myapplication
|
||||
|
||||
actual class Platform actual constructor() {
|
||||
actual val platform: String = "Android ${android.os.Build.VERSION.SDK_INT}"
|
||||
actual val platform: String = "JVM ${System.getProperty("java.version")}"
|
||||
}
|
||||
+41
-31
@@ -6,19 +6,13 @@
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp.apple
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.tasks.Copy
|
||||
import org.gradle.api.tasks.IgnoreEmptyDirectories
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.PathSensitive
|
||||
import org.gradle.api.tasks.PathSensitivity
|
||||
import org.gradle.api.tasks.SkipWhenEmpty
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.ExecOperations
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
@@ -27,9 +21,11 @@ import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.gradle.utils.mapToFile
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
internal object AppleXcodeTasks {
|
||||
const val embedAndSignTaskPrefix = "embedAndSign"
|
||||
@@ -70,7 +66,7 @@ private object XcodeEnvironment {
|
||||
get() {
|
||||
val xcodeTargetBuildDir = System.getenv("TARGET_BUILD_DIR") ?: return null
|
||||
val xcodeFrameworksFolderPath = System.getenv("FRAMEWORKS_FOLDER_PATH") ?: return null
|
||||
return File(xcodeTargetBuildDir, xcodeFrameworksFolderPath)
|
||||
return File(xcodeTargetBuildDir, xcodeFrameworksFolderPath).absoluteFile
|
||||
}
|
||||
|
||||
val sign: String? get() = System.getenv("EXPANDED_CODE_SIGN_IDENTITY")
|
||||
@@ -135,9 +131,9 @@ private fun Project.registerAssembleAppleFrameworkTask(framework: Framework): Ta
|
||||
else -> registerTask<FrameworkCopy>(frameworkTaskName) { task ->
|
||||
task.description = "Packs $frameworkBuildType ${frameworkTarget.name} framework for Xcode"
|
||||
task.isEnabled = frameworkBuildType == envBuildType
|
||||
task.dependsOn(framework.linkTaskName)
|
||||
task.files = files({ framework.outputDirectory.listFiles() })
|
||||
task.destDir = appleFrameworkDir(envFrameworkSearchDir)
|
||||
task.sourceFramework.fileProvider(framework.linkTaskProvider.flatMap { it.outputFile })
|
||||
task.dependsOn(framework.linkTaskProvider)
|
||||
task.destinationDirectory.set(appleFrameworkDir(envFrameworkSearchDir))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -193,15 +189,16 @@ internal fun Project.registerEmbedAndSignAppleFrameworkTask(framework: Framework
|
||||
if (framework.buildType != envBuildType || !envTargets.contains(framework.konanTarget)) return
|
||||
|
||||
embedAndSignTask.configure { task ->
|
||||
val frameworkFile = framework.outputFile
|
||||
task.dependsOn(assembleTask)
|
||||
task.files = files(File(appleFrameworkDir(envFrameworkSearchDir), framework.outputFile.name))
|
||||
task.destDir = envEmbeddedFrameworksDir
|
||||
task.sourceFramework.set(File(appleFrameworkDir(envFrameworkSearchDir), frameworkFile.name))
|
||||
task.destinationDirectory.set(envEmbeddedFrameworksDir)
|
||||
if (envSign != null) {
|
||||
task.doLast {
|
||||
val binary = envEmbeddedFrameworksDir
|
||||
.resolve(framework.outputFile.name)
|
||||
.resolve(framework.outputFile.nameWithoutExtension)
|
||||
exec {
|
||||
.resolve(frameworkFile.name)
|
||||
.resolve(frameworkFile.nameWithoutExtension)
|
||||
task.execOperations.exec {
|
||||
it.commandLine("codesign", "--force", "--sign", envSign, "--", binary)
|
||||
}
|
||||
}
|
||||
@@ -224,26 +221,39 @@ private fun Project.appleFrameworkDir(frameworkSearchDir: File) =
|
||||
* To preserve these symlinks we are using the `cp` command instead.
|
||||
* See https://youtrack.jetbrains.com/issue/KT-48594.
|
||||
*/
|
||||
@Suppress("LeakingThis") // Should be extended only by Gradle
|
||||
internal abstract class FrameworkCopy : DefaultTask() {
|
||||
|
||||
@get:Inject
|
||||
abstract val execOperations: ExecOperations
|
||||
|
||||
@get:InputDirectory
|
||||
abstract val sourceFramework: DirectoryProperty
|
||||
|
||||
@get:InputFiles
|
||||
@get:SkipWhenEmpty
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
abstract var files: FileCollection
|
||||
protected val sourceDsym = sourceFramework.mapToFile().map { File(it.path + ".dSYM") }
|
||||
|
||||
@get:OutputDirectory
|
||||
abstract var destDir: File
|
||||
abstract val destinationDirectory: DirectoryProperty
|
||||
|
||||
@TaskAction
|
||||
fun copy() {
|
||||
destDir.mkdirs()
|
||||
files.forEach { file ->
|
||||
File(destDir, file.name).let destFile@{ destFile ->
|
||||
if (!destFile.exists()) return@destFile
|
||||
project.exec { it.commandLine("rm", "-r", destFile.absolutePath) }
|
||||
}
|
||||
project.exec { it.commandLine("cp", "-R", file.absolutePath, destDir.absolutePath) }
|
||||
open fun copy() {
|
||||
copy(sourceFramework.mapToFile())
|
||||
if (sourceDsym.get().exists()) {
|
||||
copy(sourceDsym)
|
||||
}
|
||||
}
|
||||
|
||||
private fun copy(sourceProvider: Provider<File>) {
|
||||
val source = sourceProvider.get()
|
||||
val destination = destinationDirectory.asFile.get()
|
||||
|
||||
val destinationFile = File(destination, source.name)
|
||||
if (destinationFile.exists()) {
|
||||
execOperations.exec { it.commandLine("rm", "-r", destinationFile.absolutePath) }
|
||||
}
|
||||
|
||||
execOperations.exec { it.commandLine("cp", "-R", source.absolutePath, destination.absolutePath) }
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -269,7 +269,6 @@ class Framework(
|
||||
compilation: KotlinNativeCompilation
|
||||
) : AbstractNativeLibrary(name, baseName, buildType, compilation), HasAttributes {
|
||||
|
||||
@Transient // Is required configuration cache support for KotlinNative tasks that capture whole binary object as task state
|
||||
private val attributeContainer = HierarchyAttributeContainer(parent = compilation.attributes)
|
||||
|
||||
override fun getAttributes() = attributeContainer
|
||||
|
||||
+4
-3
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.Cocoapods
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin.Companion.POD_FRAMEWORK_PREFIX
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.Framework
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
import org.jetbrains.kotlin.gradle.utils.getFile
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import javax.inject.Inject
|
||||
@@ -135,7 +136,7 @@ abstract class CocoapodsExtension @Inject constructor(private val project: Proje
|
||||
/**
|
||||
* Configure output directory for pod publishing
|
||||
*/
|
||||
var publishDir: File = CocoapodsBuildDirs(project).publish
|
||||
var publishDir: File = CocoapodsBuildDirs(project.layout).publish.getFile()
|
||||
|
||||
internal val specRepos = SpecRepos()
|
||||
|
||||
@@ -179,8 +180,8 @@ abstract class CocoapodsExtension @Inject constructor(private val project: Proje
|
||||
val newContent = lineContent.replace(path.name, "")
|
||||
"""
|
||||
|Deprecated DSL found on ${buildScript.absolutePath}${File.pathSeparator}${lineNumber + 1}:
|
||||
|Found: "${lineContent}"
|
||||
|Expected: "${newContent}"
|
||||
|Found: "$lineContent"
|
||||
|Expected: "$newContent"
|
||||
|Please, change the path to avoid this warning.
|
||||
|
|
||||
""".trimMargin()
|
||||
|
||||
+144
-124
@@ -10,9 +10,14 @@ import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.file.RegularFile
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.api.tasks.wrapper.Wrapper
|
||||
import org.jetbrains.kotlin.daemon.common.trimQuotes
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
@@ -21,10 +26,9 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.Cocoapods
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.Idea222Api
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.ideaImportDependsOn
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.AppleSdk
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.AppleTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.FrameworkCopy
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XCFrameworkTask
|
||||
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||
import org.jetbrains.kotlin.gradle.targets.native.cocoapods.KotlinArtifactsPodspecExtension
|
||||
import org.jetbrains.kotlin.gradle.targets.native.cocoapods.kotlinArtifactsPodspecExtension
|
||||
@@ -33,7 +37,6 @@ import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.kotlinArtifacts
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.utils.*
|
||||
import org.jetbrains.kotlin.gradle.utils.asValidTaskName
|
||||
import org.jetbrains.kotlin.gradle.utils.filesProvider
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.gradle.utils.newInstance
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
@@ -44,34 +47,37 @@ import org.jetbrains.kotlin.util.capitalizeDecapitalize.capitalizeAsciiOnly
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
import java.io.File
|
||||
|
||||
internal val Project.cocoapodsBuildDirs: CocoapodsBuildDirs
|
||||
|
||||
|
||||
internal val ProjectLayout.cocoapodsBuildDirs: CocoapodsBuildDirs
|
||||
get() = CocoapodsBuildDirs(this)
|
||||
|
||||
internal class CocoapodsBuildDirs(val project: Project) {
|
||||
val root: File
|
||||
get() = project.buildDir.resolve("cocoapods")
|
||||
internal class CocoapodsBuildDirs(private val layout: ProjectLayout) {
|
||||
|
||||
val framework: File
|
||||
get() = root.resolve("framework")
|
||||
val root: Provider<Directory>
|
||||
get() = layout.buildDirectory.dir("cocoapods")
|
||||
val framework: Provider<Directory>
|
||||
get() = dir("framework")
|
||||
val dummyFramework: Provider<Directory>
|
||||
get() = dir("dummy.framework")
|
||||
val defs: Provider<Directory>
|
||||
get() = dir("defs")
|
||||
val publish: Provider<Directory>
|
||||
get() = dir("publish")
|
||||
|
||||
val dummyFramework: File
|
||||
get() = root.resolve("dummy.framework")
|
||||
fun synthetic(family: Provider<Family>): Provider<Directory> {
|
||||
return dir("synthetic").map { it.dir(family.get().platformLiteral) }
|
||||
}
|
||||
|
||||
val defs: File
|
||||
get() = root.resolve("defs")
|
||||
fun fatFramework(buildType: NativeBuildType): Provider<Directory> {
|
||||
return root.map { it.dir("fat-frameworks/${buildType.getName()}") }
|
||||
}
|
||||
|
||||
val buildSettings: File
|
||||
get() = root.resolve("buildSettings")
|
||||
fun buildSettings(pod: Provider<CocoapodsDependency>, sdk: Provider<String>): Provider<RegularFile> {
|
||||
return dir("buildSettings").map { it.file("build-settings-${sdk.get()}-${pod.get().schemeName}.properties") }
|
||||
}
|
||||
|
||||
val synthetic: File
|
||||
get() = root.resolve("synthetic")
|
||||
|
||||
fun synthetic(family: Family) = synthetic.resolve(family.platformLiteral)
|
||||
|
||||
val publish: File = root.resolve("publish")
|
||||
|
||||
fun fatFramework(buildType: NativeBuildType) =
|
||||
root.resolve("fat-frameworks/${buildType.getName()}")
|
||||
private fun dir(pathFromRoot: String): Provider<Directory> = root.map { it.dir(pathFromRoot) }
|
||||
}
|
||||
|
||||
internal fun String.asValidFrameworkName() = replace('-', '_')
|
||||
@@ -115,24 +121,13 @@ private val KotlinNativeTarget.toValidSDK: String
|
||||
else -> throw IllegalArgumentException("Bad target ${konanTarget.name}.")
|
||||
}
|
||||
|
||||
internal fun Project.getPodBuildTaskProvider(
|
||||
private fun Project.getPodBuildTaskProvider(
|
||||
target: KotlinNativeTarget,
|
||||
pod: CocoapodsDependency
|
||||
): TaskProvider<PodBuildTask> {
|
||||
return tasks.named(target.toValidSDK.toBuildDependenciesTaskName(pod), PodBuildTask::class.java)
|
||||
}
|
||||
|
||||
internal fun Project.getPodBuildSettingsProperties(
|
||||
target: KotlinNativeTarget,
|
||||
pod: CocoapodsDependency
|
||||
): PodBuildSettingsProperties {
|
||||
return getPodBuildTaskProvider(target, pod).get().buildSettingsFile.get()
|
||||
.reader()
|
||||
.use {
|
||||
PodBuildSettingsProperties.readSettingsFromReader(it)
|
||||
}
|
||||
}
|
||||
|
||||
internal val PodBuildSettingsProperties.frameworkSearchPaths: List<String>
|
||||
get() {
|
||||
val frameworkPathsSelfIncluding = mutableListOf<String>()
|
||||
@@ -154,6 +149,7 @@ private val PodBuildSettingsProperties.frameworkHeadersSearchPaths: List<String>
|
||||
* Ignores whitespaces in quotes and drops quotes, e.g. a string
|
||||
* `foo "bar baz" qux="quux"` will be split into ["foo", "bar baz", "qux=quux"].
|
||||
*/
|
||||
@Suppress("RegExpUnnecessaryNonCapturingGroup")
|
||||
internal fun String.splitQuotedArgs(): List<String> =
|
||||
Regex("""(?:[^\s"]|(?:"[^"]*"))+""").findAll(this).map {
|
||||
it.value.replace("\"", "")
|
||||
@@ -178,15 +174,15 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
private fun Project.createCopyFrameworkTask(
|
||||
originalDirectory: Provider<File>,
|
||||
frameworkFile: Provider<File>,
|
||||
buildingTask: TaskProvider<*>
|
||||
) = registerTask<FrameworkCopy>(SYNC_TASK_NAME) {
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Copies a framework for given platform and build type into the CocoaPods build directory"
|
||||
|
||||
it.sourceFramework.fileProvider(frameworkFile)
|
||||
it.dependsOn(buildingTask)
|
||||
it.files = filesProvider { originalDirectory.map { dir -> dir.listFiles().orEmpty() } }
|
||||
it.destDir = cocoapodsBuildDirs.framework
|
||||
it.destinationDirectory.set(layout.cocoapodsBuildDirs.framework)
|
||||
}
|
||||
|
||||
private fun createSyncForFatFramework(
|
||||
@@ -210,7 +206,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
val fatFrameworkTask = project.registerTask<FatFrameworkTask>("fatFramework") { task ->
|
||||
task.group = TASK_GROUP
|
||||
task.description = "Creates a fat framework for requested architectures"
|
||||
task.destinationDir = project.cocoapodsBuildDirs.fatFramework(requestedBuildType)
|
||||
task.destinationDir = project.layout.cocoapodsBuildDirs.fatFramework(requestedBuildType).getFile()
|
||||
|
||||
fatTargets.forEach { (_, targets) ->
|
||||
targets.singleOrNull()?.let {
|
||||
@@ -221,7 +217,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
}
|
||||
}
|
||||
|
||||
project.createCopyFrameworkTask(fatFrameworkTask.map { it.destinationDir }, fatFrameworkTask)
|
||||
project.createCopyFrameworkTask(fatFrameworkTask.map { it.fatFramework }, fatFrameworkTask)
|
||||
}
|
||||
|
||||
private fun createSyncForRegularFramework(
|
||||
@@ -236,7 +232,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
check(targets.size == 1) { "The project has more than one target for the requested platform: `${requestedPlatform.visibleName}`" }
|
||||
|
||||
val frameworkLinkTask = targets.single().binaries.getFramework(POD_FRAMEWORK_PREFIX, requestedBuildType).linkTaskProvider
|
||||
project.createCopyFrameworkTask(frameworkLinkTask.flatMap { it.destinationDirectory.map { dir -> dir.asFile } }, frameworkLinkTask)
|
||||
project.createCopyFrameworkTask(frameworkLinkTask.flatMap { it.outputFile }, frameworkLinkTask)
|
||||
}
|
||||
|
||||
private fun createSyncTask(
|
||||
@@ -332,6 +328,8 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
|
||||
val interopTask = project.tasks.named<CInteropProcess>(interop.interopProcessingTaskName).get()
|
||||
|
||||
interopTask.onlyIf { HostManager.hostIsMac }
|
||||
|
||||
interopTask.dependsOn(defTask)
|
||||
|
||||
pod.interopBindingDependencies.forEach { dependencyName ->
|
||||
@@ -339,21 +337,20 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
with(interop) {
|
||||
defFileProperty.set(defTask.map { it.outputFile })
|
||||
defFileProperty.set(defTask.flatMap { it.defFile.mapToFile() })
|
||||
_packageNameProp.set(project.provider { pod.packageName })
|
||||
_extraOptsProp.addAll(project.provider { pod.extraOpts })
|
||||
}
|
||||
|
||||
if (HostManager.hostIsMac) {
|
||||
val podBuildTaskProvider = project.getPodBuildTaskProvider(target, pod)
|
||||
interopTask.inputs.file(podBuildTaskProvider.map { it.buildSettingsFile })
|
||||
interopTask.dependsOn(podBuildTaskProvider)
|
||||
}
|
||||
val podBuildTaskProvider = project.getPodBuildTaskProvider(target, pod)
|
||||
val buildSettingsFileProvider = project.buildSettingsFileProvider(pod, target)
|
||||
interopTask.inputs.file(buildSettingsFileProvider)
|
||||
interopTask.dependsOn(podBuildTaskProvider)
|
||||
|
||||
interopTask.doFirst { _ ->
|
||||
// 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.
|
||||
val podBuildSettings = project.getPodBuildSettingsProperties(target, pod)
|
||||
val podBuildSettings = PodBuildSettingsProperties.readSettingsFromFile(buildSettingsFileProvider.getFile())
|
||||
|
||||
podBuildSettings.cflags?.let { args ->
|
||||
// Xcode quotes around paths with spaces.
|
||||
@@ -363,7 +360,6 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
|
||||
interop.compilerOpts.addAll(podBuildSettings.frameworkHeadersSearchPaths.map { "-I$it" })
|
||||
interop.compilerOpts.addAll(podBuildSettings.frameworkSearchPaths.map { "-F$it" })
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -409,28 +405,19 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
project: Project,
|
||||
cocoapodsExtension: CocoapodsExtension
|
||||
) {
|
||||
project.tasks.register(POD_SPEC_TASK_NAME, PodspecTask::class.java) {
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Generates a podspec file for CocoaPods import"
|
||||
it.needPodspec = project.provider { cocoapodsExtension.needPodspec }
|
||||
it.publishing.set(false)
|
||||
it.pods.set(cocoapodsExtension.pods)
|
||||
it.version.set(cocoapodsExtension.version ?: project.version.toString())
|
||||
it.specName.set(cocoapodsExtension.name)
|
||||
it.extraSpecAttributes.set(cocoapodsExtension.extraSpecAttributes)
|
||||
it.outputDir.set(project.projectDir)
|
||||
it.homepage.set(cocoapodsExtension.homepage)
|
||||
it.license.set(cocoapodsExtension.license)
|
||||
it.authors.set(cocoapodsExtension.authors)
|
||||
it.summary.set(cocoapodsExtension.summary)
|
||||
it.frameworkName = cocoapodsExtension.podFrameworkName
|
||||
it.ios = project.provider { cocoapodsExtension.ios }
|
||||
it.osx = project.provider { cocoapodsExtension.osx }
|
||||
it.tvos = project.provider { cocoapodsExtension.tvos }
|
||||
it.watchos = project.provider { cocoapodsExtension.watchos }
|
||||
project.registerTask<PodspecTask>(POD_SPEC_TASK_NAME) { task ->
|
||||
task.group = TASK_GROUP
|
||||
task.description = "Generates a podspec file for CocoaPods import"
|
||||
task.outputDir.set(project.projectDir)
|
||||
task.needPodspec.set(project.provider { cocoapodsExtension.needPodspec })
|
||||
task.publishing.set(false)
|
||||
|
||||
task.configure(cocoapodsExtension, project)
|
||||
|
||||
task.gradleWrapperPath.set(project.gradleWrapperPath())
|
||||
val generateWrapper = project.findProperty(GENERATE_WRAPPER_PROPERTY)?.toString()?.toBoolean() ?: false
|
||||
if (generateWrapper) {
|
||||
it.dependsOn(":wrapper")
|
||||
task.dependsOn(":wrapper")
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -578,10 +565,10 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
project.registerTask<PodSetupBuildTask>(sdk.toSetupBuildTaskName(pod)) { task ->
|
||||
task.group = TASK_GROUP
|
||||
task.description = "Collect environment variables from .xcworkspace file"
|
||||
task.pod = project.provider { pod }
|
||||
task.sdk = project.provider { sdk }
|
||||
task.podsXcodeProjDir = podInstallTask.map { it.podsXcodeProjDirProvider.get() }
|
||||
task.frameworkName = cocoapodsExtension.podFrameworkName
|
||||
task.pod.set(pod)
|
||||
task.sdk.set(sdk)
|
||||
task.podsXcodeProjDir.set(podInstallTask.map { it.podsXcodeProjDirProvider.get() })
|
||||
task.frameworkName.set(cocoapodsExtension.podFrameworkName)
|
||||
task.dependsOn(podInstallTask)
|
||||
}
|
||||
}
|
||||
@@ -616,13 +603,15 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
val podSetupBuildTaskProvider =
|
||||
project.tasks.named(sdk.toSetupBuildTaskName(pod), PodSetupBuildTask::class.java)
|
||||
|
||||
project.tasks.register(sdk.toBuildDependenciesTaskName(pod), PodBuildTask::class.java) {
|
||||
it.group = TASK_GROUP
|
||||
it.description = "Calls `xcodebuild` on xcworkspace for the pod scheme"
|
||||
it.sdk = project.provider { sdk }
|
||||
it.pod = project.provider { pod }
|
||||
it.podsXcodeProjDir = podSetupBuildTaskProvider.map { task -> task.podsXcodeProjDir.get() }
|
||||
it.buildSettingsFile = podSetupBuildTaskProvider.map { task -> task.buildSettingsFile.get() }
|
||||
project.tasks.register(sdk.toBuildDependenciesTaskName(pod), PodBuildTask::class.java) { task ->
|
||||
task.group = TASK_GROUP
|
||||
task.description = "Calls `xcodebuild` on xcworkspace for the pod scheme"
|
||||
task.buildSettingsFile.set(podSetupBuildTaskProvider.flatMap { it.buildSettingsFile })
|
||||
task.pod.set(pod)
|
||||
task.sdk.set(sdk)
|
||||
task.family.set(target.konanTarget.family)
|
||||
task.podsXcodeProjDir.fileProvider(podSetupBuildTaskProvider.flatMap { it.podsXcodeProjDir })
|
||||
task.dependsOn(podSetupBuildTaskProvider)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -667,28 +656,32 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
private fun configureLinkingOptions(project: Project, cocoapodsExtension: CocoapodsExtension, nativeBinary: NativeBinary) {
|
||||
cocoapodsExtension.pods.all { pod ->
|
||||
nativeBinary.linkTaskProvider.configure { task ->
|
||||
task.onlyIf { HostManager.hostIsMac }
|
||||
|
||||
val binary = task.binary
|
||||
if (HostManager.hostIsMac) {
|
||||
val podBuildTaskProvider = project.getPodBuildTaskProvider(binary.target, pod)
|
||||
task.inputs.file(podBuildTaskProvider.map { it.buildSettingsFile })
|
||||
task.dependsOn(podBuildTaskProvider)
|
||||
}
|
||||
|
||||
task.doFirst { _ ->
|
||||
val isExecutable = binary is AbstractExecutable
|
||||
val isDynamicFramework = (binary is Framework && !binary.isStatic)
|
||||
val podBuildTaskProvider = project.getPodBuildTaskProvider(binary.target, pod)
|
||||
val buildSettingsFileProvider = project.buildSettingsFileProvider(pod, binary.target)
|
||||
task.inputs.file(buildSettingsFileProvider)
|
||||
task.dependsOn(podBuildTaskProvider)
|
||||
|
||||
val podBuildSettings = project.getPodBuildSettingsProperties(binary.target, pod)
|
||||
val isExecutable = binary is AbstractExecutable
|
||||
val isDynamicFramework = project.provider { binary is Framework && !binary.isStatic }
|
||||
|
||||
task.doFirst {
|
||||
val podBuildSettings = PodBuildSettingsProperties.readSettingsFromFile(buildSettingsFileProvider.getFile())
|
||||
val frameworkFileName = pod.moduleName + ".framework"
|
||||
val frameworkSearchPaths = podBuildSettings.frameworkSearchPaths
|
||||
|
||||
if (isExecutable || isDynamicFramework) {
|
||||
val linkerOpts = task.additionalLinkerOpts
|
||||
|
||||
if (isExecutable || isDynamicFramework.get()) {
|
||||
val frameworkFileExists = frameworkSearchPaths.any { dir -> File(dir, frameworkFileName).exists() }
|
||||
if (frameworkFileExists) binary.linkerOpts.addArg("-framework", pod.moduleName)
|
||||
binary.linkerOpts.addAll(frameworkSearchPaths.map { "-F$it" })
|
||||
if (frameworkFileExists) linkerOpts.addArg("-framework", pod.moduleName)
|
||||
linkerOpts.addAll(frameworkSearchPaths.map { "-F$it" })
|
||||
}
|
||||
|
||||
if (isExecutable) binary.linkerOpts.addArgs("-rpath", frameworkSearchPaths)
|
||||
if (isExecutable) linkerOpts.addArgs("-rpath", frameworkSearchPaths)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -720,36 +713,39 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
cocoapodsExtension: CocoapodsExtension,
|
||||
xcFrameworkTask: TaskProvider<XCFrameworkTask>,
|
||||
buildType: NativeBuildType
|
||||
): TaskProvider<PodspecTask> =
|
||||
with(project) {
|
||||
val task =
|
||||
tasks.register(lowerCamelCaseName(POD_FRAMEWORK_PREFIX, "spec", buildType.getName()), PodspecTask::class.java) { task ->
|
||||
task.description = "Generates podspec for ${buildType.getName().capitalizeAsciiOnly()} XCFramework publishing"
|
||||
task.outputDir.set(xcFrameworkTask.map { it.outputDir.resolve(it.buildType.getName()) })
|
||||
task.needPodspec = provider { true }
|
||||
task.publishing.set(true)
|
||||
task.pods.set(cocoapodsExtension.pods)
|
||||
task.specName.set(cocoapodsExtension.name)
|
||||
task.version.set(cocoapodsExtension.version ?: version.toString())
|
||||
task.extraSpecAttributes.set(cocoapodsExtension.extraSpecAttributes)
|
||||
task.homepage.set(cocoapodsExtension.homepage)
|
||||
task.license.set(cocoapodsExtension.license)
|
||||
task.authors.set(cocoapodsExtension.authors)
|
||||
task.summary.set(cocoapodsExtension.summary)
|
||||
task.source.set(cocoapodsExtension.source)
|
||||
task.frameworkName = cocoapodsExtension.podFrameworkName
|
||||
task.ios = provider { cocoapodsExtension.ios }
|
||||
task.osx = provider { cocoapodsExtension.osx }
|
||||
task.tvos = provider { cocoapodsExtension.tvos }
|
||||
task.watchos = provider { cocoapodsExtension.watchos }
|
||||
val generateWrapper = project.findProperty(GENERATE_WRAPPER_PROPERTY)?.toString()?.toBoolean() ?: false
|
||||
if (generateWrapper) {
|
||||
task.dependsOn(":wrapper")
|
||||
}
|
||||
}
|
||||
xcFrameworkTask.dependsOn(task)
|
||||
return task
|
||||
): TaskProvider<PodspecTask> {
|
||||
val task = project.registerTask<PodspecTask>(lowerCamelCaseName(POD_FRAMEWORK_PREFIX, "spec", buildType.getName())) { task ->
|
||||
task.description = "Generates podspec for ${buildType.getName().capitalizeAsciiOnly()} XCFramework publishing"
|
||||
task.outputDir.set(xcFrameworkTask.map { it.outputDir.resolve(it.buildType.getName()) })
|
||||
task.needPodspec.set(true)
|
||||
task.publishing.set(true)
|
||||
task.source.set(project.provider { cocoapodsExtension.source })
|
||||
|
||||
task.configure(cocoapodsExtension, project)
|
||||
}
|
||||
xcFrameworkTask.dependsOn(task)
|
||||
return task
|
||||
}
|
||||
|
||||
private fun PodspecTask.configure(cocoapodsExtension: CocoapodsExtension, project: Project) {
|
||||
fun <T> Property<T>.setProvider(provider: () -> T?) = set(project.provider(provider))
|
||||
|
||||
pods.set(cocoapodsExtension.pods)
|
||||
specName.setProvider { cocoapodsExtension.name }
|
||||
version.setProvider { cocoapodsExtension.version ?: project.version.toString() }
|
||||
extraSpecAttributes.set(project.provider { cocoapodsExtension.extraSpecAttributes })
|
||||
homepage.setProvider { cocoapodsExtension.homepage }
|
||||
license.setProvider { cocoapodsExtension.license }
|
||||
authors.setProvider { cocoapodsExtension.authors }
|
||||
summary.setProvider { cocoapodsExtension.summary }
|
||||
frameworkName.set(cocoapodsExtension.podFrameworkName)
|
||||
ios.set(cocoapodsExtension.ios)
|
||||
osx.set(cocoapodsExtension.osx)
|
||||
tvos.set(cocoapodsExtension.tvos)
|
||||
watchos.set(cocoapodsExtension.watchos)
|
||||
projectPath.set(project.taskProjectPath())
|
||||
hasPodfile.set(project.hasPodfileOwnOrParent())
|
||||
}
|
||||
|
||||
private fun registerPodPublishFatFrameworkTasks(
|
||||
project: Project,
|
||||
@@ -811,6 +807,29 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.gradleWrapperPath(): Provider<String?> {
|
||||
return provider { rootProject.tasks.locateTask<Wrapper>("wrapper")?.get()?.scriptFile?.absolutePath }
|
||||
}
|
||||
|
||||
private fun Project.taskProjectPath(): String {
|
||||
return if (project.depth != 0) project.path else ""
|
||||
}
|
||||
|
||||
private fun Project.buildSettingsFileProvider(pod: CocoapodsDependency, target: KotlinNativeTarget): Provider<RegularFile> {
|
||||
return layout.cocoapodsBuildDirs.buildSettings(provider { pod }, provider { target.toValidSDK })
|
||||
}
|
||||
|
||||
private val KotlinMultiplatformExtension?.cocoapodsExtensionOrNull: CocoapodsExtension?
|
||||
get() = (this as? ExtensionAware)?.extensions?.findByName(COCOAPODS_EXTENSION_NAME) as? CocoapodsExtension
|
||||
|
||||
private fun Project.hasPodfileOwnOrParent(): Provider<Boolean> {
|
||||
return provider {
|
||||
multiplatformExtensionOrNull?.cocoapodsExtensionOrNull?.podfile != null
|
||||
|| (parent?.hasPodfileOwnOrParent()?.get() ?: false)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
override fun apply(project: Project): Unit = with(project) {
|
||||
|
||||
pluginManager.withPlugin("kotlin-multiplatform") {
|
||||
@@ -846,6 +865,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
companion object {
|
||||
const val COCOAPODS_EXTENSION_NAME = "cocoapods"
|
||||
const val TASK_GROUP = "CocoaPods"
|
||||
|
||||
+4
@@ -53,6 +53,10 @@ data class PodBuildSettingsProperties(
|
||||
const val PUBLIC_HEADERS_FOLDER_PATH = "PUBLIC_HEADERS_FOLDER_PATH"
|
||||
const val FRAMEWORK_SEARCH_PATHS = "FRAMEWORK_SEARCH_PATHS"
|
||||
|
||||
internal fun readSettingsFromFile(file: File): PodBuildSettingsProperties {
|
||||
return file.reader().use { readSettingsFromReader(it) }
|
||||
}
|
||||
|
||||
fun readSettingsFromReader(reader: Reader): PodBuildSettingsProperties {
|
||||
with(Properties()) {
|
||||
load(reader)
|
||||
|
||||
+15
-4
@@ -7,20 +7,26 @@
|
||||
package org.jetbrains.kotlin.gradle.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.file.RegularFile
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.Nested
|
||||
import org.gradle.api.tasks.OutputFile
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
||||
import org.jetbrains.kotlin.gradle.utils.appendLine
|
||||
import org.jetbrains.kotlin.gradle.utils.getFile
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Generates a def-file for the given CocoaPods dependency.
|
||||
*/
|
||||
abstract class DefFileTask : DefaultTask() {
|
||||
abstract class DefFileTask @Inject constructor(projectLayout: ProjectLayout) : DefaultTask() {
|
||||
|
||||
@get:Nested
|
||||
abstract val pod: Property<CocoapodsDependency>
|
||||
@@ -29,13 +35,18 @@ abstract class DefFileTask : DefaultTask() {
|
||||
abstract val useLibraries: Property<Boolean>
|
||||
|
||||
@get:OutputFile
|
||||
val defFile: Provider<RegularFile> = projectLayout.cocoapodsBuildDirs.defs.map { it.file("${pod.get().moduleName}.def") }
|
||||
|
||||
@get:Internal
|
||||
@Deprecated("Use `defFile` instead", replaceWith = ReplaceWith("defFile.get().asFile"))
|
||||
val outputFile: File
|
||||
get() = project.cocoapodsBuildDirs.defs.resolve("${pod.get().moduleName}.def")
|
||||
get() = defFile.getFile()
|
||||
|
||||
@TaskAction
|
||||
fun generate() {
|
||||
outputFile.parentFile.mkdirs()
|
||||
outputFile.writeText(buildString {
|
||||
val output = defFile.getFile()
|
||||
output.parentFile.mkdirs()
|
||||
output.writeText(buildString {
|
||||
appendLine("language = Objective-C")
|
||||
with(pod.get()) {
|
||||
when {
|
||||
|
||||
+5
-2
@@ -7,13 +7,16 @@
|
||||
package org.jetbrains.kotlin.gradle.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.OutputDirectory
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
||||
import org.jetbrains.kotlin.gradle.utils.mapToFile
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* Creates a dummy framework in the target directory.
|
||||
@@ -26,7 +29,7 @@ import java.io.File
|
||||
* So we create a dummy static framework to allow CocoaPods install our pod correctly
|
||||
* and then replace it with the real one during a real build process.
|
||||
*/
|
||||
abstract class DummyFrameworkTask : DefaultTask() {
|
||||
abstract class DummyFrameworkTask @Inject constructor(projectLayout: ProjectLayout) : DefaultTask() {
|
||||
|
||||
@get:Input
|
||||
abstract val frameworkName: Property<String>
|
||||
@@ -35,7 +38,7 @@ abstract class DummyFrameworkTask : DefaultTask() {
|
||||
abstract val useStaticFramework: Property<Boolean>
|
||||
|
||||
@get:OutputDirectory
|
||||
val outputFramework: Provider<File> = project.provider { project.cocoapodsBuildDirs.dummyFramework }
|
||||
val outputFramework: Provider<File> = projectLayout.cocoapodsBuildDirs.dummyFramework.mapToFile()
|
||||
|
||||
private val dummyFrameworkResource: String
|
||||
get() {
|
||||
|
||||
+42
-33
@@ -7,71 +7,80 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.native.tasks
|
||||
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.gradle.api.file.*
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.provider.ProviderFactory
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency.PodLocation.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
||||
import org.jetbrains.kotlin.gradle.utils.getFile
|
||||
import org.jetbrains.kotlin.gradle.utils.runCommand
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* The task compiles external cocoa pods sources.
|
||||
*/
|
||||
open class PodBuildTask : CocoapodsTask() {
|
||||
abstract class PodBuildTask @Inject constructor(
|
||||
providerFactory: ProviderFactory,
|
||||
projectLayout: ProjectLayout,
|
||||
objectFactory: ObjectFactory,
|
||||
) : CocoapodsTask() {
|
||||
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:InputFile
|
||||
lateinit var buildSettingsFile: Provider<File>
|
||||
internal set
|
||||
abstract val buildSettingsFile: RegularFileProperty
|
||||
|
||||
@get:Nested
|
||||
internal lateinit var pod: Provider<CocoapodsDependency>
|
||||
|
||||
@get:PathSensitive(PathSensitivity.ABSOLUTE)
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:InputFiles
|
||||
internal val srcDir: FileTree
|
||||
get() = project.fileTree(
|
||||
buildSettingsFile.map { PodBuildSettingsProperties.readSettingsFromReader(it.reader()).podsTargetSrcRoot }
|
||||
)
|
||||
|
||||
@get:Internal
|
||||
internal var buildDir: Provider<File> = project.provider {
|
||||
project.file(PodBuildSettingsProperties.readSettingsFromReader(buildSettingsFile.get().reader()).buildDir)
|
||||
}
|
||||
internal abstract val pod: Property<CocoapodsDependency>
|
||||
|
||||
@get:Input
|
||||
internal lateinit var sdk: Provider<String>
|
||||
internal abstract val sdk: Property<String>
|
||||
|
||||
@Suppress("unused") // declares an ouptut
|
||||
@get:OutputFiles
|
||||
internal val buildResult: Provider<FileCollection> = project.provider {
|
||||
project.fileTree(buildDir.get()) {
|
||||
it.include("**/${pod.get().schemeName}.*/")
|
||||
it.include("**/${pod.get().schemeName}/")
|
||||
@get:Input
|
||||
internal abstract val family: Property<Family>
|
||||
|
||||
private val synthetic = projectLayout.cocoapodsBuildDirs.synthetic(family)
|
||||
|
||||
@get:IgnoreEmptyDirectories
|
||||
@get:InputDirectory
|
||||
internal val srcDir: Provider<Directory> = pod.flatMap { pod ->
|
||||
val podLocation = pod.source
|
||||
if (podLocation is Path) {
|
||||
projectLayout.dir(providerFactory.provider { podLocation.dir })
|
||||
} else {
|
||||
synthetic.map { it.dir("Pods/${pod.schemeName}") }
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused") // declares an output
|
||||
@get:OutputFiles
|
||||
internal val buildResult: FileCollection = objectFactory.fileTree()
|
||||
.from(synthetic.map { it.dir("build") })
|
||||
.matching {
|
||||
it.include("**/${pod.get().schemeName}.*/")
|
||||
it.include("**/${pod.get().schemeName}/")
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
internal lateinit var podsXcodeProjDir: Provider<File>
|
||||
internal abstract val podsXcodeProjDir: DirectoryProperty
|
||||
|
||||
@TaskAction
|
||||
fun buildDependencies() {
|
||||
val podBuildSettings = PodBuildSettingsProperties.readSettingsFromReader(buildSettingsFile.get().reader())
|
||||
val podBuildSettings = PodBuildSettingsProperties.readSettingsFromFile(buildSettingsFile.getFile())
|
||||
|
||||
val podsXcodeProjDir = podsXcodeProjDir.get()
|
||||
|
||||
val podXcodeBuildCommand = listOf(
|
||||
"xcodebuild",
|
||||
"-project", podsXcodeProjDir.name,
|
||||
"-project", podsXcodeProjDir.asFile.name,
|
||||
"-scheme", pod.get().schemeName,
|
||||
"-sdk", sdk.get(),
|
||||
"-configuration", podBuildSettings.configuration
|
||||
)
|
||||
|
||||
runCommand(podXcodeBuildCommand, project.logger) { directory(podsXcodeProjDir.parentFile) }
|
||||
runCommand(podXcodeBuildCommand, logger) { directory(podsXcodeProjDir.asFile.parentFile) }
|
||||
}
|
||||
}
|
||||
|
||||
+4
-2
@@ -7,6 +7,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.native.tasks
|
||||
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
@@ -17,11 +18,12 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.platformLiteral
|
||||
import org.jetbrains.kotlin.gradle.utils.XcodeVersion
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* The task generates a synthetic project with all cocoapods dependencies
|
||||
*/
|
||||
abstract class PodGenTask : CocoapodsTask() {
|
||||
abstract class PodGenTask @Inject constructor(projectLayout: ProjectLayout) : CocoapodsTask() {
|
||||
|
||||
init {
|
||||
onlyIf {
|
||||
@@ -54,7 +56,7 @@ abstract class PodGenTask : CocoapodsTask() {
|
||||
internal abstract val xcodeVersion: Property<XcodeVersion>
|
||||
|
||||
@get:OutputFile
|
||||
val podfile: Provider<File> = family.map { project.cocoapodsBuildDirs.synthetic(it).resolve("Podfile") }
|
||||
val podfile: Provider<File> = projectLayout.cocoapodsBuildDirs.synthetic(family).map { it.file("Podfile").asFile }
|
||||
|
||||
@TaskAction
|
||||
fun generate() {
|
||||
|
||||
+4
-2
@@ -7,6 +7,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.native.tasks
|
||||
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
@@ -17,8 +18,9 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
||||
import org.jetbrains.kotlin.gradle.targets.native.cocoapods.MissingCocoapodsMessage
|
||||
import org.jetbrains.kotlin.gradle.targets.native.cocoapods.MissingSpecReposMessage
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
abstract class PodInstallTask : AbstractPodInstallTask() {
|
||||
abstract class PodInstallTask @Inject constructor(projectLayout: ProjectLayout) : AbstractPodInstallTask() {
|
||||
|
||||
@get:Optional
|
||||
@get:InputFile
|
||||
@@ -36,7 +38,7 @@ abstract class PodInstallTask : AbstractPodInstallTask() {
|
||||
@get:InputDirectory
|
||||
abstract val dummyFramework: Property<File>
|
||||
|
||||
private val framework = project.provider { project.cocoapodsBuildDirs.framework.resolve("${frameworkName.get()}.framework") }
|
||||
private val framework = projectLayout.cocoapodsBuildDirs.framework.map { it.file("${frameworkName.get()}.framework").asFile }
|
||||
private val tmpFramework = dummyFramework.map { dummy -> dummy.parentFile.resolve("tmp.framework").also { it.deleteOnExit() } }
|
||||
|
||||
override fun doPodInstall() {
|
||||
|
||||
+15
-17
@@ -7,33 +7,34 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.targets.native.tasks
|
||||
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.file.RegularFile
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
||||
import org.jetbrains.kotlin.gradle.utils.getFile
|
||||
import org.jetbrains.kotlin.gradle.utils.runCommand
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
open class PodSetupBuildTask : CocoapodsTask() {
|
||||
abstract class PodSetupBuildTask @Inject constructor(projectLayout: ProjectLayout) : CocoapodsTask() {
|
||||
|
||||
@get:Input
|
||||
lateinit var frameworkName: Provider<String>
|
||||
abstract val frameworkName: Property<String>
|
||||
|
||||
@get:Input
|
||||
internal lateinit var sdk: Provider<String>
|
||||
internal abstract val sdk: Property<String>
|
||||
|
||||
@get:Nested
|
||||
lateinit var pod: Provider<CocoapodsDependency>
|
||||
|
||||
@get:OutputFile
|
||||
val buildSettingsFile: Provider<File> = project.provider {
|
||||
project.cocoapodsBuildDirs
|
||||
.buildSettings
|
||||
.resolve(getBuildSettingFileName(pod.get(), sdk.get()))
|
||||
}
|
||||
abstract val pod: Property<CocoapodsDependency>
|
||||
|
||||
@get:Internal
|
||||
internal lateinit var podsXcodeProjDir: Provider<File>
|
||||
internal abstract val podsXcodeProjDir: Property<File>
|
||||
|
||||
@get:OutputFile
|
||||
val buildSettingsFile: Provider<RegularFile> = projectLayout.cocoapodsBuildDirs.buildSettings(pod, sdk)
|
||||
|
||||
@TaskAction
|
||||
fun setupBuild() {
|
||||
@@ -46,15 +47,12 @@ open class PodSetupBuildTask : CocoapodsTask() {
|
||||
"-sdk", sdk.get()
|
||||
)
|
||||
|
||||
val outputText = runCommand(buildSettingsReceivingCommand, project.logger) { directory(podsXcodeProjDir.parentFile) }
|
||||
val outputText = runCommand(buildSettingsReceivingCommand, logger) { directory(podsXcodeProjDir.parentFile) }
|
||||
|
||||
val buildSettingsProperties = PodBuildSettingsProperties.readSettingsFromReader(outputText.reader())
|
||||
buildSettingsFile.get().let { bsf ->
|
||||
buildSettingsFile.getFile().let { bsf ->
|
||||
buildSettingsProperties.writeSettings(bsf)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBuildSettingFileName(pod: CocoapodsDependency, sdk: String): String =
|
||||
"build-settings-$sdk-${pod.schemeName}.properties"
|
||||
|
||||
|
||||
+59
-56
@@ -3,93 +3,103 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
|
||||
@file:Suppress("PackageDirectoryMismatch", "LeakingThis") // Old package for compatibility
|
||||
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.file.ProjectLayout
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.MapProperty
|
||||
import org.gradle.api.provider.Property
|
||||
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.CocoapodsExtension.CocoapodsDependency
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.PodspecPlatformSettings
|
||||
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.SYNC_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.cocoapodsBuildDirs
|
||||
import org.jetbrains.kotlin.gradle.utils.getFile
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* The task generates a podspec file which allows a user to
|
||||
* integrate a Kotlin/Native framework into a CocoaPods project.
|
||||
*/
|
||||
open class PodspecTask : DefaultTask() {
|
||||
abstract class PodspecTask @Inject constructor(private val projectLayout: ProjectLayout) : DefaultTask() {
|
||||
|
||||
@get:Input
|
||||
internal val specName = project.objects.property(String::class.java)
|
||||
internal abstract val specName: Property<String>
|
||||
|
||||
@get:Internal
|
||||
internal val outputDir = project.objects.property(File::class.java)
|
||||
internal abstract val outputDir: Property<File>
|
||||
|
||||
@get:OutputFile
|
||||
val outputFile: File
|
||||
get() = outputDir.get().resolve("${specName.get()}.podspec")
|
||||
|
||||
@get:Input
|
||||
internal lateinit var needPodspec: Provider<Boolean>
|
||||
internal abstract val needPodspec: Property<Boolean>
|
||||
|
||||
@get:Nested
|
||||
val pods = project.objects.listProperty(CocoapodsDependency::class.java)
|
||||
abstract val pods: ListProperty<CocoapodsDependency>
|
||||
|
||||
@get:Input
|
||||
internal val version = project.objects.property(String::class.java)
|
||||
internal abstract val version: Property<String>
|
||||
|
||||
@get:Input
|
||||
internal val publishing = project.objects.property(Boolean::class.java)
|
||||
internal abstract val publishing: Property<Boolean>
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal val source = project.objects.property(String::class.java)
|
||||
internal abstract val source: Property<String>
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal val homepage = project.objects.property(String::class.java)
|
||||
internal abstract val homepage: Property<String>
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal val license = project.objects.property(String::class.java)
|
||||
internal abstract val license: Property<String>
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal val authors = project.objects.property(String::class.java)
|
||||
internal abstract val authors: Property<String>
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal val summary = project.objects.property(String::class.java)
|
||||
internal abstract val summary: Property<String>
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal val extraSpecAttributes = project.objects.mapProperty(String::class.java, String::class.java)
|
||||
internal abstract val extraSpecAttributes: MapProperty<String, String>
|
||||
|
||||
@get:Input
|
||||
internal lateinit var frameworkName: Provider<String>
|
||||
internal abstract val frameworkName: Property<String>
|
||||
|
||||
@get:Nested
|
||||
internal lateinit var ios: Provider<PodspecPlatformSettings>
|
||||
internal abstract val ios: Property<PodspecPlatformSettings>
|
||||
|
||||
@get:Nested
|
||||
internal lateinit var osx: Provider<PodspecPlatformSettings>
|
||||
internal abstract val osx: Property<PodspecPlatformSettings>
|
||||
|
||||
@get:Nested
|
||||
internal lateinit var tvos: Provider<PodspecPlatformSettings>
|
||||
internal abstract val tvos: Property<PodspecPlatformSettings>
|
||||
|
||||
@get:Nested
|
||||
internal lateinit var watchos: Provider<PodspecPlatformSettings>
|
||||
internal abstract val watchos: Property<PodspecPlatformSettings>
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal abstract val gradleWrapperPath: Property<String?>
|
||||
|
||||
@get:Input
|
||||
internal abstract val projectPath: Property<String>
|
||||
|
||||
@get:Input
|
||||
internal abstract val hasPodfile: Property<Boolean>
|
||||
|
||||
init {
|
||||
onlyIf { needPodspec.get() }
|
||||
@@ -107,17 +117,6 @@ open class PodspecTask : DefaultTask() {
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
val gradleWrapper = (project.rootProject.tasks.getByName("wrapper") as? Wrapper)?.scriptFile
|
||||
require(gradleWrapper != null && gradleWrapper.exists()) {
|
||||
"""
|
||||
The Gradle wrapper is required to run the build from Xcode.
|
||||
|
||||
Please run the same command with `-P$GENERATE_WRAPPER_PROPERTY=true` or run the `:wrapper` task to generate the wrapper manually.
|
||||
|
||||
See details about the wrapper at https://docs.gradle.org/current/userguide/gradle_wrapper.html
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
val deploymentTargets = run {
|
||||
listOf(ios, osx, tvos, watchos).map { it.get() }.filter { it.deploymentTarget != null }.joinToString("\n") {
|
||||
if (extraSpecAttributes.get().containsKey("${it.name}.deployment_target")) "" else "| spec.${it.name}.deployment_target = '${it.deploymentTarget}'"
|
||||
@@ -129,7 +128,7 @@ open class PodspecTask : DefaultTask() {
|
||||
"| spec.dependency '${pod.name}'$versionSuffix"
|
||||
}.joinToString(separator = "\n")
|
||||
|
||||
val frameworkDir = project.cocoapodsBuildDirs.framework.relativeTo(outputFile.parentFile)
|
||||
val frameworkDir = projectLayout.cocoapodsBuildDirs.framework.getFile().relativeTo(outputFile.parentFile)
|
||||
val vendoredFramework = if (publishing.get()) "${frameworkName.get()}.xcframework" else frameworkDir.resolve("${frameworkName.get()}.framework").invariantSeparatorsPath
|
||||
val vendoredFrameworks = if (extraSpecAttributes.get().containsKey("vendored_frameworks")) "" else "| spec.vendored_frameworks = '$vendoredFramework'"
|
||||
|
||||
@@ -138,12 +137,11 @@ open class PodspecTask : DefaultTask() {
|
||||
val xcConfig = if (publishing.get() || extraSpecAttributes.get().containsKey("pod_target_xcconfig")) "" else
|
||||
""" |
|
||||
| spec.pod_target_xcconfig = {
|
||||
| 'KOTLIN_PROJECT_PATH' => '${if (project.depth != 0) project.path else ""}',
|
||||
| 'KOTLIN_PROJECT_PATH' => '${projectPath.get()}',
|
||||
| 'PRODUCT_MODULE_NAME' => '${frameworkName.get()}',
|
||||
| }
|
||||
""".trimMargin()
|
||||
|
||||
val gradleCommand = "\$REPO_ROOT/${gradleWrapper.relativeTo(project.projectDir).invariantSeparatorsPath}"
|
||||
val scriptPhase = if (publishing.get() || extraSpecAttributes.get().containsKey("script_phases")) "" else
|
||||
""" |
|
||||
| spec.script_phases = [
|
||||
@@ -158,7 +156,7 @@ open class PodspecTask : DefaultTask() {
|
||||
| fi
|
||||
| set -ev
|
||||
| REPO_ROOT="${'$'}PODS_TARGET_SRCROOT"
|
||||
| "$gradleCommand" -p "${'$'}REPO_ROOT" ${'$'}KOTLIN_PROJECT_PATH:$SYNC_TASK_NAME \
|
||||
| "${gradleCommand()}" -p "${'$'}REPO_ROOT" ${'$'}KOTLIN_PROJECT_PATH:$SYNC_TASK_NAME \
|
||||
| -P${KotlinCocoapodsPlugin.PLATFORM_PROPERTY}=${'$'}PLATFORM_NAME \
|
||||
| -P${KotlinCocoapodsPlugin.ARCHS_PROPERTY}="${'$'}ARCHS" \
|
||||
| -P${KotlinCocoapodsPlugin.CONFIGURATION_PROPERTY}="${'$'}CONFIGURATION"
|
||||
@@ -191,34 +189,39 @@ open class PodspecTask : DefaultTask() {
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
if (hasPodfileOwnOrParent(project) && publishing.get().not()) {
|
||||
if (hasPodfile.get() && !publishing.get()) {
|
||||
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:
|
||||
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.get()}', :path => '${parentFile.absolutePath}'
|
||||
|
||||
""".trimIndent()
|
||||
pod '${specName.get()}', :path => '${parentFile.absolutePath}'
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun gradleCommand(): String {
|
||||
val gradleWrapperPath: String? = gradleWrapperPath.get()
|
||||
val gradleWrapper = gradleWrapperPath?.let(::File)
|
||||
require(gradleWrapper != null && gradleWrapper.exists()) {
|
||||
"""
|
||||
The Gradle wrapper is required to run the build from Xcode.
|
||||
|
||||
Please run the same command with `-P$GENERATE_WRAPPER_PROPERTY=true` or run the `:wrapper` task to generate the wrapper manually.
|
||||
|
||||
See details about the wrapper at https://docs.gradle.org/current/userguide/gradle_wrapper.html
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
return "\$REPO_ROOT/${gradleWrapper.relativeTo(projectLayout.projectDirectory.asFile).invariantSeparatorsPath}"
|
||||
}
|
||||
|
||||
private fun Provider<String>.getOrEmpty(): String = getOrElse("")
|
||||
|
||||
private fun String.surroundWithSingleQuotesIfNeeded(): String =
|
||||
if (startsWith("{") || startsWith("<<-") || startsWith("'")) this else "'$this'"
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+28
-15
@@ -43,12 +43,14 @@ abstract class KotlinNativeLink
|
||||
@Inject
|
||||
constructor(
|
||||
@Internal
|
||||
@Transient // This property can't be accessed in the execution phase
|
||||
val binary: NativeBinary,
|
||||
private val objectFactory: ObjectFactory,
|
||||
private val execOperations: ExecOperations
|
||||
private val execOperations: ExecOperations,
|
||||
) : AbstractKotlinCompileTool<K2NativeCompilerArguments>(objectFactory),
|
||||
UsesKonanPropertiesBuildService,
|
||||
KotlinToolTask<KotlinCommonCompilerToolOptions> {
|
||||
|
||||
@Deprecated("Visibility will be lifted to private in the future releases")
|
||||
@get:Internal
|
||||
val compilation: KotlinNativeCompilation
|
||||
@@ -85,16 +87,19 @@ constructor(
|
||||
)
|
||||
|
||||
@get:Input
|
||||
val outputKind: CompilerOutputKind get() = binary.outputKind.compilerOutputKind
|
||||
val outputKind: CompilerOutputKind by lazyConvention { binary.outputKind.compilerOutputKind }
|
||||
|
||||
@get:Input
|
||||
val optimized: Boolean get() = binary.optimized
|
||||
val optimized: Boolean by lazyConvention { binary.optimized }
|
||||
|
||||
@get:Input
|
||||
val debuggable: Boolean get() = binary.debuggable
|
||||
val debuggable: Boolean by lazyConvention { binary.debuggable }
|
||||
|
||||
@get:Input
|
||||
val baseName: String get() = binary.baseName
|
||||
val baseName: String by lazyConvention { binary.baseName }
|
||||
|
||||
@get:Input
|
||||
internal val binaryName: String by lazyConvention { binary.name }
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
private val konanTarget = compilation.konanTarget
|
||||
@@ -132,24 +137,29 @@ constructor(
|
||||
}
|
||||
|
||||
fun kotlinOptions(fn: Closure<*>) {
|
||||
@Suppress("DEPRECATION")
|
||||
fn.delegate = kotlinOptions
|
||||
fn.call()
|
||||
}
|
||||
|
||||
// Binary-specific options.
|
||||
@get:Input
|
||||
@get:Optional
|
||||
val entryPoint: String? get() = (binary as? Executable)?.entryPoint
|
||||
private val _entryPoint: String by lazyConvention { (binary as? Executable)?.entryPoint.orEmpty() }
|
||||
|
||||
@get:Input
|
||||
val linkerOpts: List<String> get() = binary.linkerOpts
|
||||
@get:Optional
|
||||
val entryPoint: String?
|
||||
get() = _entryPoint.ifEmpty { null }
|
||||
|
||||
@get:Input
|
||||
val linkerOpts: List<String> by lazyConvention { binary.linkerOpts }
|
||||
|
||||
@get:Input
|
||||
internal val additionalLinkerOpts: MutableList<String> = mutableListOf()
|
||||
|
||||
@get:Input
|
||||
val binaryOptions: Map<String, String> by lazy { PropertiesProvider(project).nativeBinaryOptions + binary.binaryOptions }
|
||||
|
||||
@get:Input
|
||||
val processTests: Boolean get() = binary is TestExecutable
|
||||
val processTests: Boolean by lazyConvention { binary is TestExecutable }
|
||||
|
||||
@get:Classpath
|
||||
val exportLibraries: FileCollection get() = exportLibrariesResolvedConfiguration?.files ?: objectFactory.fileCollection()
|
||||
@@ -161,8 +171,7 @@ constructor(
|
||||
}
|
||||
|
||||
@get:Input
|
||||
val isStaticFramework: Boolean
|
||||
get() = binary.let { it is Framework && it.isStatic }
|
||||
val isStaticFramework: Boolean by lazyConvention { binary.let { it is Framework && it.isStatic } }
|
||||
|
||||
@Suppress("DEPRECATION")
|
||||
@get:Input
|
||||
@@ -221,7 +230,7 @@ constructor(
|
||||
null, BitcodeEmbeddingMode.DISABLE -> Unit
|
||||
}
|
||||
|
||||
args.singleLinkerArguments = linkerOpts.toTypedArray()
|
||||
args.singleLinkerArguments = (linkerOpts + additionalLinkerOpts).toTypedArray()
|
||||
args.binaryOptions = binaryOptions.map { (key, value) -> "$key=$value" }.toTypedArray()
|
||||
args.staticFramework = isStaticFramework
|
||||
|
||||
@@ -269,7 +278,7 @@ constructor(
|
||||
}
|
||||
|
||||
"""
|
||||
|Following dependencies exported in the ${binary.name} binary are not specified as API-dependencies of a corresponding source set:
|
||||
|Following dependencies exported in the $binaryName binary are not specified as API-dependencies of a corresponding source set:
|
||||
|
|
||||
$failedDependenciesList
|
||||
|
|
||||
@@ -378,4 +387,8 @@ constructor(
|
||||
executionContext = executionContext
|
||||
).run(buildArguments)
|
||||
}
|
||||
|
||||
private inline fun <reified T : Any> lazyConvention(noinline lazyConventionValue: () -> T): Provider<T> {
|
||||
return objectFactory.providerWithLazyConvention(lazyConventionValue)
|
||||
}
|
||||
}
|
||||
|
||||
+11
-9
@@ -721,16 +721,17 @@ internal class CacheBuilder(
|
||||
val konanCacheKind: NativeCacheKind,
|
||||
val libraries: FileCollection,
|
||||
val gradleUserHomeDir: File,
|
||||
val binary: NativeBinary,
|
||||
val konanTarget: KonanTarget,
|
||||
val toolOptions: KotlinCommonCompilerToolOptions,
|
||||
val externalDependenciesArgs: List<String>
|
||||
val externalDependenciesArgs: List<String>,
|
||||
val debuggable: Boolean,
|
||||
val optimized: Boolean,
|
||||
) {
|
||||
val rootCacheDirectory
|
||||
get() = getRootCacheDirectory(
|
||||
File(runnerSettings.parent.konanHome),
|
||||
konanTarget,
|
||||
binary.debuggable,
|
||||
debuggable,
|
||||
konanCacheKind
|
||||
)
|
||||
|
||||
@@ -748,7 +749,11 @@ internal class CacheBuilder(
|
||||
konanCacheKind = konanCacheKind,
|
||||
libraries = binary.compilation.compileDependencyFiles,
|
||||
gradleUserHomeDir = project.gradle.gradleUserHomeDir,
|
||||
binary, konanTarget, toolOptions, externalDependenciesArgs
|
||||
konanTarget = konanTarget,
|
||||
toolOptions = toolOptions,
|
||||
externalDependenciesArgs = externalDependenciesArgs,
|
||||
debuggable = binary.debuggable,
|
||||
optimized = binary.optimized,
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -760,17 +765,14 @@ internal class CacheBuilder(
|
||||
listOf(KLIB_INTEROP_IR_PROVIDER_IDENTIFIER)
|
||||
)
|
||||
|
||||
private val binary: NativeBinary
|
||||
get() = settings.binary
|
||||
|
||||
private val konanTarget: KonanTarget
|
||||
get() = settings.konanTarget
|
||||
|
||||
private val optimized: Boolean
|
||||
get() = binary.optimized
|
||||
get() = settings.optimized
|
||||
|
||||
private val debuggable: Boolean
|
||||
get() = binary.debuggable
|
||||
get() = settings.debuggable
|
||||
|
||||
private val konanCacheKind: NativeCacheKind
|
||||
get() = settings.konanCacheKind
|
||||
|
||||
+13
-1
@@ -6,7 +6,9 @@
|
||||
package org.jetbrains.kotlin.gradle.utils
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.file.RegularFile
|
||||
import org.gradle.api.provider.Provider
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.nio.file.Files
|
||||
@@ -116,4 +118,14 @@ fun contentEquals(file1: File, file2: File): Boolean {
|
||||
}
|
||||
}
|
||||
|
||||
internal fun RegularFile.toUri() = asFile.toPath().toUri()
|
||||
internal fun RegularFile.toUri() = asFile.toPath().toUri()
|
||||
|
||||
internal fun Provider<RegularFile>.mapToFile(): Provider<File> = map { it.asFile }
|
||||
|
||||
@JvmName("mapDirectoryToFile") // avoids jvm signature clash
|
||||
internal fun Provider<Directory>.mapToFile(): Provider<File> = map { it.asFile }
|
||||
|
||||
internal fun Provider<RegularFile>.getFile(): File = get().asFile
|
||||
|
||||
@JvmName("getDirectoryAsFile") // avoids jvm signature clash
|
||||
internal fun Provider<Directory>.getFile(): File = get().asFile
|
||||
|
||||
Reference in New Issue
Block a user