Kapt, Refactoring: Introduce 'KaptOptions'
1. Use 'KaptOptions' for all kapt options, including paths and flags. 2. Use a single 'KAPT_OPTIONS' compiler configuration key for setting all options (using a mutable KaptOptions.Builder). 3. Pass 'KaptOptions' instead of separate flags. 4. Remove 'KaptPaths'. 5. Remove deprecated 'aptOnly' CLI option.
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.kapt3.base
|
||||
|
||||
import com.sun.tools.javac.util.Context
|
||||
import org.jetbrains.kotlin.base.kapt3.*
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.base.util.info
|
||||
@@ -16,32 +17,26 @@ object Kapt {
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("unused")
|
||||
fun kapt(
|
||||
paths: KaptPaths,
|
||||
isVerbose: Boolean,
|
||||
mapDiagnosticLocations: Boolean,
|
||||
annotationProcessorFqNames: List<String>,
|
||||
processorOptions: Map<String, String>,
|
||||
javacOptions: Map<String, String>
|
||||
): Boolean {
|
||||
val logger = WriterBackedKaptLogger(isVerbose)
|
||||
fun kaptFlags(rawFlags: Set<String>): KaptFlags {
|
||||
return KaptFlags.fromSet(KaptFlag.values().filterTo(mutableSetOf()) { it.name in rawFlags })
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Suppress("unused")
|
||||
fun kapt(options: KaptOptions): Boolean {
|
||||
val logger = WriterBackedKaptLogger(options[KaptFlag.VERBOSE])
|
||||
|
||||
if (!Kapt.checkJavacComponentsAccess(logger)) {
|
||||
return false
|
||||
}
|
||||
|
||||
val kaptContext = KaptContext(paths, false, logger, mapDiagnosticLocations, processorOptions, javacOptions)
|
||||
val kaptContext = KaptContext(options, false, logger)
|
||||
|
||||
logger.info { "Kapt3 is enabled (stand-alone mode)." }
|
||||
logger.info { "Map diagnostic locations: $mapDiagnosticLocations" }
|
||||
paths.log(logger)
|
||||
logger.info { "Javac options: $javacOptions" }
|
||||
logger.info { "AP options: $processorOptions" }
|
||||
logger.info { options.logString("stand-alone mode") }
|
||||
|
||||
val javaSourceFiles = paths.collectJavaSourceFiles()
|
||||
logger.info { "Java source files: " + javaSourceFiles.joinToString { it.canonicalPath } }
|
||||
val javaSourceFiles = options.collectJavaSourceFiles()
|
||||
|
||||
val processorLoader = ProcessorLoader(paths, annotationProcessorFqNames, logger)
|
||||
val processorLoader = ProcessorLoader(options, logger)
|
||||
|
||||
processorLoader.use {
|
||||
val processors = processorLoader.loadProcessors(findClassLoaderWithJavac())
|
||||
|
||||
@@ -11,6 +11,8 @@ import com.sun.tools.javac.main.Option
|
||||
import com.sun.tools.javac.util.Context
|
||||
import com.sun.tools.javac.util.Log
|
||||
import com.sun.tools.javac.util.Options
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaCompiler
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaFileManager
|
||||
import org.jetbrains.kotlin.kapt3.base.javac.KaptJavaLog
|
||||
@@ -21,18 +23,11 @@ import java.io.Closeable
|
||||
import java.io.File
|
||||
import javax.tools.JavaFileManager
|
||||
|
||||
open class KaptContext(
|
||||
val paths: KaptPaths,
|
||||
val withJdk: Boolean,
|
||||
val logger: KaptLogger,
|
||||
private val mapDiagnosticLocations: Boolean,
|
||||
processorOptions: Map<String, String>,
|
||||
javacOptions: Map<String, String> = emptyMap()
|
||||
) : Closeable {
|
||||
open class KaptContext(val options: KaptOptions, val withJdk: Boolean, val logger: KaptLogger) : Closeable {
|
||||
val context = Context()
|
||||
val compiler: KaptJavaCompiler
|
||||
val fileManager: KaptJavaFileManager
|
||||
val options: Options
|
||||
private val javacOptions: Options
|
||||
val javaLog: KaptJavaLog
|
||||
|
||||
protected open fun preregisterTreeMaker(context: Context) {}
|
||||
@@ -41,8 +36,8 @@ open class KaptContext(
|
||||
val interceptorData = KaptJavaLog.DiagnosticInterceptorData()
|
||||
context.put(Log.logKey, Context.Factory<Log> { newContext ->
|
||||
KaptJavaLog(
|
||||
paths.projectBaseDir, newContext, logger.errorWriter, logger.warnWriter, logger.infoWriter,
|
||||
interceptorData, mapDiagnosticLocations
|
||||
options.projectBaseDir, newContext, logger.errorWriter, logger.warnWriter, logger.infoWriter,
|
||||
interceptorData, options[KaptFlag.MAP_DIAGNOSTIC_LOCATIONS]
|
||||
)
|
||||
})
|
||||
}
|
||||
@@ -56,13 +51,13 @@ open class KaptContext(
|
||||
|
||||
KaptJavaCompiler.preRegister(context)
|
||||
|
||||
options = Options.instance(context).apply {
|
||||
for ((key, value) in processorOptions) {
|
||||
javacOptions = Options.instance(context).apply {
|
||||
for ((key, value) in options.processingOptions) {
|
||||
val option = if (value.isEmpty()) "-A$key" else "-A$key=$value"
|
||||
put(option, option) // key == value: it's intentional
|
||||
}
|
||||
|
||||
for ((key, value) in javacOptions) {
|
||||
for ((key, value) in options.javacOptions) {
|
||||
if (value.isNotEmpty()) {
|
||||
put(key, value)
|
||||
} else {
|
||||
@@ -82,26 +77,26 @@ open class KaptContext(
|
||||
}
|
||||
|
||||
putJavacOption("CLASSPATH", "CLASS_PATH",
|
||||
paths.compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
options.compileClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
|
||||
@Suppress("SpellCheckingInspection")
|
||||
putJavacOption("PROCESSORPATH", "PROCESSOR_PATH",
|
||||
paths.annotationProcessingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
options.processingClasspath.joinToString(File.pathSeparator) { it.canonicalPath })
|
||||
|
||||
put(Option.S, paths.sourcesOutputDir.canonicalPath)
|
||||
put(Option.D, paths.classFilesOutputDir.canonicalPath)
|
||||
put(Option.S, options.sourcesOutputDir.canonicalPath)
|
||||
put(Option.D, options.classesOutputDir.canonicalPath)
|
||||
put(Option.ENCODING, "UTF-8")
|
||||
}
|
||||
|
||||
if (logger.isVerbose) {
|
||||
logger.info("All Javac options: " + options.keySet().associateBy({ it }) { key -> options[key] ?: "" })
|
||||
logger.info("All Javac options: " + javacOptions.keySet().associateBy({ it }) { key -> javacOptions[key] ?: "" })
|
||||
}
|
||||
|
||||
fileManager = context.get(JavaFileManager::class.java) as KaptJavaFileManager
|
||||
|
||||
if (isJava9OrLater()) {
|
||||
for (option in Option.getJavacFileManagerOptions()) {
|
||||
val value = options.get(option) ?: continue
|
||||
val value = javacOptions.get(option) ?: continue
|
||||
fileManager.handleOptionJavac9(option, value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.base.kapt3
|
||||
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
class KaptOptions(
|
||||
val projectBaseDir: File?,
|
||||
val compileClasspath: List<File>,
|
||||
val javaSourceRoots: List<File>,
|
||||
|
||||
val sourcesOutputDir: File,
|
||||
val classesOutputDir: File,
|
||||
val stubsOutputDir: File,
|
||||
val incrementalDataOutputDir: File?,
|
||||
|
||||
val processingClasspath: List<File>,
|
||||
val processors: List<String>,
|
||||
|
||||
val processingOptions: Map<String, String>,
|
||||
val javacOptions: Map<String, String>,
|
||||
|
||||
val flags: KaptFlags,
|
||||
|
||||
val mode: AptMode,
|
||||
val detectMemoryLeaks: DetectMemoryLeaksMode
|
||||
) : KaptFlags {
|
||||
override fun get(flag: KaptFlag) = flags[flag]
|
||||
|
||||
class Builder {
|
||||
var projectBaseDir: File? = null
|
||||
val compileClasspath: MutableList<File> = mutableListOf()
|
||||
val javaSourceRoots: MutableList<File> = mutableListOf()
|
||||
|
||||
var sourcesOutputDir: File? = null
|
||||
var classesOutputDir: File? = null
|
||||
var stubsOutputDir: File? = null
|
||||
var incrementalDataOutputDir: File? = null
|
||||
|
||||
val processingClasspath: MutableList<File> = mutableListOf()
|
||||
val processors: MutableList<String> = mutableListOf()
|
||||
|
||||
val processingOptions: MutableMap<String, String> = mutableMapOf()
|
||||
val javacOptions: MutableMap<String, String> = mutableMapOf()
|
||||
|
||||
val flags: MutableSet<KaptFlag> = mutableSetOf(KaptFlag.USE_LIGHT_ANALYSIS)
|
||||
|
||||
var mode: AptMode = AptMode.WITH_COMPILATION
|
||||
var detectMemoryLeaks: DetectMemoryLeaksMode = DetectMemoryLeaksMode.DEFAULT
|
||||
|
||||
fun build(): KaptOptions {
|
||||
val sourcesOutputDir = this.sourcesOutputDir ?: error("'sourcesOutputDir' must be set")
|
||||
val classesOutputDir = this.classesOutputDir ?: error("'classesOutputDir' must be set")
|
||||
val stubsOutputDir = this.stubsOutputDir ?: error("'stubsOutputDir' must be set")
|
||||
|
||||
return KaptOptions(
|
||||
projectBaseDir, compileClasspath, javaSourceRoots,
|
||||
sourcesOutputDir, classesOutputDir, stubsOutputDir, incrementalDataOutputDir,
|
||||
processingClasspath, processors, processingOptions, javacOptions, KaptFlags.fromSet(flags),
|
||||
mode, detectMemoryLeaks
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface KaptFlags {
|
||||
operator fun get(flag: KaptFlag): Boolean
|
||||
|
||||
companion object {
|
||||
fun fromSet(flags: Set<KaptFlag>) = object : KaptFlags {
|
||||
override fun get(flag: KaptFlag) = flag in flags
|
||||
}
|
||||
}
|
||||
|
||||
object Empty : KaptFlags {
|
||||
override fun get(flag: KaptFlag) = false
|
||||
}
|
||||
}
|
||||
|
||||
enum class KaptFlag(val description: String) {
|
||||
VERBOSE("Verbose mode"),
|
||||
INFO_AS_WARNINGS("Info as warnings"),
|
||||
USE_LIGHT_ANALYSIS("Use light analysis"),
|
||||
CORRECT_ERROR_TYPES("Correct error types"),
|
||||
MAP_DIAGNOSTIC_LOCATIONS("Map diagnostic locations"),
|
||||
STRICT("Strict mode");
|
||||
}
|
||||
|
||||
interface KaptSelector {
|
||||
val stringValue: String
|
||||
}
|
||||
|
||||
enum class DetectMemoryLeaksMode(override val stringValue: String) : KaptSelector {
|
||||
DEFAULT("default"), PARANOID("paranoid"), NONE("none")
|
||||
}
|
||||
|
||||
enum class AptMode(override val stringValue: String) : KaptSelector {
|
||||
WITH_COMPILATION("compile"),
|
||||
STUBS_AND_APT("stubsAndApt"),
|
||||
STUBS_ONLY("stubs"),
|
||||
APT_ONLY("apt");
|
||||
|
||||
val runAnnotationProcessing
|
||||
get() = this != STUBS_ONLY
|
||||
|
||||
val generateStubs
|
||||
get() = this != APT_ONLY
|
||||
}
|
||||
|
||||
fun KaptOptions.collectJavaSourceFiles(): List<File> {
|
||||
return (javaSourceRoots + stubsOutputDir)
|
||||
.sortedBy { Files.isSymbolicLink(it.toPath()) } // Get non-symbolic paths first
|
||||
.flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() }
|
||||
.sortedBy { Files.isSymbolicLink(it.toPath()) } // This time is for .java files
|
||||
.distinctBy { it.canonicalPath }
|
||||
}
|
||||
|
||||
fun KaptOptions.logString(additionalInfo: String = "") = buildString {
|
||||
val additionalInfoRendered = if (additionalInfo.isEmpty()) "" else " ($additionalInfo)"
|
||||
appendln("Kapt3 is enabled$additionalInfoRendered.")
|
||||
|
||||
appendln("Annotation processing mode: ${mode.stringValue}")
|
||||
appendln("Memory leak detection mode: ${detectMemoryLeaks.stringValue}")
|
||||
KaptFlag.values().forEach { appendln(it.description + ": " + this@logString[it]) }
|
||||
|
||||
appendln("Project base dir: $projectBaseDir")
|
||||
appendln("Compile classpath: " + compileClasspath.joinToString())
|
||||
appendln("Java source roots: " + javaSourceRoots.joinToString())
|
||||
|
||||
appendln("Sources output directory: $sourcesOutputDir")
|
||||
appendln("Class files output directory: $classesOutputDir")
|
||||
appendln("Stubs output directory: $stubsOutputDir")
|
||||
appendln("Incremental data output directory: $incrementalDataOutputDir")
|
||||
|
||||
appendln("Annotation processing classpath: " + processingClasspath.joinToString())
|
||||
appendln("Annotation processors: " + processors.joinToString())
|
||||
|
||||
appendln("AP options: $processingOptions")
|
||||
appendln("Javac options: $javacOptions")
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.kapt3.base
|
||||
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
|
||||
class KaptPaths(
|
||||
val projectBaseDir: File?,
|
||||
compileClasspath: List<File>,
|
||||
annotationProcessingClasspath: List<File>,
|
||||
val javaSourceRoots: List<File>,
|
||||
val sourcesOutputDir: File,
|
||||
val classFilesOutputDir: File,
|
||||
val stubsOutputDir: File,
|
||||
val incrementalDataOutputDir: File?
|
||||
) {
|
||||
val compileClasspath = compileClasspath.distinct()
|
||||
val annotationProcessingClasspath = annotationProcessingClasspath.distinct()
|
||||
|
||||
fun collectJavaSourceFiles(): List<File> {
|
||||
return (javaSourceRoots + stubsOutputDir)
|
||||
.sortedBy { Files.isSymbolicLink(it.toPath()) } // Get non-symbolic paths first
|
||||
.flatMap { root -> root.walk().filter { it.isFile && it.extension == "java" }.toList() }
|
||||
.sortedBy { Files.isSymbolicLink(it.toPath()) } // This time is for .java files
|
||||
.distinctBy { it.canonicalPath }
|
||||
}
|
||||
}
|
||||
|
||||
fun KaptPaths.log(logger: KaptLogger) {
|
||||
if (!logger.isVerbose) return
|
||||
|
||||
logger.info("Project base dir: $projectBaseDir")
|
||||
logger.info("Compile classpath: ${compileClasspath.joinToString()}")
|
||||
logger.info("Annotation processing classpath: ${annotationProcessingClasspath.joinToString()}")
|
||||
logger.info("Java source roots: ${javaSourceRoots.joinToString()}")
|
||||
logger.info("Sources output directory: $sourcesOutputDir")
|
||||
logger.info("Class files output directory: $classFilesOutputDir")
|
||||
logger.info("Stubs output directory: $stubsOutputDir")
|
||||
logger.info("Incremental data output directory: $incrementalDataOutputDir")
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.kapt3.base
|
||||
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptLogger
|
||||
import org.jetbrains.kotlin.kapt3.base.util.info
|
||||
import java.io.Closeable
|
||||
@@ -16,23 +17,19 @@ import javax.annotation.processing.Processor
|
||||
|
||||
class LoadedProcessors(val processors: List<Processor>, val classLoader: ClassLoader)
|
||||
|
||||
open class ProcessorLoader(
|
||||
private val paths: KaptPaths,
|
||||
private val annotationProcessorFqNames: List<String>,
|
||||
private val logger: KaptLogger
|
||||
) : Closeable {
|
||||
open class ProcessorLoader(private val options: KaptOptions, private val logger: KaptLogger) : Closeable {
|
||||
private var annotationProcessingClassLoader: URLClassLoader? = null
|
||||
|
||||
fun loadProcessors(parentClassLoader: ClassLoader = ClassLoader.getSystemClassLoader()): LoadedProcessors {
|
||||
clearJarURLCache()
|
||||
|
||||
val classpath = (paths.annotationProcessingClasspath + paths.compileClasspath).distinct()
|
||||
val classpath = (options.processingClasspath + options.compileClasspath).distinct()
|
||||
val classLoader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), parentClassLoader)
|
||||
this.annotationProcessingClassLoader = classLoader
|
||||
|
||||
val processors = if (annotationProcessorFqNames.isNotEmpty()) {
|
||||
val processors = if (options.processors.isNotEmpty()) {
|
||||
logger.info("Annotation processor class names are set, skip AP discovery")
|
||||
annotationProcessorFqNames.mapNotNull { tryLoadProcessor(it, classLoader) }
|
||||
options.processors.mapNotNull { tryLoadProcessor(it, classLoader) }
|
||||
} else {
|
||||
logger.info("Need to discovery annotation processors in the AP classpath")
|
||||
doLoadProcessors(classLoader)
|
||||
|
||||
@@ -6,8 +6,10 @@
|
||||
package org.jetbrains.kotlin.kapt.base.test
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.base.kapt3.DetectMemoryLeaksMode
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptFlag
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptContext
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.kapt3.base.doAnnotationProcessing
|
||||
import org.jetbrains.kotlin.kapt3.base.util.KaptBaseError
|
||||
import org.jetbrains.kotlin.kapt3.base.util.WriterBackedKaptLogger
|
||||
@@ -49,22 +51,20 @@ class JavaKaptContextTest : TestCase() {
|
||||
}
|
||||
|
||||
private fun doAnnotationProcessing(javaSourceFile: File, processor: Processor, outputDir: File) {
|
||||
KaptContext(
|
||||
KaptPaths(
|
||||
projectBaseDir = javaSourceFile.parentFile,
|
||||
compileClasspath = emptyList(),
|
||||
annotationProcessingClasspath = emptyList(),
|
||||
javaSourceRoots = emptyList(),
|
||||
sourcesOutputDir = outputDir,
|
||||
classFilesOutputDir = outputDir,
|
||||
stubsOutputDir = outputDir,
|
||||
incrementalDataOutputDir = outputDir
|
||||
),
|
||||
withJdk = true,
|
||||
logger = WriterBackedKaptLogger(isVerbose = true),
|
||||
mapDiagnosticLocations = true,
|
||||
processorOptions = emptyMap()
|
||||
).doAnnotationProcessing(listOf(javaSourceFile), listOf(processor))
|
||||
val options = KaptOptions.Builder().apply {
|
||||
projectBaseDir = javaSourceFile.parentFile
|
||||
|
||||
sourcesOutputDir = outputDir
|
||||
classesOutputDir = outputDir
|
||||
stubsOutputDir = outputDir
|
||||
incrementalDataOutputDir = outputDir
|
||||
|
||||
flags.add(KaptFlag.MAP_DIAGNOSTIC_LOCATIONS)
|
||||
detectMemoryLeaks = DetectMemoryLeaksMode.NONE
|
||||
}.build()
|
||||
|
||||
val logger = WriterBackedKaptLogger(isVerbose = true)
|
||||
KaptContext(options, true, logger).doAnnotationProcessing(listOf(javaSourceFile), listOf(processor))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
package org.jetbrains.kotlin.kapt.base.test
|
||||
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.kapt3.base.KaptPaths
|
||||
import org.jetbrains.kotlin.base.kapt3.KaptOptions
|
||||
import org.jetbrains.kotlin.base.kapt3.collectJavaSourceFiles
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
@@ -36,16 +37,12 @@ class KaptPathsTest : TestCase() {
|
||||
|
||||
val javaRoots = listOf(simpleJava, symlinkToOtherJava, symlinkToNotJava, symlinkToJavaRootDir, javaRootDir)
|
||||
|
||||
val paths = KaptPaths(
|
||||
projectBaseDir = null,
|
||||
compileClasspath = emptyList(),
|
||||
annotationProcessingClasspath = emptyList(),
|
||||
javaSourceRoots = javaRoots,
|
||||
sourcesOutputDir = outputDir,
|
||||
classFilesOutputDir = outputDir,
|
||||
stubsOutputDir = outputDir,
|
||||
incrementalDataOutputDir = null
|
||||
)
|
||||
val paths = KaptOptions.Builder().apply {
|
||||
javaSourceRoots.addAll(javaRoots)
|
||||
sourcesOutputDir = outputDir
|
||||
classesOutputDir = outputDir
|
||||
stubsOutputDir = outputDir
|
||||
}.build()
|
||||
|
||||
val javaSourceFiles = paths.collectJavaSourceFiles()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user