From 53b325d52208bfd44ba6a524ce3dda5379aed699 Mon Sep 17 00:00:00 2001 From: Robert Jaros Date: Thu, 17 Oct 2019 18:53:08 +0200 Subject: Move the plugins to the separate directory. Fix common module detection. --- build.gradle | 4 +- .../kvision-compiler-plugin/build.gradle | 16 -- .../kvision/plugin/CommonComponentRegistrar.kt | 47 ----- .../pl/treksoft/kvision/plugin/KVProcessor.kt | 209 --------------------- kvision-modules/kvision-gradle-plugin/build.gradle | 20 -- .../treksoft/kvision/gradle/KVisionGradlePlugin.kt | 30 --- .../kvision/gradle/KVisionGradleSubplugin.kt | 57 ------ kvision-tools/kvision-compiler-plugin/build.gradle | 16 ++ .../kvision/plugin/CommonComponentRegistrar.kt | 47 +++++ .../pl/treksoft/kvision/plugin/KVProcessor.kt | 209 +++++++++++++++++++++ kvision-tools/kvision-gradle-plugin/build.gradle | 20 ++ .../treksoft/kvision/gradle/KVisionGradlePlugin.kt | 30 +++ .../kvision/gradle/KVisionGradleSubplugin.kt | 57 ++++++ settings.gradle | 4 +- 14 files changed, 383 insertions(+), 383 deletions(-) delete mode 100644 kvision-modules/kvision-compiler-plugin/build.gradle delete mode 100644 kvision-modules/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/CommonComponentRegistrar.kt delete mode 100644 kvision-modules/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt delete mode 100644 kvision-modules/kvision-gradle-plugin/build.gradle delete mode 100644 kvision-modules/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradlePlugin.kt delete mode 100644 kvision-modules/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradleSubplugin.kt create mode 100644 kvision-tools/kvision-compiler-plugin/build.gradle create mode 100644 kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/CommonComponentRegistrar.kt create mode 100644 kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt create mode 100644 kvision-tools/kvision-gradle-plugin/build.gradle create mode 100644 kvision-tools/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradlePlugin.kt create mode 100644 kvision-tools/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradleSubplugin.kt diff --git a/build.gradle b/build.gradle index 35e0e7ab..63d2fbee 100644 --- a/build.gradle +++ b/build.gradle @@ -23,7 +23,7 @@ plugins { id "io.gitlab.arturbosch.detekt" version "1.0.0-RC14" } -configure(allprojects - project(':kvision-modules')) { +configure(allprojects - project(':kvision-modules') - project(':kvision-tools')) { repositories { jcenter() mavenCentral() @@ -36,7 +36,7 @@ configure(allprojects - project(':kvision-modules')) { } } -configure(allprojects - project(':kvision-modules') - project(":kvision-modules:kvision-base")) { +configure(allprojects - project(':kvision-modules') - project(':kvision-tools') - project(":kvision-modules:kvision-base")) { apply plugin: 'io.gitlab.arturbosch.detekt' apply plugin: 'com.jfrog.bintray' apply plugin: 'maven' diff --git a/kvision-modules/kvision-compiler-plugin/build.gradle b/kvision-modules/kvision-compiler-plugin/build.gradle deleted file mode 100644 index 3b00300c..00000000 --- a/kvision-modules/kvision-compiler-plugin/build.gradle +++ /dev/null @@ -1,16 +0,0 @@ -apply plugin: 'kotlin-platform-jvm' -apply plugin: "kotlin-kapt" -apply plugin: "maven" - -dependencies { - compile "de.jensklingenberg:mpapt-runtime:$mpaptRuntimeVersion" - expectedBy project(":kvision-modules:kvision-common-annotations") - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - compileOnly "org.jetbrains.kotlin:kotlin-compiler-embeddable" - compileOnly "com.google.auto.service:auto-service:$autoServiceVersion" - kapt "com.google.auto.service:auto-service:$autoServiceVersion" -} - -kapt { - includeCompileClasspath = false -} diff --git a/kvision-modules/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/CommonComponentRegistrar.kt b/kvision-modules/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/CommonComponentRegistrar.kt deleted file mode 100644 index c71dbce8..00000000 --- a/kvision-modules/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/CommonComponentRegistrar.kt +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (c) 2017-present Robert Jaros - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package pl.treksoft.kvision.plugin - -import com.google.auto.service.AutoService -import de.jensklingenberg.mpapt.common.MpAptProject -import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension -import org.jetbrains.kotlin.com.intellij.mock.MockProject -import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar -import org.jetbrains.kotlin.config.CompilerConfiguration -import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor -import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension - -@AutoService(ComponentRegistrar::class) -open class CommonComponentRegistrar : ComponentRegistrar { - - override fun registerProjectComponents( - project: MockProject, - configuration: CompilerConfiguration - ) { - val processor = KVProcessor() - val mpapt = MpAptProject(processor, configuration) - StorageComponentContainerContributor.registerExtension(project, mpapt) - ClassBuilderInterceptorExtension.registerExtension(project, mpapt) - JsSyntheticTranslateExtension.registerExtension(project, mpapt) - - } -} diff --git a/kvision-modules/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt b/kvision-modules/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt deleted file mode 100644 index 1b49a373..00000000 --- a/kvision-modules/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright (c) 2017-present Robert Jaros - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package pl.treksoft.kvision.plugin - -import de.jensklingenberg.mpapt.common.guessingBuildFolder -import de.jensklingenberg.mpapt.common.methods -import de.jensklingenberg.mpapt.model.AbstractProcessor -import de.jensklingenberg.mpapt.model.Element -import de.jensklingenberg.mpapt.model.RoundEnvironment -import de.jensklingenberg.mpapt.utils.KotlinPlatformValues -import org.jetbrains.kotlin.backend.common.descriptors.allParameters -import org.jetbrains.kotlin.backend.common.descriptors.isSuspend -import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots -import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor -import org.jetbrains.kotlin.descriptors.ParameterDescriptor -import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe -import org.jetbrains.kotlin.types.KotlinType -import pl.treksoft.kvision.annotations.KVService -import java.io.File - -class KVProcessor : AbstractProcessor() { - - override fun isTargetPlatformSupported(platform: TargetPlatform): Boolean { - val targetName = platform.first().platformName - return when (targetName) { - KotlinPlatformValues.JS -> false - KotlinPlatformValues.JVM -> true - KotlinPlatformValues.NATIVE -> false - else -> { - log(targetName) - false - } - } - } - - override fun process(roundEnvironment: RoundEnvironment) { - val isCommon = this.configuration.kotlinSourceRoots.find { it.isCommon } != null - if (isCommon) { - roundEnvironment.getElementsAnnotatedWith(KVService::class.java.name).forEach { - if (it is Element.ClassElement && it.classDescriptor.name.asString().startsWith("I") - && it.classDescriptor.name.asString().endsWith("Service") - ) { - val cl = it.classDescriptor - val genRootDir = File(cl.guessingBuildFolder(), "generated-src").apply { - mkdirs() - } - val packageName = cl.containingDeclaration.fqNameSafe.asString() - val iName = cl.name.asString() - val baseName = iName.drop(1) - val commonCode = StringBuilder().apply { - appendln("//") - appendln("// GENERATED by KVision") - appendln("//") - appendln("package $packageName") - appendln() - appendln("import kotlinx.coroutines.CoroutineStart") - appendln("import kotlinx.coroutines.GlobalScope") - appendln("import kotlinx.coroutines.launch") - appendln("import pl.treksoft.kvision.remote.KVServiceManager") - appendln() - appendln("expect class $baseName : $iName") - appendln() - appendln("object ${baseName}Manager : KVServiceManager<$baseName>($baseName::class) {") - appendln(" init {") - appendln(" GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {") - cl.methods().forEach { - appendln(" bind($iName::${it.name})") - } - appendln(" }") - appendln(" }") - appendln("}") - }.toString() - val commonDestinationDir = File( - genRootDir, - "common" + File.separator + packageName.replace('.', File.separatorChar) - ).apply { - mkdirs() - } - val commonFile = File(commonDestinationDir, "${baseName}Manager.kt") - if (commonFile.exists()) { - val content = commonFile.readText() - if (content != commonCode) { - commonFile.writeText(commonCode) - } - } else { - commonFile.writeText(commonCode) - } - val frontendCode = StringBuilder().apply { - appendln("//") - appendln("// GENERATED by KVision") - appendln("//") - appendln("package $packageName") - appendln() - appendln("import pl.treksoft.kvision.remote.KVRemoteAgent") - getTypes(cl.methods()).sorted().forEach { - appendln("import $it") - } - appendln() - appendln("actual class $baseName : $iName, KVRemoteAgent<$baseName>(${baseName}Manager) {") - cl.methods().forEach { - val name = it.name - val params = it.allParameters.drop(1) - val wsMethod = - if (params.size == 2) - params.first().type.toString().startsWith("ReceiveChannel") - else false - if (it.isSuspend) { - if (!wsMethod) { - if (params.isNotEmpty()) { - appendln( - " override suspend fun $name(${getParameterList(params)}) = call($iName::$name, ${getParameterNames( - params - )})" - ) - } else { - appendln(" override suspend fun $name() = call($iName::$name)") - } - } else { - appendln(" override suspend fun $name(${getParameterList(params)}) {}") - val type1 = params[0].type.toString().replace("ReceiveChannel", "SendChannel") - val type2 = params[1].type.toString().replace("SendChannel", "ReceiveChannel") - appendln(" suspend fun $name(handler: suspend ($type1, $type2) -> Unit) = webSocket($iName::$name, handler)") - } - } else { - if (it.returnType.toString().startsWith("RemoteData")) { - appendln(" override fun $name(${getParameterList(params)}) = ${it.returnType.toString()}()") - } else { - appendln(" override fun $name(${getParameterList(params)}) = emptyList()") - } - } - } - appendln("}") - }.toString() - val frontendDestinationDir = File( - genRootDir, - "frontend" + File.separator + packageName.replace('.', File.separatorChar) - ).apply { - mkdirs() - } - val frontendFile = File(frontendDestinationDir, "${baseName}.kt") - if (frontendFile.exists()) { - val content = frontendFile.readText() - if (content != frontendCode) { - frontendFile.writeText(frontendCode) - } - } else { - frontendFile.writeText(frontendCode) - } - } - } - } - } - - private fun getParameterList(params: List): String { - return params.map { - "${it.name.asString()}: ${it.type}" - }.joinToString(", ") - } - - private fun getParameterNames(params: List): String { - return params.map { - it.name.asString() - }.joinToString(", ") - } - - private fun getTypes(type: KotlinType): Set { - return if (type.arguments.isNotEmpty()) { - (type.arguments.flatMap { getTypes(it.type) } + type.getJetTypeFqName(false)).toSet() - } else { - setOf(type.getJetTypeFqName(false)) - } - } - - private fun getTypes(methods: Collection): Set { - return methods.flatMap { m -> - m.allParameters.drop(1).flatMap { p -> - getTypes(p.type) - }.toSet() + (m.returnType?.let { getTypes(it) } ?: setOf()) - }.filterNot { - it.startsWith("kotlin.collections.") || it.startsWith("kotlin.") - }.toSet() - } - - override fun getSupportedAnnotationTypes(): Set = setOf( - KVService::class.java.name - ) - -} diff --git a/kvision-modules/kvision-gradle-plugin/build.gradle b/kvision-modules/kvision-gradle-plugin/build.gradle deleted file mode 100644 index 7b2d0f33..00000000 --- a/kvision-modules/kvision-gradle-plugin/build.gradle +++ /dev/null @@ -1,20 +0,0 @@ -apply plugin: 'kotlin-platform-jvm' -apply plugin: "java-gradle-plugin" -apply plugin: "kotlin-kapt" -apply plugin: "maven" - -gradlePlugin { - plugins { - simplePlugin { - id = "pl.treksoft.kvision" - implementationClass = "pl.treksoft.kvision.gradle.KVisionGradlePlugin" - } - } -} - -dependencies { - implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" - compile "org.jetbrains.kotlin:kotlin-gradle-plugin-api:$kotlinVersion" - compileOnly "com.google.auto.service:auto-service:$autoServiceVersion" - kapt "com.google.auto.service:auto-service:$autoServiceVersion" -} diff --git a/kvision-modules/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradlePlugin.kt b/kvision-modules/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradlePlugin.kt deleted file mode 100644 index ec2dd7f4..00000000 --- a/kvision-modules/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradlePlugin.kt +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (c) 2017-present Robert Jaros - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package pl.treksoft.kvision.gradle - -import org.gradle.api.Project - -open class KVisionGradlePlugin : org.gradle.api.Plugin { - override fun apply(project: Project) { - - } -} diff --git a/kvision-modules/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradleSubplugin.kt b/kvision-modules/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradleSubplugin.kt deleted file mode 100644 index 5ecfc3e9..00000000 --- a/kvision-modules/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradleSubplugin.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2017-present Robert Jaros - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ -package pl.treksoft.kvision.gradle - -import com.google.auto.service.AutoService -import org.gradle.api.Project -import org.gradle.api.tasks.compile.AbstractCompile -import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation -import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin -import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact -import org.jetbrains.kotlin.gradle.plugin.SubpluginOption - -@AutoService(KotlinGradleSubplugin::class) -class KVisionGradleSubplugin : KotlinGradleSubplugin { - override fun apply( - project: Project, - kotlinCompile: AbstractCompile, - javaCompile: AbstractCompile?, - variantData: Any?, - androidProjectHandler: Any?, - kotlinCompilation: KotlinCompilation? - ): List { - return emptyList() - } - - override fun isApplicable(project: Project, task: AbstractCompile) = - project.plugins.hasPlugin(KVisionGradlePlugin::class.java) - - override fun getCompilerPluginId(): String = "KVisionPlugin" - - override fun getPluginArtifact(): SubpluginArtifact = SubpluginArtifact( - groupId = "pl.treksoft", - artifactId = "kvision-compiler-plugin", - version = "2.0.0-SNAPSHOT" - ) - -} diff --git a/kvision-tools/kvision-compiler-plugin/build.gradle b/kvision-tools/kvision-compiler-plugin/build.gradle new file mode 100644 index 00000000..3b00300c --- /dev/null +++ b/kvision-tools/kvision-compiler-plugin/build.gradle @@ -0,0 +1,16 @@ +apply plugin: 'kotlin-platform-jvm' +apply plugin: "kotlin-kapt" +apply plugin: "maven" + +dependencies { + compile "de.jensklingenberg:mpapt-runtime:$mpaptRuntimeVersion" + expectedBy project(":kvision-modules:kvision-common-annotations") + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + compileOnly "org.jetbrains.kotlin:kotlin-compiler-embeddable" + compileOnly "com.google.auto.service:auto-service:$autoServiceVersion" + kapt "com.google.auto.service:auto-service:$autoServiceVersion" +} + +kapt { + includeCompileClasspath = false +} diff --git a/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/CommonComponentRegistrar.kt b/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/CommonComponentRegistrar.kt new file mode 100644 index 00000000..c71dbce8 --- /dev/null +++ b/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/CommonComponentRegistrar.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.plugin + +import com.google.auto.service.AutoService +import de.jensklingenberg.mpapt.common.MpAptProject +import org.jetbrains.kotlin.codegen.extensions.ClassBuilderInterceptorExtension +import org.jetbrains.kotlin.com.intellij.mock.MockProject +import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor +import org.jetbrains.kotlin.js.translate.extensions.JsSyntheticTranslateExtension + +@AutoService(ComponentRegistrar::class) +open class CommonComponentRegistrar : ComponentRegistrar { + + override fun registerProjectComponents( + project: MockProject, + configuration: CompilerConfiguration + ) { + val processor = KVProcessor() + val mpapt = MpAptProject(processor, configuration) + StorageComponentContainerContributor.registerExtension(project, mpapt) + ClassBuilderInterceptorExtension.registerExtension(project, mpapt) + JsSyntheticTranslateExtension.registerExtension(project, mpapt) + + } +} diff --git a/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt b/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt new file mode 100644 index 00000000..0e62b959 --- /dev/null +++ b/kvision-tools/kvision-compiler-plugin/src/main/kotlin/pl/treksoft/kvision/plugin/KVProcessor.kt @@ -0,0 +1,209 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.plugin + +import de.jensklingenberg.mpapt.common.guessingBuildFolder +import de.jensklingenberg.mpapt.common.methods +import de.jensklingenberg.mpapt.model.AbstractProcessor +import de.jensklingenberg.mpapt.model.Element +import de.jensklingenberg.mpapt.model.RoundEnvironment +import de.jensklingenberg.mpapt.utils.KotlinPlatformValues +import org.jetbrains.kotlin.backend.common.descriptors.allParameters +import org.jetbrains.kotlin.backend.common.descriptors.isSuspend +import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots +import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor +import org.jetbrains.kotlin.descriptors.ParameterDescriptor +import org.jetbrains.kotlin.js.descriptorUtils.getJetTypeFqName +import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe +import org.jetbrains.kotlin.types.KotlinType +import pl.treksoft.kvision.annotations.KVService +import java.io.File + +class KVProcessor : AbstractProcessor() { + + override fun isTargetPlatformSupported(platform: TargetPlatform): Boolean { + val targetName = platform.first().platformName + return when (targetName) { + KotlinPlatformValues.JS -> false + KotlinPlatformValues.JVM -> true + KotlinPlatformValues.NATIVE -> false + else -> { + log(targetName) + false + } + } + } + + override fun process(roundEnvironment: RoundEnvironment) { + val isCommon = this.configuration.kotlinSourceRoots.find { !it.isCommon } == null + if (isCommon) { + roundEnvironment.getElementsAnnotatedWith(KVService::class.java.name).forEach { + if (it is Element.ClassElement && it.classDescriptor.name.asString().startsWith("I") + && it.classDescriptor.name.asString().endsWith("Service") + ) { + val cl = it.classDescriptor + val genRootDir = File(cl.guessingBuildFolder(), "generated-src").apply { + mkdirs() + } + val packageName = cl.containingDeclaration.fqNameSafe.asString() + val iName = cl.name.asString() + val baseName = iName.drop(1) + val commonCode = StringBuilder().apply { + appendln("//") + appendln("// GENERATED by KVision") + appendln("//") + appendln("package $packageName") + appendln() + appendln("import kotlinx.coroutines.CoroutineStart") + appendln("import kotlinx.coroutines.GlobalScope") + appendln("import kotlinx.coroutines.launch") + appendln("import pl.treksoft.kvision.remote.KVServiceManager") + appendln() + appendln("expect class $baseName : $iName") + appendln() + appendln("object ${baseName}Manager : KVServiceManager<$baseName>($baseName::class) {") + appendln(" init {") + appendln(" GlobalScope.launch(start = CoroutineStart.UNDISPATCHED) {") + cl.methods().forEach { + appendln(" bind($iName::${it.name})") + } + appendln(" }") + appendln(" }") + appendln("}") + }.toString() + val commonDestinationDir = File( + genRootDir, + "common" + File.separator + packageName.replace('.', File.separatorChar) + ).apply { + mkdirs() + } + val commonFile = File(commonDestinationDir, "${baseName}Manager.kt") + if (commonFile.exists()) { + val content = commonFile.readText() + if (content != commonCode) { + commonFile.writeText(commonCode) + } + } else { + commonFile.writeText(commonCode) + } + val frontendCode = StringBuilder().apply { + appendln("//") + appendln("// GENERATED by KVision") + appendln("//") + appendln("package $packageName") + appendln() + appendln("import pl.treksoft.kvision.remote.KVRemoteAgent") + getTypes(cl.methods()).sorted().forEach { + appendln("import $it") + } + appendln() + appendln("actual class $baseName : $iName, KVRemoteAgent<$baseName>(${baseName}Manager) {") + cl.methods().forEach { + val name = it.name + val params = it.allParameters.drop(1) + val wsMethod = + if (params.size == 2) + params.first().type.toString().startsWith("ReceiveChannel") + else false + if (it.isSuspend) { + if (!wsMethod) { + if (params.isNotEmpty()) { + appendln( + " override suspend fun $name(${getParameterList(params)}) = call($iName::$name, ${getParameterNames( + params + )})" + ) + } else { + appendln(" override suspend fun $name() = call($iName::$name)") + } + } else { + appendln(" override suspend fun $name(${getParameterList(params)}) {}") + val type1 = params[0].type.toString().replace("ReceiveChannel", "SendChannel") + val type2 = params[1].type.toString().replace("SendChannel", "ReceiveChannel") + appendln(" suspend fun $name(handler: suspend ($type1, $type2) -> Unit) = webSocket($iName::$name, handler)") + } + } else { + if (it.returnType.toString().startsWith("RemoteData")) { + appendln(" override fun $name(${getParameterList(params)}) = ${it.returnType.toString()}()") + } else { + appendln(" override fun $name(${getParameterList(params)}) = emptyList()") + } + } + } + appendln("}") + }.toString() + val frontendDestinationDir = File( + genRootDir, + "frontend" + File.separator + packageName.replace('.', File.separatorChar) + ).apply { + mkdirs() + } + val frontendFile = File(frontendDestinationDir, "${baseName}.kt") + if (frontendFile.exists()) { + val content = frontendFile.readText() + if (content != frontendCode) { + frontendFile.writeText(frontendCode) + } + } else { + frontendFile.writeText(frontendCode) + } + } + } + } + } + + private fun getParameterList(params: List): String { + return params.map { + "${it.name.asString()}: ${it.type}" + }.joinToString(", ") + } + + private fun getParameterNames(params: List): String { + return params.map { + it.name.asString() + }.joinToString(", ") + } + + private fun getTypes(type: KotlinType): Set { + return if (type.arguments.isNotEmpty()) { + (type.arguments.flatMap { getTypes(it.type) } + type.getJetTypeFqName(false)).toSet() + } else { + setOf(type.getJetTypeFqName(false)) + } + } + + private fun getTypes(methods: Collection): Set { + return methods.flatMap { m -> + m.allParameters.drop(1).flatMap { p -> + getTypes(p.type) + }.toSet() + (m.returnType?.let { getTypes(it) } ?: setOf()) + }.filterNot { + it.startsWith("kotlin.collections.") || it.startsWith("kotlin.") + }.toSet() + } + + override fun getSupportedAnnotationTypes(): Set = setOf( + KVService::class.java.name + ) + +} diff --git a/kvision-tools/kvision-gradle-plugin/build.gradle b/kvision-tools/kvision-gradle-plugin/build.gradle new file mode 100644 index 00000000..7b2d0f33 --- /dev/null +++ b/kvision-tools/kvision-gradle-plugin/build.gradle @@ -0,0 +1,20 @@ +apply plugin: 'kotlin-platform-jvm' +apply plugin: "java-gradle-plugin" +apply plugin: "kotlin-kapt" +apply plugin: "maven" + +gradlePlugin { + plugins { + simplePlugin { + id = "pl.treksoft.kvision" + implementationClass = "pl.treksoft.kvision.gradle.KVisionGradlePlugin" + } + } +} + +dependencies { + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8" + compile "org.jetbrains.kotlin:kotlin-gradle-plugin-api:$kotlinVersion" + compileOnly "com.google.auto.service:auto-service:$autoServiceVersion" + kapt "com.google.auto.service:auto-service:$autoServiceVersion" +} diff --git a/kvision-tools/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradlePlugin.kt b/kvision-tools/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradlePlugin.kt new file mode 100644 index 00000000..ec2dd7f4 --- /dev/null +++ b/kvision-tools/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradlePlugin.kt @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.gradle + +import org.gradle.api.Project + +open class KVisionGradlePlugin : org.gradle.api.Plugin { + override fun apply(project: Project) { + + } +} diff --git a/kvision-tools/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradleSubplugin.kt b/kvision-tools/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradleSubplugin.kt new file mode 100644 index 00000000..5ecfc3e9 --- /dev/null +++ b/kvision-tools/kvision-gradle-plugin/src/main/kotlin/pl/treksoft/kvision/gradle/KVisionGradleSubplugin.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2017-present Robert Jaros + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package pl.treksoft.kvision.gradle + +import com.google.auto.service.AutoService +import org.gradle.api.Project +import org.gradle.api.tasks.compile.AbstractCompile +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin +import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact +import org.jetbrains.kotlin.gradle.plugin.SubpluginOption + +@AutoService(KotlinGradleSubplugin::class) +class KVisionGradleSubplugin : KotlinGradleSubplugin { + override fun apply( + project: Project, + kotlinCompile: AbstractCompile, + javaCompile: AbstractCompile?, + variantData: Any?, + androidProjectHandler: Any?, + kotlinCompilation: KotlinCompilation? + ): List { + return emptyList() + } + + override fun isApplicable(project: Project, task: AbstractCompile) = + project.plugins.hasPlugin(KVisionGradlePlugin::class.java) + + override fun getCompilerPluginId(): String = "KVisionPlugin" + + override fun getPluginArtifact(): SubpluginArtifact = SubpluginArtifact( + groupId = "pl.treksoft", + artifactId = "kvision-compiler-plugin", + version = "2.0.0-SNAPSHOT" + ) + +} diff --git a/settings.gradle b/settings.gradle index 08b7370d..2e1586e4 100644 --- a/settings.gradle +++ b/settings.gradle @@ -31,5 +31,5 @@ include 'kvision-modules:kvision-base', 'kvision-modules:kvision-electron', 'kvision-modules:kvision-cordova', 'kvision-modules:kvision-testutils', - 'kvision-modules:kvision-compiler-plugin', - 'kvision-modules:kvision-gradle-plugin' + 'kvision-tools:kvision-compiler-plugin', + 'kvision-tools:kvision-gradle-plugin' -- cgit