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:
+67
-32
@@ -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)
|
||||||
|
|||||||
+10
@@ -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) {
|
||||||
|
|||||||
+28
-1
@@ -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"
|
||||||
|
|||||||
+6
-2
@@ -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) {
|
||||||
|
|||||||
+16
-13
@@ -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:
|
||||||
|
|||||||
+3
-1
@@ -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 }
|
||||||
|
|
||||||
|
|||||||
+1
@@ -177,6 +177,7 @@ class DefaultKotlinSourceSet(
|
|||||||
baseDir,
|
baseDir,
|
||||||
doProcessFiles = true
|
doProcessFiles = true
|
||||||
)
|
)
|
||||||
|
|
||||||
MetadataDependencyTransformation(
|
MetadataDependencyTransformation(
|
||||||
group, name, projectPath,
|
group, name, projectPath,
|
||||||
resolution.projectStructureMetadata,
|
resolution.projectStructureMetadata,
|
||||||
|
|||||||
+6
-8
@@ -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 {
|
||||||
|
|||||||
+9
-23
@@ -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
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
+21
-2
@@ -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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user