Kapt: Gradle plugin for the new kapt

(cherry picked from commit f4fc8f1)
This commit is contained in:
Yan Zhulanow
2016-06-21 21:09:45 +03:00
committed by Yan Zhulanow
parent 399059729d
commit 407af3a0e5
13 changed files with 344 additions and 23 deletions
+50 -2
View File
@@ -765,6 +765,54 @@
<fileset dir="${basedir}/plugins/android-extensions/android-extensions-compiler/src" includes="META-INF/services/**"/>
</jar>
</target>
<target name="annotation-processing-under-jdk8">
<property environment="env"/>
<condition property="jdk18" value="${env.JDK_18}" else="${env.JAVA_HOME}">
<isset property="env.JDK_18" />
</condition>
<java classname="org.apache.tools.ant.launch.Launcher"
fork="true"
failonerror="true"
timeout="4000000"
taskname="startAnt"
jvm="${jdk18}/bin/java">
<env key="JAVA_HOME" value="${jdk18}"/>
<classpath>
<pathelement location="${ant.home}/lib/ant-launcher.jar"/>
</classpath>
<arg line="-f" />
<arg line="build.xml" />
<arg line="annotation-processing" />
</java>
</target>
<target name="annotation-processing">
<cleandir dir="${output}/classes/annotation-processing"/>
<javac2 destdir="${output}/classes/annotation-processing" debug="true" debuglevel="lines,vars,source" includeAntRuntime="false">
<withKotlin modulename="annotation-processing">
<compilerarg value="-version"/>
</withKotlin>
<skip pattern="kotlin/Metadata"/>
<src>
<pathelement path="plugins/annotation-processing/src"/>
<pathelement path="plugins/java-model-wrappers/src"/>
</src>
<classpath>
<pathelement path="${idea.sdk}/core/intellij-core.jar"/>
<pathelement path="${kotlin-home}/lib/kotlin-compiler.jar"/>
<pathelement path="${bootstrap.runtime}"/>
<pathelement path="${bootstrap.reflect}"/>
</classpath>
</javac2>
<jar destfile="${kotlin-home}/lib/kotlin-annotation-processing.jar">
<fileset dir="${output}/classes/annotation-processing"/>
<zipfileset file="${kotlin-home}/build.txt" prefix="META-INF"/>
<fileset dir="${basedir}/plugins/annotation-processing/src" includes="META-INF/services/**"/>
</jar>
</target>
<target name="ant-tools">
<cleandir dir="${output}/classes/ant"/>
@@ -1093,11 +1141,11 @@
depends="builtins,stdlib,kotlin-test,core,reflection,pack-runtime,pack-runtime-sources,mock-runtime-for-test"/>
<target name="dist"
depends="clean,init,prepare-dist,preloader,runner,serialize-builtins,compiler,compiler-sources,kotlin-build-common,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,daemon-client,kotlin-build-common-test"
depends="clean,init,prepare-dist,preloader,runner,serialize-builtins,compiler,compiler-sources,kotlin-build-common,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,annotation-processing-under-jdk8,daemon-client,kotlin-build-common-test"
description="Builds redistributables from sources"/>
<target name="dist-quick"
depends="clean,init,prepare-dist,preloader,serialize-builtins,compiler-quick,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler"
depends="clean,init,prepare-dist,preloader,serialize-builtins,compiler-quick,ant-tools,runtime,kotlin-js-stdlib,android-extensions-compiler,annotation-processing-under-jdk8"
description="Builds everything, but classes are reused from project out dir, doesn't run proguard and javadoc"/>
<target name="dist-quick-compiler-only"
+4
View File
@@ -91,6 +91,10 @@ messages/**)
public InputStream getInputStream();
}
-keep class com.intellij.openapi.vfs.StandardFileSystems {
public static *;
}
# needed for jar cache cleanup in the gradle plugin and compile daemon
-keepclassmembers class com.intellij.openapi.vfs.impl.ZipHandler {
public static void clearFileAccessorCache();
@@ -18,16 +18,23 @@ package example
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
public class ExampleSubplugin : KotlinGradleSubplugin {
class ExampleSubplugin : KotlinGradleSubplugin {
override fun isApplicable(project: Project, task: AbstractCompile): Boolean {
return true
}
override fun getExtraArguments(project: Project, task: AbstractCompile): List<SubpluginOption> {
override fun apply(
project: Project,
kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile?,
variantData: Any?,
javaSourceSet: SourceSet?
): List<SubpluginOption> {
println("ExampleSubplugin loaded")
return listOf(SubpluginOption("exampleKey", "exampleValue"))
}
+87 -2
View File
@@ -6,6 +6,12 @@
<modelVersion>4.0.0</modelVersion>
<properties>
<maven.version>3.0.4</maven.version>
<old-kapt.src>${basedir}/src/main/kotlin</old-kapt.src>
<annotation-processing.src>${basedir}/../../../plugins/annotation-processing/src</annotation-processing.src>
<java-model-wrappers.src>${basedir}/../../../plugins/java-model-wrappers/src</java-model-wrappers.src>
<annotation-processing.target-src>${basedir}/target/src/main/kotlin</annotation-processing.target-src>
<annotation-processing.target-src-test>${basedir}/target/src/test/kotlin</annotation-processing.target-src-test>
<annotation-processing.target-resource>${basedir}/target/resource</annotation-processing.target-resource>
</properties>
<parent>
@@ -33,6 +39,12 @@
<artifactId>kotlin-stdlib</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-compiler-embeddable</artifactId>
<version>${project.version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>gradle-api</artifactId>
@@ -48,15 +60,79 @@
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<sourceDirectory>${annotation-processing.target-src}</sourceDirectory>
<testSourceDirectory>${annotation-processing.target-src-test}</testSourceDirectory>
<resources>
<resource>
<directory>${annotation-processing.target-resource}</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>copy-sources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${annotation-processing.target-src}</outputDirectory>
<resources>
<resource><directory>${annotation-processing.src}</directory></resource>
<resource><directory>${java-model-wrappers.src}</directory></resource>
<resource><directory>${old-kapt.src}</directory></resource>
</resources>
</configuration>
</execution>
<execution>
<id>copy-resources</id>
<phase>validate</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${annotation-processing.target-resource}/META-INF</outputDirectory>
<resources>
<resource><directory>${annotation-processing.src}/META-INF</directory></resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.google.code.maven-replacer-plugin</groupId>
<artifactId>replacer</artifactId>
<version>1.5.3</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>replace</goal>
</goals>
</execution>
</executions>
<configuration>
<includes>
<include>${annotation-processing.target-src}/**</include>
</includes>
<replacements>
<replacement>
<token>com\.intellij</token>
<value>org.jetbrains.kotlin.com.intellij</value>
</replacement>
</replacements>
</configuration>
</plugin>
<plugin>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
<version>${project.version}</version>
<configuration>
<jdkHome>${env.JDK_18}</jdkHome>
<annotationPaths>
<annotationPath>${basedir}/kotlinAnnotation</annotationPath>
</annotationPaths>
@@ -67,6 +143,11 @@
<id>compile</id>
<phase>compile</phase>
<goals> <goal>compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${annotation-processing.target-src}</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
@@ -76,6 +157,10 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.6</version>
@@ -17,14 +17,23 @@
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Project
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile
public class SubpluginOption(val key: String, val value: String)
class SubpluginOption(val key: String, val value: String)
public interface KotlinGradleSubplugin {
public fun isApplicable(project: Project, task: AbstractCompile): Boolean
public fun getExtraArguments(project: Project, task: AbstractCompile): List<SubpluginOption>
public fun getPluginName(): String
public fun getGroupName(): String
public fun getArtifactName(): String
}
interface KotlinGradleSubplugin {
fun isApplicable(project: Project, task: AbstractCompile): Boolean
fun apply(
project: Project,
kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile?,
variantData: Any?,
javaSourceSet: SourceSet?
): List<SubpluginOption>
fun getPluginName(): String
fun getGroupName(): String
fun getArtifactName(): String
}
@@ -21,6 +21,7 @@ import com.android.build.gradle.api.AndroidSourceSet
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.UnknownDomainObjectException
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
@@ -58,7 +59,13 @@ class AndroidSubplugin : KotlinGradleSubplugin {
return true
}
override fun getExtraArguments(project: Project, task: AbstractCompile): List<SubpluginOption> {
override fun apply(
project: Project,
kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile?,
variantData: Any?,
javaSourceSet: SourceSet?
): List<SubpluginOption> {
val androidExtension = project.extensions.getByName("android") as? BaseExtension ?: return emptyList()
val sourceSets = androidExtension.sourceSets
@@ -63,7 +63,7 @@ fun Project.initKapt(
kotlinAfterJavaTask.source(kaptManager.generatedKotlinSourceDir)
kotlinAfterJavaTask.source(kaptManager.aptOutputDir)
subpluginEnvironment.addSubpluginArguments(this, kotlinAfterJavaTask)
subpluginEnvironment.addSubpluginArguments(this, kotlinAfterJavaTask, javaTask, null, null)
javaTask.doLast {
moveGeneratedJavaFilesToCorrespondingDirectories(kaptManager.aptOutputDir)
@@ -0,0 +1,150 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.gradle.internal
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.api.AndroidSourceSet
import com.android.build.gradle.internal.variant.BaseVariantData
import com.android.builder.model.SourceProvider
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.UnknownDomainObjectException
import org.gradle.api.artifacts.Configuration
import org.gradle.api.internal.HasConvention
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.tasks.compile.JavaCompile
import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin
import org.jetbrains.kotlin.gradle.plugin.SubpluginOption
import java.io.File
// apply plugin: 'kotlin-kapt2'
class Kapt2GradleSubplugin : Plugin<Project> {
private val kapt2Configurations = mutableMapOf<Project, MutableMap<String, Configuration>>()
fun getConfigurations(project: Project): Map<String, Configuration> = kapt2Configurations[project] ?: emptyMap()
override fun apply(project: Project) {
val androidExt = project.extensions.findByName("android") as? BaseExtension
if (androidExt != null) {
androidExt.sourceSets.all { sourceSet ->
addKapt2Configuration(project, sourceSet.name)
}
}
else {
val javaPluginConvention = project.convention.getPlugin(JavaPluginConvention::class.java)
javaPluginConvention.sourceSets.all { sourceSet ->
addKapt2Configuration(project, sourceSet.name)
}
}
}
private fun addKapt2Configuration(project: Project, sourceSetName: String) {
val aptConfigurationName = if (sourceSetName != "main") "kapt2${sourceSetName.capitalize()}" else "kapt2"
val configuration = project.configurations.create(aptConfigurationName)
kapt2Configurations.getOrPut(project, { mutableMapOf() }).put(sourceSetName, configuration)
}
}
// Subplugin for the Kotlin Gradle plugin
class Kapt2KotlinGradleSubplugin : KotlinGradleSubplugin {
private companion object {
val VERBOSE_OPTION_NAME = "kapt2.verbose"
}
override fun isApplicable(project: Project, task: AbstractCompile): Boolean {
return project.plugins.findPlugin(Kapt2GradleSubplugin::class.java) != null
}
fun getKaptGeneratedDir(project: Project, sourceSetName: String): File {
return File(project.project.buildDir, "generated/source/kapt2/$sourceSetName")
}
override fun apply(
project: Project,
kotlinCompile: AbstractCompile,
javaCompile: AbstractCompile?,
variantData: Any?,
javaSourceSet: SourceSet?
): List<SubpluginOption> {
//assertion only one variantData / javaSourceSet
// delete
if (javaCompile == null) error("Java compile task should exist")
val kapt2Configurations = project.plugins.findPlugin(Kapt2GradleSubplugin::class.java).getConfigurations(project)
val pluginOptions = mutableListOf<SubpluginOption>()
val kaptClasspath = arrayListOf<File>()
val generatedFilesDir = if (variantData != null) {
variantData as BaseVariantData<*>
for (provider in variantData.sourceProviders) {
val kapt2Configuration = kapt2Configurations[(provider as AndroidSourceSet).name]
// extract & java
if (kapt2Configuration != null && kapt2Configuration.dependencies.size > 0) {
javaCompile.dependsOn(kapt2Configuration.buildDependencies)
kaptClasspath.addAll(kapt2Configuration.resolve())
}
}
getKaptGeneratedDir(project, variantData.name).apply { variantData.addJavaSourceFoldersToModel(this) }
}
else if (javaSourceSet != null) {
val kapt2Configuration = kapt2Configurations[javaSourceSet.name]
if (kapt2Configuration != null && kapt2Configuration.dependencies.size > 0) {
javaCompile.dependsOn(kapt2Configuration.buildDependencies)
kaptClasspath.addAll(kapt2Configuration.resolve())
}
getKaptGeneratedDir(project, javaSourceSet.name)
}
else {
throw IllegalArgumentException("variantData or javaSourceSet should be provided")
}
// Skip annotation processing in kotlinc if no kapt dependencies were provided
if (kaptClasspath.isEmpty()) return emptyList()
kaptClasspath.forEach { pluginOptions += SubpluginOption("apclasspath", it.absolutePath) }
javaCompile.source(generatedFilesDir)
// Completely disable annotation processing in Java
(javaCompile as? JavaCompile)?.let { javaCompile ->
val options = javaCompile.options
options.compilerArgs = options.compilerArgs.filter { !it.startsWith("-proc:") } + "-proc:none"
}
pluginOptions += SubpluginOption("generated", generatedFilesDir.canonicalPath)
pluginOptions += SubpluginOption("classes", kotlinCompile.destinationDir.canonicalPath)
if (project.hasProperty(VERBOSE_OPTION_NAME) && project.property(VERBOSE_OPTION_NAME) == "true") {
pluginOptions += SubpluginOption("verbose", "true")
}
return pluginOptions
}
private val BaseVariantData<*>.sourceProviders: List<SourceProvider>
get() = variantConfiguration.sortedSourceProviders
override fun getPluginName() = "org.jetbrains.kotlin.kapt2"
override fun getGroupName() = "org.jetbrains.kotlin"
override fun getArtifactName() = "kotlin-annotation-processing"
}
@@ -125,10 +125,12 @@ class Kotlin2JvmSourceSetProcessor(
project.afterEvaluate { project ->
if (project != null) {
val subpluginEnvironment = loadSubplugins(project)
subpluginEnvironment.addSubpluginArguments(project, kotlinTask)
val javaTask = project.tasks.findByName(sourceSet.compileJavaTaskName)
val subpluginEnvironment = loadSubplugins(project)
subpluginEnvironment.addSubpluginArguments(project, kotlinTask,
javaTask as? AbstractCompile, null, sourceSet)
if (javaTask !is JavaCompile) return@afterEvaluate
var kotlinAfterJavaTask: KotlinCompile? = null
@@ -340,7 +342,7 @@ open class KotlinAndroidPlugin(
}
}
subpluginEnvironment.addSubpluginArguments(project, kotlinTask)
subpluginEnvironment.addSubpluginArguments(project, kotlinTask, javaTask, variantData, null)
kotlinTask.mapClasspath { javaTask.classpath + project.files(AndroidGradleWrapper.getRuntimeJars(androidPlugin, androidExt)) }
val (aptOutputDir, aptWorkingDir) = project.getAptDirsForSourceSet(variantDataName)
variantData.addJavaSourceFoldersToModel(aptOutputDir)
@@ -471,7 +473,12 @@ class SubpluginEnvironment(
val subplugins: List<KotlinGradleSubplugin>
) {
fun addSubpluginArguments(project: Project, kotlinTask: KotlinCompile) {
fun addSubpluginArguments(
project: Project,
kotlinTask: KotlinCompile,
javaTask: AbstractCompile?,
variantData: Any?,
javaSourceSet: SourceSet?) {
val pluginOptions = kotlinTask.pluginOptions
for (subplugin in subplugins) {
@@ -484,7 +491,7 @@ class SubpluginEnvironment(
val subpluginClasspath = subpluginClasspaths[subplugin] ?: continue
subpluginClasspath.forEach { pluginOptions.addClasspathEntry(it) }
for (arg in subplugin.getExtraArguments(project, kotlinTask)) {
for (arg in subplugin.apply(project, kotlinTask, javaTask, variantData, javaSourceSet)) {
pluginOptions.addPluginArgument(subplugin.getPluginName(), arg.key, arg.value)
}
}
@@ -0,0 +1 @@
implementation-class=org.jetbrains.kotlin.gradle.internal.Kapt2GradleSubplugin
@@ -1 +1,2 @@
org.jetbrains.kotlin.gradle.internal.AndroidSubplugin
org.jetbrains.kotlin.gradle.internal.AndroidSubplugin
org.jetbrains.kotlin.gradle.internal.Kapt2KotlinGradleSubplugin
@@ -0,0 +1 @@
org.jetbrains.kotlin.annotation.processing.AnnotationProcessingCommandLineProcessor
@@ -0,0 +1 @@
org.jetbrains.kotlin.annotation.processing.AnnotationProcessingComponentRegistrar