diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index 31cfe6b5918..c37f45266e0 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -920,4 +920,35 @@ class NewMultiplatformIT : BaseGradleIT() { assertTrue(fileInWorkingDir("$pathPrefix/kotlin.js").length() < 500 * 1000, "Looks like kotlin.js file was not minified by DCE") } } + + + @Test + fun testStaleOutputCleanup() = with(Project("new-mpp-lib-with-tests", gradleVersion)) { + setupWorkingDir() + // Check that output directories of Kotlin compilations are registered for Gradle stale outputs cleanup. + // One way to check that is to run a Gradle build with no Gradle history (no .gradle directory) and see that the compilation + // output directories are cleaned up, even those outside the project's buildDir + + gradleBuildScript().appendText( + "\n" + """ + kotlin.targets.js.compilations.main.output.classesDirs.from("foo") // should affect Gradle's behavior wrt stale output cleanup + task('foo') { + outputs.dir("foo") + doFirst { + println 'hello' + file("foo/2.txt").text = System.currentTimeMillis() + } + } + """.trimIndent() + ) + + val staleFilePath = "foo/1.txt" + projectDir.resolve(staleFilePath).run { parentFile.mkdirs(); createNewFile() } + + build("foo") { + assertSuccessful() + assertNoSuchFile(staleFilePath) + assertFileExists("foo/2.txt") + } + } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index 18852a68bd1..b1566af02c2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -22,7 +22,6 @@ import org.gradle.api.internal.FeaturePreviews import org.gradle.api.internal.file.FileResolver import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging -import org.gradle.internal.cleanup.BuildOutputCleanupRegistry import org.gradle.internal.reflect.Instantiator import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.jetbrains.kotlin.gradle.dsl.* @@ -134,12 +133,11 @@ open class Kotlin2JsPluginWrapper @Inject constructor( open class KotlinMultiplatformPluginWrapper @Inject constructor( fileResolver: FileResolver, private val instantiator: Instantiator, - private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry, private val featurePreviews: FeaturePreviews ): KotlinBasePluginWrapper(fileResolver) { override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin = KotlinMultiplatformPlugin( - buildOutputCleanupRegistry, fileResolver, + fileResolver, instantiator, kotlinPluginVersion, featurePreviews ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt index 4b04781ae4c..a1d4db5d78d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt @@ -44,7 +44,6 @@ import java.util.* import java.util.concurrent.Callable abstract class AbstractKotlinTargetConfigurator( - private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry, protected val createDefaultSourceSets: Boolean, protected val createTestCompilation: Boolean ) { @@ -62,12 +61,17 @@ abstract class AbstractKotlinTargetConfigurator abstract fun configureArchivesAndComponent(target: KotlinTargetType) + private fun Project.registerOutputsForStaleOutputCleanup(kotlinCompilation: KotlinCompilation) { + val cleanTask = tasks.getByName(LifecycleBasePlugin.CLEAN_TASK_NAME) as Delete + cleanTask.delete(kotlinCompilation.output.allOutputs) + } + protected fun configureCompilations(platformTarget: KotlinTargetType) { val project = platformTarget.project val main = platformTarget.compilations.create(KotlinCompilation.MAIN_COMPILATION_NAME) platformTarget.compilations.all { - buildOutputCleanupRegistry.registerOutputs(it.output) + project.registerOutputsForStaleOutputCleanup(it) it.compileDependencyFiles = project.configurations.maybeCreate(it.compileDependencyConfigurationName) if (it is KotlinCompilationToRunnableFiles) { it.runtimeDependencyFiles = project.configurations.maybeCreate(it.runtimeDependencyConfigurationName) @@ -324,11 +328,9 @@ internal val KotlinCompilationToRunnableFiles.deprecatedRuntimeConfigurationName get() = disambiguateName("runtime") open class KotlinTargetConfigurator( - buildOutputCleanupRegistry: BuildOutputCleanupRegistry, createDefaultSourceSets: Boolean, createTestCompilation: Boolean ) : AbstractKotlinTargetConfigurator>( - buildOutputCleanupRegistry, createDefaultSourceSets, createTestCompilation ) { @@ -378,10 +380,8 @@ open class KotlinTargetConfigurator( open class KotlinNativeTargetConfigurator( - buildOutputCleanupRegistry: BuildOutputCleanupRegistry, private val kotlinPluginVersion: String ) : AbstractKotlinTargetConfigurator( - buildOutputCleanupRegistry, createDefaultSourceSets = true, createTestCompilation = true ) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 85b92dcf2bc..7f7c7c251f7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -19,7 +19,6 @@ import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal import org.gradle.api.publish.maven.tasks.AbstractPublishToMaven -import org.gradle.internal.cleanup.BuildOutputCleanupRegistry import org.gradle.internal.reflect.Instantiator import org.gradle.jvm.tasks.Jar import org.gradle.util.ConfigureUtil @@ -34,7 +33,6 @@ internal val Project.multiplatformExtension get(): KotlinMultiplatformExtension? project.extensions.findByName("kotlin") as? KotlinMultiplatformExtension class KotlinMultiplatformPlugin( - private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry, private val fileResolver: FileResolver, private val instantiator: Instantiator, private val kotlinPluginVersion: String, @@ -87,19 +85,19 @@ class KotlinMultiplatformPlugin( // set up metadata publishing targetsFromPreset.fromPreset( - KotlinMetadataTargetPreset(project, instantiator, fileResolver, buildOutputCleanupRegistry, kotlinPluginVersion), + KotlinMetadataTargetPreset(project, instantiator, fileResolver, kotlinPluginVersion), METADATA_TARGET_NAME ) } fun setupDefaultPresets(project: Project) { with((project.kotlinExtension as KotlinMultiplatformExtension).presets) { - add(KotlinJvmTargetPreset(project, instantiator, fileResolver, buildOutputCleanupRegistry, kotlinPluginVersion)) - add(KotlinJsTargetPreset(project, instantiator, fileResolver, buildOutputCleanupRegistry, kotlinPluginVersion)) + add(KotlinJvmTargetPreset(project, instantiator, fileResolver, kotlinPluginVersion)) + add(KotlinJsTargetPreset(project, instantiator, fileResolver, kotlinPluginVersion)) add(KotlinAndroidTargetPreset(project, kotlinPluginVersion)) add(KotlinJvmWithJavaTargetPreset(project, kotlinPluginVersion)) HostManager().targets.forEach { _, target -> - add(KotlinNativeTargetPreset(target.presetName, project, target, buildOutputCleanupRegistry, kotlinPluginVersion)) + add(KotlinNativeTargetPreset(target.presetName, project, target, kotlinPluginVersion)) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargetPresets.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargetPresets.kt index ea0756c2ceb..f403549219f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargetPresets.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargetPresets.kt @@ -11,7 +11,6 @@ import org.gradle.api.artifacts.repositories.IvyArtifactRepository import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout import org.gradle.api.internal.file.FileResolver import org.gradle.api.plugins.JavaPlugin -import org.gradle.internal.cleanup.BuildOutputCleanupRegistry import org.gradle.internal.reflect.Instantiator import org.jetbrains.kotlin.compilerRunner.KotlinNativeProjectProperty import org.jetbrains.kotlin.compilerRunner.hasProperty @@ -33,12 +32,11 @@ abstract class KotlinOnlyTargetPreset( protected val project: Project, private val instantiator: Instantiator, private val fileResolver: FileResolver, - protected val buildOutputCleanupRegistry: BuildOutputCleanupRegistry, protected val kotlinPluginVersion: String ) : KotlinTargetPreset> { protected open fun createKotlinTargetConfigurator(): KotlinTargetConfigurator = - KotlinTargetConfigurator(buildOutputCleanupRegistry, createDefaultSourceSets = true, createTestCompilation = true) + KotlinTargetConfigurator(createDefaultSourceSets = true, createTestCompilation = true) override fun createTarget(name: String): KotlinOnlyTarget { val result = KotlinOnlyTarget(project, platformType).apply { @@ -67,13 +65,11 @@ class KotlinMetadataTargetPreset( project: Project, instantiator: Instantiator, fileResolver: FileResolver, - buildOutputCleanupRegistry: BuildOutputCleanupRegistry, kotlinPluginVersion: String ) : KotlinOnlyTargetPreset( project, instantiator, fileResolver, - buildOutputCleanupRegistry, kotlinPluginVersion ) { override fun getName(): String = PRESET_NAME @@ -99,7 +95,7 @@ class KotlinMetadataTargetPreset( } override fun createKotlinTargetConfigurator(): KotlinTargetConfigurator = - KotlinTargetConfigurator(buildOutputCleanupRegistry, createDefaultSourceSets = false, createTestCompilation = false) + KotlinTargetConfigurator(createDefaultSourceSets = false, createTestCompilation = false) override fun createTarget(name: String): KotlinOnlyTarget = super.createTarget(name).apply { @@ -120,13 +116,11 @@ class KotlinJvmTargetPreset( project: Project, instantiator: Instantiator, fileResolver: FileResolver, - buildOutputCleanupRegistry: BuildOutputCleanupRegistry, kotlinPluginVersion: String ) : KotlinOnlyTargetPreset( project, instantiator, fileResolver, - buildOutputCleanupRegistry, kotlinPluginVersion ) { override fun getName(): String = PRESET_NAME @@ -149,13 +143,11 @@ class KotlinJsTargetPreset( project: Project, instantiator: Instantiator, fileResolver: FileResolver, - buildOutputCleanupRegistry: BuildOutputCleanupRegistry, kotlinPluginVersion: String ) : KotlinOnlyTargetPreset( project, instantiator, fileResolver, - buildOutputCleanupRegistry, kotlinPluginVersion ) { override fun getName(): String = PRESET_NAME @@ -248,7 +240,6 @@ class KotlinNativeTargetPreset( private val name: String, val project: Project, val konanTarget: KonanTarget, - private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry, private val kotlinPluginVersion: String ) : KotlinTargetPreset { @@ -317,7 +308,7 @@ class KotlinNativeTargetPreset( compilations = project.container(compilationFactory.itemClass, compilationFactory) } - KotlinNativeTargetConfigurator(buildOutputCleanupRegistry, kotlinPluginVersion).configureTarget(result) + KotlinNativeTargetConfigurator(kotlinPluginVersion).configureTarget(result) // Allow IDE to resolve the libraries provided by the compiler by adding them into dependencies. result.compilations.all { compilation ->