Store processed metadata artifacts in .gradle/ rather than build/
This allows the files to survive Gradle's `clean` task that deletes the `build/` directory with all its contents, which leads to the IDE losing dependencies until next re-import. The `.gradle` directory is chosen because Gradle creates it in every project and it is normally included in .gitignore (or otherwise ignored in VCS). Related to issue #KT-39568
This commit is contained in:
+17
-4
@@ -103,6 +103,14 @@ class HierarchicalMppIT : BaseGradleIT() {
|
|||||||
assertTrue("$it") { it.newVisibleSourceSets == emptySet<String>() }
|
assertTrue("$it") { it.newVisibleSourceSets == emptySet<String>() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ALso check that the files produced by dependency transformations survive a clean build:
|
||||||
|
val existingFilesFromReports = reports.flatMap { it.useFiles }.filter { it.isFile }
|
||||||
|
assertTrue { existingFilesFromReports.isNotEmpty() }
|
||||||
|
build("clean") {
|
||||||
|
assertSuccessful()
|
||||||
|
existingFilesFromReports.forEach { assertTrue("Expected that $it exists after clean build.") { it.isFile } }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Move the dependency from jvmAndJsMain to commonMain, expect that it is now propagated to commonTest:
|
// --- Move the dependency from jvmAndJsMain to commonMain, expect that it is now propagated to commonTest:
|
||||||
@@ -582,7 +590,8 @@ class HierarchicalMppIT : BaseGradleIT() {
|
|||||||
scope,
|
scope,
|
||||||
it.groupId + ":" + it.moduleName,
|
it.groupId + ":" + it.moduleName,
|
||||||
it.allVisibleSourceSets.joinToString(","),
|
it.allVisibleSourceSets.joinToString(","),
|
||||||
it.useFilesForSourceSets.keys.joinToString(",")
|
it.useFilesForSourceSets.keys.joinToString(","),
|
||||||
|
it.useFilesForSourceSets.values.flatten().joinToString(",")
|
||||||
)
|
)
|
||||||
|
|
||||||
println(" " + line.joinToString(" :: "))
|
println(" " + line.joinToString(" :: "))
|
||||||
@@ -613,7 +622,8 @@ class HierarchicalMppIT : BaseGradleIT() {
|
|||||||
val scope: String,
|
val scope: String,
|
||||||
val groupAndModule: String,
|
val groupAndModule: String,
|
||||||
val allVisibleSourceSets: Set<String>,
|
val allVisibleSourceSets: Set<String>,
|
||||||
val newVisibleSourceSets: Set<String> // those which the dependsOn parents don't see
|
val newVisibleSourceSets: Set<String>, // those which the dependsOn parents don't see
|
||||||
|
val useFiles: List<File>
|
||||||
) {
|
) {
|
||||||
val isExcluded: Boolean get() = allVisibleSourceSets.isEmpty()
|
val isExcluded: Boolean get() = allVisibleSourceSets.isEmpty()
|
||||||
|
|
||||||
@@ -622,14 +632,17 @@ class HierarchicalMppIT : BaseGradleIT() {
|
|||||||
const val TEST_OUTPUT_COMPONENT_SEPARATOR = " :: "
|
const val TEST_OUTPUT_COMPONENT_SEPARATOR = " :: "
|
||||||
const val TEST_OUTPUT_ITEMS_SEPARATOR = ","
|
const val TEST_OUTPUT_ITEMS_SEPARATOR = ","
|
||||||
|
|
||||||
|
private operator fun <T> List<T>.component6() = this[5]
|
||||||
|
|
||||||
fun parseTestOutputLine(line: String): DependencyTransformationReport {
|
fun parseTestOutputLine(line: String): DependencyTransformationReport {
|
||||||
val tail = line.substringAfter(TEST_OUTPUT_MARKER + TEST_OUTPUT_COMPONENT_SEPARATOR)
|
val tail = line.substringAfter(TEST_OUTPUT_MARKER + TEST_OUTPUT_COMPONENT_SEPARATOR)
|
||||||
val (sourceSetName, scope, groupAndModule, allVisibleSourceSets, newVisibleSourceSets) =
|
val (sourceSetName, scope, groupAndModule, allVisibleSourceSets, newVisibleSourceSets, useFiles) =
|
||||||
tail.split(TEST_OUTPUT_COMPONENT_SEPARATOR)
|
tail.split(TEST_OUTPUT_COMPONENT_SEPARATOR)
|
||||||
return DependencyTransformationReport(
|
return DependencyTransformationReport(
|
||||||
sourceSetName, scope, groupAndModule,
|
sourceSetName, scope, groupAndModule,
|
||||||
allVisibleSourceSets.split(TEST_OUTPUT_ITEMS_SEPARATOR).filter { it.isNotEmpty() }.toSet(),
|
allVisibleSourceSets.split(TEST_OUTPUT_ITEMS_SEPARATOR).filter { it.isNotEmpty() }.toSet(),
|
||||||
newVisibleSourceSets.split(TEST_OUTPUT_ITEMS_SEPARATOR).filter { it.isNotEmpty() }.toSet()
|
newVisibleSourceSets.split(TEST_OUTPUT_ITEMS_SEPARATOR).filter { it.isNotEmpty() }.toSet(),
|
||||||
|
useFiles.split(TEST_OUTPUT_ITEMS_SEPARATOR).map { File(it) }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-3
@@ -29,18 +29,16 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
|||||||
import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
|
import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
|
||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.Companion.sourceSetFreeCompilerArgsPropertyName
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.Companion.sourceSetFreeCompilerArgsPropertyName
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
|
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.checkSourceSetVisibilityRequirements
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
|
||||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||||
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
|
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
|
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
|
||||||
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
|
||||||
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
||||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||||
import org.jetbrains.kotlin.gradle.tasks.withType
|
|
||||||
import org.jetbrains.kotlin.gradle.utils.*
|
import org.jetbrains.kotlin.gradle.utils.*
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||||
@@ -111,6 +109,12 @@ class KotlinMultiplatformPlugin(
|
|||||||
project.pluginManager.apply(ScriptingGradleSubplugin::class.java)
|
project.pluginManager.apply(ScriptingGradleSubplugin::class.java)
|
||||||
|
|
||||||
exportProjectStructureMetadataForOtherBuilds(project)
|
exportProjectStructureMetadataForOtherBuilds(project)
|
||||||
|
|
||||||
|
SingleActionPerBuild.run(project.rootProject, "cleanup-processed-metadata") {
|
||||||
|
project.gradle.buildFinished {
|
||||||
|
SourceSetMetadataStorageForIde.cleanupStaleEntries(project)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exportProjectStructureMetadataForOtherBuilds(
|
private fun exportProjectStructureMetadataForOtherBuilds(
|
||||||
|
|||||||
+2
-1
@@ -155,7 +155,8 @@ class DefaultKotlinSourceSet(
|
|||||||
?.associateBy { ModuleIds.fromComponent(project, it.dependency) }
|
?.associateBy { ModuleIds.fromComponent(project, it.dependency) }
|
||||||
?: emptyMap()
|
?: emptyMap()
|
||||||
|
|
||||||
val baseDir = project.buildDir.resolve("tmp/kotlinMetadata/$name/${scope.scopeName}")
|
val baseDir = SourceSetMetadataStorageForIde.sourceSetStorage(project, this@DefaultKotlinSourceSet.name)
|
||||||
|
|
||||||
if (metadataDependencyResolutionByModule.values.any { it is MetadataDependencyResolution.ChooseVisibleSourceSets }) {
|
if (metadataDependencyResolutionByModule.values.any { it is MetadataDependencyResolution.ChooseVisibleSourceSets }) {
|
||||||
if (baseDir.isDirectory) {
|
if (baseDir.isDirectory) {
|
||||||
baseDir.deleteRecursively()
|
baseDir.deleteRecursively()
|
||||||
|
|||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.plugin.sources
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
object SourceSetMetadataStorageForIde {
|
||||||
|
fun cleanupStaleEntries(project: Project) {
|
||||||
|
val projectStorageDirectories = project.rootProject.allprojects.associateBy { projectStorage(it) }
|
||||||
|
getStorageRoot(project).listFiles().orEmpty().filter { it.isDirectory }.forEach { directory ->
|
||||||
|
// If no project corresponds to the directory, remove the directory
|
||||||
|
if (directory !in projectStorageDirectories) {
|
||||||
|
directory.deleteRecursively()
|
||||||
|
} else {
|
||||||
|
// Under the project's directory, delete subdirectories that don't correspond to any source set:
|
||||||
|
val sourceSets = projectStorageDirectories.getValue(directory)?.project?.multiplatformExtensionOrNull?.sourceSets.orEmpty()
|
||||||
|
val sourceSetNames = sourceSets.map { it.name }
|
||||||
|
directory.listFiles().orEmpty().filter { it.isDirectory }.forEach { subdirectory ->
|
||||||
|
if (subdirectory.name !in sourceSetNames)
|
||||||
|
subdirectory.deleteRecursively()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getStorageRoot(project: Project): File = project.rootDir.resolve(".gradle/kotlin/sourceSetMetadata")
|
||||||
|
|
||||||
|
private fun projectStorage(project: Project): File {
|
||||||
|
val projectPathSegments = generateSequence(project) { it.parent }.map { it.name }
|
||||||
|
return getStorageRoot(project).resolve(
|
||||||
|
// Escape dots in project names to avoid ambiguous paths.
|
||||||
|
projectPathSegments.joinToString(".") { it.replace(".", "_.") }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun sourceSetStorage(project: Project, sourceSetName: String) = projectStorage(project).resolve(sourceSetName)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user