KT-54969 Kotlin artifacts withPodspec DSL

This commit is contained in:
Artem Daugel-Dauge
2022-10-06 18:27:29 +02:00
committed by Space Team
parent 4af32b8d36
commit 4f736524b2
24 changed files with 647 additions and 10 deletions
+8
View File
@@ -0,0 +1,8 @@
<component name="ProjectDictionaryState">
<dictionary name="Artem.Daugel-Dauge">
<words>
<w>vendored</w>
<w>xcframework</w>
</words>
</dictionary>
</component>
@@ -143,6 +143,7 @@ public abstract interface class org/jetbrains/kotlin/gradle/dsl/KaptJavacOption
public abstract interface class org/jetbrains/kotlin/gradle/dsl/KotlinArtifact : org/gradle/api/Named, org/gradle/api/plugins/ExtensionAware {
public abstract fun getArtifactName ()Ljava/lang/String;
public abstract fun getModules ()Ljava/util/Set;
public abstract fun getOutDir ()Ljava/lang/String;
public abstract fun getTaskName ()Ljava/lang/String;
public abstract fun registerAssembleTask (Lorg/gradle/api/Project;)V
}
@@ -15,6 +15,7 @@ interface KotlinArtifact : Named, ExtensionAware {
val artifactName: String
val modules: Set<Any>
val taskName: String
val outDir: String
fun registerAssembleTask(project: Project)
}
@@ -0,0 +1,125 @@
/*
* Copyright 2010-2022 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.native
import org.jetbrains.kotlin.gradle.BaseGradleIT
import org.jetbrains.kotlin.gradle.GradleVersionRequired
import org.jetbrains.kotlin.gradle.transformProjectWithPluginsDsl
import org.jetbrains.kotlin.konan.target.HostManager
import org.junit.Assume
import org.junit.BeforeClass
import kotlin.test.Test
import kotlin.test.assertEquals
class NativeLibraryDslWithCocoapodsIT : BaseGradleIT() {
companion object {
@BeforeClass
@JvmStatic
fun assumeMacHost() {
Assume.assumeTrue(HostManager.hostIsMac)
}
}
override val defaultGradleVersion = GradleVersionRequired.FOR_MPP_SUPPORT
@Test
fun `check registered gradle tasks`() {
project {
build(":shared:tasks") {
assertSuccessful()
assertTasksRegistered(
":shared:generateMylibPodspec",
":shared:generateMyslibPodspec",
":shared:generateMyframePodspec",
":shared:generateMyfatframePodspec",
":shared:generateSharedPodspec",
":lib:generateGrooframePodspec",
)
assertTasksNotRegistered(
":shared:generateMyfatframewithoutpodspecPodspec",
)
}
}
}
@Test
fun `generate podspec when assembling lib`() {
project {
build(":shared:assembleMylibSharedLibraryLinuxX64") {
assertSuccessful()
assertTasksExecuted(":shared:generateMylibPodspec")
assertFilesContentEqual("podspecs/mylib.podspec", "/shared/build/out/dynamic/mylib.podspec")
}
}
}
@Test
fun `generate podspec when assembling shared lib`() {
project {
build(":shared:assembleMyslibSharedLibraryLinuxX64") {
assertSuccessful()
assertTasksExecuted(":shared:generateMyslibPodspec")
assertFilesContentEqual("podspecs/myslib.podspec", "/shared/build/out/dynamic/myslib.podspec")
}
}
}
@Test
fun `generate podspec when assembling framework`() {
project {
build(":shared:assembleMyframeFrameworkIosArm64") {
assertSuccessful()
assertTasksExecuted(":shared:generateMyframePodspec")
assertFilesContentEqual("podspecs/myframe.podspec", "/shared/build/out/framework/myframe.podspec")
}
}
}
@Test
fun `generate podspec when assembling fat framework`() {
project {
build(":shared:assembleMyfatframeFatFramework") {
assertSuccessful()
assertTasksExecuted(":shared:generateMyfatframePodspec")
assertFilesContentEqual("podspecs/myfatframe.podspec", "/shared/build/out/fatframework/myfatframe.podspec")
}
}
}
@Test
fun `generate podspec when assembling xcframework`() {
project {
build(":shared:assembleSharedXCFramework") {
assertSuccessful()
assertTasksExecuted(":shared:generateSharedPodspec")
assertFilesContentEqual("podspecs/shared.podspec", "/shared/build/out/xcframework/shared.podspec")
}
}
}
@Test
fun `generate podspec when assembling framework from groovy`() {
project {
build(":lib:assembleGrooframeFrameworkIosArm64") {
assertSuccessful()
assertTasksExecuted(":lib:generateGrooframePodspec")
assertFilesContentEqual("podspecs/grooframe.podspec", "/lib/build/out/framework/grooframe.podspec")
}
}
}
private fun project(block: Project.() -> Unit) {
transformProjectWithPluginsDsl("new-kn-library-dsl-cocoapods").block()
}
private fun CompiledProject.assertFilesContentEqual(expected: String, actual: String) {
assertFileExists(expected)
assertFileExists(actual)
assertEquals(fileInWorkingDir(expected).readText(), fileInWorkingDir(actual).readText())
}
}
@@ -0,0 +1,10 @@
plugins {
kotlin("multiplatform").apply(false)
}
allprojects {
repositories {
mavenLocal()
mavenCentral()
}
}
@@ -0,0 +1,31 @@
plugins {
id 'org.jetbrains.kotlin.multiplatform'
id 'org.jetbrains.kotlin.native.cocoapods'
}
version '0.2'
kotlin {
linuxX64()
iosX64()
iosArm64()
iosSimulatorArm64()
}
kotlinArtifacts {
it.native.Framework("grooframe") {
modes(DEBUG, RELEASE)
target = iosArm64
addModule(project(":shared"))
withPodspec {
attribute('license', 'Apache-2.0')
attribute('homepage', 'https://example.com/lib')
attribute('ios.deployment_target', '"10.0"')
attribute('swift_versions', '[\'4\', \'5\']')
rawStatement(' # This is raw statement that is appended \'as is\' to the podspec')
rawStatement(' spec.frameworks = \'CFNetwork\'')
}
}
}
@@ -0,0 +1,5 @@
package org.my.sam
class Greeting {
fun greeting() = "Hello, lib!"
}
@@ -0,0 +1,13 @@
Pod::Spec.new do |spec|
spec.name = 'grooframe'
spec.version = '0.2'
spec.vendored_frameworks = 'grooframe.framework'
spec.license = 'Apache-2.0'
spec.homepage = 'https://example.com/lib'
spec.ios.deployment_target = "10.0"
spec.swift_versions = ['4', '5']
# This is raw statement that is appended 'as is' to the podspec
spec.frameworks = 'CFNetwork'
end
@@ -0,0 +1,6 @@
Pod::Spec.new do |spec|
spec.version = '0.1'
spec.vendored_frameworks = 'myfatframe.framework'
spec.name = 'custom-podspec-name'
end
@@ -0,0 +1,7 @@
Pod::Spec.new do |spec|
spec.name = 'myframe'
spec.version = '0.1'
spec.vendored_frameworks = 'myframe.framework'
spec.prefix_header_file = false
end
@@ -0,0 +1,16 @@
Pod::Spec.new do |spec|
spec.name = 'mylib'
spec.version = '0.1'
spec.vendored_library = 'mylib.dylib'
spec.description = <<-DESC
Computes the meaning of life.
Features:
1. Is self aware
...
42. Likes candies
DESC
spec.static_framework = true
spec.requires_arc = 'true'
spec.authors = 'Tony O\'Connor'
end
@@ -0,0 +1,5 @@
Pod::Spec.new do |spec|
spec.name = 'myslib'
spec.version = '0.1'
spec.vendored_library = 'myslib.dylib'
end
@@ -0,0 +1,16 @@
Pod::Spec.new do |spec|
spec.name = 'shared'
spec.vendored_frameworks = 'shared.xcframework'
spec.version = '5.6.2'
spec.license = 'MIT'
spec.homepage = 'https://github.com/Alpaca/Alpaca'
spec.source = { :git => 'https://github.com/Alpaca/Alpaca.git', :tag => spec.version }
spec.ios.deployment_target = '10.0'
spec.osx.deployment_target = '10.12'
spec.watchos.deployment_target = '3.0'
spec.swift_versions = ['4', '5']
# This is raw statement that is appended 'as is' to the podspec
spec.frameworks = 'CFNetwork'
end
@@ -0,0 +1,96 @@
import org.jetbrains.kotlin.gradle.plugin.cocoapods.withPodspec
plugins {
kotlin("multiplatform")
kotlin("native.cocoapods")
}
version = "0.1"
kotlin {
linuxX64()
iosX64()
iosArm64()
iosSimulatorArm64()
}
kotlinArtifacts {
Native.Library("mylib") {
target = linuxX64
withPodspec {
attribute(
"description", """ |<<-DESC
| Computes the meaning of life.
| Features:
| 1. Is self aware
| ...
| 42. Likes candies
| DESC
""".trimMargin()
)
attribute("static_framework", "true")
attribute("requires_arc", "'true'")
attribute("authors", "Tony O'Connor")
}
}
Native.Library("myslib") {
target = linuxX64
isStatic = false
modes(DEBUG)
addModule(project(":lib"))
withPodspec {} // intentionally empty
}
Native.Framework("myframe") {
modes(DEBUG, RELEASE)
target = iosArm64
isStatic = false
embedBitcode = EmbedBitcodeMode.MARKER
withPodspec {
attribute("prefix_header_file", "false")
}
}
Native.Framework("myframewihtoutpodspec") {
modes(DEBUG, RELEASE)
target = iosArm64
isStatic = false
embedBitcode = EmbedBitcodeMode.MARKER
}
Native.FatFramework("myfatframe") {
targets(iosX64, iosSimulatorArm64)
embedBitcode = EmbedBitcodeMode.DISABLE
toolOptions {
suppressWarnings.set(true)
}
withPodspec {
attribute("name", "custom-podspec-name")
}
}
Native.XCFramework {
targets(iosX64, iosArm64, iosSimulatorArm64)
setModules(
project(":shared"),
project(":lib")
)
withPodspec {
attribute("version", "5.6.2")
attribute("license", "MIT")
attribute("homepage", "https://github.com/Alpaca/Alpaca")
attribute("source", "{ :git => 'https://github.com/Alpaca/Alpaca.git', :tag => spec.version }")
attribute("ios.deployment_target", "10.0")
attribute("osx.deployment_target", "10.12")
attribute("watchos.deployment_target", "3.0")
attribute("swift_versions", "['4', '5']")
rawStatement(" # This is raw statement that is appended 'as is' to the podspec")
rawStatement(" spec.frameworks = 'CFNetwork'")
}
}
}
@@ -0,0 +1,5 @@
package org.sample.application
class Greeting {
fun greeting() = "Hello, new DSL!"
}
@@ -1,3 +1,5 @@
import org.jetbrains.kotlin.gradle.plugin.cocoapods.withPodspec
plugins {
kotlin("multiplatform")
}
@@ -49,4 +51,4 @@ kotlinArtifacts {
project(":lib")
)
}
}
}
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2022 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.targets.native.cocoapods
import org.gradle.api.*
import org.gradle.api.plugins.ExtensionAware
import org.jetbrains.kotlin.gradle.plugin.cocoapods.KotlinCocoapodsPlugin
import org.jetbrains.kotlin.gradle.plugin.findExtension
import javax.inject.Inject
abstract class KotlinArtifactsPodspecExtension @Inject constructor(private val project: Project) {
private val attrs = mutableMapOf<String, String>()
private val statements = mutableListOf<String>()
internal val attributes: Map<String, String>
get() = attrs
internal val rawStatements: List<String>
get() = statements
fun attribute(key: String, value: String) {
attrs[key] = value
}
fun rawStatement(statement: String) {
statements.add(statement)
}
}
val ExtensionAware.kotlinArtifactsPodspecExtension: KotlinArtifactsPodspecExtension?
get() = findExtension(KotlinCocoapodsPlugin.ARTIFACTS_PODSPEC_EXTENSION_NAME)
@@ -9,11 +9,11 @@ package org.jetbrains.kotlin.gradle.plugin.cocoapods
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.daemon.common.trimQuotes
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.addExtension
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency
@@ -25,15 +25,20 @@ 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
import org.jetbrains.kotlin.gradle.targets.native.tasks.*
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.kotlinArtifactsExtension
import org.jetbrains.kotlin.gradle.tasks.*
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
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.KonanTarget.*
import org.jetbrains.kotlin.utils.addToStdlib.cast
import java.io.File
internal val Project.cocoapodsBuildDirs: CocoapodsBuildDirs
@@ -149,7 +154,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
private fun KotlinMultiplatformExtension.targetsForPlatform(requestedPlatform: KonanTarget) =
supportedTargets().matching { it.konanTarget == requestedPlatform }
private fun createDefaultFrameworks(kotlinExtension: KotlinMultiplatformExtension, cocoapodsExtension: CocoapodsExtension) {
private fun createDefaultFrameworks(kotlinExtension: KotlinMultiplatformExtension) {
kotlinExtension.supportedTargets().all { target ->
target.binaries.framework(POD_FRAMEWORK_PREFIX) {
baseName = project.name.asValidFrameworkName()
@@ -216,7 +221,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 { it.asFile } }, frameworkLinkTask)
project.createCopyFrameworkTask(frameworkLinkTask.flatMap { it.destinationDirectory.map { dir -> dir.asFile } }, frameworkLinkTask)
}
private fun createSyncTask(
@@ -387,6 +392,58 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
}
}
private fun registerPodspecTask(
project: Project,
artifact: KotlinNativeArtifact,
podspecExtension: KotlinArtifactsPodspecExtension,
cocoapodsExtension: CocoapodsExtension,
) {
val artifactName = artifact.artifactName
val assembleTask = project.tasks.named(artifact.taskName)
val podspecTaskName = lowerCamelCaseName("generate", artifactName, "podspec")
val artifactType = when (artifact) {
is KotlinNativeLibrary -> GenerateArtifactPodspecTask.ArtifactType.Library
is KotlinNativeFramework -> GenerateArtifactPodspecTask.ArtifactType.Framework
is KotlinNativeFatFramework -> GenerateArtifactPodspecTask.ArtifactType.FatFramework
is KotlinNativeXCFramework -> GenerateArtifactPodspecTask.ArtifactType.XCFramework
else -> error("Podspec can only be generated for Library, Framework, FatFramework or XCFramework")
}
val podspecTask = project.tasks.register(podspecTaskName, GenerateArtifactPodspecTask::class.java) { task ->
task.group = TASK_GROUP
task.description = "Generates a podspec file for '$artifactName' artifact"
task.specName.set(artifactName)
task.specVersion.set(project.version.takeIf { it != Project.DEFAULT_VERSION }.toString())
task.destinationDir.set(project.buildDir.resolve(artifact.outDir))
task.attributes.set(podspecExtension.attributes)
task.rawStatements.set(podspecExtension.rawStatements)
task.dependencies.set(cocoapodsExtension.pods)
task.artifactType.set(artifactType)
}
assembleTask.dependsOn(podspecTask)
}
private fun injectPodspecExtensionToArtifacts(
project: Project,
artifactsExtension: KotlinArtifactsExtension,
cocoapodsExtension: CocoapodsExtension,
) {
artifactsExtension.artifactConfigs.withType(KotlinNativeArtifactConfig::class.java) { artifactConfig ->
val podspecExtension = project.objects.newInstance<KotlinArtifactsPodspecExtension>(project)
artifactConfig.addExtension(ARTIFACTS_PODSPEC_EXTENSION_NAME, podspecExtension)
}
artifactsExtension.artifacts.withType(KotlinNativeArtifact::class.java) { artifact ->
val podspecExtension = artifact.kotlinArtifactsPodspecExtension
if (podspecExtension != null) {
registerPodspecTask(project, artifact, podspecExtension, cocoapodsExtension)
}
}
}
private fun registerPodInstallTask(
project: Project,
cocoapodsExtension: CocoapodsExtension
@@ -688,11 +745,15 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
pluginManager.withPlugin("kotlin-multiplatform") {
val kotlinExtension = project.multiplatformExtension
val kotlinArtifactsExtension = project.kotlinArtifactsExtension
val cocoapodsExtension = project.objects.newInstance(CocoapodsExtension::class.java, this)
kotlinExtension.addExtension(COCOAPODS_EXTENSION_NAME, cocoapodsExtension)
createDefaultFrameworks(kotlinExtension, cocoapodsExtension)
createDefaultFrameworks(kotlinExtension)
registerDummyFrameworkTask(project, cocoapodsExtension)
createSyncTask(project, kotlinExtension, cocoapodsExtension)
injectPodspecExtensionToArtifacts(project, kotlinArtifactsExtension, cocoapodsExtension)
registerPodspecTask(project, cocoapodsExtension)
registerPodGenTask(project, kotlinExtension, cocoapodsExtension)
@@ -726,6 +787,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
const val POD_SETUP_BUILD_TASK_NAME = "podSetupBuild"
const val POD_BUILD_TASK_NAME = "podBuild"
const val POD_IMPORT_TASK_NAME = "podImport"
const val ARTIFACTS_PODSPEC_EXTENSION_NAME = "withPodspec"
// We don't move these properties in PropertiesProvider because
// they are not intended to be overridden in local.properties.
@@ -741,3 +803,16 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
const val GENERATE_WRAPPER_PROPERTY = "kotlin.native.cocoapods.generate.wrapper"
}
}
/**
* Extends a KotlinArtifact with a corresponding Podspec
*
* Only needed in *.kts build files. In Groovy you can use the same syntax but without explicit extension import
*/
fun KotlinNativeArtifactConfig.withPodspec(configure: KotlinArtifactsPodspecExtension.() -> Unit) {
val extension = cast<ExtensionAware>().kotlinArtifactsPodspecExtension
checkNotNull(extension) { "CocoaPods plugin should be applied before using `${KotlinCocoapodsPlugin.ARTIFACTS_PODSPEC_EXTENSION_NAME}` extension" }
extension.configure()
}
@@ -0,0 +1,171 @@
/*
* Copyright 2010-2022 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.targets.native.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFile
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.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension.CocoapodsDependency
import org.jetbrains.kotlin.gradle.targets.native.tasks.GenerateArtifactPodspecTask.ArtifactType.*
import org.jetbrains.kotlin.gradle.utils.appendLine
abstract class GenerateArtifactPodspecTask : DefaultTask() {
enum class ArtifactType {
Library, Framework, FatFramework, XCFramework
}
@get:Input
abstract val specName: Property<String>
@get:Input
abstract val specVersion: Property<String?>
@get:OutputDirectory
abstract val destinationDir: DirectoryProperty
@get:Input
abstract val attributes: MapProperty<String, String>
@get:Input
abstract val rawStatements: ListProperty<String>
@get:Nested
abstract val dependencies: ListProperty<CocoapodsDependency>
@get:Input
abstract val artifactType: Property<ArtifactType>
@get:OutputFile
@Suppress("LeakingThis") // should be inherited only by gradle machinery
val outputFile: Provider<RegularFile> = specName.flatMap { specName ->
destinationDir.file("$specName.podspec")
}
@TaskAction
fun generate() {
outputFile.get().asFile.writeText(buildString {
append("Pod::Spec.new do |spec|")
appendAttributes(buildAdditionalAttrs())
appendAttributes(attributes.get())
appendDependencies()
appendRawStatements()
appendLine("end")
})
}
private fun Appendable.appendAttributes(attributes: Map<String, String>) {
if (attributes.isNotEmpty()) {
appendLine()
}
for ((key, value) in attributes) {
append(" spec.")
append(key)
repeat(podspecValueIndent - key.length) { append(' ') }
append(" = ")
append(value.wrapInSingleQuotesIfNeeded())
appendLine()
}
}
private fun Appendable.appendDependencies() {
if (dependencies.get().isNotEmpty()) {
appendLine()
}
for (dependency in dependencies.get()) {
append(" spec.dependency ")
append(dependency.name.wrapInSingleQuotes())
val version = dependency.version
if (version != null) {
append(", ")
append(version.wrapInSingleQuotes())
}
appendLine()
}
}
private fun Appendable.appendRawStatements() {
if (rawStatements.get().isNotEmpty()) {
appendLine()
}
for (statement in rawStatements.get()) {
appendLine(statement)
}
}
private fun buildAdditionalAttrs(): Map<String, String> {
val artifactTypeValue: ArtifactType = artifactType.get()
return mutableMapOf<String, String>().apply {
if (!attributes.get().containsKey(specNameKey)) {
put(specNameKey, specName.get())
}
if (!attributes.get().containsKey(specVersionKey)) {
specVersion.get()?.let { put(specVersionKey, it) }
}
if (vendoredKeys.none { attributes.get().containsKey(it) }) {
val vendoredKey = when (artifactTypeValue) {
Library -> vendoredLibrary
Framework, FatFramework, XCFramework -> vendoredFrameworks
}
val vendoredValue = specName.get() + "." + when (artifactTypeValue) {
Library -> "dylib"
Framework, FatFramework -> "framework"
XCFramework -> "xcframework"
}
put(vendoredKey, vendoredValue)
}
}
}
private fun String.wrapInSingleQuotesIfNeeded(): String {
return when {
startsWith('{') ||
startsWith('[') ||
startsWith("<<-") ||
startsWith('\'') ||
startsWith('"') ||
equals("true") ||
equals("false") -> this
else -> wrapInSingleQuotes()
}
}
private fun String.wrapInSingleQuotes() = "'" + replace("'", "\\'") + "'"
companion object {
private const val specNameKey = "name"
private const val specVersionKey = "version"
private const val vendoredLibrary = "vendored_library"
private const val vendoredLibraries = "vendored_libraries"
private const val vendoredFrameworks = "vendored_frameworks"
private const val podspecValueIndent = 24
private val vendoredKeys = listOf(vendoredLibrary, vendoredLibraries, vendoredFrameworks)
}
}
@@ -78,6 +78,8 @@ class KotlinNativeFatFrameworkImpl(
) : KotlinNativeFatFramework, ExtensionAware by extensions {
override fun getName() = lowerCamelCaseName(artifactName, "FatFramework")
override val taskName = lowerCamelCaseName("assemble", name)
override val outDir
get() = "out/fatframework"
override fun registerAssembleTask(project: Project) {
val parentTask = project.registerTask<Task>(taskName) {
@@ -91,7 +93,7 @@ class KotlinNativeFatFrameworkImpl(
lowerCamelCaseName("assemble", artifactName, buildType.visibleName, "FatFramework")
) {
it.baseName = artifactName
it.destinationDir = project.buildDir.resolve("out/fatframework/${buildType.getName()}")
it.destinationDir = project.buildDir.resolve("$outDir/${buildType.getName()}")
}
parentTask.dependsOn(fatTask)
@@ -72,6 +72,7 @@ class KotlinNativeFrameworkImpl(
private val kind = NativeOutputKind.FRAMEWORK
override fun getName() = lowerCamelCaseName(artifactName, kind.taskNameClassifier, target.presetName)
override val taskName = lowerCamelCaseName("assemble", name)
override val outDir = "out/${kind.visibleName}"
override fun registerAssembleTask(project: Project) {
val resultTask = project.registerTask<Task>(taskName) { task ->
@@ -105,11 +106,11 @@ internal fun KotlinNativeArtifact.registerLinkFrameworkTask(
librariesConfigurationName: String,
exportConfigurationName: String,
embedBitcode: BitcodeEmbeddingMode?,
outDirName: String = "out",
outDirName: String = outDir,
taskNameSuffix: String = ""
): TaskProvider<KotlinNativeLinkArtifactTask> {
val kind = NativeOutputKind.FRAMEWORK
val destinationDir = project.buildDir.resolve("$outDirName/${kind.visibleName}/${target.visibleName}/${buildType.visibleName}")
val destinationDir = project.buildDir.resolve("$outDirName/${target.visibleName}/${buildType.visibleName}")
val resultTask = project.registerTask<KotlinNativeLinkArtifactTask>(
lowerCamelCaseName("assemble", name, buildType.visibleName, kind.taskNameClassifier, target.presetName, taskNameSuffix),
listOf(target, kind.compilerOutputKind)
@@ -67,6 +67,7 @@ class KotlinNativeLibraryImpl(
private val kind = if (isStatic) NativeOutputKind.STATIC else NativeOutputKind.DYNAMIC
override fun getName() = lowerCamelCaseName(artifactName, kind.taskNameClassifier, "Library", target.presetName)
override val taskName = lowerCamelCaseName("assemble", name)
override val outDir = "out/${kind.visibleName}"
override fun registerAssembleTask(project: Project) {
val resultTask = project.registerTask<Task>(taskName) { task ->
@@ -84,6 +85,7 @@ class KotlinNativeLibraryImpl(
listOf(target, kind.compilerOutputKind)
) { task ->
task.description = "Assemble ${kind.description} '$artifactName' for a target '${target.name}'."
task.destinationDir.set(project.buildDir.resolve("$outDir/${target.visibleName}/${buildType.visibleName}"))
task.enabled = target.enabledOnCurrentHost
task.baseName.set(artifactName)
task.optimized.set(buildType.optimized)
@@ -78,6 +78,8 @@ class KotlinNativeXCFrameworkImpl(
) : KotlinNativeXCFramework, ExtensionAware by extensions {
override fun getName() = lowerCamelCaseName(artifactName, "XCFramework")
override val taskName = lowerCamelCaseName("assemble", name)
override val outDir: String
get() = "out/xcframework"
override fun registerAssembleTask(project: Project) {
val parentTask = project.registerTask<Task>(taskName) {
@@ -120,7 +122,7 @@ class KotlinNativeXCFrameworkImpl(
}
holder.task.configure {
it.fromFrameworkDescriptors(frameworkDescriptors)
it.outputDir = project.buildDir.resolve("out/xcframework")
it.outputDir = project.buildDir.resolve(outDir)
}
}
}