55import org.gradle.api.*
66import org.gradle.api.attributes.*
77import org.gradle.api.file.*
8- import org.gradle.api.provider.*
9- import org.gradle.api.specs.*
8+ import org.gradle.api.tasks.*
109import org.gradle.api.tasks.bundling.*
1110import org.gradle.api.tasks.compile.*
1211import org.gradle.jvm.toolchain.*
1312import org.gradle.kotlin.dsl.*
14- import org.gradle.api.logging.Logger
13+ import org.gradle.work.*
1514import org.jetbrains.kotlin.gradle.dsl.*
16- import java.io.*
1715
1816/* *
1917 * This object configures the Java compilation of a JPMS (aka Jigsaw) module descriptor.
@@ -27,30 +25,40 @@ import java.io.*
2725 */
2826object Java9Modularity {
2927
30- private class ModuleInfoFilter (
31- private val compileKotlinTaskPath : String ,
32- private val javaVersionProvider : Provider <JavaVersion >,
33- private val moduleInfoFile : File ,
34- private val logger : Logger
35- ) : Spec<FileTreeElement> {
36- private val isJava9Compatible
37- get() = javaVersionProvider.orNull?.isJava9Compatible == true
38- private var logged = false
39-
40- private fun logStatusOnce () {
41- if (logged) return
42- if (isJava9Compatible) {
43- logger.info(" Module-info checking is enabled; $compileKotlinTaskPath is compiled using Java ${javaVersionProvider.get()} " )
44- } else {
45- logger.info(" Module-info checking is disabled" )
28+ /* *
29+ * Task that patches `module-info.java` and removes `requires kotlinx.atomicfu` directive.
30+ *
31+ * To have JPMS properly supported, Kotlin compiler **must** be supplied with the correct `module-info.java`.
32+ * The correct module info has to contain `atomicfu` requirement because atomicfu plugin kicks-in **after**
33+ * the compilation process. But `atomicfu` is compile-only dependency that shouldn't be present in the final
34+ * `module-info.java` and that's exactly what this task ensures.
35+ */
36+ abstract class ProcessModuleInfoFile : DefaultTask () {
37+ @get:InputFile
38+ @get:NormalizeLineEndings
39+ abstract val moduleInfoFile: RegularFileProperty
40+
41+ @get:OutputFile
42+ abstract val processedModuleInfoFile: RegularFileProperty
43+
44+ private val projectPath = project.path
45+
46+ @TaskAction
47+ fun process () {
48+ val sourceFile = moduleInfoFile.get().asFile
49+ if (! sourceFile.exists()) {
50+ throw IllegalStateException (" $sourceFile not found in $projectPath " )
51+ }
52+ val outputFile = processedModuleInfoFile.get().asFile
53+ sourceFile.useLines { lines ->
54+ outputFile.outputStream().bufferedWriter().use { writer ->
55+ for (line in lines) {
56+ if (" kotlinx.atomicfu" in line) continue
57+ writer.write(line)
58+ writer.newLine()
59+ }
60+ }
4661 }
47- logged = true
48- }
49-
50- override fun isSatisfiedBy (element : FileTreeElement ): Boolean {
51- logStatusOnce()
52- if (isJava9Compatible) return false
53- return element.file == moduleInfoFile
5462 }
5563 }
5664
@@ -74,12 +82,13 @@ object Java9Modularity {
7482 )
7583 }
7684
85+ val processModuleInfoFile by tasks.registering(ProcessModuleInfoFile ::class ) {
86+ moduleInfoFile.set(file(" ${target.name.ifEmpty { " ." }} /src/module-info.java" ))
87+ processedModuleInfoFile.set(project.layout.buildDirectory.file(" generated-sources/module-info-processor/module-info.java" ))
88+ }
89+
7790 val compileJavaModuleInfo = tasks.register(" compileModuleInfoJava" , JavaCompile ::class .java) {
7891 val moduleName = project.name.replace(' -' , ' .' ) // this module's name
79- val sourceFile = file(" ${target.name.ifEmpty { " ." }} /src/module-info.java" )
80- if (! sourceFile.exists()) {
81- throw IllegalStateException (" $sourceFile not found in $project " )
82- }
8392 val compileKotlinTask =
8493 compilation.compileTaskProvider.get() as ? org.jetbrains.kotlin.gradle.tasks.KotlinCompile
8594 ? : error(" Cannot access Kotlin compile task ${compilation.compileKotlinTaskName} " )
@@ -97,15 +106,9 @@ object Java9Modularity {
97106 // Note that we use the parent dir and an include filter,
98107 // this is needed for Gradle's module detection to work in
99108 // org.gradle.api.tasks.compile.JavaCompile.createSpec
100- source(sourceFile.parentFile)
101- include { it.file == sourceFile }
102-
103- // The Kotlin compiler will parse and check module dependencies,
104- // but it currently won't compile to a module-info.class file.
105- // Note that module checking only works on JDK 9+,
106- // because the JDK built-in base modules are not available in earlier versions.
107- val javaVersionProvider = compileKotlinTask.kotlinJavaToolchain.javaVersion
108- compileKotlinTask.exclude(ModuleInfoFilter (compileKotlinTask.path, javaVersionProvider, sourceFile, logger))
109+ source(processModuleInfoFile.map { it.processedModuleInfoFile.asFile.get().parentFile })
110+ val generatedModuleInfoFile = processModuleInfoFile.flatMap { it.processedModuleInfoFile.asFile }
111+ include { it.file == generatedModuleInfoFile.get() }
109112
110113 // Set the task outputs and destination directory
111114 outputs.dir(targetDir)
0 commit comments