Kotlin2Js Gradle plugin implementation
This commit is contained in:
committed by
Zalim Bashorov
parent
ec47cb57c5
commit
b1723668ce
+218
-49
@@ -35,10 +35,187 @@ import org.gradle.api.UnknownDomainObjectException
|
|||||||
import org.gradle.api.initialization.dsl.ScriptHandler
|
import org.gradle.api.initialization.dsl.ScriptHandler
|
||||||
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
import org.jetbrains.kotlin.gradle.plugin.android.AndroidGradleWrapper
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||||
|
import org.gradle.api.tasks.Copy
|
||||||
|
import org.gradle.api.file.SourceDirectorySet
|
||||||
|
import kotlin.properties.Delegates
|
||||||
|
import org.gradle.api.tasks.Delete
|
||||||
|
import org.codehaus.groovy.runtime.MethodClosure
|
||||||
|
import groovy.lang.Closure
|
||||||
|
import org.gradle.api.artifacts.ProjectDependency
|
||||||
|
|
||||||
val DEFAULT_ANNOTATIONS = "org.jebrains.kotlin.gradle.defaultAnnotations"
|
val DEFAULT_ANNOTATIONS = "org.jebrains.kotlin.gradle.defaultAnnotations"
|
||||||
|
|
||||||
open class KotlinPlugin [Inject] (val scriptHandler: ScriptHandler): Plugin<Project> {
|
|
||||||
|
abstract class KotlinSourceSetProcessor<T : AbstractCompile>(val project: ProjectInternal,
|
||||||
|
val javaBasePlugin: JavaBasePlugin,
|
||||||
|
val sourceSet: SourceSet,
|
||||||
|
val pluginName: String,
|
||||||
|
val compileTaskNameSuffix: String,
|
||||||
|
val taskDescription: String,
|
||||||
|
val compilerClass: Class<T>) {
|
||||||
|
abstract protected fun doTargetSpecificProcessing()
|
||||||
|
val logger = Logging.getLogger(this.javaClass)
|
||||||
|
|
||||||
|
protected val sourceSetName: String = sourceSet.getName()
|
||||||
|
protected val sourceRootDir: String = "src/${sourceSetName}/kotlin"
|
||||||
|
protected val absoluteSourceRootDir: String = project.getProjectDir().getPath() + "/" + sourceRootDir
|
||||||
|
protected val kotlinSourceSet: KotlinSourceSet? by Delegates.lazy { createKotlinSourceSet() }
|
||||||
|
protected val kotlinDirSet: SourceDirectorySet? by Delegates.lazy { createKotlinDirSet() }
|
||||||
|
protected val kotlinTask: T by Delegates.lazy { createKotlinCompileTask() }
|
||||||
|
protected val kotlinTaskName: String by Delegates.lazy { kotlinTask.getName() }
|
||||||
|
|
||||||
|
public fun run() {
|
||||||
|
if (kotlinSourceSet == null || kotlinDirSet == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
addSourcesToKotlinDirSet()
|
||||||
|
commonTaskConfiguration()
|
||||||
|
doTargetSpecificProcessing()
|
||||||
|
}
|
||||||
|
|
||||||
|
open protected fun createKotlinSourceSet(): KotlinSourceSet? =
|
||||||
|
if (sourceSet is HasConvention) {
|
||||||
|
logger.debug("Creating KotlinSourceSet for source set ${sourceSet}")
|
||||||
|
val kotlinSourceSet = KotlinSourceSetImpl(sourceSet.getName(), project.getFileResolver())
|
||||||
|
sourceSet.getConvention().getPlugins().put(pluginName, kotlinSourceSet)
|
||||||
|
kotlinSourceSet
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
open protected fun createKotlinDirSet(): SourceDirectorySet? {
|
||||||
|
val srcDir = project.file(sourceRootDir)
|
||||||
|
logger.debug("Creating Kotlin SourceDirectorySet for source set ${kotlinSourceSet} with src dir ${srcDir}")
|
||||||
|
val kotlinDirSet = kotlinSourceSet?.getKotlin()
|
||||||
|
kotlinDirSet?.srcDir(srcDir)
|
||||||
|
return kotlinDirSet
|
||||||
|
}
|
||||||
|
|
||||||
|
open protected fun addSourcesToKotlinDirSet() {
|
||||||
|
logger.debug("Adding Kotlin SourceDirectorySet ${kotlinDirSet} to source set ${sourceSet}")
|
||||||
|
sourceSet.getAllJava()?.source(kotlinDirSet)
|
||||||
|
sourceSet.getAllSource()?.source(kotlinDirSet)
|
||||||
|
sourceSet.getResources()?.getFilter()?.exclude { kotlinDirSet!!.contains(it.getFile()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
open protected fun createKotlinCompileTask(): T {
|
||||||
|
val name = sourceSet.getCompileTaskName(compileTaskNameSuffix)
|
||||||
|
logger.debug("Creating kotlin compile task $name with class $compilerClass")
|
||||||
|
return project.getTasks().create(name, compilerClass)
|
||||||
|
}
|
||||||
|
|
||||||
|
open protected fun commonTaskConfiguration() {
|
||||||
|
javaBasePlugin.configureForSourceSet(sourceSet, kotlinTask)
|
||||||
|
kotlinTask.setDescription(taskDescription)
|
||||||
|
kotlinTask.source(kotlinDirSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Kotlin2JvmSourceSetProcessor(
|
||||||
|
project: ProjectInternal,
|
||||||
|
javaBasePlugin: JavaBasePlugin,
|
||||||
|
sourceSet: SourceSet,
|
||||||
|
val scriptHandler: ScriptHandler)
|
||||||
|
: KotlinSourceSetProcessor<KotlinCompile>(
|
||||||
|
project, javaBasePlugin, sourceSet,
|
||||||
|
pluginName = "kotlin",
|
||||||
|
compileTaskNameSuffix = "kotlin",
|
||||||
|
taskDescription = "Compiles the $sourceSet.kotlin.",
|
||||||
|
compilerClass = javaClass()) {
|
||||||
|
|
||||||
|
override fun doTargetSpecificProcessing() {
|
||||||
|
// store kotlin classes in separate directory. They will serve as class-path to java compiler
|
||||||
|
kotlinTask.kotlinDestinationDir = File(project.getBuildDir(), "kotlin-classes/${sourceSetName}")
|
||||||
|
|
||||||
|
val javaTask = project.getTasks().findByName(sourceSet.getCompileJavaTaskName()) as AbstractCompile?
|
||||||
|
|
||||||
|
if (javaTask != null) {
|
||||||
|
javaTask.dependsOn(kotlinTaskName)
|
||||||
|
val javacClassPath = javaTask.getClasspath() + project.files(kotlinTask.kotlinDestinationDir);
|
||||||
|
javaTask.setClasspath(javacClassPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class Kotlin2JsSourceSetProcessor(
|
||||||
|
project: ProjectInternal,
|
||||||
|
javaBasePlugin: JavaBasePlugin,
|
||||||
|
sourceSet: SourceSet,
|
||||||
|
val scriptHandler: ScriptHandler
|
||||||
|
) : KotlinSourceSetProcessor<Kotlin2JsCompile>(
|
||||||
|
project, javaBasePlugin, sourceSet,
|
||||||
|
pluginName = "kotlin2js",
|
||||||
|
taskDescription = "Compiles the kotlin sources in $sourceSet to JavaScript.",
|
||||||
|
compileTaskNameSuffix = "kotlin2Js",
|
||||||
|
compilerClass = javaClass<Kotlin2JsCompile>()) {
|
||||||
|
val copyKotlinJsTaskName = sourceSet.getTaskName("copy", "kotlinJs")
|
||||||
|
val clean = project.getTasks().findByName("clean")
|
||||||
|
val build = project.getTasks().findByName("build")
|
||||||
|
|
||||||
|
val defaultKotlinDestinationDir = File(project.getBuildDir(), "kotlin2js/${sourceSetName}")
|
||||||
|
private fun kotlinTaskDestinationDir(): File? = kotlinTask.kotlinDestinationDir
|
||||||
|
private fun kotlinJsDestinationDir(): File? = if (kotlinTask.outputFile() == null) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
File(kotlinTask.outputFile()).directory
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun copyKotlinJsTaskOutput(): String? = if (kotlinJsDestinationDir() == null) {
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
val copyTask = project.getTasks().getByName(copyKotlinJsTaskName) as Copy
|
||||||
|
"${copyTask.getDestinationDir()}/kotlin.js"
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun kotlinSourcePathsForSourceMap() = sourceSet.getAllSource()
|
||||||
|
.map { it.path }
|
||||||
|
.filter { it.endsWith(".kt") }
|
||||||
|
.map { it.replace(absoluteSourceRootDir, kotlinTask.sourceMapDestinationDir().getPath()) }
|
||||||
|
|
||||||
|
private fun shouldGenerateSourceMap() = kotlinTask.kotlinOptions.sourceMap
|
||||||
|
|
||||||
|
override fun doTargetSpecificProcessing() {
|
||||||
|
kotlinTask.kotlinDestinationDir = defaultKotlinDestinationDir
|
||||||
|
build?.dependsOn(kotlinTaskName)
|
||||||
|
clean?.dependsOn("clean" + kotlinTaskName.capitalize())
|
||||||
|
|
||||||
|
createCopyKotlinJsTask(GradleUtils(scriptHandler, project).resolveJsLibrary().getAbsolutePath())
|
||||||
|
createCleanSourceMapTask()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCopyKotlinJsTask(jsLibraryJar: String) {
|
||||||
|
val copyKotlinJsTaskName = sourceSet.getTaskName("copy", "kotlinJs")
|
||||||
|
|
||||||
|
val copyKotlinJsTask = project.getTasks().create(copyKotlinJsTaskName, javaClass<Copy>())
|
||||||
|
copyKotlinJsTask.from(project.zipTree(jsLibraryJar))
|
||||||
|
copyKotlinJsTask.into(MethodClosure(this, "kotlinJsDestinationDir"))
|
||||||
|
copyKotlinJsTask.include("kotlin.js")
|
||||||
|
copyKotlinJsTask.onlyIf { kotlinJsDestinationDir() != null }
|
||||||
|
build?.dependsOn(copyKotlinJsTaskName)
|
||||||
|
|
||||||
|
val cleanTaskName = "clean" + copyKotlinJsTaskName.capitalize()
|
||||||
|
val cleanTask = project.getTasks().create(cleanTaskName, javaClass<Delete>())
|
||||||
|
cleanTask.delete(MethodClosure(this, "copyKotlinJsTaskOutput"))
|
||||||
|
copyKotlinJsTask.onlyIf { copyKotlinJsTaskOutput() != null }
|
||||||
|
clean?.dependsOn(cleanTaskName)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createCleanSourceMapTask() {
|
||||||
|
val taskName = sourceSet.getTaskName("clean", "sourceMap")
|
||||||
|
val task = project.getTasks().create(taskName, javaClass<Delete>())
|
||||||
|
task.onlyIf { kotlinTask.kotlinOptions.sourceMap }
|
||||||
|
task.delete(object : Closure<String>(this) {
|
||||||
|
override fun call(): String? = kotlinTask.outputFile() + ".map"
|
||||||
|
})
|
||||||
|
clean?.dependsOn(taskName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
abstract class AbstractKotlinPlugin [Inject] (val scriptHandler: ScriptHandler) : Plugin<Project> {
|
||||||
|
abstract fun buildSourceSetProcessor(project: ProjectInternal, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet): KotlinSourceSetProcessor<*>
|
||||||
|
|
||||||
public override fun apply(project: Project) {
|
public override fun apply(project: Project) {
|
||||||
val javaBasePlugin = project.getPlugins().apply(javaClass<JavaBasePlugin>())
|
val javaBasePlugin = project.getPlugins().apply(javaClass<JavaBasePlugin>())
|
||||||
@@ -49,49 +226,23 @@ open class KotlinPlugin [Inject] (val scriptHandler: ScriptHandler): Plugin<Proj
|
|||||||
configureSourceSetDefaults(project as ProjectInternal, javaBasePlugin, javaPluginConvention)
|
configureSourceSetDefaults(project as ProjectInternal, javaBasePlugin, javaPluginConvention)
|
||||||
configureKDoc(project, javaPluginConvention)
|
configureKDoc(project, javaPluginConvention)
|
||||||
|
|
||||||
val version = project.getProperties()["kotlin.gradle.plugin.version"] as String
|
val gradleUtils = GradleUtils(scriptHandler, project)
|
||||||
project.getExtensions().add(DEFAULT_ANNOTATIONS, GradleUtils(scriptHandler).resolveDependencies("org.jetbrains.kotlin:kotlin-jdk-annotations:$version"))
|
project.getExtensions().add(DEFAULT_ANNOTATIONS, gradleUtils.resolveKotlinPluginDependency("kotlin-jdk-annotations"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open protected fun configureSourceSetDefaults(project: ProjectInternal,
|
||||||
private fun configureSourceSetDefaults(project: ProjectInternal,
|
javaBasePlugin: JavaBasePlugin,
|
||||||
javaBasePlugin: JavaBasePlugin,
|
javaPluginConvention: JavaPluginConvention) {
|
||||||
javaPluginConvention: JavaPluginConvention) {
|
javaPluginConvention.getSourceSets()?.all(object : Action<SourceSet> {
|
||||||
javaPluginConvention.getSourceSets()?.all(Action<SourceSet> { sourceSet ->
|
override fun execute(sourceSet: SourceSet?) {
|
||||||
if (sourceSet is HasConvention) {
|
if (sourceSet != null) {
|
||||||
val sourceSetName = sourceSet.getName()
|
buildSourceSetProcessor(project, javaBasePlugin, sourceSet).run()
|
||||||
val kotlinSourceSet = KotlinSourceSetImpl( sourceSetName, project.getFileResolver())
|
|
||||||
sourceSet.getConvention().getPlugins().put("kotlin", kotlinSourceSet)
|
|
||||||
|
|
||||||
val kotlinDirSet = kotlinSourceSet.getKotlin()
|
|
||||||
kotlinDirSet.srcDir(project.file("src/${sourceSetName}/kotlin"))
|
|
||||||
|
|
||||||
sourceSet.getAllJava()?.source(kotlinDirSet)
|
|
||||||
sourceSet.getAllSource()?.source(kotlinDirSet)
|
|
||||||
sourceSet.getResources()?.getFilter()?.exclude({ kotlinDirSet.contains(it.getFile()) })
|
|
||||||
|
|
||||||
val kotlinTaskName = sourceSet.getCompileTaskName("kotlin")
|
|
||||||
val kotlinTask: KotlinCompile = project.getTasks().create(kotlinTaskName, javaClass<KotlinCompile>())
|
|
||||||
|
|
||||||
javaBasePlugin.configureForSourceSet(sourceSet, kotlinTask)
|
|
||||||
// store kotlin classes in separate directory. They will serve as class-path to java compiler
|
|
||||||
kotlinTask.kotlinDestinationDir = File(project.getBuildDir(), "kotlin-classes/${sourceSetName}")
|
|
||||||
|
|
||||||
kotlinTask.setDescription("Compiles the $sourceSet.kotlin.")
|
|
||||||
kotlinTask.source(kotlinDirSet)
|
|
||||||
|
|
||||||
val javaTask = project.getTasks().findByName(sourceSet.getCompileJavaTaskName()) as AbstractCompile?
|
|
||||||
|
|
||||||
if (javaTask != null) {
|
|
||||||
javaTask.dependsOn(kotlinTaskName)
|
|
||||||
val javacClassPath = javaTask.getClasspath() + project.files(kotlinTask.kotlinDestinationDir)
|
|
||||||
javaTask.setClasspath(javacClassPath)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun configureKDoc(project: Project, javaPluginConvention: JavaPluginConvention) {
|
open protected fun configureKDoc(project: Project, javaPluginConvention: JavaPluginConvention) {
|
||||||
val mainSourceSet = javaPluginConvention.getSourceSets()?.findByName(SourceSet.MAIN_SOURCE_SET_NAME) as HasConvention?
|
val mainSourceSet = javaPluginConvention.getSourceSets()?.findByName(SourceSet.MAIN_SOURCE_SET_NAME) as HasConvention?
|
||||||
|
|
||||||
if (mainSourceSet != null) {
|
if (mainSourceSet != null) {
|
||||||
@@ -113,7 +264,19 @@ open class KotlinPlugin [Inject] (val scriptHandler: ScriptHandler): Plugin<Proj
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open class KotlinAndroidPlugin [Inject] (val scriptHandler: ScriptHandler): Plugin<Project> {
|
open class KotlinPlugin [Inject] (scriptHandler: ScriptHandler) : AbstractKotlinPlugin(scriptHandler) {
|
||||||
|
override fun buildSourceSetProcessor(project: ProjectInternal, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet): KotlinSourceSetProcessor<KotlinCompile> =
|
||||||
|
Kotlin2JvmSourceSetProcessor(project, javaBasePlugin, sourceSet, scriptHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open class Kotlin2JsPlugin [Inject] (scriptHandler: ScriptHandler) : AbstractKotlinPlugin(scriptHandler) {
|
||||||
|
override fun buildSourceSetProcessor(project: ProjectInternal, javaBasePlugin: JavaBasePlugin, sourceSet: SourceSet) =
|
||||||
|
Kotlin2JsSourceSetProcessor(project, javaBasePlugin, sourceSet, scriptHandler)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
open class KotlinAndroidPlugin [Inject] (val scriptHandler: ScriptHandler) : Plugin<Project> {
|
||||||
|
|
||||||
val log = Logging.getLogger(this.javaClass)
|
val log = Logging.getLogger(this.javaClass)
|
||||||
|
|
||||||
@@ -125,7 +288,7 @@ open class KotlinAndroidPlugin [Inject] (val scriptHandler: ScriptHandler): Plug
|
|||||||
ext.getSourceSets().all(Action<AndroidSourceSet> { sourceSet ->
|
ext.getSourceSets().all(Action<AndroidSourceSet> { sourceSet ->
|
||||||
if (sourceSet is HasConvention) {
|
if (sourceSet is HasConvention) {
|
||||||
val sourceSetName = sourceSet.getName()
|
val sourceSetName = sourceSet.getName()
|
||||||
val kotlinSourceSet = KotlinSourceSetImpl( sourceSetName, project.getFileResolver())
|
val kotlinSourceSet = KotlinSourceSetImpl(sourceSetName, project.getFileResolver())
|
||||||
sourceSet.getConvention().getPlugins().put("kotlin", kotlinSourceSet)
|
sourceSet.getConvention().getPlugins().put("kotlin", kotlinSourceSet)
|
||||||
val kotlinDirSet = kotlinSourceSet.getKotlin()
|
val kotlinDirSet = kotlinSourceSet.getKotlin()
|
||||||
kotlinDirSet.srcDir(project.file("src/${sourceSetName}/kotlin"))
|
kotlinDirSet.srcDir(project.file("src/${sourceSetName}/kotlin"))
|
||||||
@@ -161,8 +324,7 @@ open class KotlinAndroidPlugin [Inject] (val scriptHandler: ScriptHandler): Plug
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val version = project.getProperties()["kotlin.gradle.plugin.version"] as String
|
project.getExtensions().add(DEFAULT_ANNOTATIONS, GradleUtils(scriptHandler, project).resolveKotlinPluginDependency("kotlin-android-sdk-annotations"))
|
||||||
project.getExtensions().add(DEFAULT_ANNOTATIONS, GradleUtils(scriptHandler!!).resolveDependencies("org.jetbrains.kotlin:kotlin-android-sdk-annotations:$version"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun processVariants(variants: DefaultDomainObjectSet<out BaseVariant>, project: Project, androidExt: BaseExtension): Unit {
|
private fun processVariants(variants: DefaultDomainObjectSet<out BaseVariant>, project: Project, androidExt: BaseExtension): Unit {
|
||||||
@@ -182,13 +344,13 @@ open class KotlinAndroidPlugin [Inject] (val scriptHandler: ScriptHandler): Plug
|
|||||||
val buildTypeSourceSetName = AndroidGradleWrapper.getVariantName(variant)
|
val buildTypeSourceSetName = AndroidGradleWrapper.getVariantName(variant)
|
||||||
|
|
||||||
logger.debug("Variant build type is [$buildTypeSourceSetName]")
|
logger.debug("Variant build type is [$buildTypeSourceSetName]")
|
||||||
val buildTypeSourceSet : AndroidSourceSet? = sourceSets.findByName(buildTypeSourceSetName)
|
val buildTypeSourceSet: AndroidSourceSet? = sourceSets.findByName(buildTypeSourceSetName)
|
||||||
|
|
||||||
val javaTask = variant.getJavaCompile()!!
|
val javaTask = variant.getJavaCompile()!!
|
||||||
val variantName = variant.getName()
|
val variantName = variant.getName()
|
||||||
|
|
||||||
val kotlinTaskName = "compile${variantName.capitalize()}Kotlin"
|
val kotlinTaskName = "compile${variantName.capitalize()}Kotlin"
|
||||||
val kotlinTask: KotlinCompile = project.getTasks().create(kotlinTaskName, javaClass<KotlinCompile>())
|
val kotlinTask = project.getTasks().create(kotlinTaskName, javaClass<KotlinCompile>())
|
||||||
kotlinTask.kotlinOptions = kotlinOptions
|
kotlinTask.kotlinOptions = kotlinOptions
|
||||||
|
|
||||||
|
|
||||||
@@ -246,7 +408,7 @@ open class KotlinAndroidPlugin [Inject] (val scriptHandler: ScriptHandler): Plug
|
|||||||
if (null == plugin) {
|
if (null == plugin) {
|
||||||
plugin = project.getPlugins().findPlugin("android-library")
|
plugin = project.getPlugins().findPlugin("android-library")
|
||||||
}
|
}
|
||||||
val basePlugin : BasePlugin = plugin as BasePlugin
|
val basePlugin: BasePlugin = plugin as BasePlugin
|
||||||
val javaSources = project.files(javaSourceList)
|
val javaSources = project.files(javaSourceList)
|
||||||
val androidRT = project.files(AndroidGradleWrapper.getRuntimeJars(basePlugin))
|
val androidRT = project.files(AndroidGradleWrapper.getRuntimeJars(basePlugin))
|
||||||
val fullClasspath = (javaTask.getClasspath() + (javaSources + androidRT)) - project.files(kotlinTask.kotlinDestinationDir)
|
val fullClasspath = (javaTask.getClasspath() + (javaSources + androidRT)) - project.files(kotlinTask.kotlinDestinationDir)
|
||||||
@@ -273,16 +435,23 @@ open class KotlinAndroidPlugin [Inject] (val scriptHandler: ScriptHandler): Plug
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
open class GradleUtils(val scriptHandler: ScriptHandler) {
|
open class GradleUtils(val scriptHandler: ScriptHandler, val project: ProjectInternal) {
|
||||||
public fun resolveDependencies(vararg coordinates: String): Collection<File> {
|
public fun resolveDependencies(vararg coordinates: String): Collection<File> {
|
||||||
val dependencyHandler : DependencyHandler = scriptHandler.getDependencies()
|
val dependencyHandler: DependencyHandler = scriptHandler.getDependencies()
|
||||||
val configurationsContainer : ConfigurationContainer = scriptHandler.getConfigurations()
|
val configurationsContainer: ConfigurationContainer = scriptHandler.getConfigurations()
|
||||||
|
|
||||||
val deps = coordinates map { dependencyHandler.create(it) }
|
val deps = coordinates map { dependencyHandler.create(it) }
|
||||||
val configuration = configurationsContainer.detachedConfiguration(*deps.copyToArray())
|
val configuration = configurationsContainer.detachedConfiguration(*deps.copyToArray())
|
||||||
|
|
||||||
return configuration.getResolvedConfiguration().getFiles({true})
|
return configuration.getResolvedConfiguration().getFiles({true})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
public fun kotlinPluginVersion(): String = project.getProperties()["kotlin.gradle.plugin.version"] as String
|
||||||
|
public fun kotlinPluginArtifactCoordinates(artifact: String): String = "org.jetbrains.kotlin:${artifact}:${kotlinPluginVersion()}"
|
||||||
|
public fun kotlinJsLibraryCoordinates(): String = kotlinPluginArtifactCoordinates("kotlin-js-library")
|
||||||
|
|
||||||
|
public fun resolveKotlinPluginDependency(artifact: String): Collection<File> =
|
||||||
|
resolveDependencies(kotlinPluginArtifactCoordinates(artifact))
|
||||||
|
public fun resolveJsLibrary(): File = resolveDependencies(kotlinJsLibraryCoordinates()).first()
|
||||||
|
}
|
||||||
|
|||||||
+145
-47
@@ -24,19 +24,44 @@ import org.apache.commons.io.FileUtils
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.*
|
import org.jetbrains.kotlin.gradle.plugin.*
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.jetbrains.jet.config.Services
|
import org.jetbrains.jet.config.Services
|
||||||
|
import org.jetbrains.jet.cli.js.K2JSCompiler
|
||||||
|
import org.jetbrains.jet.cli.common.arguments.K2JSCompilerArguments
|
||||||
|
import org.jetbrains.k2js.config.MetaInfServices
|
||||||
|
import org.jetbrains.k2js.config.ClassPathLibraryDefintionsConfig
|
||||||
|
import org.jetbrains.jet.cli.common.CLIConfigurationKeys
|
||||||
|
import org.jetbrains.jet.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.jet.cli.jvm.compiler.CompileEnvironmentUtil
|
||||||
|
import org.jetbrains.jet.cli.jvm.compiler.JetCoreEnvironment
|
||||||
|
import com.intellij.openapi.Disposable
|
||||||
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import org.jetbrains.k2js.config.EcmaVersion
|
||||||
|
import org.gradle.api.tasks.Copy
|
||||||
|
import org.gradle.api.Action
|
||||||
|
import org.gradle.api.internal.project.ProjectInternal
|
||||||
|
import groovy.lang.Closure
|
||||||
|
import org.codehaus.groovy.runtime.MethodClosure
|
||||||
|
import org.gradle.api.DefaultTask
|
||||||
|
import org.jetbrains.jet.cli.common.arguments.CommonCompilerArguments
|
||||||
|
import org.jetbrains.jet.cli.common.CLICompiler
|
||||||
|
import com.intellij.ide.highlighter.JavaFileType
|
||||||
|
import org.jetbrains.jet.plugin.JetFileType
|
||||||
|
|
||||||
public open class KotlinCompile(): AbstractCompile() {
|
|
||||||
|
|
||||||
|
abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractCompile() {
|
||||||
|
abstract protected val compiler: CLICompiler<T>
|
||||||
|
abstract protected fun createBlankArgs(): T
|
||||||
|
open protected fun afterCompileHook(args: T) {
|
||||||
|
}
|
||||||
|
abstract protected fun populateTargetSpecificArgs(args: T)
|
||||||
|
|
||||||
|
public var kotlinOptions: T = createBlankArgs()
|
||||||
val srcDirsSources = HashSet<SourceDirectorySet>()
|
val srcDirsSources = HashSet<SourceDirectorySet>()
|
||||||
val compiler = K2JVMCompiler()
|
|
||||||
|
public var kotlinDestinationDir: File? = getDestinationDir()
|
||||||
|
|
||||||
private val logger = Logging.getLogger(this.javaClass)
|
private val logger = Logging.getLogger(this.javaClass)
|
||||||
override fun getLogger() = logger
|
override fun getLogger() = logger
|
||||||
|
|
||||||
public var kotlinOptions: K2JVMCompilerArguments = K2JVMCompilerArguments()
|
|
||||||
|
|
||||||
public var kotlinDestinationDir : File? = getDestinationDir()
|
|
||||||
|
|
||||||
// override setSource to track source directory sets
|
// override setSource to track source directory sets
|
||||||
override fun setSource(source: Any?) {
|
override fun setSource(source: Any?) {
|
||||||
srcDirsSources.clear()
|
srcDirsSources.clear()
|
||||||
@@ -71,48 +96,69 @@ public open class KotlinCompile(): AbstractCompile() {
|
|||||||
|
|
||||||
[TaskAction]
|
[TaskAction]
|
||||||
override fun compile() {
|
override fun compile() {
|
||||||
|
getLogger().debug("Starting ${javaClass} task")
|
||||||
getLogger().debug("Starting Kotlin compilation task")
|
val args = createBlankArgs()
|
||||||
|
val sources = getKotlinSources()
|
||||||
val args = K2JVMCompilerArguments()
|
|
||||||
|
|
||||||
val javaSrcRoots = HashSet<File>()
|
|
||||||
val sources = ArrayList<File>()
|
|
||||||
|
|
||||||
// collect source directory roots for all java files to allow cross compilation
|
|
||||||
for (file in getSource()) {
|
|
||||||
if (FilenameUtils.getExtension(file.getName()).equalsIgnoreCase("java")) {
|
|
||||||
val javaRoot = findSrcDirRoot(file)
|
|
||||||
if (javaRoot != null) {
|
|
||||||
javaSrcRoots.add(javaRoot)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sources.add(file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sources.empty) {
|
if (sources.empty) {
|
||||||
getLogger().warn("No Kotlin files found, skipping Kotlin compiler task")
|
getLogger().warn("No Kotlin files found, skipping Kotlin compiler task")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
args.suppressWarnings = kotlinOptions.suppressWarnings
|
populateTargetSpecificArgs(args)
|
||||||
args.version = kotlinOptions.version
|
populateCommonArgs(args, sources)
|
||||||
args.verbose = logger.isDebugEnabled()
|
callCompiler(args)
|
||||||
|
afterCompileHook(args)
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun isJava(it: File): Boolean = it.extension.equalsIgnoreCase(JavaFileType.INSTANCE.getDefaultExtension())
|
||||||
|
protected fun isKotlin(it: File): Boolean = it.extension.equalsIgnoreCase(JetFileType.INSTANCE.getDefaultExtension())
|
||||||
|
|
||||||
|
private fun getKotlinSources(): List<File> = getSource().filter{ isKotlin(it) }
|
||||||
|
|
||||||
|
private fun populateCommonArgs(args: T, sources: List<File>) {
|
||||||
args.freeArgs = sources.map { it.getAbsolutePath() }
|
args.freeArgs = sources.map { it.getAbsolutePath() }
|
||||||
|
args.suppressWarnings = kotlinOptions.suppressWarnings
|
||||||
|
args.verbose = kotlinOptions.verbose
|
||||||
|
args.version = kotlinOptions.version
|
||||||
|
args.noInline = kotlinOptions.noInline
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun callCompiler(args: T) {
|
||||||
|
val messageCollector = GradleMessageCollector(getLogger())
|
||||||
|
getLogger().debug("Calling compiler")
|
||||||
|
val exitCode = compiler.exec(messageCollector, Services.EMPTY, args)
|
||||||
|
|
||||||
|
when (exitCode) {
|
||||||
|
ExitCode.COMPILATION_ERROR -> throw GradleException("Compilation error. See log for more details")
|
||||||
|
ExitCode.INTERNAL_ERROR -> throw GradleException("Internal compiler error. See log for more details")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public open class KotlinCompile() : AbstractKotlinCompile<K2JVMCompilerArguments>() {
|
||||||
|
override val compiler = K2JVMCompiler()
|
||||||
|
|
||||||
|
override fun createBlankArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments()
|
||||||
|
|
||||||
|
override fun populateTargetSpecificArgs(args: K2JVMCompilerArguments) {
|
||||||
if (StringUtils.isEmpty(kotlinOptions.classpath)) {
|
if (StringUtils.isEmpty(kotlinOptions.classpath)) {
|
||||||
val existingClasspathEntries = getClasspath().filter({ it != null && it.exists() })
|
val existingClasspathEntries = getClasspath().filter({ it != null && it.exists() })
|
||||||
val effectiveClassPath = (javaSrcRoots + existingClasspathEntries).makeString(File.pathSeparator)
|
val effectiveClassPath = (getJavaSourceRoots() + existingClasspathEntries).makeString(File.pathSeparator)
|
||||||
args.classpath = effectiveClassPath
|
args.classpath = effectiveClassPath
|
||||||
}
|
}
|
||||||
|
|
||||||
args.destination = if (StringUtils.isEmpty(kotlinOptions.destination)) { kotlinDestinationDir?.getPath() } else { kotlinOptions.destination }
|
args.destination = if (StringUtils.isEmpty(kotlinOptions.destination)) {
|
||||||
|
kotlinDestinationDir?.getPath()
|
||||||
|
} else {
|
||||||
|
kotlinOptions.destination
|
||||||
|
}
|
||||||
|
|
||||||
val embeddedAnnotations = getAnnotations(getProject(), getLogger())
|
val embeddedAnnotations = getAnnotations(getProject(), getLogger())
|
||||||
val userAnnotations = (kotlinOptions.annotations ?: "").split(File.pathSeparatorChar).toList()
|
val userAnnotations = (kotlinOptions.annotations ?: "").split(File.pathSeparatorChar).toList()
|
||||||
val allAnnotations = if (kotlinOptions.noJdkAnnotations) userAnnotations else userAnnotations.plus(embeddedAnnotations.map {it.getPath()})
|
val allAnnotations = if (kotlinOptions.noJdkAnnotations) userAnnotations else userAnnotations.plus(embeddedAnnotations.map { it.getPath() })
|
||||||
args.annotations = allAnnotations.makeString(File.pathSeparator)
|
args.annotations = allAnnotations.makeString(File.pathSeparator)
|
||||||
|
|
||||||
args.noStdlib = true
|
args.noStdlib = true
|
||||||
@@ -121,17 +167,15 @@ public open class KotlinCompile(): AbstractCompile() {
|
|||||||
args.noOptimize = kotlinOptions.noOptimize
|
args.noOptimize = kotlinOptions.noOptimize
|
||||||
args.noCallAssertions = kotlinOptions.noCallAssertions
|
args.noCallAssertions = kotlinOptions.noCallAssertions
|
||||||
args.noParamAssertions = kotlinOptions.noParamAssertions
|
args.noParamAssertions = kotlinOptions.noParamAssertions
|
||||||
|
}
|
||||||
|
|
||||||
val messageCollector = GradleMessageCollector(getLogger())
|
private fun getJavaSourceRoots(): Set<File> = getSource()
|
||||||
getLogger().debug("Calling compiler")
|
.filter { isJava(it) }
|
||||||
val exitCode = compiler.exec(messageCollector, Services.EMPTY, args)
|
.map { findSrcDirRoot(it) }
|
||||||
|
.filterNotNull()
|
||||||
when (exitCode) {
|
.toSet()
|
||||||
ExitCode.COMPILATION_ERROR -> throw GradleException("Compilation error. See log for more details")
|
|
||||||
ExitCode.INTERNAL_ERROR -> throw GradleException("Internal compiler error. See log for more details")
|
|
||||||
else -> {}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
override fun afterCompileHook(args: K2JVMCompilerArguments) {
|
||||||
getLogger().debug("Copying resulting files to classes")
|
getLogger().debug("Copying resulting files to classes")
|
||||||
// Copy kotlin classes to all classes directory
|
// Copy kotlin classes to all classes directory
|
||||||
val outputDirFile = File(args.destination!!)
|
val outputDirFile = File(args.destination!!)
|
||||||
@@ -141,7 +185,58 @@ public open class KotlinCompile(): AbstractCompile() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public open class KDoc(): SourceTask() {
|
public open class Kotlin2JsCompile() : AbstractKotlinCompile<K2JSCompilerArguments>() {
|
||||||
|
override val compiler = K2JSCompiler()
|
||||||
|
|
||||||
|
override fun createBlankArgs(): K2JSCompilerArguments {
|
||||||
|
val args = K2JSCompilerArguments()
|
||||||
|
args.libraryFiles = array<String>() // defaults to null
|
||||||
|
return args
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun addLibraryFiles(vararg fs: String) {
|
||||||
|
kotlinOptions.libraryFiles = (kotlinOptions.libraryFiles + fs).copyToArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun addLibraryFiles(vararg fs: File) {
|
||||||
|
val strs = fs.map { it.getPath() }.copyToArray()
|
||||||
|
addLibraryFiles(*strs)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun outputFile(): String? = kotlinOptions.outputFile
|
||||||
|
|
||||||
|
public fun sourceMapDestinationDir(): File = File(outputFile()).directory
|
||||||
|
|
||||||
|
{
|
||||||
|
getOutputs().file(MethodClosure(this, "outputFile"))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun populateTargetSpecificArgs(args: K2JSCompilerArguments) {
|
||||||
|
args.outputFile = outputFile()
|
||||||
|
args.outputPrefix = kotlinOptions.outputPrefix
|
||||||
|
args.outputPostfix = kotlinOptions.outputPostfix
|
||||||
|
args.libraryFiles = (kotlinOptions.libraryFiles + getProject().getConfigurations().getByName("compile").map{ it.canonicalPath }).copyToArray()
|
||||||
|
args.target = kotlinOptions.target
|
||||||
|
args.sourceMap = kotlinOptions.sourceMap
|
||||||
|
|
||||||
|
if (args.outputFile == null) {
|
||||||
|
throw GradleException("${getName()}.kotlinOptions.outputFile must be set to a string.")
|
||||||
|
}
|
||||||
|
|
||||||
|
val outputDir = File(args.outputFile).directory
|
||||||
|
if (!outputDir.exists()) {
|
||||||
|
if (!outputDir.mkdirs()) {
|
||||||
|
throw GradleException("Failed to create output directory ${outputDir} or one of its ancestors")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogger().debug("${getName()} set libraryFiles to ${args.libraryFiles.join(",")}")
|
||||||
|
getLogger().debug("${getName()} set outputFile to ${args.outputFile}")
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public open class KDoc() : SourceTask() {
|
||||||
|
|
||||||
private val logger = Logging.getLogger(this.javaClass)
|
private val logger = Logging.getLogger(this.javaClass)
|
||||||
override fun getLogger() = logger
|
override fun getLogger() = logger
|
||||||
@@ -161,7 +256,11 @@ public open class KDoc(): SourceTask() {
|
|||||||
|
|
||||||
val kdocOptions = kdocArgs.docConfig
|
val kdocOptions = kdocArgs.docConfig
|
||||||
|
|
||||||
cfg.docOutputDir = if ((kdocOptions.docOutputDir.length == 0) && (destinationDir != null)) { destinationDir!!.path } else { kdocOptions.docOutputDir }
|
cfg.docOutputDir = if ((kdocOptions.docOutputDir.length == 0) && (destinationDir != null)) {
|
||||||
|
destinationDir!!.path
|
||||||
|
} else {
|
||||||
|
kdocOptions.docOutputDir
|
||||||
|
}
|
||||||
cfg.title = kdocOptions.title
|
cfg.title = kdocOptions.title
|
||||||
cfg.sourceRootHref = kdocOptions.sourceRootHref
|
cfg.sourceRootHref = kdocOptions.sourceRootHref
|
||||||
cfg.projectRootDir = kdocOptions.projectRootDir
|
cfg.projectRootDir = kdocOptions.projectRootDir
|
||||||
@@ -180,7 +279,7 @@ public open class KDoc(): SourceTask() {
|
|||||||
getLogger().warn(args.freeArgs.toString())
|
getLogger().warn(args.freeArgs.toString())
|
||||||
val embeddedAnnotations = getAnnotations(getProject(), getLogger())
|
val embeddedAnnotations = getAnnotations(getProject(), getLogger())
|
||||||
val userAnnotations = (kdocArgs.annotations ?: "").split(File.pathSeparatorChar).toList()
|
val userAnnotations = (kdocArgs.annotations ?: "").split(File.pathSeparatorChar).toList()
|
||||||
val allAnnotations = if (kdocArgs.noJdkAnnotations) userAnnotations else userAnnotations.plus(embeddedAnnotations.map {it.getPath()})
|
val allAnnotations = if (kdocArgs.noJdkAnnotations) userAnnotations else userAnnotations.plus(embeddedAnnotations.map { it.getPath() })
|
||||||
args.annotations = allAnnotations.makeString(File.pathSeparator)
|
args.annotations = allAnnotations.makeString(File.pathSeparator)
|
||||||
|
|
||||||
args.noStdlib = true
|
args.noStdlib = true
|
||||||
@@ -195,7 +294,6 @@ public open class KDoc(): SourceTask() {
|
|||||||
when (exitCode) {
|
when (exitCode) {
|
||||||
ExitCode.COMPILATION_ERROR -> throw GradleException("Failed to generate kdoc. See log for more details")
|
ExitCode.COMPILATION_ERROR -> throw GradleException("Failed to generate kdoc. See log for more details")
|
||||||
ExitCode.INTERNAL_ERROR -> throw GradleException("Internal generation error. See log for more details")
|
ExitCode.INTERNAL_ERROR -> throw GradleException("Internal generation error. See log for more details")
|
||||||
else -> {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -205,14 +303,14 @@ fun getAnnotations(project: Project, logger: Logger): Collection<File> {
|
|||||||
val annotations = project.getExtensions().getByName(DEFAULT_ANNOTATIONS) as Collection<File>
|
val annotations = project.getExtensions().getByName(DEFAULT_ANNOTATIONS) as Collection<File>
|
||||||
|
|
||||||
if (!annotations.isEmpty()) {
|
if (!annotations.isEmpty()) {
|
||||||
logger.info("using default annontations from [${annotations.map {it.getPath()}}]")
|
logger.info("using default annontations from [${annotations.map { it.getPath() }}]")
|
||||||
return annotations
|
return annotations
|
||||||
} else {
|
} else {
|
||||||
throw GradleException("Default annotations not found in Kotlin gradle plugin classpath")
|
throw GradleException("Default annotations not found in Kotlin gradle plugin classpath")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GradleMessageCollector(val logger : Logger): MessageCollector {
|
class GradleMessageCollector(val logger: Logger) : MessageCollector {
|
||||||
public override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
|
public override fun report(severity: CompilerMessageSeverity, message: String, location: CompilerMessageLocation) {
|
||||||
val text = with(StringBuilder()) {
|
val text = with(StringBuilder()) {
|
||||||
append(when (severity) {
|
append(when (severity) {
|
||||||
|
|||||||
@@ -93,6 +93,7 @@
|
|||||||
<extraArtifacts>
|
<extraArtifacts>
|
||||||
<extraArtifact>org.jetbrains.kotlin:kotlin-gradle-plugin-core:${project.version}</extraArtifact>
|
<extraArtifact>org.jetbrains.kotlin:kotlin-gradle-plugin-core:${project.version}</extraArtifact>
|
||||||
<extraArtifact>org.jetbrains.kotlin:kotlin-jdk-annotations:${project.version}</extraArtifact>
|
<extraArtifact>org.jetbrains.kotlin:kotlin-jdk-annotations:${project.version}</extraArtifact>
|
||||||
|
<extraArtifact>org.jetbrains.kotlin:kotlin-js-library:${project.version}</extraArtifact>
|
||||||
<extraArtifact>org.jetbrains.kotlin:kotlin-android-sdk-annotations:${project.version}</extraArtifact>
|
<extraArtifact>org.jetbrains.kotlin:kotlin-android-sdk-annotations:${project.version}</extraArtifact>
|
||||||
</extraArtifacts>
|
</extraArtifacts>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
+8
-1
@@ -111,4 +111,11 @@ open class KotlinAndriodPluginWrapper: KotlinBasePluginWrapper() {
|
|||||||
public override fun getPluginClassName():String {
|
public override fun getPluginClassName():String {
|
||||||
return "org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPlugin"
|
return "org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPlugin"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
open class Kotlin2JsPluginWrapper : KotlinBasePluginWrapper() {
|
||||||
|
public override fun getPluginClassName():String {
|
||||||
|
return "org.jetbrains.kotlin.gradle.plugin.Kotlin2JsPlugin"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
implementation-class=org.jetbrains.kotlin.gradle.plugin.Kotlin2JsPluginWrapper
|
||||||
Reference in New Issue
Block a user