Gradle Kotlin Android plugin first working variant

This commit is contained in:
Nikita Skvortsov
2013-07-08 19:40:35 +04:00
parent f5a88e851d
commit d5320adb02
7 changed files with 229 additions and 102 deletions
@@ -0,0 +1,5 @@
<root>
<item name='com.android.build.gradle.BaseExtension org.gradle.api.NamedDomainObjectContainer&lt;com.android.build.gradle.api.AndroidSourceSet&gt; getSourceSets()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item name="com.android.build.gradle.api.AndroidSourceSet org.gradle.api.file.SourceDirectorySet getAllJava()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="com.android.build.gradle.api.AndroidSourceSet org.gradle.api.file.SourceDirectorySet getAllSource()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="com.android.build.gradle.api.ApkVariant com.android.builder.DefaultBuildType getBuildType()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="com.android.build.gradle.api.ApkVariant java.util.List&lt;com.android.builder.DefaultProductFlavor&gt; getProductFlavors()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="com.android.build.gradle.api.LibraryVariant com.android.builder.DefaultBuildType getBuildType()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
</root>
@@ -1,18 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item name='org.gradle.api.Plugin void apply(T)'>
<annotation name='jet.runtime.typeinfo.KotlinSignature'>
<val name="value" val="&quot;fun apply(p0 : T) : Unit&quot;"/>
</annotation>
</item>
<item name='org.gradle.api.Project org.gradle.api.plugins.PluginContainer getPlugins()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='org.gradle.api.Project org.gradle.api.plugins.Convention getConvention()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='org.gradle.api.Project org.gradle.api.initialization.dsl.ScriptHandler getBuildscript()'>
<annotation name='jet.runtime.typeinfo.KotlinSignature'>
<val name="value" val="&quot;fun getBuildscript() : ScriptHandler&quot;"/>
</annotation>
</item>
</root>
<item name="org.gradle.api.NamedDomainObjectCollection T getByName(java.lang.String)">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="org.gradle.api.Plugin void apply(T)">
<annotation name="jet.runtime.typeinfo.KotlinSignature">
<val name="value" val="&quot;fun apply(p0 : T) : Unit&quot;" />
</annotation>
</item>
<item name="org.gradle.api.Project org.gradle.api.initialization.dsl.ScriptHandler getBuildscript()">
<annotation name="jet.runtime.typeinfo.KotlinSignature">
<val name="value" val="&quot;fun getBuildscript() : ScriptHandler&quot;" />
</annotation>
</item>
<item name="org.gradle.api.Project org.gradle.api.logging.Logger getLogger()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="org.gradle.api.Project org.gradle.api.plugins.Convention getConvention()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="org.gradle.api.Project org.gradle.api.plugins.PluginContainer getPlugins()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
</root>
@@ -1,15 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item name='org.gradle.api.internal.HasConvention org.gradle.api.plugins.Convention getConvention()'>
<annotation name='jet.runtime.typeinfo.KotlinSignature'>
<val name="value" val="&quot;fun getConvention() : Convention&quot;"/>
</annotation>
</item>
<item name='org.gradle.api.internal.AbstractTask org.gradle.api.logging.Logger getLogger()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='org.gradle.api.internal.AbstractTask org.gradle.api.Project getProject()'>
<annotation name='jet.runtime.typeinfo.KotlinSignature'>
<val name="value" val="&quot;fun getProject() : Project&quot;"/>
</annotation>
</item>
</root>
<item name="org.gradle.api.internal.AbstractTask org.gradle.api.Project getProject()">
<annotation name="jet.runtime.typeinfo.KotlinSignature">
<val name="value" val="&quot;fun getProject() : Project&quot;" />
</annotation>
</item>
<item name="org.gradle.api.internal.AbstractTask org.gradle.api.logging.Logger getLogger()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="org.gradle.api.internal.HasConvention org.gradle.api.plugins.Convention getConvention()">
<annotation name="jet.runtime.typeinfo.KotlinSignature">
<val name="value" val="&quot;fun getConvention() : Convention&quot;" />
</annotation>
</item>
</root>
@@ -1,22 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<root>
<item name='org.gradle.api.plugins.Convention java.util.Map&lt;java.lang.String,java.lang.Object&gt; getPlugins()'>
<annotation name='jet.runtime.typeinfo.KotlinSignature'>
<val name="value" val="&quot;fun getPlugins() : MutableMap&lt;String, Any&gt;&quot;"/>
</annotation>
</item>
<item name='org.gradle.api.plugins.Convention org.gradle.api.internal.DynamicObject getExtensionsAsDynamicObject()'>
<annotation name='org.jetbrains.annotations.NotNull'/>
<annotation name='jet.runtime.typeinfo.KotlinSignature'>
<val name="value" val="&quot;fun getExtensionsAsDynamicObject() : DynamicObject&quot;"/>
</annotation>
</item>
<item name='org.gradle.api.plugins.PluginContainer org.gradle.api.Plugin apply(java.lang.String)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='org.gradle.api.plugins.PluginContainer T apply(java.lang.Class&lt;T&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
<item name='org.gradle.api.plugins.Convention T getPlugin(java.lang.Class&lt;T&gt;)'>
<annotation name='org.jetbrains.annotations.NotNull'/>
</item>
</root>
<item name="org.gradle.api.plugins.Convention T getPlugin(java.lang.Class&lt;T&gt;)">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="org.gradle.api.plugins.Convention java.util.Map&lt;java.lang.String,java.lang.Object&gt; getPlugins()">
<annotation name="jet.runtime.typeinfo.KotlinSignature">
<val name="value" val="&quot;fun getPlugins() : MutableMap&lt;String, Any&gt;&quot;" />
</annotation>
</item>
<item name="org.gradle.api.plugins.Convention org.gradle.api.internal.DynamicObject getExtensionsAsDynamicObject()">
<annotation name="org.jetbrains.annotations.NotNull" />
<annotation name="jet.runtime.typeinfo.KotlinSignature">
<val name="value" val="&quot;fun getExtensionsAsDynamicObject() : DynamicObject&quot;" />
</annotation>
</item>
<item name="org.gradle.api.plugins.ExtensionAware org.gradle.api.plugins.ExtensionContainer getExtensions()">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="org.gradle.api.plugins.PluginContainer T apply(java.lang.Class&lt;T&gt;)">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
<item name="org.gradle.api.plugins.PluginContainer org.gradle.api.Plugin apply(java.lang.String)">
<annotation name="org.jetbrains.annotations.NotNull" />
</item>
</root>
@@ -4,18 +4,11 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.plugins.JavaPlugin
import groovy.lang.Closure
import org.gradle.api.tasks.SourceSet
import org.jetbrains.kotlin.gradle.internal.KotlinSourceSetImpl
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.internal.IConventionAware
import org.gradle.api.internal.HasConvention
import org.gradle.api.internal.file.collections.SimpleFileCollection
import org.gradle.api.file.FileTreeElement
import org.jetbrains.kotlin.gradle.internal.KotlinSourceSet
import org.gradle.api.file.SourceDirectorySet
import org.codehaus.groovy.runtime.MethodClosure
import org.gradle.api.specs.Spec
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.KDoc
@@ -23,14 +16,22 @@ import java.io.File
import java.util.concurrent.Callable
import org.gradle.api.Action
import org.gradle.api.tasks.compile.AbstractCompile
import java.util.Arrays
import org.gradle.api.logging.Logging
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.AppExtension
import com.android.build.gradle.LibraryExtension
import org.gradle.api.internal.DefaultDomainObjectSet
import com.android.build.gradle.api.BaseVariant
import org.gradle.api.tasks.compile.JavaCompile
import com.android.build.gradle.api.AndroidSourceSet
import org.gradle.api.plugins.ExtensionAware
import org.jetbrains.jet.cli.jvm.K2JVMCompilerArguments
import java.util.ArrayList
import com.android.build.gradle.BasePlugin
import com.android.build.gradle.api.LibraryVariant
import com.android.build.gradle.api.ApkVariant
import com.android.builder.model.BuildType
import com.android.builder.BuilderConstants
import com.android.build.gradle.api.TestVariant
open class KotlinPlugin: Plugin<Project> {
@@ -50,17 +51,15 @@ open class KotlinPlugin: Plugin<Project> {
javaPluginConvention: JavaPluginConvention) {
javaPluginConvention.getSourceSets()?.all(object : Action<SourceSet> {
override fun execute(sourceSet: SourceSet?) {
if (sourceSet is HasConvention) {
if (sourceSet is ExtensionAware) {
val sourceSetName = sourceSet.getName()
val kotlinSourceSet = KotlinSourceSetImpl(sourceSetName, project.getFileResolver())
val kotlinSourceSet = sourceSet.getExtensions().create("kotlin", javaClass<KotlinSourceSetImpl>(), sourceSetName, project.getFileResolver())!!
val kotlinDirSet = kotlinSourceSet.getKotlin()
kotlinDirSet.srcDir(project.file("src/${sourceSetName}/kotlin"))
sourceSet.getAllJava()?.source(kotlinDirSet)
sourceSet.getAllSource()?.source(kotlinDirSet)
sourceSet.getConvention().getPlugins().put("kotlin", kotlinSourceSet)
sourceSet.getResources()?.getFilter()?.exclude(KSpec({ elem ->
kotlinDirSet.contains(elem.getFile())
}))
@@ -116,61 +115,150 @@ open class KotlinPlugin: Plugin<Project> {
open class KotlinAndroidPlugin: Plugin<Project> {
val log = Logging.getLogger(getClass())!!
val log = Logging.getLogger(getClass())
public override fun apply(p0: Project) {
val project = p0 as ProjectInternal
val ext = project.getExtensions().getByName("android") as BaseExtension
ext.getSourceSets()?.all(object : Action<AndroidSourceSet> {
override fun execute(sourceSet: AndroidSourceSet?) {
if (sourceSet is ExtensionAware) {
val sourceSetName = sourceSet.getName()
val kotlinSourceSet = sourceSet.getExtensions().create("kotlin", javaClass<KotlinSourceSetImpl>(), sourceSetName, project.getFileResolver())!!
val kotlinDirSet = kotlinSourceSet.getKotlin()
kotlinDirSet.srcDir(project.file("src/${sourceSetName}/kotlin"))
sourceSet.getAllJava().source(kotlinDirSet)
sourceSet.getAllSource().source(kotlinDirSet)
sourceSet.getResources()?.getFilter()?.exclude(KSpec({ elem ->
kotlinDirSet.contains(elem.getFile())
}))
project.getLogger().debug("Created kotlin sourceDirectorySet at ${kotlinDirSet.getSrcDirs()}")
}
}
})
(ext as ExtensionAware).getExtensions().add("kotlinOptions", K2JVMCompilerArguments())
public override fun apply(project: Project) {
project.afterEvaluate( { (project: Project?): Unit ->
if (project != null) {
val extension = project.getExtensions()!!.getByName("android") as BaseExtension
val testVariants = extension.getTestVariants()!!
processVariants(testVariants, project)
if (extension is AppExtension) {
val appVariants = extension.getApplicationVariants()!!
processVariants(appVariants, project)
val testVariants = ext.getTestVariants()!!
processVariants(testVariants, project, ext)
if (ext is AppExtension) {
val appVariants = ext.getApplicationVariants()!!
processVariants(appVariants, project, ext)
}
if (extension is LibraryExtension) {
val libVariants = extension.getLibraryVariants()!!;
processVariants(libVariants, project)
if (ext is LibraryExtension) {
val libVariants = ext.getLibraryVariants()!!;
processVariants(libVariants, project, ext)
}
}
})
}
private fun processVariants(variants: DefaultDomainObjectSet<out BaseVariant>, project: Project): Unit {
private fun processVariants(variants: DefaultDomainObjectSet<out BaseVariant>, project: Project, androidExt: BaseExtension): Unit {
val logger = project.getLogger()
logger.debug("Kotlin plugin processing variants")
val kotlinOptions = (androidExt as ExtensionAware).getExtensions().getByName("kotlinOptions") as K2JVMCompilerArguments
val sourceSets = androidExt.getSourceSets()
val mainSourceSet = sourceSets.getByName(BuilderConstants.MAIN)
val testSourceSet = sourceSets.getByName(BuilderConstants.INSTRUMENT_TEST)
logger.debug("Loaded ${BuilderConstants.MAIN} and ${BuilderConstants.INSTRUMENT_TEST} source sets")
for (variant in variants) {
val javaTask = variant.getJavaCompile()!!
val destinationDir = javaTask.getDestinationDir()
val classPath = javaTask.getClasspath()
logger.debug("Processing variant [${variant}]")
if (variant is LibraryVariant || variant is ApkVariant) {
val buildType: BuildType = if (variant is LibraryVariant) {
variant.getBuildType()
} else {
(variant as ApkVariant).getBuildType()
}
val buildTypeSourceSetName = buildType.getName()
logger.debug("Variant build type is [$buildTypeSourceSetName]")
val buildTypeSourceSet : AndroidSourceSet? = sourceSets.findByName(buildTypeSourceSetName)
val javaTask = variant.getJavaCompile()!!
val variantName = variant.getName()
val kotlinTaskName = "compile${variantName}Kotlin"
val kotlinTask: KotlinCompile = project.getTasks()!!.add(kotlinTaskName, javaClass<KotlinCompile>())!!
kotlinTask.kotlinOptions = kotlinOptions
val variantName = variant.getName()
val kotlinTaskName = "compile${variantName}Kotlin"
val kotlinTask: KotlinCompile = project.getTasks()!!.add(kotlinTaskName, javaClass<KotlinCompile>())!!
// store kotlin classes in separate directory. They will serve as class-path to java compiler
val kotlinOutputDir = File(project.getBuildDir(), "kotlin-classes/${variantName}")
kotlinTask.kotlinDestinationDir = kotlinOutputDir;
kotlinTask.setDestinationDir(destinationDir)
kotlinTask.setDescription("Compiles the ${variantName} kotlin.")
// store kotlin classes in separate directory. They will serve as class-path to java compiler
val kotlinOutputDir = File(project.getBuildDir(), "kotlin-classes/${variantName}")
kotlinTask.kotlinDestinationDir = kotlinOutputDir;
kotlinTask.setDestinationDir(javaTask.getDestinationDir())
kotlinTask.setDescription("Compiles the ${variantName} kotlin.")
kotlinTask.setClasspath(javaTask.getClasspath())
kotlinTask.setDependsOn(javaTask.getDependsOn())
kotlinTask.source("src/main/kotlin")
kotlinTask.source(javaTask.getSource()) // for cross compilation
val javaSourceList = ArrayList<Any?>()
kotlinTask.setClasspath(javaTask.getClasspath())
kotlinTask.setDependsOn(javaTask.getDependsOn())
if (variant is TestVariant) {
javaSourceList.addAll(testSourceSet.getJava()!!.getSrcDirs()!!)
val testKotlinSource = (testSourceSet as ExtensionAware).getExtensions().getByName("kotlin") as KotlinSourceSet
logger.debug("Attaching ${testKotlinSource.getKotlin().getSrcDirs()} to variant ${variantName}")
kotlinTask.source(testKotlinSource.getKotlin())
} else {
javaSourceList.addAll(mainSourceSet.getJava()!!.getSrcDirs()!!)
val mainKotlinSource = (mainSourceSet as ExtensionAware).getExtensions().getByName("kotlin") as KotlinSourceSet
logger.debug("Attaching ${mainKotlinSource.getKotlin().getSrcDirs()} to variant ${variantName}")
kotlinTask.source(mainKotlinSource.getKotlin())
}
javaTask.dependsOn(kotlinTaskName)
val javacClassPath = javaTask.getClasspath() + project.files(kotlinTask.kotlinDestinationDir);
javaTask.setClasspath(javacClassPath)
if (null != buildTypeSourceSet) {
javaSourceList.add(buildTypeSourceSet.getJava()!!.getSrcDirs()!!)
kotlinTask.source(((buildTypeSourceSet as ExtensionAware).getExtensions().getByName("kotlin") as KotlinSourceSet).getKotlin())
}
javaSourceList.add(callable<File>{ variant.getProcessResources()!!.getSourceOutputDir()!! })
javaSourceList.add(callable<File>{ variant.getGenerateBuildConfig()!!.getSourceOutputDir()!! })
javaSourceList.add(callable<File>{ variant.getAidlCompile()!!.getSourceOutputDir()!! })
javaSourceList.add(callable<File>{ variant.getRenderscriptCompile()!!.getSourceOutputDir()!! })
if (variant is ApkVariant) {
for (flavour in variant.getProductFlavors().iterator()) {
val flavourSourceSetName = buildTypeSourceSetName + flavour.getName()
val flavourSourceSet : AndroidSourceSet? = sourceSets.findByName(flavourSourceSetName)
if (flavourSourceSet != null) {
javaSourceList.add(flavourSourceSet.getJava())
kotlinTask.source((buildTypeSourceSet as ExtensionAware).getExtensions().getByName("kotlin"))
}
}
}
logger.debug("Kotlin Source list for [${variantName}]")
kotlinTask.getSource().forEach { f -> logger.debug(f.getPath()) }
logger.debug("Kotlin Source list end")
val basePlugin : BasePlugin = project.getPlugins().getPlugin("android") as BasePlugin
kotlinTask.doFirst({ task ->
val javaSources = project.files(javaSourceList)
logger.debug("Java Source list for [${variantName}]")
javaSources?.forEach { f -> logger.debug(f.getPath()) }
logger.debug("Java Source list end")
val cp = javaTask.getClasspath() + javaSources
val cpWithRt = project.files(basePlugin.getRuntimeJarList())!! + cp
(task as AbstractCompile).setClasspath(cpWithRt)
logger.debug("Final Classpath for variant [${variantName}]")
cpWithRt?.forEach { f -> logger.debug(f.getPath()) }
logger.debug("Final Classpath end")
})
javaTask.dependsOn(kotlinTaskName)
val javacClassPath = javaTask.getClasspath() + project.files(kotlinTask.kotlinDestinationDir);
javaTask.setClasspath(javacClassPath)
}
}
}
private fun configureKotlinCompileTask(javaCompile : JavaCompile) : Unit {
}
}
open class KSpec<T: Any?>(val predicate: (T) -> Boolean): Spec<T> {
@@ -31,7 +31,7 @@ public open class KotlinCompile(): AbstractCompile() {
val compiler = K2JVMCompiler()
val logger = Logging.getLogger(getClass())
public val kotlinOptions: K2JVMCompilerArguments = K2JVMCompilerArguments();
public var kotlinOptions: K2JVMCompilerArguments = K2JVMCompilerArguments();
public var kotlinDestinationDir : File? = getDestinationDir()