1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-25 07:57:12 -07:00

Add support for kapt3.

This commit is contained in:
Cedric Beust 2017-04-17 16:27:12 -07:00
parent afacd86267
commit 9e1c9bd87b
2 changed files with 151 additions and 96 deletions

View file

@ -3,8 +3,8 @@ package com.beust.kobalt.plugin.apt
import com.beust.kobalt.Constants
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.*
import com.beust.kobalt.api.annotation.AnnotationDefault
import com.beust.kobalt.api.annotation.Directive
import com.beust.kobalt.api.annotation.Task
import com.beust.kobalt.homeDir
import com.beust.kobalt.internal.CompilerUtils
import com.beust.kobalt.maven.DependencyManager
@ -12,6 +12,7 @@ import com.beust.kobalt.maven.aether.Filters
import com.beust.kobalt.maven.aether.Scope
import com.beust.kobalt.maven.dependency.FileDependency
import com.beust.kobalt.misc.KFiles
import com.beust.kobalt.misc.KobaltLogger
import com.beust.kobalt.misc.warn
import com.beust.kobalt.plugin.kotlin.KotlinPlugin
import com.google.common.collect.ArrayListMultimap
@ -21,7 +22,7 @@ import java.util.*
import javax.inject.Singleton
/**
* The AptPlugin has two components:
* The AptPlugin manages both apt and kapt. Each of them has two components:
* 1) A new apt directive inside a dependency{} block (similar to compile()) that declares where
* the annotation processor is found
* 2) An apt{} configuration on Project that lets the user configure how the annotation is performed
@ -30,13 +31,53 @@ import javax.inject.Singleton
@Singleton
class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, val kotlinPlugin: KotlinPlugin,
val compilerUtils: CompilerUtils)
: BasePlugin(), ICompilerFlagContributor, ISourceDirectoryContributor {
: BasePlugin(), ICompilerFlagContributor, ISourceDirectoryContributor, IClasspathContributor, ITaskContributor {
// ISourceDirectoryContributor
companion object {
const val PLUGIN_NAME = "Apt"
const val KAPT_CONFIG = "kaptConfig"
const val APT_CONFIG = "aptConfig"
}
override val name = PLUGIN_NAME
var kaptConfig: KaptConfig? = null
override fun apply(project: Project, context: KobaltContext) {
super.apply(project, context)
kaptConfig = kaptConfigs[project.name]
// Delete the output directories
listOf(aptConfigs[project.name]?.outputDir, kaptConfig?.outputDir)
.filterNotNull()
.distinct()
.map { generatedDir(project, it) }
.forEach {
it.normalize().absolutePath.let { path ->
context.logger.log(project.name, 1, " Deleting " + path)
val success = it.deleteRecursively()
if (!success) warn(" Couldn't delete " + path)
}
}
}
// IClasspathContributor
override fun classpathEntriesFor(project: Project?, context: KobaltContext): Collection<IClasspathDependency> {
val result = arrayListOf<IClasspathDependency>()
if (project != null && kaptConfig != null) {
kaptConfig?.let { config ->
val c = generatedClasses(project, context, config.outputDir)
File(c).mkdirs()
result.add(FileDependency(c))
}
}
return result
}
private fun generatedDir(project: Project, outputDir: String) : File
= File(KFiles.joinDir(project.directory, KFiles.KOBALT_BUILD_DIR, outputDir))
= File(KFiles.joinDir(project.directory, KFiles.KOBALT_BUILD_DIR, outputDir))
// ISourceDirectoryContributor
override fun sourceDirectoriesFor(project: Project, context: KobaltContext): List<File> {
val result = arrayListOf<File>()
aptConfigs[project.name]?.let { config ->
@ -50,29 +91,6 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va
return result
}
companion object {
const val PLUGIN_NAME = "Apt"
const val KAPT_CONFIG = "kaptConfig"
const val APT_CONFIG = "aptConfig"
}
override val name = PLUGIN_NAME
override fun apply(project: Project, context: KobaltContext) {
super.apply(project, context)
listOf(aptConfigs[project.name]?.outputDir, aptConfigs[project.name]?.outputDir)
.filterNotNull()
.distinct()
.map { generatedDir(project, it) }
.forEach {
it.normalize().absolutePath.let { path ->
context.logger.log(project.name, 1, " Deleting " + path)
val success = it.deleteRecursively()
if (!success) warn(" Couldn't delete " + path)
}
}
}
private fun generated(project: Project, context: KobaltContext, outputDir: String) =
KFiles.joinAndMakeDir(project.directory, project.buildDirectory, outputDir,
context.variant.toIntermediateDir())
@ -84,13 +102,32 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va
private fun generatedClasses(project: Project, context: KobaltContext, outputDir: String) =
KFiles.joinDir(generated(project, context, outputDir), "classes")
// @Task(name = "compileKapt", dependsOn = arrayOf("runKapt"), reverseDependsOn = arrayOf("compile"))
// ITaskContributor
override fun tasksFor(project: Project, context: KobaltContext): List<DynamicTask> {
val result =
if (kaptConfig != null) {
listOf(
DynamicTask(this, "runKapt", "Run kapt", AnnotationDefault.GROUP, project,
reverseDependsOn = listOf("compile"), runAfter = listOf("clean"),
closure = {p: Project -> taskRunKapt(p)}),
DynamicTask(this, "compileKapt", "Compile the sources generated by kapt",
AnnotationDefault.GROUP, project,
dependsOn = listOf("runKapt"), reverseDependsOn = listOf("compile"),
closure = {p: Project -> taskCompileKapt(p)})
)
} else {
emptyList()
}
return result
}
fun taskCompileKapt(project: Project) : TaskResult {
var success = true
kaptConfigs[project.name]?.let { config ->
val sourceDirs = listOf(
generatedStubs(project, context, config.outputDir),
generatedSources(project, context, config.outputDir))
val sourceFiles = KFiles.findSourceFiles(project.directory, sourceDirs, listOf("kt", "java")).toList()
val sourceFiles = KFiles.findSourceFiles(project.directory, sourceDirs, listOf("kt")).toList()
val buildDirectory = File(KFiles.joinDir(project.directory,
generatedClasses(project, context, config.outputDir)))
val flags = listOf<String>()
@ -98,10 +135,10 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va
buildDirectory, flags, emptyList(), forceRecompile = true)
val cr = compilerUtils.invokeCompiler(project, context, kotlinPlugin.compiler, cai)
println("")
success = cr.failedResult == null
}
return TaskResult()
return TaskResult(success)
}
val annotationDependencyId = "org.jetbrains.kotlin:kotlin-annotation-processing:" +
@ -121,31 +158,41 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va
return allDeps
}
// @Task(name = "runKapt", reverseDependsOn = arrayOf("compile"), runAfter = arrayOf("clean"))
fun taskRunKapt(project: Project) : TaskResult {
var success = true
val flags = arrayListOf<String>()
kaptConfigs[project.name]?.let { config ->
kaptConfig?.let { config ->
fun kaptPluginFlag(flagValue: String): String {
return "plugin:org.jetbrains.kotlin.kapt3:$flagValue"
}
val generated = generated(project, context, config.outputDir)
val generatedSources = generatedSources(project, context, config.outputDir)
val generatedSources = generatedSources(project, context, config.outputDir).replace("//", "/")
File(generatedSources).mkdirs()
//
// Tell the Kotlin compiler to use the annotation plug-in
//
val allDeps = allDependencies()
flags.add("-Xplugin")
flags.add(annotationProcessorDependency().jarFile.get().absolutePath)
flags.add("-P")
val kaptPluginFlags = arrayListOf<String>()
// kaptPluginFlags.add(kaptPluginFlag("aptOnly=true"))
kaptPluginFlags.add(kaptPluginFlag("sources=" + generatedSources))
kaptPluginFlags.add(kaptPluginFlag("classes=" + generatedClasses(project, context, config.outputDir)))
kaptPluginFlags.add(kaptPluginFlag("stubs=" + generatedStubs(project, context, config.outputDir)))
kaptPluginFlags.add(kaptPluginFlag("verbose=true"))
kaptPluginFlags.add(kaptPluginFlag("aptOnly=false"))
//
// Pass options to the annotation plugin
//
fun kaptPluginFlag(flagValue: String) = "plugin:org.jetbrains.kotlin.kapt3:$flagValue"
val kaptPluginFlags = arrayListOf<String>()
val verbose = KobaltLogger.LOG_LEVEL >= 2
listOf("sources=" + generatedSources,
"classes=" + generatedClasses(project, context, config.outputDir),
"stubs=" + generatedStubs(project, context, config.outputDir),
"verbose=$verbose",
"aptOnly=true").forEach {
kaptPluginFlags.add(kaptPluginFlag(it))
}
//
// Dependencies for the annotation plug-in and the generation
//
val dependencies = dependencyManager.calculateDependencies(project, context,
Filters.EXCLUDE_OPTIONAL_FILTER,
listOf(Scope.COMPILE),
@ -159,35 +206,30 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va
listOf("-language-version", "1.1", " -api-version", "1.1").forEach {
flags.add(it)
}
val sourceFiles =
// KFiles.findSourceFiles(project.directory,
// listOf("src/tmp/kotlin"),
// listOf("kt"))
// .toList()
KFiles.findSourceFiles(project.directory, project.sourceDirectories, listOf("kt")).toList() +
generatedSources
//
val sourceFiles =
KFiles.findSourceFiles(project.directory, project.sourceDirectories, listOf("kt"))
.toList() + generatedSources
val buildDirectory = File(KFiles.joinDir(project.directory, generated))
val cai = CompilerActionInfo(project.directory, allDeps, sourceFiles, listOf(".kt"),
buildDirectory, flags, emptyList(), forceRecompile = true)
println("FLAGS: " + flags.joinToString("\n"))
println(" " + kaptPluginFlags.joinToString("\n "))
context.logger.log(project.name, 2, " " + kaptPluginFlags.joinToString("\n "))
val cr = compilerUtils.invokeCompiler(project, context, kotlinPlugin.compiler, cai)
println("")
success = cr.failedResult == null
}
return TaskResult()
return TaskResult(success)
}
// ICompilerFlagContributor
override fun compilerFlagsFor(project: Project, context: KobaltContext, currentFlags: List<String>,
suffixesBeingCompiled: List<String>): List<String> {
if (!suffixesBeingCompiled.contains("java")) return emptyList()
val result = arrayListOf<String>()
// Only run for Java files
if (!suffixesBeingCompiled.contains("java")) return emptyList()
fun addFlags(outputDir: String) {
aptDependencies[project.name]?.let {
result.add("-s")
@ -199,10 +241,6 @@ class AptPlugin @Inject constructor(val dependencyManager: DependencyManager, va
addFlags(config.outputDir)
}
kaptConfigs[project.name]?.let { config ->
addFlags(config.outputDir)
}
context.logger.log(project.name, 2, "New flags from apt: " + result.joinToString(" "))
return result
}

View file

@ -44,14 +44,16 @@ class KotlinCompiler @Inject constructor(
var filesToCompile = 0
if (! info.outputDir.path.endsWith("ript.jar")) {
// Don't display the message if compiling Build.kt
filesToCompile =
info.sourceFiles.map(::File).map {
if (it.isDirectory) KFiles.findRecursively(it).size else 1
}.reduce { a, b ->
a + b
}
kobaltLog.log(projectName ?: "", 1,
" Kotlin $version compiling " + Strings.pluralizeAll(filesToCompile, "file"))
if (info.sourceFiles.isNotEmpty()) {
filesToCompile =
info.sourceFiles.map(::File).map {
if (it.isDirectory) KFiles.findRecursively(it).size else 1
}.reduce { a, b ->
a + b
}
kobaltLog.log(projectName ?: "", 1,
" Kotlin $version compiling " + Strings.pluralizeAll(filesToCompile, "file"))
}
}
val cp = compilerFirst(info.dependencies.map { it.jarFile.get() })
val infoDir = info.directory
@ -135,8 +137,10 @@ class KotlinCompiler @Inject constructor(
val friends = info.friendPaths.toTypedArray()
// Collect the compiler args from kotlinCompiler{} and from settings.xml and parse them
val args2 = (kotlinConfig(project)?.args ?: arrayListOf<String>()) +
(settings.kobaltCompilerFlags?.split(" ") ?: listOf<String>())
val args2 =
info.compilerArgs +
(kotlinConfig(project)?.args ?: arrayListOf<String>()) +
(settings.kobaltCompilerFlags?.split(" ") ?: listOf<String>())
val args = K2JVMCompilerArguments()
val compiler = K2JVMCompiler()
compiler.parseArguments(args2.toTypedArray(), args)
@ -185,13 +189,27 @@ class KotlinCompiler @Inject constructor(
fun logk(level: Int, message: CharSequence) = kobaltLog.log(projectName, level, message)
logk(2, " Invoking K2JVMCompiler with arguments:"
fun pluginClasspaths(args: K2JVMCompilerArguments) : String {
var result = ""
args.pluginClasspaths?.forEach {
result += " -Xplugin " + it
}
args.pluginOptions?.let {
result += " -P "
result += it.joinToString(",")
}
return result
}
logk(2, " Invoking K2JVMCompiler with arguments: kotlinc "
+ if (args.skipMetadataVersionCheck) " -Xskip-metadata-version-check" else ""
+ " -moduleName " + args.moduleName
+ " -d " + args.destination
+ " -friendPaths " + args.friendPaths.joinToString(";")
+ " -classpath " + args.classpath
+ pluginClasspaths(args)
+ " " + sourceFiles.joinToString(" "))
logk(2, " Additional kotlinc arguments: "
+ " -moduleName " + args.moduleName
+ " -friendPaths " + args.friendPaths.joinToString(";"))
val collector = object : MessageCollector {
override fun clear() {
throw UnsupportedOperationException("not implemented")
@ -214,7 +232,6 @@ class KotlinCompiler @Inject constructor(
message: String, location: CompilerMessageLocation) {
if (severity.isError) {
"Couldn't compile file: ${dump(location, message)}".let { fullMessage ->
System.err.println(fullMessage)
throw KobaltException(fullMessage)
}
} else if (severity == CompilerMessageSeverity.WARNING && KobaltLogger.LOG_LEVEL >= 2) {
@ -224,28 +241,28 @@ class KotlinCompiler @Inject constructor(
}
}
}
System.setProperty("kotlin.incremental.compilation", "true")
// TODO: experimental should be removed as soon as it becomes standard
System.setProperty("kotlin.incremental.compilation.experimental", "true")
//
// System.setProperty("kotlin.incremental.compilation", "true")
// // TODO: experimental should be removed as soon as it becomes standard
// System.setProperty("kotlin.incremental.compilation.experimental", "true")
val result =
if (cliArgs.noIncrementalKotlin || Kobalt.context?.internalContext?.noIncrementalKotlin ?: false) {
log(2, " Kotlin incremental compilation is disabled")
val duration = benchmarkMillis {
compiler.exec(collector, Services.Builder().build(), args)
if (cliArgs.noIncrementalKotlin || Kobalt.context?.internalContext?.noIncrementalKotlin ?: false) {
log(2, " Kotlin incremental compilation is disabled")
val duration = benchmarkMillis {
compiler.exec(collector, Services.Builder().build(), args)
}
log(1, " Regular compilation time: ${duration.first} ms")
TaskResult(duration.second == ExitCode.OK)
} else {
log(1, " Kotlin incremental compilation is enabled")
val start = System.currentTimeMillis()
val duration = benchmarkMillis {
compileIncrementally(filesToCompile, sourceFiles, outputDir, info, args, collector)
}
log(1, " Incremental compilation time: ${duration.first} ms")
TaskResult()
}
log(1, " Regular compilation time: ${duration.first} ms")
TaskResult(duration.second == ExitCode.OK)
} else {
log(1, " Kotlin incremental compilation is enabled")
val start = System.currentTimeMillis()
val duration = benchmarkMillis {
compileIncrementally(filesToCompile, sourceFiles, outputDir, info, args, collector)
}
log(1, " Incremental compilation time: ${duration.first} ms")
TaskResult()
}
return result
}