General fixes for composite builds in HMPP

* Register project structure metadata providers globally, so included
  builds can access it from the root build.

* Rework some dependency management logic so that it doesn't assume that
  dependencies resolved to projects are safe to access – it is so only
  if the project is in the same build; also, in dependency handling, use
  proper keys which distinguish project with same ID in different
  builds.

* Add a separate implementation of `MppDependencyMetadataExtractor` that
  reads the project structure metadata from the mentioned global storage
  (as we can't read it from artifacts – those are not yet build at the
  project configuration phase) but when it comes to artifacts
  processing, takes real artifacts rather than introspect the project
  structure.

* Register the Kotlin/Native host-specific metadata artifact
  configurations as consumable, so that a consumer from a different
  build can properly resolve a dependency to such a configuration and
  get the artifact.
This commit is contained in:
Sergey Igushkin
2020-09-29 18:45:24 +03:00
parent 7d1a3a137b
commit 3a5ffe479e
11 changed files with 168 additions and 83 deletions
@@ -6,8 +6,9 @@
package org.jetbrains.kotlin.gradle.plugin.mpp package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.* import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.* import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.artifacts.result.ResolvedComponentResult import org.gradle.api.artifacts.result.ResolvedComponentResult
import org.gradle.api.artifacts.result.ResolvedDependencyResult import org.gradle.api.artifacts.result.ResolvedDependencyResult
import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.Attribute
@@ -164,15 +165,12 @@ internal class GranularMetadataTransformation(
while (resolvedDependencyQueue.isNotEmpty()) { while (resolvedDependencyQueue.isNotEmpty()) {
val (resolvedDependency: ResolvedComponentResult, parent: ResolvedComponentResult?) = resolvedDependencyQueue.poll() val (resolvedDependency: ResolvedComponentResult, parent: ResolvedComponentResult?) = resolvedDependencyQueue.poll()
val resolvedToProject: Project? = (resolvedDependency.id as? ProjectComponentIdentifier)?.projectPath?.let(project::project)
visitedDependencies.add(resolvedDependency) visitedDependencies.add(resolvedDependency)
val dependencyResult = processDependency( val dependencyResult = processDependency(
resolvedDependency, resolvedDependency,
parentResolutions[ModuleIds.fromComponent(project, resolvedDependency)].orEmpty(), parentResolutions[ModuleIds.fromComponent(project, resolvedDependency)].orEmpty(),
parent, parent
resolvedToProject
) )
result.add(dependencyResult) result.add(dependencyResult)
@@ -196,7 +194,9 @@ internal class GranularMetadataTransformation(
result.add( result.add(
MetadataDependencyResolution.ExcludeAsUnrequested( MetadataDependencyResolution.ExcludeAsUnrequested(
resolvedDependency.selected, resolvedDependency.selected,
(resolvedDependency.selected.id as? ProjectComponentIdentifier)?.let { project.project(it.projectPath) } (resolvedDependency.selected.id as? ProjectComponentIdentifier)
?.takeIf { it.build.isCurrentBuild() }
?.let { project.project(it.projectPath) }
) )
) )
} }
@@ -222,23 +222,28 @@ internal class GranularMetadataTransformation(
private fun processDependency( private fun processDependency(
module: ResolvedComponentResult, module: ResolvedComponentResult,
parentResolutionsForModule: Iterable<MetadataDependencyResolution>, parentResolutionsForModule: Iterable<MetadataDependencyResolution>,
parent: ResolvedComponentResult?, parent: ResolvedComponentResult?
resolvedToProject: Project?
): MetadataDependencyResolution { ): MetadataDependencyResolution {
val resolvedMppVariantsProvider = ResolvedMppVariantsProvider.get(project) val resolvedMppVariantsProvider = ResolvedMppVariantsProvider.get(project)
val metadataArtifact = resolvedMppVariantsProvider.getPlatformArtifactByPlatformModule(
val mppDependencyMetadataExtractor = if (resolvedToProject != null) { ModuleIds.fromComponent(project, module),
ProjectMppDependencyMetadataExtractor(project, module, resolvedToProject) configurationToResolve
} else { )
val metadataArtifact = resolvedMppVariantsProvider.getPlatformArtifactByPlatformModule( val moduleId = module.id
ModuleIds.fromComponent(project, module), val mppDependencyMetadataExtractor: MppDependencyMetadataExtractor? = when {
configurationToResolve moduleId is ProjectComponentIdentifier -> when {
) moduleId.build.isCurrentBuild ->
if (metadataArtifact != null) { ProjectMppDependencyMetadataExtractor(project, module, project.project(moduleId.projectPath))
JarArtifactMppDependencyMetadataExtractor(project, module, metadataArtifact) metadataArtifact != null ->
} else null IncludedBuildMetadataExtractor(project, module, metadataArtifact)
else -> null
}
metadataArtifact != null -> JarArtifactMppDependencyMetadataExtractor(project, module, metadataArtifact)
else -> null
} }
val resolvedToProject: Project? = (mppDependencyMetadataExtractor as? ProjectMppDependencyMetadataExtractor)?.dependencyProject
val projectStructureMetadata = mppDependencyMetadataExtractor?.getProjectStructureMetadata() val projectStructureMetadata = mppDependencyMetadataExtractor?.getProjectStructureMetadata()
?: return MetadataDependencyResolution.KeepOriginalDependency(module, resolvedToProject) ?: return MetadataDependencyResolution.KeepOriginalDependency(module, resolvedToProject)
@@ -318,7 +323,7 @@ private abstract class MppDependencyMetadataExtractor(val project: Project, val
private class ProjectMppDependencyMetadataExtractor( private class ProjectMppDependencyMetadataExtractor(
project: Project, project: Project,
dependency: ResolvedComponentResult, dependency: ResolvedComponentResult,
private val dependencyProject: Project val dependencyProject: Project
) : MppDependencyMetadataExtractor(project, dependency) { ) : MppDependencyMetadataExtractor(project, dependency) {
override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? = override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? =
buildKotlinProjectStructureMetadata(dependencyProject) buildKotlinProjectStructureMetadata(dependencyProject)
@@ -337,7 +342,26 @@ private class ProjectMppDependencyMetadataExtractor(
} }
} }
private class JarArtifactMppDependencyMetadataExtractor( private class IncludedBuildMetadataExtractor(
project: Project,
dependency: ResolvedComponentResult,
primaryArtifact: File
) : JarArtifactMppDependencyMetadataExtractor(project, dependency, primaryArtifact) {
private val id: ProjectComponentIdentifier
init {
val id = dependency.id
require(id is ProjectComponentIdentifier) { "dependency should resolve to a project" }
require(!(id as ProjectComponentIdentifier).build.isCurrentBuild) { "should be a project from an included build" }
this.id = id
}
override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? =
GlobalProjectStructureMetadataStorage.getProjectStructureMetadata(project, id.build.name, id.projectPath)
}
private open class JarArtifactMppDependencyMetadataExtractor(
project: Project, project: Project,
dependency: ResolvedComponentResult, dependency: ResolvedComponentResult,
val primaryArtifact: File val primaryArtifact: File
@@ -394,20 +418,31 @@ private class JarArtifactMppDependencyMetadataExtractor(
val projectStructureMetadata = projectStructureMetadata val projectStructureMetadata = projectStructureMetadata
artifactBySourceSet.forEach { (sourceSetName, artifact) -> artifactBySourceSet.forEach { (sourceSetName, artifact) ->
ZipFile(artifact).use { zip -> val extension = projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension
val entries = zip.entries().asSequence().filter { it.name.startsWith("$sourceSetName/") }.toList() ?: SourceSetMetadataLayout.METADATA.archiveExtension
val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension")
// TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR /** NB: the result may contain files that do not exist and won't be created if the actual metadata artifact doesn't contain
// Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed * entries for the corresponding source set. It's the consumer's responsibility to filter the result if they need only
* existing files! */
resultFiles[sourceSetName] = project.files(extractToJarFile)
if (entries.any()) { if (doProcessFiles) {
val extension = projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension if (extractToJarFile.exists()) {
?: SourceSetMetadataLayout.METADATA.archiveExtension extractToJarFile.delete()
}
val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension") /** In composite builds, we don't really need tro process the file in IDE import, so ignore it if it's missing */
resultFiles[sourceSetName] = project.files(extractToJarFile) // refactor: allow only included builds to provide no artifacts, and allow this only in IDE import
if (!artifact.isFile) return@forEach
if (doProcessFiles) { ZipFile(artifact).use { zip ->
val entries = zip.entries().asSequence().filter { it.name.startsWith("$sourceSetName/") }.toList()
// TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR
// Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed
if (entries.any()) {
ZipOutputStream(extractToJarFile.outputStream()).use { resultZipOutput -> ZipOutputStream(extractToJarFile.outputStream()).use { resultZipOutput ->
for (entry in entries) { for (entry in entries) {
if (entry.isDirectory) if (entry.isDirectory)
@@ -110,6 +110,16 @@ class KotlinMultiplatformPlugin(
project.setupGeneralKotlinExtensionParameters() project.setupGeneralKotlinExtensionParameters()
project.pluginManager.apply(ScriptingGradleSubplugin::class.java) project.pluginManager.apply(ScriptingGradleSubplugin::class.java)
exportProjectStructureMetadataForOtherBuilds(project)
}
private fun exportProjectStructureMetadataForOtherBuilds(
project: Project
) {
GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(project) {
checkNotNull(buildKotlinProjectStructureMetadata(project))
}
} }
private fun setupAdditionalCompilerArguments(project: Project) { private fun setupAdditionalCompilerArguments(project: Project) {
@@ -125,7 +125,9 @@ internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjec
} }
sourceSet.name to sourceSetExportedDependencies.map { ModuleIds.fromDependency(it) }.toSet() sourceSet.name to sourceSetExportedDependencies.map { ModuleIds.fromDependency(it) }.toSet()
}, },
hostSpecificSourceSets = getHostSpecificSourceSets(project).map { it.name }.toSet(), hostSpecificSourceSets = getHostSpecificSourceSets(project)
.filter { it in sourceSetsWithMetadataCompilations }.map { it.name }
.toSet(),
sourceSetBinaryLayout = sourceSetsWithMetadataCompilations.keys.associate { sourceSet -> sourceSetBinaryLayout = sourceSetsWithMetadataCompilations.keys.associate { sourceSet ->
sourceSet.name to SourceSetMetadataLayout.chooseForProducingProject(project) sourceSet.name to SourceSetMetadataLayout.chooseForProducingProject(project)
}, },
@@ -289,6 +291,31 @@ internal fun <ParsingContext> parseKotlinSourceSetMetadata(
) )
} }
object GlobalProjectStructureMetadataStorage {
fun propertyName(buildName: String, projectPath: String) = "kotlin.projectStructureMetadata.build.$buildName.path.$projectPath"
fun registerProjectStructureMetadata(project: Project, metadataProvider: () -> KotlinProjectStructureMetadata) {
val compositeBuildRoot = generateSequence(project.gradle) { it.parent }.last().rootProject
compositeBuildRoot.extensions.extraProperties.set(
propertyName(project.rootProject.name, project.path),
{ metadataProvider().toJson() }
)
}
fun getProjectStructureMetadata(project: Project, otherBuildName: String, otherProjectPath: String): KotlinProjectStructureMetadata? {
val compositeBuildRoot = generateSequence(project.gradle) { it.parent }.last().rootProject
val property = propertyName(otherBuildName, otherProjectPath)
return with(compositeBuildRoot.extensions.extraProperties) {
if (has(property)) {
val jsonStringProvider = get(property) as? Function0<*> ?: return null
val jsonString = jsonStringProvider.invoke() as? String ?: return null
parseKotlinSourceSetMetadataFromJson(jsonString)
} else null
}
}
}
private const val ROOT_NODE_NAME = "projectStructure" private const val ROOT_NODE_NAME = "projectStructure"
private const val PUBLISHED_AS_ROOT_NAME = "isPublishedAsRoot" private const val PUBLISHED_AS_ROOT_NAME = "isPublishedAsRoot"
private const val FORMAT_VERSION_NODE_NAME = "formatVersion" private const val FORMAT_VERSION_NODE_NAME = "formatVersion"
@@ -28,7 +28,7 @@ internal object ModuleIds {
else -> idFromName(componentSelector.displayName) else -> idFromName(componentSelector.displayName)
} }
fun fromComponentId( private fun fromComponentId(
thisProject: Project, thisProject: Project,
componentIdentifier: ComponentIdentifier componentIdentifier: ComponentIdentifier
): ModuleDependencyIdentifier = ): ModuleDependencyIdentifier =
@@ -39,7 +39,11 @@ internal object ModuleIds {
} }
fun fromComponent(thisProject: Project, component: ResolvedComponentResult) = fun fromComponent(thisProject: Project, component: ResolvedComponentResult) =
fromComponentId(thisProject, component.id) // If the project component comes from another build, we can't extract anything from it, so just use the module coordinates:
if ((component.id as? ProjectComponentIdentifier)?.build?.isCurrentBuild == false)
ModuleDependencyIdentifier(component.moduleVersion?.group ?: "unspecified", component.moduleVersion?.name ?: "unspecified")
else
fromComponentId(thisProject, component.id)
private fun idOfRootModule(project: Project): ModuleDependencyIdentifier = private fun idOfRootModule(project: Project): ModuleDependencyIdentifier =
if (project.multiplatformExtensionOrNull != null) { if (project.multiplatformExtensionOrNull != null) {
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ComponentIdentifier
import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.artifacts.component.ProjectComponentIdentifier
import org.gradle.api.artifacts.result.ResolvedArtifactResult import org.gradle.api.artifacts.result.ResolvedArtifactResult
import org.gradle.api.artifacts.result.ResolvedComponentResult import org.gradle.api.artifacts.result.ResolvedComponentResult
@@ -61,6 +60,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje
if (configuration !in resolvedMetadataArtifactByConfiguration) { if (configuration !in resolvedMetadataArtifactByConfiguration) {
resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.METADATA) resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.METADATA)
} }
// At this point the map should contain the result if calculation above succeeded. If not, put null to avoid recalculation.
resolvedMetadataArtifactByConfiguration.getOrPut(configuration) { null } resolvedMetadataArtifactByConfiguration.getOrPut(configuration) { null }
} }
} }
@@ -71,6 +71,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje
if (configuration !in resolvedArtifactByConfiguration) { if (configuration !in resolvedArtifactByConfiguration) {
resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.NORMAL) resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.NORMAL)
} }
// At this point the map should contain the result if the calculation above succeeded. If not, put null to avoid recalculation.
resolvedArtifactByConfiguration.getOrPut(configuration) { null } resolvedArtifactByConfiguration.getOrPut(configuration) { null }
} }
@@ -79,7 +80,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje
private val entriesCache: MutableMap<ModuleDependencyIdentifier, ModuleEntry> = mutableMapOf() private val entriesCache: MutableMap<ModuleDependencyIdentifier, ModuleEntry> = mutableMapOf()
private val mppComponentIdsByConfiguration: MutableMap<Configuration, Set<ComponentIdentifier>> = mutableMapOf() private val mppComponentsByConfiguration: MutableMap<Configuration, Set<ResolvedComponentResult>> = mutableMapOf()
private enum class ArtifactResolutionMode { private enum class ArtifactResolutionMode {
NONE, NORMAL, METADATA NONE, NORMAL, METADATA
@@ -89,7 +90,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje
configuration: Configuration, configuration: Configuration,
artifactResolutionMode: ArtifactResolutionMode artifactResolutionMode: ArtifactResolutionMode
) { ) {
val mppComponentIds: Set<ComponentIdentifier> = mppComponentIdsByConfiguration.getOrPut(configuration) { val mppComponentIds: Set<ResolvedComponentResult> = mppComponentsByConfiguration.getOrPut(configuration) {
resolveMppComponents(configuration) resolveMppComponents(configuration)
} }
@@ -99,7 +100,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje
} }
} }
private fun resolveMppComponents(configuration: Configuration): MutableSet<ComponentIdentifier> { private fun resolveMppComponents(configuration: Configuration): Set<ResolvedComponentResult> {
val result = mutableListOf<ResolvedComponentResult>() val result = mutableListOf<ResolvedComponentResult>()
configuration.incoming.resolutionResult.allComponents { component -> configuration.incoming.resolutionResult.allComponents { component ->
@@ -123,14 +124,16 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje
} }
} }
return result.mapTo(mutableSetOf()) { it.id } return result.toSet()
} }
private fun resolveArtifacts( private fun resolveArtifacts(
artifactResolutionMode: ArtifactResolutionMode, artifactResolutionMode: ArtifactResolutionMode,
configuration: Configuration, configuration: Configuration,
mppComponentIds: Set<ComponentIdentifier> mppComponents: Set<ResolvedComponentResult>
): Map<ComponentIdentifier, ResolvedArtifactResult> { ): Map<ResolvedComponentResult, ResolvedArtifactResult> {
val mppComponentById = mppComponents.associateBy { it.id }
val artifactsConfiguration = val artifactsConfiguration =
if ( if (
artifactResolutionMode == ArtifactResolutionMode.NORMAL || artifactResolutionMode == ArtifactResolutionMode.NORMAL ||
@@ -144,22 +147,22 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje
} }
return artifactsConfiguration.incoming.artifactView { view -> return artifactsConfiguration.incoming.artifactView { view ->
view.componentFilter { it in mppComponentIds } view.componentFilter { it in mppComponentById }
view.attributes { attrs -> attrs.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA)) } view.attributes { attrs -> attrs.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA)) }
view.lenient(true) view.lenient(true)
}.artifacts.associateBy { it.id.componentIdentifier } }.artifacts.associateBy { mppComponentById.getValue(it.id.componentIdentifier) }
} }
private fun matchMppComponentsWithResolvedArtifacts( private fun matchMppComponentsWithResolvedArtifacts(
mppComponentIds: Set<ComponentIdentifier>, mppComponentIds: Set<ResolvedComponentResult>,
artifacts: Map<ComponentIdentifier, ResolvedArtifactResult>, artifacts: Map<ResolvedComponentResult, ResolvedArtifactResult>,
configuration: Configuration, configuration: Configuration,
artifactResolutionMode: ArtifactResolutionMode artifactResolutionMode: ArtifactResolutionMode
) { ) {
val mppModuleIds = mppComponentIds.mapTo(mutableSetOf()) { ModuleIds.fromComponentId(project, it) } val mppModuleIds = mppComponentIds.mapTo(mutableSetOf()) { ModuleIds.fromComponent(project, it) }
mppComponentIds.forEach { componentId -> mppComponentIds.forEach { componentId ->
val moduleEntry = getEntryForModule(ModuleIds.fromComponentId(project, componentId)) val moduleEntry = getEntryForModule(ModuleIds.fromComponent(project, componentId))
val artifact = artifacts[componentId] val artifact = artifacts[componentId]
when { when {
// With project dependencies, we don't need the host-specific metadata artifacts, as we have the compilation outputs: // With project dependencies, we don't need the host-specific metadata artifacts, as we have the compilation outputs:
@@ -101,7 +101,9 @@ open class TransformKotlinGranularMetadata
@get:Internal @get:Internal
internal val filesByResolution: Map<out MetadataDependencyResolution, FileCollection> internal val filesByResolution: Map<out MetadataDependencyResolution, FileCollection>
get() = extractableFilesByResolution.mapValues { (_, value) -> project.files(value.getMetadataFilesPerSourceSet(false).values) } get() = extractableFilesByResolution.mapValues { (_, value) ->
project.files(value.getMetadataFilesPerSourceSet(false).values)
}
private val extractableFiles by project.provider { extractableFilesByResolution.values } private val extractableFiles by project.provider { extractableFilesByResolution.values }
@@ -177,6 +177,7 @@ class DefaultKotlinSourceSet(
baseDir, baseDir,
doProcessFiles = true doProcessFiles = true
) )
MetadataDependencyTransformation( MetadataDependencyTransformation(
group, name, projectPath, group, name, projectPath,
resolution.projectStructureMetadata, resolution.projectStructureMetadata,
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.metadata
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.component.ComponentIdentifier
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.internal.component.SoftwareComponentInternal import org.gradle.api.internal.component.SoftwareComponentInternal
@@ -28,7 +29,6 @@ import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import java.util.concurrent.Callable
internal const val ALL_COMPILE_METADATA_CONFIGURATION_NAME = "allSourceSetsCompileDependenciesMetadata" internal const val ALL_COMPILE_METADATA_CONFIGURATION_NAME = "allSourceSetsCompileDependenciesMetadata"
internal const val ALL_RUNTIME_METADATA_CONFIGURATION_NAME = "allSourceSetsRuntimeDependenciesMetadata" internal const val ALL_RUNTIME_METADATA_CONFIGURATION_NAME = "allSourceSetsRuntimeDependenciesMetadata"
@@ -408,12 +408,12 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
project.locateTask<TransformKotlinGranularMetadata>(transformGranularMetadataTaskName(hierarchySourceSet.name)) project.locateTask<TransformKotlinGranularMetadata>(transformGranularMetadataTaskName(hierarchySourceSet.name))
} }
val allResolutionsByModule: Map<ModuleDependencyIdentifier, List<MetadataDependencyResolution>> = val allResolutionsByComponentId: Map<ComponentIdentifier, List<MetadataDependencyResolution>> =
mutableMapOf<ModuleDependencyIdentifier, MutableList<MetadataDependencyResolution>>().apply { mutableMapOf<ComponentIdentifier, MutableList<MetadataDependencyResolution>>().apply {
transformationTaskHolders.forEach { transformationTaskHolders.forEach {
val resolutions = it.get().metadataDependencyResolutions val resolutions = it.get().metadataDependencyResolutions
resolutions.forEach { resolution -> resolutions.forEach { resolution ->
getOrPut(ModuleIds.fromComponent(project, resolution.dependency)) { mutableListOf() }.add(resolution) getOrPut(resolution.dependency.id) { mutableListOf() }.add(resolution)
} }
} }
} }
@@ -428,8 +428,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
val artifactView = fromFiles.incoming.artifactView { view -> val artifactView = fromFiles.incoming.artifactView { view ->
view.componentFilter { id -> view.componentFilter { id ->
val moduleId = ModuleIds.fromComponentId(project, id) allResolutionsByComponentId[id].let { resolutions ->
allResolutionsByModule[moduleId].let { resolutions ->
resolutions == null || resolutions.any { it !is MetadataDependencyResolution.ExcludeAsUnrequested } resolutions == null || resolutions.any { it !is MetadataDependencyResolution.ExcludeAsUnrequested }
} }
} }
@@ -438,8 +437,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
mutableSetOf<Any /* File | FileCollection */>().apply { mutableSetOf<Any /* File | FileCollection */>().apply {
addAll(dependsOnCompilationOutputs) addAll(dependsOnCompilationOutputs)
artifactView.artifacts.forEach { artifact -> artifactView.artifacts.forEach { artifact ->
val resolutions = val resolutions = allResolutionsByComponentId[artifact.id.componentIdentifier]
allResolutionsByModule[ModuleIds.fromComponentId(project, artifact.id.componentIdentifier)]
if (resolutions == null) { if (resolutions == null) {
add(artifact.file) add(artifact.file)
} else { } else {
@@ -44,7 +44,7 @@ open class KotlinNativeTarget @Inject constructor(
private val hostSpecificMetadataJarTaskName get() = disambiguateName("MetadataJar") private val hostSpecificMetadataJarTaskName get() = disambiguateName("MetadataJar")
private val hostSpecificMetadataElementsConfigurationName get() = disambiguateName("MetadataElements") internal val hostSpecificMetadataElementsConfigurationName get() = disambiguateName("MetadataElements")
override val kotlinComponents: Set<KotlinTargetComponent> by lazy { override val kotlinComponents: Set<KotlinTargetComponent> by lazy {
if (!project.isKotlinGranularMetadataEnabled) if (!project.isKotlinGranularMetadataEnabled)
@@ -60,13 +60,10 @@ open class KotlinNativeTarget @Inject constructor(
.intersect(mainCompilation.allKotlinSourceSets) .intersect(mainCompilation.allKotlinSourceSets)
if (hostSpecificSourceSets.isNotEmpty()) { if (hostSpecificSourceSets.isNotEmpty()) {
val hostSpecificMetadataJar = project.locateOrRegisterTask<Jar>(hostSpecificMetadataJarTaskName) { val hostSpecificMetadataJar = project.locateOrRegisterTask<Jar>(hostSpecificMetadataJarTaskName) { metadataJar ->
it.archiveAppendix.set(project.provider { disambiguationClassifier.orEmpty().toLowerCase() }) metadataJar.archiveAppendix.set(project.provider { disambiguationClassifier.orEmpty().toLowerCase() })
it.archiveClassifier.set("metadata") metadataJar.archiveClassifier.set("metadata")
}
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, hostSpecificMetadataJar)
hostSpecificMetadataJar.configure { metadataJar ->
metadataJar.onlyIf { this@KotlinNativeTarget.publishable } metadataJar.onlyIf { this@KotlinNativeTarget.publishable }
val metadataCompilations = hostSpecificSourceSets.mapNotNull { val metadataCompilations = hostSpecificSourceSets.mapNotNull {
@@ -80,29 +77,18 @@ open class KotlinNativeTarget @Inject constructor(
metadataJar.dependsOn(it.output.classesDirs) metadataJar.dependsOn(it.output.classesDirs)
} }
} }
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, hostSpecificMetadataJar)
val metadataConfiguration = project.configurations.findByName(hostSpecificMetadataElementsConfigurationName) val metadataConfiguration = project.configurations.getByName(hostSpecificMetadataElementsConfigurationName)
?: project.configurations.create(hostSpecificMetadataElementsConfigurationName) { configuration -> project.artifacts.add(metadataConfiguration.name, hostSpecificMetadataJar) { artifact ->
configuration.isCanBeConsumed = false artifact.classifier = "metadata"
configuration.isCanBeResolved = false }
project.artifacts.add(configuration.name, hostSpecificMetadataJar) { artifact ->
artifact.classifier = "metadata"
}
configuration.extendsFrom(*configurations.getByName(apiElementsConfigurationName).extendsFrom.toTypedArray())
}
val metadataAttributes =
HierarchyAttributeContainer(project.configurations.getByName(apiElementsConfigurationName).attributes).apply {
attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA))
}
mutableUsageContexts.add( mutableUsageContexts.add(
DefaultKotlinUsageContext( DefaultKotlinUsageContext(
mainCompilation, mainCompilation,
project.usageByName(javaApiUsageForMavenScoping()), project.usageByName(javaApiUsageForMavenScoping()),
metadataConfiguration.name, metadataConfiguration.name,
overrideConfigurationAttributes = metadataAttributes,
includeIntoProjectStructureMetadata = false includeIntoProjectStructureMetadata = false
) )
) )
@@ -10,6 +10,9 @@ import org.gradle.api.DefaultTask
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.Dependency
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.internal.artifacts.ArtifactAttributes import org.gradle.api.internal.artifacts.ArtifactAttributes
import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
@@ -23,6 +26,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPI
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.KOTLIN_NATIVE_IGNORE_INCORRECT_DEPENDENCIES import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.KOTLIN_NATIVE_IGNORE_INCORRECT_DEPENDENCIES
import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.targets.native.* import org.jetbrains.kotlin.gradle.targets.native.*
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeHostTest import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeHostTest
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest
@@ -243,8 +247,23 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
createKlibCompilationTask(it) createKlibCompilationTask(it)
} }
with(configurations.getByName(target.apiElementsConfigurationName)) { val apiElements = configurations.getByName(target.apiElementsConfigurationName)
outgoing.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB)
apiElements.outgoing.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB)
if (project.isKotlinGranularMetadataEnabled) {
project.configurations.create(target.hostSpecificMetadataElementsConfigurationName) { configuration ->
configuration.isCanBeConsumed = true
configuration.isCanBeResolved = false
configuration.extendsFrom(*apiElements.extendsFrom.toTypedArray())
fun <T> copyAttribute(from: AttributeContainer, to: AttributeContainer, attribute: Attribute<T>) {
to.attribute(attribute, from.getAttribute(attribute)!!)
}
with(apiElements.attributes) { keySet().forEach { copyAttribute(this, configuration.attributes, it) } }
configuration.attributes.attribute(USAGE_ATTRIBUTE, objects.named(Usage::class.java, KotlinUsages.KOTLIN_METADATA))
}
} }
} }
@@ -64,7 +64,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
if (defaultsOnly) return if (defaultsOnly) return
val classpathList = classpath.files.toMutableList() val classpathList = classpath.files.filter { it.exists() }.toMutableList()
with(args) { with(args) {
classpath = classpathList.joinToString(File.pathSeparator) classpath = classpathList.joinToString(File.pathSeparator)