Publish multiplatform resources as variants for wasm, js and native targets
^KT-65540
This commit is contained in:
committed by
Space Team
parent
5bbec23123
commit
b145796e14
@@ -765,6 +765,7 @@ public abstract class org/jetbrains/kotlin/gradle/plugin/mpp/external/DecoratedE
|
|||||||
public fun getPreset ()Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetPreset;
|
public fun getPreset ()Lorg/jetbrains/kotlin/gradle/plugin/KotlinTargetPreset;
|
||||||
public fun getProject ()Lorg/gradle/api/Project;
|
public fun getProject ()Lorg/gradle/api/Project;
|
||||||
public fun getPublishable ()Z
|
public fun getPublishable ()Z
|
||||||
|
public fun getResourcesElementsConfigurationName ()Ljava/lang/String;
|
||||||
public final fun getRuntimeElementsConfiguration ()Lorg/gradle/api/artifacts/Configuration;
|
public final fun getRuntimeElementsConfiguration ()Lorg/gradle/api/artifacts/Configuration;
|
||||||
public fun getRuntimeElementsConfigurationName ()Ljava/lang/String;
|
public fun getRuntimeElementsConfigurationName ()Ljava/lang/String;
|
||||||
public final fun getRuntimeElementsPublishedConfiguration ()Lorg/gradle/api/artifacts/Configuration;
|
public final fun getRuntimeElementsPublishedConfiguration ()Lorg/gradle/api/artifacts/Configuration;
|
||||||
|
|||||||
+7
-1
@@ -31,9 +31,11 @@ import org.jetbrains.kotlin.gradle.internal.KOTLIN_BUILD_TOOLS_API_IMPL
|
|||||||
import org.jetbrains.kotlin.gradle.internal.KOTLIN_COMPILER_EMBEDDABLE
|
import org.jetbrains.kotlin.gradle.internal.KOTLIN_COMPILER_EMBEDDABLE
|
||||||
import org.jetbrains.kotlin.gradle.internal.KOTLIN_MODULE_GROUP
|
import org.jetbrains.kotlin.gradle.internal.KOTLIN_MODULE_GROUP
|
||||||
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
||||||
import org.jetbrains.kotlin.gradle.plugin.internal.*
|
import org.jetbrains.kotlin.gradle.plugin.internal.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.swiftexport.initSwiftExportClasspathConfigurations
|
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.swiftexport.initSwiftExportClasspathConfigurations
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resolve.KotlinTargetResourcesResolutionStrategy
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSetFactory
|
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSetFactory
|
||||||
import org.jetbrains.kotlin.gradle.plugin.statistics.BuildFusService
|
import org.jetbrains.kotlin.gradle.plugin.statistics.BuildFusService
|
||||||
import org.jetbrains.kotlin.gradle.report.BuildMetricsService
|
import org.jetbrains.kotlin.gradle.report.BuildMetricsService
|
||||||
@@ -210,7 +212,11 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
|
|||||||
isKotlinGranularMetadata: Boolean = project.isKotlinGranularMetadataEnabled,
|
isKotlinGranularMetadata: Boolean = project.isKotlinGranularMetadataEnabled,
|
||||||
) = with(project.dependencies.attributesSchema) {
|
) = with(project.dependencies.attributesSchema) {
|
||||||
KotlinPlatformType.setupAttributesMatchingStrategy(this)
|
KotlinPlatformType.setupAttributesMatchingStrategy(this)
|
||||||
KotlinUsages.setupAttributesMatchingStrategy(this, isKotlinGranularMetadata)
|
KotlinUsages.setupAttributesMatchingStrategy(
|
||||||
|
this,
|
||||||
|
isKotlinGranularMetadata,
|
||||||
|
project.kotlinPropertiesProvider.mppResourcesResolutionStrategy == KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration
|
||||||
|
)
|
||||||
ProjectLocalConfigurations.setupAttributesMatchingStrategy(this)
|
ProjectLocalConfigurations.setupAttributesMatchingStrategy(this)
|
||||||
|
|
||||||
project.whenJsOrMppEnabled {
|
project.whenJsOrMppEnabled {
|
||||||
|
|||||||
+4
-2
@@ -55,7 +55,9 @@ internal fun Project.categoryByName(categoryName: String): Category =
|
|||||||
internal inline fun <reified T : Named> Project.attributeValueByName(attributeValueName: String): T =
|
internal inline fun <reified T : Named> Project.attributeValueByName(attributeValueName: String): T =
|
||||||
objects.named(T::class.java, attributeValueName)
|
objects.named(T::class.java, attributeValueName)
|
||||||
|
|
||||||
fun Configuration.usesPlatformOf(target: KotlinTarget): Configuration {
|
fun Configuration.usesPlatformOf(target: KotlinTarget) = setUsesPlatformOf(target)
|
||||||
|
|
||||||
|
internal fun <T : HasAttributes> T.setUsesPlatformOf(target: KotlinTarget): T {
|
||||||
attributes.setAttribute(KotlinPlatformType.attribute, target.platformType)
|
attributes.setAttribute(KotlinPlatformType.attribute, target.platformType)
|
||||||
|
|
||||||
when (target.platformType) {
|
when (target.platformType) {
|
||||||
@@ -94,7 +96,7 @@ fun Configuration.usesPlatformOf(target: KotlinTarget): Configuration {
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Configuration.setJavaTargetEnvironmentAttributeIfSupported(project: Project, value: String) {
|
private fun HasAttributes.setJavaTargetEnvironmentAttributeIfSupported(project: Project, value: String) {
|
||||||
if (GradleVersion.current() >= GradleVersion.version("7.0")) {
|
if (GradleVersion.current() >= GradleVersion.version("7.0")) {
|
||||||
attributes.setAttribute(
|
attributes.setAttribute(
|
||||||
TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
|
TargetJvmEnvironment.TARGET_JVM_ENVIRONMENT_ATTRIBUTE,
|
||||||
|
|||||||
+20
@@ -39,10 +39,12 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_OPTIMISTIC_NUMBER_COMMONIZATION
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_OPTIMISTIC_NUMBER_COMMONIZATION
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_PLATFORM_INTEGER_COMMONIZATION
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_PLATFORM_INTEGER_COMMONIZATION
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_RESOURCES_PUBLICATION
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_RESOURCES_PUBLICATION
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_FILTER_RESOURCES_BY_EXTENSION
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_HIERARCHICAL_STRUCTURE_SUPPORT
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_HIERARCHICAL_STRUCTURE_SUPPORT
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_IMPORT_ENABLE_KGP_DEPENDENCY_RESOLUTION
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_IMPORT_ENABLE_KGP_DEPENDENCY_RESOLUTION
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_IMPORT_ENABLE_SLOW_SOURCES_JAR_RESOLVER
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_IMPORT_ENABLE_SLOW_SOURCES_JAR_RESOLVER
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_RESOURCES_RESOLUTION_STRATEGY
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_TOOLCHAIN_ENABLED
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_TOOLCHAIN_ENABLED
|
||||||
@@ -53,7 +55,9 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_JDK_VARIANTS_VERSION_ALIGNMENT
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_JDK_VARIANTS_VERSION_ALIGNMENT
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.MPP_13X_FLAGS_SET_BY_PLUGIN
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.MPP_13X_FLAGS_SET_BY_PLUGIN
|
||||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
|
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnostic
|
||||||
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnosticOncePerBuild
|
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnosticOncePerBuild
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resolve.KotlinTargetResourcesResolutionStrategy
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinIrJsGeneratedTSValidationStrategy
|
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinIrJsGeneratedTSValidationStrategy
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrOutputGranularity
|
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrOutputGranularity
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy
|
||||||
@@ -203,6 +207,20 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
|||||||
val mppResourcesPublication: Boolean
|
val mppResourcesPublication: Boolean
|
||||||
get() = this.booleanProperty(KOTLIN_MPP_ENABLE_RESOURCES_PUBLICATION) ?: true
|
get() = this.booleanProperty(KOTLIN_MPP_ENABLE_RESOURCES_PUBLICATION) ?: true
|
||||||
|
|
||||||
|
val mppResourcesResolutionStrategy: KotlinTargetResourcesResolutionStrategy
|
||||||
|
get() = this.get(KOTLIN_MPP_RESOURCES_RESOLUTION_STRATEGY)?.let {
|
||||||
|
val strategy = KotlinTargetResourcesResolutionStrategy.fromProperty(it)
|
||||||
|
if (strategy == null) { project.reportDiagnostic(KotlinToolingDiagnostics.UnknownValueProvidedForResourcesStrategy(it)) }
|
||||||
|
return@let strategy
|
||||||
|
} ?: KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration
|
||||||
|
|
||||||
|
val mppFilterResourcesByExtension: Provider<Boolean>
|
||||||
|
get() = project.providers
|
||||||
|
.provider<Boolean> {
|
||||||
|
booleanProperty(KOTLIN_MPP_FILTER_RESOURCES_BY_EXTENSION)
|
||||||
|
}
|
||||||
|
.orElse(false)
|
||||||
|
|
||||||
val wasmStabilityNoWarn: Boolean
|
val wasmStabilityNoWarn: Boolean
|
||||||
get() = booleanProperty("kotlin.wasm.stability.nowarn") ?: false
|
get() = booleanProperty("kotlin.wasm.stability.nowarn") ?: false
|
||||||
|
|
||||||
@@ -635,6 +653,8 @@ internal class PropertiesProvider private constructor(private val project: Proje
|
|||||||
val KOTLIN_MPP_ENABLE_INTRANSITIVE_METADATA_CONFIGURATION = property("kotlin.mpp.enableIntransitiveMetadataConfiguration")
|
val KOTLIN_MPP_ENABLE_INTRANSITIVE_METADATA_CONFIGURATION = property("kotlin.mpp.enableIntransitiveMetadataConfiguration")
|
||||||
val KOTLIN_MPP_APPLY_DEFAULT_HIERARCHY_TEMPLATE = property("kotlin.mpp.applyDefaultHierarchyTemplate")
|
val KOTLIN_MPP_APPLY_DEFAULT_HIERARCHY_TEMPLATE = property("kotlin.mpp.applyDefaultHierarchyTemplate")
|
||||||
val KOTLIN_MPP_ENABLE_RESOURCES_PUBLICATION = property("kotlin.mpp.enableResourcesPublication")
|
val KOTLIN_MPP_ENABLE_RESOURCES_PUBLICATION = property("kotlin.mpp.enableResourcesPublication")
|
||||||
|
val KOTLIN_MPP_RESOURCES_RESOLUTION_STRATEGY = property("kotlin.mpp.resourcesResolutionStrategy")
|
||||||
|
val KOTLIN_MPP_FILTER_RESOURCES_BY_EXTENSION = property("kotlin.mpp.filterResourcesByExtension")
|
||||||
val KOTLIN_NATIVE_DEPENDENCY_PROPAGATION = property("kotlin.native.enableDependencyPropagation")
|
val KOTLIN_NATIVE_DEPENDENCY_PROPAGATION = property("kotlin.native.enableDependencyPropagation")
|
||||||
val KOTLIN_NATIVE_CACHE_ORCHESTRATION = property("kotlin.native.cacheOrchestration")
|
val KOTLIN_NATIVE_CACHE_ORCHESTRATION = property("kotlin.native.cacheOrchestration")
|
||||||
val KOTLIN_NATIVE_PARALLEL_THREADS = property("kotlin.native.parallelThreads")
|
val KOTLIN_NATIVE_PARALLEL_THREADS = property("kotlin.native.parallelThreads")
|
||||||
|
|||||||
+38
@@ -796,6 +796,44 @@ object KotlinToolingDiagnostics {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
object ResourceMayNotBeResolvedForTarget : ToolingDiagnosticFactory(ERROR) {
|
||||||
|
operator fun invoke(targetName: String) = build(
|
||||||
|
"""
|
||||||
|
Resources resolution for target $targetName is not supported.
|
||||||
|
|
||||||
|
$resourcesBugReportRequest
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
object UnknownValueProvidedForResourcesStrategy : ToolingDiagnosticFactory(ERROR) {
|
||||||
|
operator fun invoke(value: String) = build(
|
||||||
|
"""
|
||||||
|
Unknown value $value provided for ${PropertiesProvider.PropertyNames.KOTLIN_MPP_RESOURCES_RESOLUTION_STRATEGY}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
object MissingConfigurationForWasmTarget : ToolingDiagnosticFactory(ERROR) {
|
||||||
|
operator fun invoke(targetName: String) = build(
|
||||||
|
"""
|
||||||
|
Resources will not be resolved for $targetName as it is missing runtimeDependencyConfiguration.
|
||||||
|
|
||||||
|
$resourcesBugReportRequest
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
object MissingResourcesConfigurationForTarget : ToolingDiagnosticFactory(ERROR) {
|
||||||
|
operator fun invoke(targetName: String) = build(
|
||||||
|
"""
|
||||||
|
Resources will not be resolved for $targetName as it is missing resourcesConfiguration.
|
||||||
|
|
||||||
|
$resourcesBugReportRequest
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
object DependencyDoesNotPhysicallyExist : ToolingDiagnosticFactory(WARNING) {
|
object DependencyDoesNotPhysicallyExist : ToolingDiagnosticFactory(WARNING) {
|
||||||
operator fun invoke(dependency: File) = build(
|
operator fun invoke(dependency: File) = build(
|
||||||
"""
|
"""
|
||||||
|
|||||||
+4
@@ -54,6 +54,10 @@ abstract class AbstractKotlinTarget(
|
|||||||
override val sourcesElementsConfigurationName: String
|
override val sourcesElementsConfigurationName: String
|
||||||
get() = disambiguateName("sourcesElements")
|
get() = disambiguateName("sourcesElements")
|
||||||
|
|
||||||
|
@InternalKotlinGradlePluginApi
|
||||||
|
override val resourcesElementsConfigurationName: String
|
||||||
|
get() = disambiguateName("resourcesElements")
|
||||||
|
|
||||||
override val artifactsTaskName: String
|
override val artifactsTaskName: String
|
||||||
get() = disambiguateName("jar")
|
get() = disambiguateName("jar")
|
||||||
|
|
||||||
|
|||||||
+2
@@ -39,6 +39,8 @@ internal interface InternalKotlinTarget : KotlinTarget, HasMutableExtras {
|
|||||||
|
|
||||||
@Deprecated(TOOLCHAIN_DSL_WRONG_USAGE_ERROR, level = DeprecationLevel.ERROR)
|
@Deprecated(TOOLCHAIN_DSL_WRONG_USAGE_ERROR, level = DeprecationLevel.ERROR)
|
||||||
fun jvmToolchain(jdkVersion: Int): Unit = error(TOOLCHAIN_DSL_WRONG_USAGE_ERROR)
|
fun jvmToolchain(jdkVersion: Int): Unit = error(TOOLCHAIN_DSL_WRONG_USAGE_ERROR)
|
||||||
|
|
||||||
|
val resourcesElementsConfigurationName: String
|
||||||
}
|
}
|
||||||
|
|
||||||
private const val TOOLCHAIN_DSL_WRONG_USAGE_ERROR =
|
private const val TOOLCHAIN_DSL_WRONG_USAGE_ERROR =
|
||||||
|
|||||||
+40
-1
@@ -37,6 +37,15 @@ object KotlinUsages {
|
|||||||
const val KOTLIN_COMMONIZED_CINTEROP = "kotlin-commonized-cinterop"
|
const val KOTLIN_COMMONIZED_CINTEROP = "kotlin-commonized-cinterop"
|
||||||
const val KOTLIN_SOURCES = "kotlin-sources"
|
const val KOTLIN_SOURCES = "kotlin-sources"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Multiplatform resources usage:
|
||||||
|
* Resources variants for native, wasmJs and wasmWasi targets publish with these usages. To resolve a resources configuration with
|
||||||
|
* transitive dependencies that might not have a resource variant, we must use a compatibility rule to take dependencies from
|
||||||
|
* the klib variant. For native that is a "kotlin-api" variant and for wasmJs and wasmWasi that is a "kotlin-runtime" variant.
|
||||||
|
*/
|
||||||
|
const val KOTLIN_RESOURCES = "kotlin-multiplatformresources"
|
||||||
|
const val KOTLIN_RESOURCES_JS = "kotlin-multiplatformresourcesjs"
|
||||||
|
|
||||||
// Following two constants were removed in Gradle 8.0 from 'Usages' class
|
// Following two constants were removed in Gradle 8.0 from 'Usages' class
|
||||||
private const val JAVA_RUNTIME_CLASSES = "java-runtime-classes"
|
private const val JAVA_RUNTIME_CLASSES = "java-runtime-classes"
|
||||||
private const val JAVA_RUNTIME_RESOURCES = "java-runtime-resources"
|
private const val JAVA_RUNTIME_RESOURCES = "java-runtime-resources"
|
||||||
@@ -125,6 +134,27 @@ object KotlinUsages {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class KotlinResourcesCompatibility : AttributeCompatibilityRule<Usage> {
|
||||||
|
override fun execute(details: CompatibilityCheckDetails<Usage>) = with(details) {
|
||||||
|
/**
|
||||||
|
* When resolving resources using KotlinTarget.resourcesConfiguration, if a dependency doesn't have resources variant, we must
|
||||||
|
* take dependencies from the klib variant because they might contain transitive resources variants.
|
||||||
|
* */
|
||||||
|
val consumerValueName = consumerValue?.name
|
||||||
|
val producerValueName = producerValue?.name
|
||||||
|
if (consumerValueName == null || producerValueName == null) return
|
||||||
|
|
||||||
|
if (
|
||||||
|
mapOf(
|
||||||
|
KOTLIN_RESOURCES to KOTLIN_API,
|
||||||
|
KOTLIN_RESOURCES_JS to KOTLIN_RUNTIME,
|
||||||
|
)[consumerValueName] == producerValueName
|
||||||
|
) {
|
||||||
|
compatible()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class KotlinCinteropDisambiguation : AttributeDisambiguationRule<Usage> {
|
private class KotlinCinteropDisambiguation : AttributeDisambiguationRule<Usage> {
|
||||||
override fun execute(details: MultipleCandidatesDetails<Usage?>) = details.run {
|
override fun execute(details: MultipleCandidatesDetails<Usage?>) = details.run {
|
||||||
if (consumerValue?.name == KOTLIN_CINTEROP) {
|
if (consumerValue?.name == KOTLIN_CINTEROP) {
|
||||||
@@ -186,7 +216,11 @@ object KotlinUsages {
|
|||||||
closestMatch(candidateValues.single { it?.name == name }!!)
|
closestMatch(candidateValues.single { it?.name == name }!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun setupAttributesMatchingStrategy(attributesSchema: AttributesSchema, isKotlinGranularMetadata: Boolean) {
|
internal fun setupAttributesMatchingStrategy(
|
||||||
|
attributesSchema: AttributesSchema,
|
||||||
|
isKotlinGranularMetadata: Boolean,
|
||||||
|
isKotlinResourcesCompatibilityRuleEnabled: Boolean
|
||||||
|
) {
|
||||||
attributesSchema.attribute(USAGE_ATTRIBUTE) { strategy ->
|
attributesSchema.attribute(USAGE_ATTRIBUTE) { strategy ->
|
||||||
strategy.compatibilityRules.add(KotlinJavaRuntimeJarsCompatibility::class.java)
|
strategy.compatibilityRules.add(KotlinJavaRuntimeJarsCompatibility::class.java)
|
||||||
strategy.disambiguationRules.add(KotlinUsagesDisambiguation::class.java)
|
strategy.disambiguationRules.add(KotlinUsagesDisambiguation::class.java)
|
||||||
@@ -198,6 +232,11 @@ object KotlinUsages {
|
|||||||
strategy.compatibilityRules.add(KotlinMetadataCompatibility::class.java)
|
strategy.compatibilityRules.add(KotlinMetadataCompatibility::class.java)
|
||||||
strategy.disambiguationRules.add(KotlinMetadataDisambiguation::class.java)
|
strategy.disambiguationRules.add(KotlinMetadataDisambiguation::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Only enable resources compatibility rule when resources configuration is used, so that for variant reselection klibs aren't selected
|
||||||
|
if (isKotlinResourcesCompatibilityRuleEnabled) {
|
||||||
|
strategy.compatibilityRules.add(KotlinResourcesCompatibility::class.java)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+26
@@ -10,6 +10,8 @@ import org.gradle.api.artifacts.Configuration
|
|||||||
import org.gradle.api.attributes.Bundling
|
import org.gradle.api.attributes.Bundling
|
||||||
import org.gradle.api.attributes.Category
|
import org.gradle.api.attributes.Category
|
||||||
import org.gradle.api.attributes.DocsType
|
import org.gradle.api.attributes.DocsType
|
||||||
|
import org.gradle.api.attributes.HasAttributes
|
||||||
|
import org.gradle.api.attributes.LibraryElements
|
||||||
import org.gradle.api.attributes.Usage
|
import org.gradle.api.attributes.Usage
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.publish.PublicationContainer
|
import org.gradle.api.publish.PublicationContainer
|
||||||
@@ -24,6 +26,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
|
||||||
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
||||||
import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask
|
import org.jetbrains.kotlin.gradle.tooling.buildKotlinToolingMetadataTask
|
||||||
import org.jetbrains.kotlin.gradle.utils.*
|
import org.jetbrains.kotlin.gradle.utils.*
|
||||||
@@ -177,3 +180,26 @@ internal fun Configuration.configureSourcesPublicationAttributes(target: KotlinT
|
|||||||
attributes.setAttribute(Bundling.BUNDLING_ATTRIBUTE, project.attributeValueByName(Bundling.EXTERNAL))
|
attributes.setAttribute(Bundling.BUNDLING_ATTRIBUTE, project.attributeValueByName(Bundling.EXTERNAL))
|
||||||
usesPlatformOf(target)
|
usesPlatformOf(target)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun HasAttributes.configureResourcesPublicationAttributes(target: KotlinTarget) {
|
||||||
|
val project = target.project
|
||||||
|
|
||||||
|
val usage = if (target is KotlinJsIrTarget) {
|
||||||
|
KotlinUsages.KOTLIN_RESOURCES_JS
|
||||||
|
} else {
|
||||||
|
KotlinUsages.KOTLIN_RESOURCES
|
||||||
|
}
|
||||||
|
attributes.setAttribute(
|
||||||
|
Usage.USAGE_ATTRIBUTE,
|
||||||
|
project.usageByName(usage)
|
||||||
|
)
|
||||||
|
attributes.setAttribute(
|
||||||
|
LibraryElements.LIBRARY_ELEMENTS_ATTRIBUTE,
|
||||||
|
project.objects.named(usage)
|
||||||
|
)
|
||||||
|
|
||||||
|
attributes.setAttribute(Category.CATEGORY_ATTRIBUTE, project.objects.named(Category.LIBRARY))
|
||||||
|
attributes.setAttribute(Bundling.BUNDLING_ATTRIBUTE, project.attributeValueByName(Bundling.EXTERNAL))
|
||||||
|
|
||||||
|
setUsesPlatformOf(target)
|
||||||
|
}
|
||||||
|
|||||||
+3
-1
@@ -23,6 +23,7 @@ interface KotlinCompilationConfigurationsContainer {
|
|||||||
val runtimeDependencyConfiguration: Configuration?
|
val runtimeDependencyConfiguration: Configuration?
|
||||||
val hostSpecificMetadataConfiguration: Configuration?
|
val hostSpecificMetadataConfiguration: Configuration?
|
||||||
val pluginConfiguration: Configuration
|
val pluginConfiguration: Configuration
|
||||||
|
val resourcesConfiguration: Configuration?
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class DefaultKotlinCompilationConfigurationsContainer(
|
internal class DefaultKotlinCompilationConfigurationsContainer(
|
||||||
@@ -35,7 +36,8 @@ internal class DefaultKotlinCompilationConfigurationsContainer(
|
|||||||
override val compileDependencyConfiguration: Configuration,
|
override val compileDependencyConfiguration: Configuration,
|
||||||
override val runtimeDependencyConfiguration: Configuration?,
|
override val runtimeDependencyConfiguration: Configuration?,
|
||||||
override val hostSpecificMetadataConfiguration: Configuration?,
|
override val hostSpecificMetadataConfiguration: Configuration?,
|
||||||
override val pluginConfiguration: Configuration
|
override val pluginConfiguration: Configuration,
|
||||||
|
override val resourcesConfiguration: Configuration?,
|
||||||
) : KotlinCompilationConfigurationsContainer
|
) : KotlinCompilationConfigurationsContainer
|
||||||
|
|
||||||
internal fun HasKotlinDependencies(
|
internal fun HasKotlinDependencies(
|
||||||
|
|||||||
+29
-5
@@ -5,15 +5,19 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory
|
package org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory
|
||||||
|
|
||||||
|
import org.gradle.api.attributes.Bundling
|
||||||
import org.gradle.api.attributes.Category
|
import org.gradle.api.attributes.Category
|
||||||
|
import org.gradle.api.attributes.LibraryElements
|
||||||
import org.gradle.api.attributes.Usage
|
import org.gradle.api.attributes.Usage
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationConfigurationsContainer
|
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.DefaultKotlinCompilationConfigurationsContainer
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationConfigurationsContainer
|
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationConfigurationsContainer
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.configureResourcesPublicationAttributes
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.javaSourceSets
|
import org.jetbrains.kotlin.gradle.plugin.mpp.javaSourceSets
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublicationImpl.Companion.RESOURCES_PATH
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
|
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
|
||||||
import org.jetbrains.kotlin.gradle.utils.*
|
import org.jetbrains.kotlin.gradle.utils.*
|
||||||
|
|
||||||
internal sealed class DefaultKotlinCompilationDependencyConfigurationsFactory :
|
internal sealed class DefaultKotlinCompilationDependencyConfigurationsFactory :
|
||||||
@@ -43,6 +47,7 @@ internal object NativeKotlinCompilationDependencyConfigurationsFactory :
|
|||||||
naming = naming,
|
naming = naming,
|
||||||
withRuntime = false,
|
withRuntime = false,
|
||||||
withHostSpecificMetadata = true,
|
withHostSpecificMetadata = true,
|
||||||
|
withResources = true,
|
||||||
compileClasspathConfigurationName = naming.name("compileKlibraries")
|
compileClasspathConfigurationName = naming.name("compileKlibraries")
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -82,7 +87,7 @@ private const val compileClasspath = "compileClasspath"
|
|||||||
private const val runtimeClasspath = "runtimeClasspath"
|
private const val runtimeClasspath = "runtimeClasspath"
|
||||||
|
|
||||||
private fun KotlinCompilationDependencyConfigurationsContainer(
|
private fun KotlinCompilationDependencyConfigurationsContainer(
|
||||||
target: KotlinTarget, compilationName: String, withRuntime: Boolean, withHostSpecificMetadata: Boolean = false,
|
target: KotlinTarget, compilationName: String, withRuntime: Boolean, withHostSpecificMetadata: Boolean = false, withResources: Boolean = false,
|
||||||
naming: ConfigurationNaming = ConfigurationNaming.Default(target, compilationName),
|
naming: ConfigurationNaming = ConfigurationNaming.Default(target, compilationName),
|
||||||
apiConfigurationName: String = naming.name(compilation, API),
|
apiConfigurationName: String = naming.name(compilation, API),
|
||||||
implementationConfigurationName: String = naming.name(compilation, IMPLEMENTATION),
|
implementationConfigurationName: String = naming.name(compilation, IMPLEMENTATION),
|
||||||
@@ -95,7 +100,8 @@ private fun KotlinCompilationDependencyConfigurationsContainer(
|
|||||||
PLUGIN_CLASSPATH_CONFIGURATION_NAME,
|
PLUGIN_CLASSPATH_CONFIGURATION_NAME,
|
||||||
target.disambiguationClassifier,
|
target.disambiguationClassifier,
|
||||||
compilationName
|
compilationName
|
||||||
)
|
),
|
||||||
|
resourcesPathConfigurationName: String = naming.name(RESOURCES_PATH),
|
||||||
): KotlinCompilationConfigurationsContainer {
|
): KotlinCompilationConfigurationsContainer {
|
||||||
val compilationCoordinates = "${target.disambiguationClassifier}/$compilationName"
|
val compilationCoordinates = "${target.disambiguationClassifier}/$compilationName"
|
||||||
|
|
||||||
@@ -198,6 +204,23 @@ private fun KotlinCompilationDependencyConfigurationsContainer(
|
|||||||
description = "Kotlin compiler plugins for $compilation"
|
description = "Kotlin compiler plugins for $compilation"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val resourcesConfiguration = if (withResources || target is KotlinJsIrTarget) {
|
||||||
|
target.project.configurations.maybeCreateResolvable(resourcesPathConfigurationName).apply {
|
||||||
|
// Inherit from compile dependency configuration, i.e. from the configuration that consumes apiElements
|
||||||
|
if (target is KotlinJsIrTarget) {
|
||||||
|
extendsFrom(runtimeDependencyConfiguration)
|
||||||
|
} else {
|
||||||
|
extendsFrom(compileDependencyConfiguration)
|
||||||
|
}
|
||||||
|
|
||||||
|
isVisible = false
|
||||||
|
|
||||||
|
configureResourcesPublicationAttributes(target)
|
||||||
|
|
||||||
|
description = "Kotlin resources for $compilation"
|
||||||
|
}
|
||||||
|
} else null
|
||||||
|
|
||||||
return DefaultKotlinCompilationConfigurationsContainer(
|
return DefaultKotlinCompilationConfigurationsContainer(
|
||||||
deprecatedCompileConfiguration = deprecatedCompileConfiguration,
|
deprecatedCompileConfiguration = deprecatedCompileConfiguration,
|
||||||
deprecatedRuntimeConfiguration = deprecatedRuntimeConfiguration,
|
deprecatedRuntimeConfiguration = deprecatedRuntimeConfiguration,
|
||||||
@@ -208,6 +231,7 @@ private fun KotlinCompilationDependencyConfigurationsContainer(
|
|||||||
compileDependencyConfiguration = compileDependencyConfiguration,
|
compileDependencyConfiguration = compileDependencyConfiguration,
|
||||||
runtimeDependencyConfiguration = runtimeDependencyConfiguration,
|
runtimeDependencyConfiguration = runtimeDependencyConfiguration,
|
||||||
hostSpecificMetadataConfiguration = hostSpecificMetadataConfiguration,
|
hostSpecificMetadataConfiguration = hostSpecificMetadataConfiguration,
|
||||||
pluginConfiguration = pluginConfiguration
|
pluginConfiguration = pluginConfiguration,
|
||||||
|
resourcesConfiguration = resourcesConfiguration,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
+4
@@ -36,6 +36,7 @@ internal class ExternalKotlinTargetImpl internal constructor(
|
|||||||
val apiElementsPublishedConfiguration: Configuration,
|
val apiElementsPublishedConfiguration: Configuration,
|
||||||
val runtimeElementsPublishedConfiguration: Configuration,
|
val runtimeElementsPublishedConfiguration: Configuration,
|
||||||
val sourcesElementsPublishedConfiguration: Configuration,
|
val sourcesElementsPublishedConfiguration: Configuration,
|
||||||
|
val resourcesElementsPublishedConfiguration: Configuration,
|
||||||
val kotlinTargetComponent: ExternalKotlinTargetComponent,
|
val kotlinTargetComponent: ExternalKotlinTargetComponent,
|
||||||
private val artifactsTaskLocator: ArtifactsTaskLocator,
|
private val artifactsTaskLocator: ArtifactsTaskLocator,
|
||||||
) : InternalKotlinTarget,
|
) : InternalKotlinTarget,
|
||||||
@@ -86,6 +87,9 @@ internal class ExternalKotlinTargetImpl internal constructor(
|
|||||||
override val sourcesElementsConfigurationName: String
|
override val sourcesElementsConfigurationName: String
|
||||||
get() = sourcesElementsConfiguration.name
|
get() = sourcesElementsConfiguration.name
|
||||||
|
|
||||||
|
override val resourcesElementsConfigurationName: String
|
||||||
|
get() = resourcesElementsPublishedConfiguration.name
|
||||||
|
|
||||||
@InternalKotlinGradlePluginApi
|
@InternalKotlinGradlePluginApi
|
||||||
override val kotlinComponents: Set<KotlinTargetComponent> = setOf(kotlinTargetComponent)
|
override val kotlinComponents: Set<KotlinTargetComponent> = setOf(kotlinTargetComponent)
|
||||||
|
|
||||||
|
|||||||
+5
@@ -59,6 +59,10 @@ fun <T : DecoratedExternalKotlinTarget> KotlinMultiplatformExtension.createExter
|
|||||||
.maybeCreateDependencyScope(lowerCamelCaseName(descriptor.targetName, "sourcesElements-published"))
|
.maybeCreateDependencyScope(lowerCamelCaseName(descriptor.targetName, "sourcesElements-published"))
|
||||||
.notVisible()
|
.notVisible()
|
||||||
|
|
||||||
|
val resourcesElementsPublishedConfiguration = project.configurations
|
||||||
|
.maybeCreateDependencyScope(lowerCamelCaseName(descriptor.targetName, "resourcesElements-published"))
|
||||||
|
.notVisible()
|
||||||
|
|
||||||
val kotlinTargetComponent = ExternalKotlinTargetComponent(
|
val kotlinTargetComponent = ExternalKotlinTargetComponent(
|
||||||
ExternalKotlinTargetComponent.TargetProvider.byTargetName(this, descriptor.targetName)
|
ExternalKotlinTargetComponent.TargetProvider.byTargetName(this, descriptor.targetName)
|
||||||
)
|
)
|
||||||
@@ -88,6 +92,7 @@ fun <T : DecoratedExternalKotlinTarget> KotlinMultiplatformExtension.createExter
|
|||||||
apiElementsPublishedConfiguration = apiElementsPublishedConfiguration,
|
apiElementsPublishedConfiguration = apiElementsPublishedConfiguration,
|
||||||
runtimeElementsPublishedConfiguration = runtimeElementsPublishedConfiguration,
|
runtimeElementsPublishedConfiguration = runtimeElementsPublishedConfiguration,
|
||||||
sourcesElementsPublishedConfiguration = sourcesElementsPublishedConfiguration,
|
sourcesElementsPublishedConfiguration = sourcesElementsPublishedConfiguration,
|
||||||
|
resourcesElementsPublishedConfiguration = resourcesElementsPublishedConfiguration,
|
||||||
kotlinTargetComponent = kotlinTargetComponent,
|
kotlinTargetComponent = kotlinTargetComponent,
|
||||||
artifactsTaskLocator = artifactsTaskLocator
|
artifactsTaskLocator = artifactsTaskLocator
|
||||||
)
|
)
|
||||||
|
|||||||
+9
@@ -36,6 +36,8 @@ internal abstract class KotlinTargetResourcesPublicationImpl @Inject constructor
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val targetsThatSupportPublication = listOf(
|
private val targetsThatSupportPublication = listOf(
|
||||||
|
KotlinJsIrTarget::class,
|
||||||
|
KotlinNativeTarget::class,
|
||||||
KotlinJvmTarget::class,
|
KotlinJvmTarget::class,
|
||||||
KotlinAndroidTarget::class,
|
KotlinAndroidTarget::class,
|
||||||
)
|
)
|
||||||
@@ -64,6 +66,9 @@ internal abstract class KotlinTargetResourcesPublicationImpl @Inject constructor
|
|||||||
|
|
||||||
override fun canPublishResources(target: KotlinTarget): Boolean {
|
override fun canPublishResources(target: KotlinTarget): Boolean {
|
||||||
if (targetsThatSupportPublication.none { it.isInstance(target) }) return false
|
if (targetsThatSupportPublication.none { it.isInstance(target) }) return false
|
||||||
|
if (target is KotlinJsIrTarget) {
|
||||||
|
return target.platformType == KotlinPlatformType.wasm
|
||||||
|
}
|
||||||
if (target is KotlinAndroidTarget) {
|
if (target is KotlinAndroidTarget) {
|
||||||
return AndroidGradlePluginVersion.current >= KotlinAndroidTargetResourcesPublication.MIN_AGP_VERSION
|
return AndroidGradlePluginVersion.current >= KotlinAndroidTargetResourcesPublication.MIN_AGP_VERSION
|
||||||
}
|
}
|
||||||
@@ -114,6 +119,10 @@ internal abstract class KotlinTargetResourcesPublicationImpl @Inject constructor
|
|||||||
|
|
||||||
internal companion object {
|
internal companion object {
|
||||||
const val MULTIPLATFORM_RESOURCES_DIRECTORY = "kotlin-multiplatform-resources"
|
const val MULTIPLATFORM_RESOURCES_DIRECTORY = "kotlin-multiplatform-resources"
|
||||||
|
const val RESOURCES_CLASSIFIER = "kotlin_resources"
|
||||||
|
const val RESOURCES_ZIP_EXTENSION = "${RESOURCES_CLASSIFIER}.zip"
|
||||||
|
|
||||||
|
const val RESOURCES_PATH = "ResourcesPath"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+71
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.plugin.mpp.resources.publication
|
||||||
|
|
||||||
|
import org.gradle.api.file.DuplicatesStrategy
|
||||||
|
import org.gradle.api.tasks.bundling.Zip
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.launch
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinUsageContext
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublicationImpl
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublicationImpl.Companion.RESOURCES_CLASSIFIER
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublicationImpl.Companion.RESOURCES_ZIP_EXTENSION
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.assembleHierarchicalResources
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resourcesPublicationExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||||
|
|
||||||
|
// Use KotlinMultiplatformExtension to make sure this usage context is only creatable in MPP
|
||||||
|
@Suppress("UnusedReceiverParameter")
|
||||||
|
internal fun KotlinMultiplatformExtension.setUpResourcesVariant(
|
||||||
|
target: AbstractKotlinTarget,
|
||||||
|
compilation: KotlinCompilation<*>,
|
||||||
|
): DefaultKotlinUsageContext = with(target) {
|
||||||
|
var targetRegistersResourcesForPublication = false
|
||||||
|
val resourcesVariant = DefaultKotlinUsageContext(
|
||||||
|
compilation = compilation,
|
||||||
|
dependencyConfigurationName = resourcesElementsConfigurationName,
|
||||||
|
includeIntoProjectStructureMetadata = false,
|
||||||
|
publishOnlyIf = {
|
||||||
|
targetRegistersResourcesForPublication
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
project.multiplatformExtension.resourcesPublicationExtension?.subscribeOnPublishResources(this) { resources ->
|
||||||
|
targetRegistersResourcesForPublication = true
|
||||||
|
val copyTask = compilation.assembleHierarchicalResources(
|
||||||
|
targetName,
|
||||||
|
resources,
|
||||||
|
)
|
||||||
|
val zippedResourcesDirectory = project.layout.buildDirectory.dir(
|
||||||
|
"${KotlinTargetResourcesPublicationImpl.MULTIPLATFORM_RESOURCES_DIRECTORY}/zip-for-publication/${targetName}"
|
||||||
|
)
|
||||||
|
val zipResourcesForPublication = project.registerTask<Zip>(
|
||||||
|
"${targetName}ZipMultiplatformResourcesForPublication"
|
||||||
|
) { copy ->
|
||||||
|
copy.destinationDirectory.set(zippedResourcesDirectory)
|
||||||
|
copy.duplicatesStrategy = DuplicatesStrategy.FAIL
|
||||||
|
copy.archiveExtension.set(RESOURCES_ZIP_EXTENSION)
|
||||||
|
}
|
||||||
|
zipResourcesForPublication.configure {
|
||||||
|
it.from(copyTask)
|
||||||
|
}
|
||||||
|
|
||||||
|
project.artifacts.add(
|
||||||
|
compilation.target.internal.resourcesElementsConfigurationName,
|
||||||
|
zipResourcesForPublication
|
||||||
|
) { artifact ->
|
||||||
|
artifact.extension = RESOURCES_ZIP_EXTENSION
|
||||||
|
artifact.classifier = RESOURCES_CLASSIFIER
|
||||||
|
artifact.type = "zip"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resourcesVariant
|
||||||
|
}
|
||||||
+67
@@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.plugin.mpp.resources.resolve
|
||||||
|
|
||||||
|
import org.gradle.api.file.FileCollection
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnostic
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.configureResourcesPublicationAttributes
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.copyAttributesTo
|
||||||
|
|
||||||
|
enum class KotlinTargetResourcesResolutionStrategy {
|
||||||
|
VariantReselection,
|
||||||
|
ResourcesConfiguration;
|
||||||
|
|
||||||
|
fun resourceArchives(
|
||||||
|
compilation: KotlinCompilation<*>,
|
||||||
|
): FileCollection {
|
||||||
|
return when (this) {
|
||||||
|
VariantReselection -> {
|
||||||
|
val dependenciesConfiguration = if (compilation.target is KotlinJsIrTarget) {
|
||||||
|
compilation.internal.configurations.runtimeDependencyConfiguration
|
||||||
|
?: return compilation.project.files().also {
|
||||||
|
compilation.project.reportDiagnostic(
|
||||||
|
KotlinToolingDiagnostics.MissingConfigurationForWasmTarget(compilation.target.name)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
compilation.internal.configurations.compileDependencyConfiguration
|
||||||
|
}
|
||||||
|
dependenciesConfiguration.incoming.artifactView {
|
||||||
|
it.withVariantReselection()
|
||||||
|
it.attributes { viewAttributes ->
|
||||||
|
viewAttributes.configureResourcesPublicationAttributes(compilation.target)
|
||||||
|
}
|
||||||
|
it.isLenient = true
|
||||||
|
}.files
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourcesConfiguration -> compilation.internal.configurations.resourcesConfiguration
|
||||||
|
?: return compilation.project.files().also {
|
||||||
|
compilation.project.reportDiagnostic(
|
||||||
|
KotlinToolingDiagnostics.MissingResourcesConfigurationForTarget(compilation.target.name)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val propertyName: String
|
||||||
|
get() = when (this) {
|
||||||
|
VariantReselection -> "variantReselection"
|
||||||
|
ResourcesConfiguration -> "resourcesConfiguration"
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun fromProperty(name: String): KotlinTargetResourcesResolutionStrategy? = when (name) {
|
||||||
|
VariantReselection.propertyName -> VariantReselection
|
||||||
|
ResourcesConfiguration.propertyName -> ResourcesConfiguration
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+19
-2
@@ -7,11 +7,13 @@ package org.jetbrains.kotlin.gradle.targets
|
|||||||
|
|
||||||
import org.gradle.api.attributes.Category
|
import org.gradle.api.attributes.Category
|
||||||
import org.gradle.api.attributes.Usage
|
import org.gradle.api.attributes.Usage
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.configureSourcesPublicationAttributes
|
import org.jetbrains.kotlin.gradle.plugin.mpp.configureSourcesPublicationAttributes
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.isSourcesPublishableFuture
|
import org.jetbrains.kotlin.gradle.plugin.mpp.isSourcesPublishableFuture
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resourcesPublicationExtension
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
|
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
|
||||||
import org.jetbrains.kotlin.gradle.utils.maybeCreateConsumable
|
import org.jetbrains.kotlin.gradle.utils.maybeCreateConsumable
|
||||||
import org.jetbrains.kotlin.gradle.utils.maybeCreateDependencyScope
|
import org.jetbrains.kotlin.gradle.utils.maybeCreateDependencyScope
|
||||||
@@ -33,12 +35,13 @@ internal val CreateTargetConfigurationsSideEffect = KotlinTargetSideEffect { tar
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val apiElementScope = configurations.maybeCreateDependencyScope(mainCompilation.apiConfigurationName)
|
||||||
configurations.maybeCreateConsumable(target.apiElementsConfigurationName).apply {
|
configurations.maybeCreateConsumable(target.apiElementsConfigurationName).apply {
|
||||||
description = "API elements for main."
|
description = "API elements for main."
|
||||||
isVisible = false
|
isVisible = false
|
||||||
attributes.setAttribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
|
attributes.setAttribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
|
||||||
attributes.setAttribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
|
attributes.setAttribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
|
||||||
extendsFrom(configurations.maybeCreateDependencyScope(mainCompilation.apiConfigurationName))
|
extendsFrom(apiElementScope)
|
||||||
@Suppress("TYPEALIAS_EXPANSION_DEPRECATION")
|
@Suppress("TYPEALIAS_EXPANSION_DEPRECATION")
|
||||||
if (mainCompilation is DeprecatedKotlinCompilationToRunnableFiles) {
|
if (mainCompilation is DeprecatedKotlinCompilationToRunnableFiles) {
|
||||||
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
|
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
|
||||||
@@ -69,6 +72,20 @@ internal val CreateTargetConfigurationsSideEffect = KotlinTargetSideEffect { tar
|
|||||||
project.launch { isCanBeConsumed = target.internal.isSourcesPublishableFuture.await() }
|
project.launch { isCanBeConsumed = target.internal.isSourcesPublishableFuture.await() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
project.multiplatformExtensionOrNull?.resourcesPublicationExtension?.subscribeOnPublishResources(target) {
|
||||||
|
configurations.maybeCreateConsumable(target.internal.resourcesElementsConfigurationName).apply {
|
||||||
|
description = "Resource files of main compilation of ${target.name}."
|
||||||
|
isVisible = false
|
||||||
|
// Publish with dependencies of apiElements configuration, so that transitives are resolved correctly. Don't inherit from
|
||||||
|
// apiElementsConfiguration directly, because it contains klibs in project dependencies.
|
||||||
|
extendsFrom(apiElementScope)
|
||||||
|
// Resources from implementation scope should also be resolved transitively, hence extend from it.
|
||||||
|
extendsFrom(implementationConfiguration)
|
||||||
|
|
||||||
|
configureResourcesPublicationAttributes(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (target !is KotlinMetadataTarget) {
|
if (target !is KotlinMetadataTarget) {
|
||||||
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
|
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
|
||||||
val compileTestsConfiguration = testCompilation.internal.configurations.deprecatedCompileConfiguration
|
val compileTestsConfiguration = testCompilation.internal.configurations.deprecatedCompileConfiguration
|
||||||
@@ -104,4 +121,4 @@ internal val CreateTargetConfigurationsSideEffect = KotlinTargetSideEffect { tar
|
|||||||
attributes.setAttribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
|
attributes.setAttribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+13
@@ -20,7 +20,9 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetComponent
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetComponent
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTests
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTests
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.publication.setUpResourcesVariant
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.JsAggregatingExecutionSource
|
import org.jetbrains.kotlin.gradle.targets.js.JsAggregatingExecutionSource
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
|
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTestRunFactory
|
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTestRunFactory
|
||||||
@@ -90,6 +92,17 @@ constructor(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (project.kotlinPropertiesProvider.mppResourcesPublication) {
|
||||||
|
project.multiplatformExtensionOrNull?.let {
|
||||||
|
usageContexts.add(
|
||||||
|
it.setUpResourcesVariant(
|
||||||
|
this,
|
||||||
|
mainCompilation
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val result = createKotlinVariant(componentName, mainCompilation, usageContexts)
|
val result = createKotlinVariant(componentName, mainCompilation, usageContexts)
|
||||||
|
|
||||||
setOf(result)
|
setOf(result)
|
||||||
|
|||||||
+11
@@ -12,6 +12,8 @@ import org.gradle.api.attributes.Attribute
|
|||||||
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
|
||||||
import org.jetbrains.kotlin.gradle.dsl.*
|
import org.jetbrains.kotlin.gradle.dsl.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.publication.setUpResourcesVariant
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.awaitPlatformCompilations
|
import org.jetbrains.kotlin.gradle.plugin.sources.awaitPlatformCompilations
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
import org.jetbrains.kotlin.gradle.plugin.sources.internal
|
||||||
import org.jetbrains.kotlin.gradle.targets.metadata.*
|
import org.jetbrains.kotlin.gradle.targets.metadata.*
|
||||||
@@ -81,6 +83,15 @@ abstract class KotlinNativeTarget @Inject constructor(
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (project.kotlinPropertiesProvider.mppResourcesPublication) {
|
||||||
|
mutableUsageContexts.add(
|
||||||
|
project.multiplatformExtension.setUpResourcesVariant(
|
||||||
|
this,
|
||||||
|
mainCompilation,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val result = createKotlinVariant(targetName, mainCompilation, mutableUsageContexts)
|
val result = createKotlinVariant(targetName, mainCompilation, mutableUsageContexts)
|
||||||
|
|
||||||
setOf(result)
|
setOf(result)
|
||||||
|
|||||||
+151
@@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:OptIn(ExperimentalWasmDsl::class)
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.unitTests
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublication
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resourcesPublicationExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
|
||||||
|
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
|
||||||
|
import org.jetbrains.kotlin.gradle.util.enableMppResourcesPublication
|
||||||
|
import org.jetbrains.kotlin.gradle.util.kotlin
|
||||||
|
import org.junit.Test
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertNull
|
||||||
|
|
||||||
|
class KotlinTargetVariantResourcesPublicationTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test variant publication - doesn't happen - when resources publication is disabled`() {
|
||||||
|
val enableResourcePublication = false
|
||||||
|
testPublishedVariants(
|
||||||
|
enableResourcePublication = enableResourcePublication,
|
||||||
|
afterEvaluation = { target ->
|
||||||
|
publishFakeResources(target)
|
||||||
|
},
|
||||||
|
shouldPublishVariant = enableResourcePublication,
|
||||||
|
targetsToTest = listOf(
|
||||||
|
{ linuxX64() },
|
||||||
|
{ wasmWasi() },
|
||||||
|
{ wasmJs() },
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test variant publication - doesn't happen - when publishing api is not called`() {
|
||||||
|
testPublishedVariants(
|
||||||
|
enableResourcePublication = true,
|
||||||
|
afterEvaluation = { /* don't call publishing api */ },
|
||||||
|
shouldPublishVariant = false,
|
||||||
|
targetsToTest = listOf(
|
||||||
|
{ linuxX64() },
|
||||||
|
{ wasmWasi() },
|
||||||
|
{ wasmJs() },
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test variant publication - creates a variant - when publishing api is called`() {
|
||||||
|
testPublishedVariants(
|
||||||
|
enableResourcePublication = true,
|
||||||
|
afterEvaluation = { target ->
|
||||||
|
publishFakeResources(target)
|
||||||
|
},
|
||||||
|
shouldPublishVariant = true,
|
||||||
|
targetsToTest = listOf(
|
||||||
|
{ linuxX64() },
|
||||||
|
{ wasmWasi() },
|
||||||
|
{ wasmJs() },
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test resources configuration - outputs a single zip file - in outgoing artifacts`() {
|
||||||
|
val project = buildProjectWithMPP {
|
||||||
|
kotlin {
|
||||||
|
linuxX64()
|
||||||
|
}
|
||||||
|
enableMppResourcesPublication(true)
|
||||||
|
}.evaluate()
|
||||||
|
|
||||||
|
assertNull(
|
||||||
|
project.configurations.findByName(
|
||||||
|
project.multiplatformExtension.linuxX64().resourcesElementsConfigurationName
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
project.publishFakeResources(project.multiplatformExtension.linuxX64())
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
listOf(
|
||||||
|
project.layout.buildDirectory.file(
|
||||||
|
"kotlin-multiplatform-resources/zip-for-publication/linuxX64/test.kotlin_resources.zip"
|
||||||
|
).get().asFile
|
||||||
|
),
|
||||||
|
project.configurations.findByName(
|
||||||
|
project.multiplatformExtension.linuxX64().resourcesElementsConfigurationName
|
||||||
|
)?.outgoing?.artifacts?.map { it.file },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testPublishedVariants(
|
||||||
|
enableResourcePublication: Boolean,
|
||||||
|
afterEvaluation: Project.(KotlinTarget) -> Unit,
|
||||||
|
shouldPublishVariant: Boolean,
|
||||||
|
targetsToTest: List<KotlinMultiplatformExtension.() -> KotlinTarget>,
|
||||||
|
) {
|
||||||
|
val project = buildProjectWithMPP {
|
||||||
|
kotlin {
|
||||||
|
targetsToTest.forEach { createTarget ->
|
||||||
|
createTarget()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
enableMppResourcesPublication(enableResourcePublication)
|
||||||
|
}.evaluate()
|
||||||
|
|
||||||
|
targetsToTest.forEach { targetToTest ->
|
||||||
|
val target = project.multiplatformExtension.targetToTest()
|
||||||
|
|
||||||
|
// Resources configuration should never be published before publishing API is called
|
||||||
|
assert(target.internal.resourcesElementsConfigurationName !in configurationNamesUsedInVariantPublications(target))
|
||||||
|
project.afterEvaluation(target)
|
||||||
|
assert(
|
||||||
|
shouldPublishVariant == target.internal.resourcesElementsConfigurationName in configurationNamesUsedInVariantPublications(target)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun configurationNamesUsedInVariantPublications(target: KotlinTarget): Set<String> {
|
||||||
|
return target.internal.kotlinComponents.flatMap { component ->
|
||||||
|
component.internal.usages.map { it.dependencyConfigurationName }
|
||||||
|
}.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.publishFakeResources(target: KotlinTarget) {
|
||||||
|
project.multiplatformExtension.resourcesPublicationExtension?.publishResourcesAsKotlinComponent(
|
||||||
|
target,
|
||||||
|
resourcePathForSourceSet = {
|
||||||
|
KotlinTargetResourcesPublication.ResourceRoot(
|
||||||
|
project.provider { File(it.name) },
|
||||||
|
emptyList(),
|
||||||
|
emptyList(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
relativeResourcePlacement = project.provider { File("test") },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+564
@@ -0,0 +1,564 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2024 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:OptIn(ExperimentalWasmDsl::class)
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.unitTests
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.artifacts.Configuration
|
||||||
|
import org.gradle.api.artifacts.Dependency
|
||||||
|
import org.gradle.api.artifacts.ResolveException
|
||||||
|
import org.gradle.api.attributes.Attribute
|
||||||
|
import org.gradle.api.attributes.Usage
|
||||||
|
import org.gradle.api.internal.project.ProjectInternal
|
||||||
|
import org.gradle.kotlin.dsl.project
|
||||||
|
import org.gradle.testfixtures.ProjectBuilder
|
||||||
|
import org.jetbrains.kotlin.gradle.dependencyResolutionTests.mavenCentralCacheRedirector
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.KotlinTargetResourcesPublication
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resolve.KotlinTargetResourcesResolutionStrategy
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resourcesPublicationExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.usageByName
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.js.dsl.ExperimentalWasmDsl
|
||||||
|
import org.jetbrains.kotlin.gradle.util.*
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.buildOrNull
|
||||||
|
import org.jetbrains.kotlin.util.assertThrows
|
||||||
|
import org.junit.Test
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class KotlinTargetVariantResourcesResolutionTests {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test direct dependency - is the same - for all resolution methods and supported scopes`() {
|
||||||
|
KotlinTargetResourcesResolutionStrategy.values().forEach { resolutionMethod ->
|
||||||
|
dependencyScopesWithResources().forEach { dependencyScope ->
|
||||||
|
testDirectDependencyOnResourcesProducer(
|
||||||
|
producerTarget = { linuxX64() },
|
||||||
|
consumerTarget = { linuxX64() },
|
||||||
|
dependencyScope = dependencyScope,
|
||||||
|
resolutionStrategy = resolutionMethod,
|
||||||
|
expectedResult = { _, producer ->
|
||||||
|
hashSetOf(producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/producer.kotlin_resources.zip"))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test direct dependency - between different native targets - with artifact view`() {
|
||||||
|
testDirectDependencyOnResourcesProducer(
|
||||||
|
producerTarget = { linuxX64() },
|
||||||
|
consumerTarget = { linuxArm64() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.VariantReselection,
|
||||||
|
expectedResult = { _, _ -> emptySet() },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test direct dependency - between different native targets - with resources configuration`() {
|
||||||
|
directDependencyOnResourcesProducer(
|
||||||
|
producerTarget = { linuxX64() },
|
||||||
|
consumerTarget = { linuxArm64() },
|
||||||
|
strategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
assert = { consumer, _ ->
|
||||||
|
assertThrows<ResolveException> {
|
||||||
|
KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration.resourceArchives(
|
||||||
|
consumer.multiplatformExtension.linuxArm64().compilations.getByName("main")
|
||||||
|
).files
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test direct dependency - for wasmJs and wasmWasi targets - when using artifact view`() {
|
||||||
|
listOf<TargetProvider>(
|
||||||
|
{ wasmJs() },
|
||||||
|
{ wasmWasi() },
|
||||||
|
).forEach { target ->
|
||||||
|
testDirectDependencyOnResourcesProducer(
|
||||||
|
producerTarget = { target() },
|
||||||
|
consumerTarget = { target() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.VariantReselection,
|
||||||
|
expectedResult = { _, producer ->
|
||||||
|
hashSetOf(
|
||||||
|
producer.buildFile(
|
||||||
|
"kotlin-multiplatform-resources/zip-for-publication/${producer.multiplatformExtension.target().name}/producer.kotlin_resources.zip"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test direct dependency - for wasmJs - when using resources configuration`() {
|
||||||
|
testDirectDependencyOnResourcesProducer(
|
||||||
|
producerTarget = { wasmJs() },
|
||||||
|
consumerTarget = { wasmJs() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
filterResolvedFiles = {
|
||||||
|
it.filterNot {
|
||||||
|
it.path.contains("kotlin-stdlib-wasm-js")
|
||||||
|
}.toSet()
|
||||||
|
},
|
||||||
|
expectedResult = { _, producer ->
|
||||||
|
hashSetOf(
|
||||||
|
producer.buildFile(
|
||||||
|
"kotlin-multiplatform-resources/zip-for-publication/wasmJs/producer.kotlin_resources.zip"
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test direct dependency - for wasmWasi - when using resources configuration`() {
|
||||||
|
testDirectDependencyOnResourcesProducer(
|
||||||
|
producerTarget = { wasmWasi() },
|
||||||
|
consumerTarget = { wasmWasi() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
filterResolvedFiles = {
|
||||||
|
it.filterNot {
|
||||||
|
it.path.contains("kotlin-stdlib-wasm-wasi")
|
||||||
|
}.toSet()
|
||||||
|
},
|
||||||
|
expectedResult = { _, producer ->
|
||||||
|
hashSetOf(
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/wasmWasi/producer.kotlin_resources.zip"),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test transitive dependency - without resources in middle project - with configuration`() {
|
||||||
|
testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider = { linuxX64() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
expectedResult = { _, middle, producer ->
|
||||||
|
setOf(
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/producer.kotlin_resources.zip"),
|
||||||
|
middle.buildFile("classes/kotlin/linuxX64/main/klib/middle.klib"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test transitive dependency - without resources in middle project in wasm - with configuration`() {
|
||||||
|
dependencyScopesWithResources().forEach { dependencyScope ->
|
||||||
|
testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider = { wasmJs() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
dependencyScope = dependencyScope,
|
||||||
|
filterResolvedFiles = {
|
||||||
|
it.filterNot {
|
||||||
|
it.path.contains("kotlin-stdlib-wasm-js")
|
||||||
|
}.toSet()
|
||||||
|
},
|
||||||
|
expectedResult = { _, middle, producer ->
|
||||||
|
setOf(
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/wasmJs/producer.kotlin_resources.zip"),
|
||||||
|
middle.buildFile("libs/middle-wasm-js.klib"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test transitive dependency - without resources in middle project in wasm - with artifact view`() {
|
||||||
|
dependencyScopesWithResources().forEach { dependencyScope ->
|
||||||
|
testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider = { wasmJs() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.VariantReselection,
|
||||||
|
dependencyScope = dependencyScope,
|
||||||
|
filterResolvedFiles = {
|
||||||
|
it.filterNot {
|
||||||
|
it.path.contains("kotlin-stdlib-wasm-js")
|
||||||
|
}.toSet()
|
||||||
|
},
|
||||||
|
expectedResult = { _, _, producer ->
|
||||||
|
setOf(
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/wasmJs/producer.kotlin_resources.zip"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test transitive dependency - without resources in middle project - with artifact view`() {
|
||||||
|
testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider = { linuxX64() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.VariantReselection,
|
||||||
|
expectedResult = { _, _, producer ->
|
||||||
|
setOf(
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/producer.kotlin_resources.zip"),
|
||||||
|
// VariantReselection strategy disables compatibility rule that resolves klibs for resources configuration
|
||||||
|
// middle.buildFile("classes/kotlin/linuxX64/main/klib/middle.klib"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test transitive dependency - with resources in middle project - with artifact view`() {
|
||||||
|
dependencyScopesWithResources().forEach { dependencyScope ->
|
||||||
|
testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider = { linuxX64() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.VariantReselection,
|
||||||
|
dependencyScope = dependencyScope,
|
||||||
|
middlePublishesResources = true,
|
||||||
|
expectedResult = { _, middle, producer ->
|
||||||
|
setOf(
|
||||||
|
middle.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/middle.kotlin_resources.zip"),
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/producer.kotlin_resources.zip"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider = { linuxX64() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.VariantReselection,
|
||||||
|
middlePublishesResources = true,
|
||||||
|
consumerPublishesResources = true,
|
||||||
|
expectedResult = { _, middle, producer ->
|
||||||
|
setOf(
|
||||||
|
middle.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/middle.kotlin_resources.zip"),
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/producer.kotlin_resources.zip"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test transitive dependency - with resources in middle project - with configuration`() {
|
||||||
|
dependencyScopesWithResources().forEach { dependencyScope ->
|
||||||
|
testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider = { linuxX64() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
dependencyScope = dependencyScope,
|
||||||
|
middlePublishesResources = true,
|
||||||
|
expectedResult = { _, middle, producer ->
|
||||||
|
setOf(
|
||||||
|
middle.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/middle.kotlin_resources.zip"),
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/producer.kotlin_resources.zip"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider = { linuxX64() },
|
||||||
|
resolutionStrategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
middlePublishesResources = true,
|
||||||
|
consumerPublishesResources = true,
|
||||||
|
expectedResult = { _, middle, producer ->
|
||||||
|
setOf(
|
||||||
|
middle.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/middle.kotlin_resources.zip"),
|
||||||
|
producer.buildFile("kotlin-multiplatform-resources/zip-for-publication/linuxX64/producer.kotlin_resources.zip"),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `test resources - don't leak into non-resources configurations`() {
|
||||||
|
resourcesConfigurationResolutionSanityCheck()
|
||||||
|
|
||||||
|
val targetsToTest = listOf<TargetProvider>(
|
||||||
|
{ wasmJs() },
|
||||||
|
{ wasmWasi() },
|
||||||
|
{ linuxX64() },
|
||||||
|
{ iosArm64() },
|
||||||
|
)
|
||||||
|
targetsToTest.indices.forEach { index ->
|
||||||
|
// Test when target is matching
|
||||||
|
testNonResourcesConfigurationDontResolveResourceVariants(
|
||||||
|
producerTarget = targetsToTest[index],
|
||||||
|
consumerTarget = targetsToTest[index],
|
||||||
|
strategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test when target is not matching
|
||||||
|
testNonResourcesConfigurationDontResolveResourceVariants(
|
||||||
|
producerTarget = targetsToTest[index],
|
||||||
|
consumerTarget = targetsToTest[(index + 1) % targetsToTest.count()],
|
||||||
|
strategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun dependencyScopesWithResources(): List<DependencyScopeProvider> {
|
||||||
|
return listOf(
|
||||||
|
{ this::implementation },
|
||||||
|
{ this::api },
|
||||||
|
// What are these supposed to mean for resources?
|
||||||
|
// { this::compileOnly }, ?
|
||||||
|
// { this::runtimeOnly }, ?
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun resourcesConfigurationResolutionSanityCheck() {
|
||||||
|
directDependencyOnResourcesProducer(
|
||||||
|
producerTarget = { linuxX64() },
|
||||||
|
consumerTarget = { linuxX64() },
|
||||||
|
strategy = KotlinTargetResourcesResolutionStrategy.ResourcesConfiguration,
|
||||||
|
assert = { consumer, _ ->
|
||||||
|
val resourcesConfiguration = consumer.multiplatformExtension.linuxX64()
|
||||||
|
.compilations.getByName("main")
|
||||||
|
.internal.configurations.resourcesConfiguration ?: error("Missing resources configuration")
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
mapOf(
|
||||||
|
// linuxX64ResourcesPath is the root resolvable configuration for the resolution
|
||||||
|
"test:consumer" to listOf(listOf("linuxX64ResourcesPath")),
|
||||||
|
// stdlib doesn't have resources, so apiElements is selected as per compatibility rule
|
||||||
|
"org.jetbrains.kotlin:kotlin-stdlib" to listOf(listOf("nativeApiElements")),
|
||||||
|
// producer provides the consumable configuration with resources for the consumer
|
||||||
|
"test:producer" to listOf(listOf("linuxX64ResourcesElements")),
|
||||||
|
),
|
||||||
|
resourcesConfiguration.incoming.resolutionResult.allComponents.groupBy(
|
||||||
|
keySelector = { "${it.moduleVersion?.group}:${it.moduleVersion?.name}" },
|
||||||
|
valueTransform = { it.variants.map { it.displayName } },
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testNonResourcesConfigurationDontResolveResourceVariants(
|
||||||
|
producerTarget: TargetProvider,
|
||||||
|
consumerTarget: TargetProvider,
|
||||||
|
strategy: KotlinTargetResourcesResolutionStrategy,
|
||||||
|
) {
|
||||||
|
directDependencyOnResourcesProducer(
|
||||||
|
producerTarget = producerTarget,
|
||||||
|
consumerTarget = consumerTarget,
|
||||||
|
strategy = strategy,
|
||||||
|
assert = { consumer, _ ->
|
||||||
|
val resourcesConfigurations = consumer.multiplatformExtension.targets.flatMap {
|
||||||
|
it.compilations.mapNotNull { it.internal.configurations.resourcesConfiguration }
|
||||||
|
}
|
||||||
|
|
||||||
|
val nonResourcesConfigurations: Set<Configuration> = consumer.configurations.filter {
|
||||||
|
it.isCanBeResolved
|
||||||
|
}.toHashSet() - resourcesConfigurations
|
||||||
|
assert(nonResourcesConfigurations.isNotEmpty())
|
||||||
|
|
||||||
|
nonResourcesConfigurations.forEach { resolvableConfiguration ->
|
||||||
|
val resolvedComponents = resolvableConfiguration.incoming.resolutionResult.allComponents
|
||||||
|
|
||||||
|
resolvedComponents.forEach { resolvedComponent ->
|
||||||
|
val resolvedVariants = resolvedComponent.variants
|
||||||
|
|
||||||
|
resolvedVariants.forEach { variant ->
|
||||||
|
val variantPath = { "$resolvableConfiguration -> $resolvedComponent -> $variant" }
|
||||||
|
val typedUsage = variant.attributes.getAttribute(Usage.USAGE_ATTRIBUTE)
|
||||||
|
val stringUsage = variant.attributes.getAttribute(Attribute.of(Usage.USAGE_ATTRIBUTE.name, String::class.java))
|
||||||
|
val isKotlinCompilerClasspath = variant.attributes.keySet().isEmpty()
|
||||||
|
assert(
|
||||||
|
typedUsage != null || stringUsage != null || isKotlinCompilerClasspath,
|
||||||
|
variantPath
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
typedUsage != consumer.project.usageByName(KotlinUsages.KOTLIN_RESOURCES),
|
||||||
|
variantPath,
|
||||||
|
)
|
||||||
|
assert(
|
||||||
|
stringUsage != KotlinUsages.KOTLIN_RESOURCES,
|
||||||
|
variantPath,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testDirectDependencyOnResourcesProducer(
|
||||||
|
producerTarget: TargetProvider,
|
||||||
|
consumerTarget: TargetProvider,
|
||||||
|
dependencyScope: DependencyScopeProvider = { ::implementation },
|
||||||
|
resolutionStrategy: KotlinTargetResourcesResolutionStrategy,
|
||||||
|
filterResolvedFiles: (Set<File>) -> Set<File> = { it },
|
||||||
|
expectedResult: (consumer: Project, producer: Project) -> Set<File>,
|
||||||
|
) = directDependencyOnResourcesProducer(
|
||||||
|
producerTarget = producerTarget,
|
||||||
|
consumerTarget = consumerTarget,
|
||||||
|
dependencyScope = dependencyScope,
|
||||||
|
strategy = resolutionStrategy,
|
||||||
|
assert = { consumer: Project, producer: Project ->
|
||||||
|
consumer.setMppResourcesResolutionStrategy(resolutionStrategy)
|
||||||
|
assertEquals(
|
||||||
|
expectedResult(consumer, producer),
|
||||||
|
filterResolvedFiles(
|
||||||
|
resolutionStrategy.resourceArchives(
|
||||||
|
consumer.multiplatformExtension.consumerTarget().compilations.getByName("main"),
|
||||||
|
).files
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun directDependencyOnResourcesProducer(
|
||||||
|
producerTarget: TargetProvider,
|
||||||
|
consumerTarget: TargetProvider,
|
||||||
|
strategy: KotlinTargetResourcesResolutionStrategy,
|
||||||
|
dependencyScope: DependencyScopeProvider = { ::implementation },
|
||||||
|
assert: (consumer: Project, producer: Project) -> Unit,
|
||||||
|
) {
|
||||||
|
val rootProject = buildProject()
|
||||||
|
val producer = rootProject.createSubproject("producer") {
|
||||||
|
kotlin { producerTarget() }
|
||||||
|
}
|
||||||
|
val consumer = rootProject.createSubproject(
|
||||||
|
"consumer",
|
||||||
|
preApplyCode = { setMppResourcesResolutionStrategy(strategy) }
|
||||||
|
) {
|
||||||
|
kotlin {
|
||||||
|
consumerTarget()
|
||||||
|
sourceSets.commonMain {
|
||||||
|
dependencies {
|
||||||
|
dependencyScope()(project(":${producer.name}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf(rootProject, producer, consumer).forEach { it.evaluate() }
|
||||||
|
producer.publishFakeResources(producer.multiplatformExtension.producerTarget())
|
||||||
|
|
||||||
|
assert(consumer, producer)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun testTransitiveDependencyOnResourcesProducer(
|
||||||
|
targetProvider: TargetProvider,
|
||||||
|
resolutionStrategy: KotlinTargetResourcesResolutionStrategy,
|
||||||
|
filterResolvedFiles: (Set<File>) -> Set<File> = { it },
|
||||||
|
dependencyScope: DependencyScopeProvider = { ::implementation },
|
||||||
|
middlePublishesResources: Boolean = false,
|
||||||
|
consumerPublishesResources: Boolean = false,
|
||||||
|
expectedResult: (consumer: Project, middle: Project, producer: Project) -> Set<File>,
|
||||||
|
) {
|
||||||
|
val rootProject = buildProject()
|
||||||
|
val producer = rootProject.createSubproject(
|
||||||
|
"producer",
|
||||||
|
preApplyCode = {
|
||||||
|
enableMppResourcesPublication(true)
|
||||||
|
setMppResourcesResolutionStrategy(resolutionStrategy)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
kotlin { targetProvider() }
|
||||||
|
}
|
||||||
|
|
||||||
|
val middle = rootProject.createSubproject(
|
||||||
|
"middle",
|
||||||
|
preApplyCode = {
|
||||||
|
enableMppResourcesPublication(middlePublishesResources)
|
||||||
|
setMppResourcesResolutionStrategy(resolutionStrategy)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
kotlin {
|
||||||
|
targetProvider()
|
||||||
|
sourceSets.commonMain {
|
||||||
|
dependencies {
|
||||||
|
dependencyScope()(dependencies.project(":${producer.name}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val consumer = rootProject.createSubproject(
|
||||||
|
"consumer",
|
||||||
|
preApplyCode = {
|
||||||
|
enableMppResourcesPublication(consumerPublishesResources)
|
||||||
|
setMppResourcesResolutionStrategy(resolutionStrategy)
|
||||||
|
}
|
||||||
|
) {
|
||||||
|
kotlin {
|
||||||
|
targetProvider()
|
||||||
|
sourceSets.commonMain {
|
||||||
|
dependencies {
|
||||||
|
dependencyScope()(dependencies.project(":${middle.name}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setMppResourcesResolutionStrategy(resolutionStrategy)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
listOf(rootProject, producer, middle, consumer).forEach { it.evaluate() }
|
||||||
|
|
||||||
|
producer.publishFakeResources(producer.multiplatformExtension.targetProvider())
|
||||||
|
if (middlePublishesResources) middle.publishFakeResources(middle.multiplatformExtension.targetProvider())
|
||||||
|
if (consumerPublishesResources) consumer.publishFakeResources(consumer.multiplatformExtension.targetProvider())
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
expectedResult(consumer, middle, producer),
|
||||||
|
filterResolvedFiles(
|
||||||
|
resolutionStrategy.resourceArchives(
|
||||||
|
consumer.multiplatformExtension.targetProvider().compilations.getByName("main"),
|
||||||
|
).files
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.buildFile(path: String) = layout.buildDirectory.file(path).get().asFile
|
||||||
|
|
||||||
|
private fun ProjectInternal.createSubproject(
|
||||||
|
name: String,
|
||||||
|
preApplyCode: Project.() -> Unit = {},
|
||||||
|
code: Project.() -> Unit = {},
|
||||||
|
) = buildProjectWithMPPAndStdlib(
|
||||||
|
projectBuilder = {
|
||||||
|
withParent(this@createSubproject)
|
||||||
|
withName(name)
|
||||||
|
},
|
||||||
|
preApplyCode = preApplyCode,
|
||||||
|
code = code,
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun buildProjectWithMPPAndStdlib(
|
||||||
|
projectBuilder: ProjectBuilder.() -> Unit = { },
|
||||||
|
preApplyCode: Project.() -> Unit = {},
|
||||||
|
code: Project.() -> Unit = {},
|
||||||
|
) = buildProjectWithMPP(
|
||||||
|
projectBuilder = projectBuilder,
|
||||||
|
preApplyCode = preApplyCode,
|
||||||
|
) {
|
||||||
|
enableDependencyVerification(false)
|
||||||
|
enableDefaultStdlibDependency(true)
|
||||||
|
repositories.mavenLocal()
|
||||||
|
repositories.mavenCentralCacheRedirector()
|
||||||
|
code()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.publishFakeResources(target: KotlinTarget) {
|
||||||
|
project.multiplatformExtension.resourcesPublicationExtension?.publishResourcesAsKotlinComponent(
|
||||||
|
target,
|
||||||
|
resourcePathForSourceSet = {
|
||||||
|
KotlinTargetResourcesPublication.ResourceRoot(
|
||||||
|
project.provider { File(it.name) },
|
||||||
|
emptyList(),
|
||||||
|
emptyList(),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
relativeResourcePlacement = project.provider { File("test") },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private typealias TargetProvider = KotlinMultiplatformExtension.() -> (KotlinTarget)
|
||||||
|
private typealias DependencyScopeProvider = KotlinDependencyHandler.() -> ((Any) -> Dependency?)
|
||||||
+5
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_INTRANSITIVE_METADATA_CONFIGURATION
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_INTRANSITIVE_METADATA_CONFIGURATION
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.CocoapodsExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.getExtension
|
import org.jetbrains.kotlin.gradle.plugin.getExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.resources.resolve.KotlinTargetResourcesResolutionStrategy
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.KotlinArtifactsExtensionImpl
|
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.KotlinArtifactsExtensionImpl
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.kotlinArtifactsExtension
|
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.kotlinArtifactsExtension
|
||||||
|
|
||||||
@@ -117,6 +118,10 @@ fun Project.enableMppResourcesPublication(enabled: Boolean = true) {
|
|||||||
propertiesExtension.set(PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_RESOURCES_PUBLICATION, enabled.toString())
|
propertiesExtension.set(PropertiesProvider.PropertyNames.KOTLIN_MPP_ENABLE_RESOURCES_PUBLICATION, enabled.toString())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Project.setMppResourcesResolutionStrategy(strategy: KotlinTargetResourcesResolutionStrategy) {
|
||||||
|
propertiesExtension.set(PropertiesProvider.PropertyNames.KOTLIN_MPP_RESOURCES_RESOLUTION_STRATEGY, strategy.propertyName)
|
||||||
|
}
|
||||||
|
|
||||||
fun Project.enableIntransitiveMetadataConfiguration(enabled: Boolean = true) {
|
fun Project.enableIntransitiveMetadataConfiguration(enabled: Boolean = true) {
|
||||||
propertiesExtension.set(KOTLIN_MPP_ENABLE_INTRANSITIVE_METADATA_CONFIGURATION, enabled.toString())
|
propertiesExtension.set(KOTLIN_MPP_ENABLE_INTRANSITIVE_METADATA_CONFIGURATION, enabled.toString())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user