diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt index 4a9417fb344..6b3b695ff01 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt @@ -29,6 +29,7 @@ import java.io.File import java.util.zip.ZipFile import kotlin.test.assertEquals import kotlin.test.assertNotEquals +import kotlin.test.assertNotNull import kotlin.test.assertTrue class KotlinGradleIT: BaseGradleIT() { @@ -659,4 +660,60 @@ class KotlinGradleIT: BaseGradleIT() { } } } -} \ No newline at end of file + + @Test + fun testSrcDirTaskDependency() { + Project("simpleProject", "4.1").apply { + setupWorkingDir() + File(projectDir, "build.gradle").appendText("""${'\n'} + task generateSources { + outputs.dir('generated') + doLast { + def file = new File('generated/test/TestClass.java') + file.parentFile.mkdirs() + file.text = ""${'"'} + package test; + + public class TestClass { } + ""${'"'} + } + } + sourceSets.main.java.srcDir(tasks.generateSources) + """.trimIndent()) + File(projectDir, "src/main/kotlin/helloWorld.kt").appendText("""${'\n'} + fun usageOfGeneratedSource() = test.TestClass() + """.trimIndent()) + + build("build") { + assertSuccessful() + } + } + } + + @Test + fun testSourceJar() { + Project("simpleProject", "4.1").apply { + setupWorkingDir() + val additionalSrcDir = "src/additional/kotlin/" + + File(projectDir, additionalSrcDir).mkdirs() + File(projectDir, "$additionalSrcDir/additionalSource.kt").writeText("fun hello() = 123") + + File(projectDir, "build.gradle").appendText("""${'\n'} + task sourcesJar(type: Jar) { + from sourceSets.main.allSource + classifier 'source' + duplicatesStrategy = 'fail' // fail in case of Java source duplication, see KT-17564 + } + + sourceSets.main.kotlin.srcDir('$additionalSrcDir') // test that additional srcDir is included + """.trimIndent()) + + build("sourcesJar") { + assertSuccessful() + val sourcesJar = ZipFile(File(projectDir, "build/libs/simpleProject-source.jar")) + assertNotNull(sourcesJar.getEntry("additionalSource.kt")) + } + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index d12a08e7ab7..30964a15dcc 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -10,6 +10,7 @@ import org.gradle.api.* import org.gradle.api.artifacts.Configuration import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.FileCollection +import org.gradle.api.file.SourceDirectorySet import org.gradle.api.logging.Logger import org.gradle.api.logging.Logging import org.gradle.api.plugins.InvalidPluginException @@ -86,11 +87,30 @@ internal abstract class KotlinSourceSetProcessor>( private fun addKotlinDirSetToSources() { val kotlinDirSet = kotlinSourceSet.kotlin - sourceSet.allJava.source(kotlinDirSet) - sourceSet.allSource.source(kotlinDirSet) + + // Try to avoid duplicate Java sources in allSource: + val kotlinSrcDirsToAdd = filterOutJavaSrcDirsIfPossible(kotlinDirSet) + + sourceSet.allJava.srcDirs(kotlinSrcDirsToAdd) + sourceSet.allSource.srcDirs(kotlinSrcDirsToAdd) sourceSet.resources.filter.exclude { it.file in kotlinDirSet } } + private fun filterOutJavaSrcDirsIfPossible(sourceDirectorySet: SourceDirectorySet): FileCollection { + // If the API used below is not available, fall back to not filtering the Java sources. + if (SourceDirectorySet::class.java.methods.none { it.name == "getSourceDirectories" }) { + return sourceDirectorySet + } + + fun getSourceDirectories(sourceDirectorySet: SourceDirectorySet): FileCollection { + val method = SourceDirectorySet::class.java.getMethod("getSourceDirectories") + return method(sourceDirectorySet) as FileCollection + } + + // Build a lazily-resolved file collection that filters out Java sources from sources of this sourceDirectorySet + return getSourceDirectories(sourceDirectorySet).minus(getSourceDirectories(sourceSet.java)) + } + private fun createKotlinCompileTask(): T { val name = sourceSet.getCompileTaskName(compileTaskNameSuffix) logger.kotlinDebug("Creating kotlin compile task $name") @@ -129,6 +149,7 @@ internal class Kotlin2JvmSourceSetProcessor( override fun doTargetSpecificProcessing() { val aptConfiguration = project.createAptConfiguration(sourceSet.name, kotlinPluginVersion) + kotlinSourceSet.kotlin.source(sourceSet.java) project.afterEvaluate { project -> if (project != null) { @@ -154,8 +175,6 @@ internal class Kotlin2JvmSourceSetProcessor( removeAnnotationProcessingPluginClasspathEntry(kotlinTask) } - sourceSet.java.srcDirs.forEach { kotlinSourceSet.kotlin.srcDir(it) } - // KotlinCompile.source(kotlinDirSet) should be called only after all java roots are added to kotlinDirSet // otherwise some java roots can be ignored kotlinTask.source(kotlinSourceSet.kotlin)