From 3b878336dd5b5513925a6799c6d2a89032fb8dd7 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Mon, 24 Jul 2023 12:01:37 +0200 Subject: [PATCH] [Gradle] Fix additional java resource dirs are erased on KGP/Jvm plugin apply User scripts may apply KGP/Jvm plugin not immediately in 'plugins {}' block. And a script may also already add some additional resources into a java source set before plugin apply. On apply plugin has erased such additionally configured resource dirs as it assumed only the default one are set. Now it also syncs them. ^KT-60459 Fixed --- .../jetbrains/kotlin/gradle/ResourcesIT.kt | 66 +++++++++++++++---- .../kotlin/gradle/testbase/fileAssertions.kt | 14 ++++ .../gradle/plugin/AbstractKotlinPlugin.kt | 17 +++-- 3 files changed, 80 insertions(+), 17 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ResourcesIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ResourcesIT.kt index bfeb8da8770..406914dac73 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ResourcesIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/ResourcesIT.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle import org.gradle.util.GradleVersion import org.jetbrains.kotlin.gradle.testbase.* import org.junit.jupiter.api.DisplayName -import java.util.zip.ZipFile import kotlin.io.path.* @DisplayName("Handles resources correctly") @@ -32,22 +31,18 @@ class ResourcesIT : KGPBaseTest() { |kotlin { | sourceSets.main.resources.srcDir("additionalRes") |} + | + |tasks.named("jar", Jar) { + | duplicatesStrategy = DuplicatesStrategy.INCLUDE + |} """.trimMargin() ) build("jar") { assertFileInProjectExists("build/libs/simpleProject.jar") - ZipFile(projectPath.resolve("build/libs/simpleProject.jar").toFile()).use { jar -> - assert(jar.entries().asSequence().count { it.name == mainResFile.name } == 1) { - "The jar should contain one entry `${mainResFile.name}` with no duplicates\n" + - jar.entries().asSequence().map { it.name }.joinToString() - } - - assert(jar.entries().asSequence().count { it.name == additionalResFile.name } == 1) { - "The jar should contain one entry `${additionalResFile.name}` with no duplicates\n" + - jar.entries().asSequence().map { it.name }.joinToString() - } - } + projectPath.resolve("build/libs/simpleProject.jar").assertZipArchiveContainsFilesOnce( + listOf(mainResFile.name, additionalResFile.name) + ) } } } @@ -65,4 +60,51 @@ class ResourcesIT : KGPBaseTest() { build("assemble") } } + + @GradleTest + @DisplayName("KT-60459: should not overwrite custom resource directories") + @JvmGradlePluginTests + fun notOverwriteCustomResDirs(gradleVersion: GradleVersion) { + project("simpleProject", gradleVersion) { + val mainResDir = projectPath.resolve("src/main/resources").apply { createDirectories() } + val mainResFile = mainResDir.resolve("main.txt").apply { writeText("Yay, Kotlin!") } + + val additionalResDir = projectPath.resolve("src/main/extra-resources").apply { createDirectory() } + val additionalResFile = additionalResDir.resolve("test.txt").apply { writeText("Kotlin!") } + + buildGradle.writeText( + """ + |plugins { + | id 'java' + | id 'org.jetbrains.kotlin.jvm' apply false + |} + | + |repositories { + | mavenLocal() + | mavenCentral() + |} + | + |dependencies { + | implementation 'com.google.guava:guava:12.0' + |} + | + |tasks.named("jar", Jar) { + | duplicatesStrategy = DuplicatesStrategy.INCLUDE + |} + | + |sourceSets.main.resources.srcDir "src/main/extra-resources" + | + |apply plugin: 'org.jetbrains.kotlin.jvm' + | + """.trimMargin() + ) + + build("jar", forceOutput = true) { + assertFileInProjectExists("build/libs/simpleProject.jar") + projectPath.resolve("build/libs/simpleProject.jar").assertZipArchiveContainsFilesOnce( + listOf(mainResFile.name, additionalResFile.name) + ) + } + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt index 6b480e7c30a..40b35c6ab95 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/testbase/fileAssertions.kt @@ -9,6 +9,7 @@ import com.google.gson.JsonObject import com.google.gson.JsonParser import java.nio.file.Files import java.nio.file.Path +import java.util.zip.ZipFile import kotlin.io.path.exists import kotlin.io.path.isDirectory import kotlin.io.path.readLines @@ -288,4 +289,17 @@ fun assertGradleVariant(gradleModuleFile: Path, variantName: String, code: Gradl } GradleVariantAssertions(variantJson.asJsonObject).apply(code) +} + +fun Path.assertZipArchiveContainsFilesOnce( + fileNames: List +) { + ZipFile(toFile()).use { zip -> + fileNames.forEach { fileName -> + assert(zip.entries().asSequence().count { it.name == fileName } == 1) { + "The jar should contain one entry `$fileName` with no duplicates\n" + + zip.entries().asSequence().map { it.name }.joinToString() + } + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/AbstractKotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/AbstractKotlinPlugin.kt index 7f62e975963..5b759b540e2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/AbstractKotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/AbstractKotlinPlugin.kt @@ -187,12 +187,19 @@ internal abstract class AbstractKotlinPlugin( if (duplicateJavaSourceSetsAsKotlinSourceSets) { val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinCompilation.name) kotlinSourceSet.kotlin.source(javaSourceSet.java) - // Registering resources from KotlinSourceSet as Java SourceSet resources. In case of KotlinPlugin - // Java Sources set will create ProcessResources task to process all resources into output - // 'kotlinSourceSet.resources' should contain Java SourceSet default resource directories and to avoid - // duplication error we are replacing here already configured default one. + + // Registering resources from KotlinSourceSet as Java SourceSet resources. + // In the case of KotlinPlugin Java Sources set will create ProcessResources task to process all resources into output + // 'kotlinSourceSet.resources' should contain Java SourceSet default resource directories, + // and to avoid duplication error, we are replacing the already configured default one. + + // If KGP was applied with delay, it is possible that 'javaSourceSet.resources' may already have some additional + // configuration. So we are syncing it into 'kotlinSourceSet.resources'. + kotlinSourceSet.resources.srcDirs(javaSourceSet.resources.sourceDirectories.files) javaSourceSet.resources.setSrcDirs( - listOf { kotlinSourceSet.resources.sourceDirectories } + listOf { + kotlinSourceSet.resources.sourceDirectories + } ) @Suppress("DEPRECATION") kotlinCompilation.addSourceSet(kotlinSourceSet)