Fix visibility for MPP dependencies from non-root source sets, KT-32204
Fix incorrect source sets visibility when a dependency is added to a non-root source set and its visible source sets are mistakenly treated as already visible by the dependsOn parents and are thus not extracted from the metadata package. To simplify the logic, reuse the GranularMetadataTransformation instances from the dependsOn parent source sets: they can provide the requested dependencies sets for the parents and their transformation results, so that excluding the dependency source sets which are seen the parents gets simpler. The issue is then fixed by naturally excluding only the source sets which are mentioned in the parents' transformation results. Issue #KT-32204 Fixed
This commit is contained in:
+144
-15
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.gradle.internals.MULTIPLATFORM_PROJECT_METADATA_FILE
|
||||
import org.jetbrains.kotlin.gradle.internals.parseKotlinSourceSetMetadataFromXml
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.ModuleDependencyIdentifier
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.util.modify
|
||||
import java.io.File
|
||||
import java.util.zip.ZipFile
|
||||
@@ -24,13 +25,7 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
|
||||
@Test
|
||||
fun testPublishedModules() {
|
||||
Project("third-party-lib", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
setupWorkingDir()
|
||||
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||
build("publish") {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
publishThirdPartyLib(withGranularMetadata = false)
|
||||
|
||||
Project("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
setupWorkingDir()
|
||||
@@ -59,13 +54,7 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
|
||||
@Test
|
||||
fun testProjectDependencies() {
|
||||
Project("third-party-lib", gradleVersion, "hierarchical-mpp-project-dependency").run {
|
||||
setupWorkingDir()
|
||||
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||
build("publish") {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
publishThirdPartyLib(withGranularMetadata = false)
|
||||
|
||||
with(Project("hierarchical-mpp-project-dependency", gradleVersion)) {
|
||||
setupWorkingDir()
|
||||
@@ -79,6 +68,20 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun publishThirdPartyLib(withGranularMetadata: Boolean): Project =
|
||||
Project("third-party-lib", gradleVersion, "hierarchical-mpp-published-modules").apply {
|
||||
setupWorkingDir()
|
||||
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||
|
||||
if (withGranularMetadata) {
|
||||
projectDir.resolve("gradle.properties").appendText("kotlin.mpp.enableGranularSourceSetsMetadata=true")
|
||||
}
|
||||
|
||||
build("publish") {
|
||||
assertSuccessful()
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkMyLibFoo(compiledProject: CompiledProject, subprojectPrefix: String? = null) = with(compiledProject) {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(expectedTasks(subprojectPrefix))
|
||||
@@ -273,7 +276,7 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
"compileKotlinMetadata",
|
||||
"compileJvmAndJsMainKotlinMetadata",
|
||||
"compileLinuxAndJsMainKotlinMetadata"
|
||||
).map { subprojectPrefix?.let { ":$it" }.orEmpty() + ":" + it }
|
||||
).map { task -> subprojectPrefix?.let { ":$it" }.orEmpty() + ":" + task }
|
||||
|
||||
// the projects used in these tests are similar and only the dependencies differ:
|
||||
private fun expectedProjectStructureMetadata(
|
||||
@@ -317,4 +320,130 @@ class HierarchicalMppIT : BaseGradleIT() {
|
||||
.use { inputStream -> documentBuilder.parse(inputStream) }
|
||||
return checkNotNull(parseKotlinSourceSetMetadataFromXml(document))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testProcessingDependencyDeclaredInNonRootSourceSet() {
|
||||
publishThirdPartyLib(withGranularMetadata = true)
|
||||
|
||||
Project("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
setupWorkingDir()
|
||||
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||
|
||||
val intermediateMetadataCompileTask = ":compileJvmAndJsMainKotlinMetadata"
|
||||
|
||||
build(intermediateMetadataCompileTask) {
|
||||
assertSuccessful()
|
||||
|
||||
checkNamesOnCompileClasspath(
|
||||
intermediateMetadataCompileTask,
|
||||
shouldInclude = listOf(
|
||||
"third-party-lib" to "commonMain"
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testDependenciesInNonPublishedSourceSets() {
|
||||
publishThirdPartyLib(withGranularMetadata = true)
|
||||
|
||||
Project("my-lib-foo", gradleVersion, "hierarchical-mpp-published-modules").run {
|
||||
setupWorkingDir()
|
||||
gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl)
|
||||
|
||||
testDependencyTransformations { reports ->
|
||||
reports.single {
|
||||
it.sourceSetName == "jvmAndJsMain" && it.scope == "api" && it.groupAndModule.startsWith("com.example")
|
||||
}.let {
|
||||
assertEquals(setOf("commonMain"), it.allVisibleSourceSets)
|
||||
assertEquals(setOf("commonMain"), it.newVisibleSourceSets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.testDependencyTransformations(
|
||||
subproject: String? = null,
|
||||
check: CompiledProject.(reports: Iterable<DependencyTransformationReport>) -> Unit
|
||||
) {
|
||||
setupWorkingDir()
|
||||
val buildGradleKts = gradleBuildScript(subproject)
|
||||
assert(buildGradleKts.extension == "kts") { "Only Kotlin scripts are supported." }
|
||||
|
||||
val testTaskName = "reportDependencyTransformationsForTest"
|
||||
|
||||
if (testTaskName !in buildGradleKts.readText()) {
|
||||
buildGradleKts.modify {
|
||||
"import ${DefaultKotlinSourceSet::class.qualifiedName}\n" + it + "\n" + """
|
||||
val $testTaskName by tasks.creating {
|
||||
doFirst {
|
||||
for (scope in listOf("api", "implementation", "compileOnly", "runtimeOnly")) {
|
||||
println("========\n${'$'}scope\n")
|
||||
|
||||
kotlin.sourceSets.withType<DefaultKotlinSourceSet>().forEach { sourceSet ->
|
||||
println("--------\n${'$'}{sourceSet.name}")
|
||||
|
||||
sourceSet
|
||||
.getDependenciesTransformation(
|
||||
"${'$'}{sourceSet.name}${'$'}{scope.capitalize()}DependenciesMetadata"
|
||||
).forEach {
|
||||
val line = listOf(
|
||||
"${DependencyTransformationReport.TEST_OUTPUT_MARKER}",
|
||||
sourceSet.name,
|
||||
scope,
|
||||
it.groupId + ":" + it.moduleName,
|
||||
it.allVisibleSourceSets.joinToString(","),
|
||||
it.useFilesForSourceSets.keys.joinToString(",")
|
||||
)
|
||||
|
||||
println(" " + line.joinToString(" :: "))
|
||||
}
|
||||
println()
|
||||
}
|
||||
println()
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
}
|
||||
|
||||
build(":${subproject?.plus(":").orEmpty()}$testTaskName") {
|
||||
assertSuccessful()
|
||||
|
||||
val reports = output.lines()
|
||||
.filter { DependencyTransformationReport.TEST_OUTPUT_MARKER in it }
|
||||
.map { DependencyTransformationReport.parseTestOutputLine(it) }
|
||||
|
||||
check(this, reports)
|
||||
}
|
||||
}
|
||||
|
||||
private data class DependencyTransformationReport(
|
||||
val sourceSetName: String,
|
||||
val scope: String,
|
||||
val groupAndModule: String,
|
||||
val allVisibleSourceSets: Set<String>,
|
||||
val newVisibleSourceSets: Set<String> // those which the dependsOn parents don't see
|
||||
) {
|
||||
val isExcluded: Boolean get() = allVisibleSourceSets.isEmpty()
|
||||
|
||||
companion object {
|
||||
const val TEST_OUTPUT_MARKER = "###transformation"
|
||||
const val TEST_OUTPUT_COMPONENT_SEPARATOR = " :: "
|
||||
const val TEST_OUTPUT_ITEMS_SEPARATOR = ","
|
||||
|
||||
fun parseTestOutputLine(line: String): DependencyTransformationReport {
|
||||
val tail = line.substringAfter(TEST_OUTPUT_MARKER + TEST_OUTPUT_COMPONENT_SEPARATOR)
|
||||
val (sourceSetName, scope, groupAndModule, allVisibleSourceSets, newVisibleSourceSets) =
|
||||
tail.split(TEST_OUTPUT_COMPONENT_SEPARATOR)
|
||||
return DependencyTransformationReport(
|
||||
sourceSetName, scope, groupAndModule,
|
||||
allVisibleSourceSets.split(TEST_OUTPUT_ITEMS_SEPARATOR).filter { it.isNotEmpty() }.toSet(),
|
||||
newVisibleSourceSets.split(TEST_OUTPUT_ITEMS_SEPARATOR).filter { it.isNotEmpty() }.toSet()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+45
-29
@@ -11,6 +11,8 @@ import org.gradle.api.file.FileCollection
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_MAIN_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||
@@ -71,6 +73,9 @@ private typealias ModuleId = Pair<String?, String> // group ID, artifact ID
|
||||
private val ResolvedDependency.moduleId: ModuleId
|
||||
get() = moduleGroup to moduleName
|
||||
|
||||
private val Dependency.moduleId: ModuleId
|
||||
get() = group to name
|
||||
|
||||
internal class GranularMetadataTransformation(
|
||||
val project: Project,
|
||||
val kotlinSourceSet: KotlinSourceSet,
|
||||
@@ -78,6 +83,7 @@ internal class GranularMetadataTransformation(
|
||||
val sourceSetRequestedScopes: List<KotlinDependencyScope>,
|
||||
/** A configuration that holds the dependencies of the appropriate scope for all Kotlin source sets in the project */
|
||||
val allSourceSetsConfigurations: Iterable<Configuration>
|
||||
val parentTransformations: Lazy<Iterable<GranularMetadataTransformation>>
|
||||
) {
|
||||
val metadataDependencyResolutions: Iterable<MetadataDependencyResolution> by lazy { doTransform() }
|
||||
|
||||
@@ -115,48 +121,50 @@ internal class GranularMetadataTransformation(
|
||||
return result
|
||||
}
|
||||
|
||||
private fun getRequestedDependencies(kotlinSourceSet: KotlinSourceSet): Set<Dependency> {
|
||||
val hierarchy = kotlinSourceSet.getSourceSetHierarchy().toMutableSet()
|
||||
|
||||
// This is an ad-hoc mechanism for exposing the commonMain dependencies to test source sets as well:
|
||||
// TODO once a general production-test visibility mechanism is implemented, replace this workaround with the general solution
|
||||
if (hierarchy.any { it.name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME }) {
|
||||
hierarchy += project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME).getSourceSetHierarchy()
|
||||
}
|
||||
|
||||
return hierarchy.flatMapTo(mutableSetOf()) { sourceSet ->
|
||||
sourceSetRequestedScopes.flatMap { scope ->
|
||||
private val requestedDependencies: Iterable<Dependency> by lazy {
|
||||
fun collectScopedDependenciesFromSourceSet(sourceSet: KotlinSourceSet): Set<Dependency> =
|
||||
sourceSetRequestedScopes.flatMapTo(mutableSetOf()) { scope ->
|
||||
project.sourceSetDependencyConfigurationByScope(sourceSet, scope).allDependencies
|
||||
}
|
||||
}
|
||||
|
||||
val ownDependencies = collectScopedDependenciesFromSourceSet(kotlinSourceSet)
|
||||
val parentDependencies = parentTransformations.value.flatMapTo(mutableSetOf<Dependency>()) { it.requestedDependencies }
|
||||
|
||||
ownDependencies + parentDependencies
|
||||
}
|
||||
|
||||
private val resolvedConfigurations: Iterable<LenientConfiguration> by lazy {
|
||||
allSourceSetsConfigurations.map { it.resolvedConfiguration.lenientConfiguration }
|
||||
}
|
||||
|
||||
private fun doTransform(): Iterable<MetadataDependencyResolution> {
|
||||
val result = mutableListOf<MetadataDependencyResolution>()
|
||||
|
||||
val resolvedDependenciesFromAllSourceSets = allSourceSetsConfigurations.map { it.resolvedConfiguration.lenientConfiguration }
|
||||
val parentResolutions =
|
||||
parentTransformations.value.flatMap { it.metadataDependencyResolutions }.groupBy { it.dependency.moduleId }
|
||||
|
||||
val visitedDependencies = mutableSetOf<ResolvedDependency>()
|
||||
val allRequestedDependencies = requestedDependencies
|
||||
|
||||
val directRequestedDependencies = getRequestedDependencies(kotlinSourceSet)
|
||||
|
||||
val directRequestedModules: Set<ModuleId> = directRequestedDependencies.mapTo(mutableSetOf()) { it.group to it.name }
|
||||
|
||||
val allModuleDependencies = resolvedDependenciesFromAllSourceSets.flatMapTo(mutableSetOf()) { it.allModuleDependencies }
|
||||
val allModuleDependencies = resolvedConfigurations.flatMap { it.allModuleDependencies }
|
||||
|
||||
val knownProjectDependencies = collectProjectDependencies(
|
||||
directRequestedDependencies.filterIsInstance<ProjectDependency>(),
|
||||
allRequestedDependencies.filterIsInstance<ProjectDependency>(),
|
||||
allModuleDependencies
|
||||
)
|
||||
|
||||
val resolvedDependencyQueue: Queue<ResolvedDependencyWithParent> = ArrayDeque<ResolvedDependencyWithParent>().apply {
|
||||
val requestedModules: Set<ModuleId> = allRequestedDependencies.mapTo(mutableSetOf()) { it.moduleId }
|
||||
|
||||
addAll(
|
||||
resolvedDependenciesFromAllSourceSets.flatMap { it.firstLevelModuleDependencies }
|
||||
.filter { it.moduleId in directRequestedModules }
|
||||
resolvedConfigurations.flatMap { it.firstLevelModuleDependencies }
|
||||
.filter { it.moduleId in requestedModules }
|
||||
.map { ResolvedDependencyWithParent(it, null) }
|
||||
)
|
||||
}
|
||||
|
||||
val visitedDependencies = mutableSetOf<ResolvedDependency>()
|
||||
|
||||
while (resolvedDependencyQueue.isNotEmpty()) {
|
||||
val (resolvedDependency, parent: ResolvedDependency?) = resolvedDependencyQueue.poll()
|
||||
|
||||
@@ -164,7 +172,13 @@ internal class GranularMetadataTransformation(
|
||||
|
||||
visitedDependencies.add(resolvedDependency)
|
||||
|
||||
val dependencyResult = processDependency(resolvedDependency, parent, projectDependency)
|
||||
val dependencyResult = processDependency(
|
||||
resolvedDependency,
|
||||
parentResolutions[resolvedDependency.moduleId].orEmpty(),
|
||||
parent,
|
||||
projectDependency
|
||||
)
|
||||
|
||||
result.add(dependencyResult)
|
||||
|
||||
val transitiveDependenciesToVisit = when (dependencyResult) {
|
||||
@@ -209,6 +223,7 @@ internal class GranularMetadataTransformation(
|
||||
*/
|
||||
private fun processDependency(
|
||||
module: ResolvedDependency,
|
||||
parentResolutionsForModule: Iterable<MetadataDependencyResolution>,
|
||||
parent: ResolvedDependency?,
|
||||
projectDependency: ProjectDependency?
|
||||
): MetadataDependencyResolution {
|
||||
@@ -220,13 +235,10 @@ internal class GranularMetadataTransformation(
|
||||
}
|
||||
|
||||
val projectStructureMetadata = mppDependencyMetadataExtractor?.getProjectStructureMetadata()
|
||||
?: return MetadataDependencyResolution.KeepOriginalDependency(module, projectDependency)
|
||||
|
||||
if (projectStructureMetadata == null) {
|
||||
return MetadataDependencyResolution.KeepOriginalDependency(module, projectDependency)
|
||||
}
|
||||
|
||||
val (allVisibleSourceSets, visibleByParents) =
|
||||
SourceSetVisibilityProvider(project).getVisibleSourceSets(
|
||||
val allVisibleSourceSets =
|
||||
SourceSetVisibilityProvider(project).getVisibleSourceSetNames(
|
||||
kotlinSourceSet,
|
||||
sourceSetRequestedScopes,
|
||||
parent ?: module,
|
||||
@@ -234,6 +246,10 @@ internal class GranularMetadataTransformation(
|
||||
projectDependency?.dependencyProject
|
||||
)
|
||||
|
||||
val sourceSetsVisibleInParents = parentResolutionsForModule
|
||||
.filterIsInstance<MetadataDependencyResolution.ChooseVisibleSourceSets>()
|
||||
.flatMapTo(mutableSetOf()) { it.allVisibleSourceSetNames }
|
||||
|
||||
// Keep only the transitive dependencies requested by the visible source sets:
|
||||
// Visit the transitive dependencies visible by parents, too (i.e. allVisibleSourceSets), as this source set might get a more
|
||||
// concrete view on them:
|
||||
@@ -250,7 +266,7 @@ internal class GranularMetadataTransformation(
|
||||
(it.moduleId) in requestedTransitiveDependencies
|
||||
}
|
||||
|
||||
val visibleSourceSetsExcludingDependsOn = allVisibleSourceSets.filterTo(mutableSetOf()) { it !in visibleByParents }
|
||||
val visibleSourceSetsExcludingDependsOn = allVisibleSourceSets.filterTo(mutableSetOf()) { it !in sourceSetsVisibleInParents }
|
||||
|
||||
return object : MetadataDependencyResolution.ChooseVisibleSourceSets(
|
||||
module,
|
||||
|
||||
+20
-33
@@ -15,43 +15,29 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||
import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations
|
||||
|
||||
internal data class DependencySourceSetVisibilityResult(
|
||||
val sourceSetsVisibleByThisSourceSet: Set<String>,
|
||||
val sourceSetsVisibleThroughDependsOn: Set<String>
|
||||
)
|
||||
|
||||
internal class SourceSetVisibilityProvider(
|
||||
private val project: Project
|
||||
) {
|
||||
fun getVisibleSourceSets(
|
||||
/**
|
||||
* Determine which source sets of the [resolvedMppDependency] are visible in the [visibleFrom] source set.
|
||||
*
|
||||
* This requires resolving dependencies of the compilations which [visibleFrom] takes part in, in order to find which variants the
|
||||
* [resolvedMppDependency] got resolved to for those compilations. The [resolvedMppDependency] should therefore be the dependency
|
||||
* on the 'root' module of the MPP (such as 'com.example:lib-foo', not 'com.example:lib-foo-metadata').
|
||||
*
|
||||
* Once the variants are known, they are checked against the [dependencyProjectStructureMetadata], and the
|
||||
* source sets of the dependency are determined that are compiled for all those variants and thus should be visible here.
|
||||
*
|
||||
* If the [resolvedMppDependency] is a project dependency, its project should be passed as [resolvedToOtherProject], as
|
||||
* the Gradle API for dependency variants behaves differently for project dependencies and published ones.
|
||||
*/
|
||||
@Suppress("UnstableApiUsage")
|
||||
fun getVisibleSourceSetNames(
|
||||
visibleFrom: KotlinSourceSet,
|
||||
dependencyScopes: Iterable<KotlinDependencyScope>,
|
||||
resolvedMppDependency: ResolvedDependency,
|
||||
dependencyProjectStructureMetadata: KotlinProjectStructureMetadata,
|
||||
resolvedToOtherProject: Project?
|
||||
): DependencySourceSetVisibilityResult {
|
||||
val visibleByThisSourceSet =
|
||||
getVisibleSourceSetsImpl(
|
||||
visibleFrom, dependencyScopes, resolvedMppDependency, dependencyProjectStructureMetadata, resolvedToOtherProject
|
||||
)
|
||||
|
||||
val visibleByParents = visibleFrom.dependsOn
|
||||
.flatMapTo(mutableSetOf()) {
|
||||
getVisibleSourceSetsImpl(
|
||||
it, dependencyScopes, resolvedMppDependency, dependencyProjectStructureMetadata, resolvedToOtherProject
|
||||
)
|
||||
}
|
||||
|
||||
return DependencySourceSetVisibilityResult(visibleByThisSourceSet, visibleByParents)
|
||||
}
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
private fun getVisibleSourceSetsImpl(
|
||||
visibleFrom: KotlinSourceSet,
|
||||
dependencyScopes: Iterable<KotlinDependencyScope>,
|
||||
mppDependency: ResolvedDependency,
|
||||
dependencyProjectMetadata: KotlinProjectStructureMetadata,
|
||||
otherProject: Project?
|
||||
): Set<String> {
|
||||
val compilations = CompilationSourceSetUtil.compilationsBySourceSets(project).getValue(visibleFrom)
|
||||
|
||||
@@ -66,7 +52,8 @@ internal class SourceSetVisibilityProvider(
|
||||
// Resolve the configuration but don't trigger artifacts download, only download component metadata:
|
||||
configuration.incoming.resolutionResult.allComponents
|
||||
.find {
|
||||
it.moduleVersion?.group == mppDependency.moduleGroup && it.moduleVersion?.name == mppDependency.moduleName
|
||||
it.moduleVersion?.group == resolvedMppDependency.moduleGroup &&
|
||||
it.moduleVersion?.name == resolvedMppDependency.moduleName
|
||||
}
|
||||
?.variant?.displayName
|
||||
}
|
||||
@@ -76,15 +63,15 @@ internal class SourceSetVisibilityProvider(
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
if (otherProject != null) {
|
||||
val publishedVariants = getPublishedPlatformCompilations(otherProject).keys
|
||||
if (resolvedToOtherProject != null) {
|
||||
val publishedVariants = getPublishedPlatformCompilations(resolvedToOtherProject).keys
|
||||
|
||||
visiblePlatformVariantNames = visiblePlatformVariantNames.mapTo(mutableSetOf()) { configurationName ->
|
||||
publishedVariants.first { it.dependencyConfigurationName == configurationName }.name
|
||||
}
|
||||
}
|
||||
|
||||
return dependencyProjectMetadata.sourceSetNamesByVariantName
|
||||
return dependencyProjectStructureMetadata.sourceSetNamesByVariantName
|
||||
.filterKeys { it in visiblePlatformVariantNames }
|
||||
.values.let { if (it.isEmpty()) emptySet() else it.reduce { acc, item -> acc intersect item } }
|
||||
}
|
||||
|
||||
+12
-2
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.API_SCOP
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope.IMPLEMENTATION_SCOPE
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
|
||||
import org.jetbrains.kotlin.gradle.targets.metadata.ALL_COMPILE_METADATA_CONFIGURATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -64,13 +65,22 @@ open class TransformKotlinGranularMetadata
|
||||
.allDependencies.map { listOf(it.group, it.name, it.version) }.toSet()
|
||||
}
|
||||
|
||||
private val transformation =
|
||||
@get:Internal
|
||||
internal val transformation: GranularMetadataTransformation by lazy {
|
||||
GranularMetadataTransformation(
|
||||
project,
|
||||
kotlinSourceSet,
|
||||
listOf(API_SCOPE, IMPLEMENTATION_SCOPE),
|
||||
listOf(project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME))
|
||||
listOf(project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME)),
|
||||
lazy {
|
||||
KotlinMetadataTargetConfigurator.dependsOnWithInterCompilationDependencies(project, kotlinSourceSet).map {
|
||||
project.tasks.withType(TransformKotlinGranularMetadata::class.java)
|
||||
.getByName(KotlinMetadataTargetConfigurator.transformGranularMetadataTaskName(it))
|
||||
.transformation
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
internal val metadataDependencyResolutions: Iterable<MetadataDependencyResolution>
|
||||
|
||||
+22
-10
@@ -43,6 +43,17 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
|
||||
|
||||
companion object {
|
||||
internal const val ALL_METADATA_JAR_NAME = "allMetadataJar"
|
||||
|
||||
internal fun transformGranularMetadataTaskName(sourceSet: KotlinSourceSet) =
|
||||
lowerCamelCaseName("transform", sourceSet.name, "DependenciesMetadata")
|
||||
|
||||
// TODO generalize once a general production-test and other kinds of inter-compilation visibility are supported
|
||||
// Currently, this is a temporary ad-hoc mechanism for exposing the commonMain dependencies to the test source sets
|
||||
internal fun dependsOnWithInterCompilationDependencies(project: Project, sourceSet: KotlinSourceSet): Set<KotlinSourceSet> =
|
||||
sourceSet.dependsOn.toMutableSet().apply {
|
||||
if (sourceSet.name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME)
|
||||
add(project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME))
|
||||
}
|
||||
}
|
||||
|
||||
private val KotlinOnlyTarget<KotlinCommonCompilation>.apiElementsConfiguration: Configuration
|
||||
@@ -97,9 +108,6 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformGranularMetadataTaskName(sourceSet: KotlinSourceSet) =
|
||||
lowerCamelCaseName("transform", sourceSet.name, "DependenciesMetadata")
|
||||
|
||||
private fun setupDependencyTransformationForCommonSourceSets(target: KotlinMetadataTarget) {
|
||||
target.project.whenEvaluated {
|
||||
val publishedCommonSourceSets: Set<KotlinSourceSet> = getPublishedCommonSourceSets(project)
|
||||
@@ -201,18 +209,22 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
|
||||
isSourceSetPublished: Boolean
|
||||
) {
|
||||
KotlinDependencyScope.values().forEach { scope ->
|
||||
val allMetadataConfigurations = mutableListOf<Configuration>().apply {
|
||||
if (scope != KotlinDependencyScope.COMPILE_ONLY_SCOPE)
|
||||
add(project.configurations.getByName(ALL_RUNTIME_METADATA_CONFIGURATION_NAME))
|
||||
if (scope != KotlinDependencyScope.RUNTIME_ONLY_SCOPE)
|
||||
add(project.configurations.getByName(ALL_COMPILE_METADATA_CONFIGURATION_NAME))
|
||||
}
|
||||
val allMetadataConfiguration = project.configurations.getByName(
|
||||
when (scope) {
|
||||
KotlinDependencyScope.RUNTIME_ONLY_SCOPE -> ALL_RUNTIME_METADATA_CONFIGURATION_NAME
|
||||
else -> ALL_COMPILE_METADATA_CONFIGURATION_NAME
|
||||
}
|
||||
)
|
||||
|
||||
val granularMetadataTransformation = GranularMetadataTransformation(
|
||||
project,
|
||||
sourceSet,
|
||||
listOf(scope),
|
||||
allMetadataConfigurations
|
||||
allMetadataConfiguration,
|
||||
lazy {
|
||||
dependsOnWithInterCompilationDependencies(project, sourceSet).filterIsInstance<DefaultKotlinSourceSet>()
|
||||
.map { checkNotNull(it.dependencyTransformations[scope]) }
|
||||
}
|
||||
)
|
||||
|
||||
(sourceSet as DefaultKotlinSourceSet).dependencyTransformations[scope] = granularMetadataTransformation
|
||||
|
||||
Reference in New Issue
Block a user