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 d71928a5e64..3d5efdbf66c 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 @@ -60,7 +60,7 @@ class ResourcesIT : KGPBaseTest() { build("assemble") } } - + @GradleTest @DisplayName("KT-60459: should not overwrite custom resource directories") @JvmGradlePluginTests @@ -107,4 +107,52 @@ class ResourcesIT : KGPBaseTest() { } } } + + @GradleTest + @DisplayName("KT-62490: should not drop reference to task producing resources") + @JvmGradlePluginTests + fun keepReferenceToResourcesProducingTask(gradleVersion: GradleVersion) { + project("kt-62490", gradleVersion) { + build("processResources") { + assertTasksExecuted(":customResGenerator") + assertFileInProjectExists("build/custom-res/myres.txt") + } + } + } + + @GradleTest + @DisplayName("KT-62490: should keep previously configured Kotlin resources") + @JvmGradlePluginTests + fun keepConfiguredKotlinResources(gradleVersion: GradleVersion) { + project( + "kt-62490", + gradleVersion, + buildOptions = defaultBuildOptions.suppressDeprecationWarningsOn( + reason = "KT-64462: Gradle complains about already created configurations", + predicate = { gradleVersion >= GradleVersion.version(TestVersions.Gradle.G_8_2) } + ) + ) { + buildGradleKts.appendText( + //language=kotlin + """ + | + |val customResGenerator1 = tasks.register("customResGenerator1") { + | outputFile.value(project.layout.buildDirectory.dir("custom-res-1")) + |} + |project.extensions.getByType() + | .sourceSets.create("x").resources.srcDir(customResGenerator1) + |sourceSets.create("x") + """.trimMargin() + ) + + val xResFile = projectPath.resolve("src/x/resources").resolve("test.txt").toFile() + xResFile.parentFile.mkdirs() + xResFile.writeText("some resource") + + build("processXResources", enableGradleDebug = true) { + assertTasksExecuted(":customResGenerator1") + assertFileInProjectExists("build/custom-res-1/myres.txt") + } + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kt-62490/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kt-62490/build.gradle.kts new file mode 100644 index 00000000000..c3fc55965c3 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kt-62490/build.gradle.kts @@ -0,0 +1,24 @@ +plugins { + `java` + id("org.jetbrains.kotlin.jvm") apply false +} + +abstract class CustomResGenerator : DefaultTask() { + @get:OutputDirectory + abstract val outputFile: DirectoryProperty + + @TaskAction + fun doGenerate() { + val dir = outputFile.get().asFile + dir.mkdirs() + dir.resolve("myres.txt").writeText("Banana!") + } +} + +val customResGenerator = tasks.register("customResGenerator") { + outputFile.value(project.layout.buildDirectory.dir("custom-res")) +} + +sourceSets.getByName("main").resources.srcDir(customResGenerator) + +plugins.apply("org.jetbrains.kotlin.jvm") 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 0577c481703..454aba55f38 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 @@ -26,6 +26,8 @@ import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessor import org.jetbrains.kotlin.gradle.plugin.internal.MavenPluginConfigurator import org.jetbrains.kotlin.gradle.plugin.internal.compatibilityConventionRegistrar import org.jetbrains.kotlin.gradle.plugin.mpp.* +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.sources.KotlinSourceSetFactory import org.jetbrains.kotlin.gradle.tasks.InspectClassesForMultiModuleIC import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.tasks.locateTask @@ -180,19 +182,24 @@ internal abstract class AbstractKotlinPlugin( val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinCompilation.name) kotlinSourceSet.kotlin.source(javaSourceSet.java) - // Registering resources from KotlinSourceSet as Java SourceSet resources. + // Registering resources from JavaSourceSet as KotlinSourceSet 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. + // and to avoid duplication error, we are replacing the already created default one. + with(kotlinSourceSet as DefaultKotlinSourceSet) { + val defaultResources = actualResources + actualResources = javaSourceSet.resources + // Filtering out default resource directory to avoid duplicates error + val defaultResourcesDir = KotlinSourceSetFactory.defaultSourceFolder( + project, + javaSourceSet.name, + javaSourceSet.resources.name + ) + resources.srcDir(defaultResources.sourceDirectories.filter { + !it.startsWith(defaultResourcesDir) + }) + } - // 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 - } - ) @Suppress("DEPRECATION") kotlinCompilation.addSourceSet(kotlinSourceSet) project.compatibilityConventionRegistrar.addConvention(javaSourceSet, kotlinSourceSetDslName, kotlinSourceSet) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt index d67458b6d65..bc1a5292ff2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt @@ -73,7 +73,9 @@ abstract class DefaultKotlinSourceSet @Inject constructor( override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder(project) - override val resources: SourceDirectorySet = createDefaultSourceDirectorySet(project, "$name resources") + internal var actualResources: SourceDirectorySet = createDefaultSourceDirectorySet(project, "$name resources") + + override val resources: SourceDirectorySet get() = actualResources override fun kotlin(configure: SourceDirectorySet.() -> Unit): SourceDirectorySet = kotlin.apply { configure(this) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/KotlinSourceSetFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/KotlinSourceSetFactory.kt index 7c55c23de62..22355bb8c56 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/KotlinSourceSetFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/KotlinSourceSetFactory.kt @@ -36,7 +36,7 @@ internal abstract class KotlinSourceSetFactory internal con } protected open fun setUpSourceSetDefaults(sourceSet: T) { - sourceSet.kotlin.srcDir(defaultSourceFolder(project, sourceSet.name, "kotlin")) + sourceSet.kotlin.srcDir(defaultSourceFolder(project, sourceSet.name, SOURCE_SET_TYPE_KOTLIN)) defineSourceSetConfigurations(project, sourceSet) } @@ -68,6 +68,9 @@ internal abstract class KotlinSourceSetFactory internal con fun defaultSourceFolder(project: Project, sourceSetName: String, type: String): File { return project.file("src/$sourceSetName/$type") } + + internal const val SOURCE_SET_TYPE_RESOURCES = "resources" + internal const val SOURCE_SET_TYPE_KOTLIN = "kotlin" } } @@ -81,7 +84,7 @@ internal class DefaultKotlinSourceSetFactory( override fun setUpSourceSetDefaults(sourceSet: DefaultKotlinSourceSet) { super.setUpSourceSetDefaults(sourceSet) - sourceSet.resources.srcDir(defaultSourceFolder(project, sourceSet.name, "resources")) + sourceSet.resources.srcDir(defaultSourceFolder(project, sourceSet.name, SOURCE_SET_TYPE_RESOURCES)) val dependencyConfigurationWithMetadata = with(sourceSet) { @Suppress("DEPRECATION")