From ed7c38fb96d0e270969ed6e2346f7ff0c834aacd Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Thu, 29 Sep 2016 15:01:55 +0300 Subject: [PATCH] Allopen: Add allopen Gradle subplugin --- libraries/pom.xml | 1 + libraries/tools/kotlin-allopen/pom.xml | 148 ++++++++++++++++++ .../kotlin/allopen/gradle/AllOpenExtension.kt | 33 ++++ .../kotlin/allopen/gradle/AllOpenSubplugin.kt | 70 +++++++++ .../allopen/gradle/KotlinSpringSubplugin.kt | 31 ++++ .../gradle-plugins/kotlin-allopen.properties | 1 + .../gradle-plugins/kotlin-spring.properties | 1 + ...kotlin.gradle.plugin.KotlinGradleSubplugin | 1 + .../pom.xml | 6 + .../kotlin/gradle/SimpleKotlinGradleIT.kt | 45 ++++++ .../testProject/allOpenSimple/build.gradle | 28 ++++ .../allOpenSimple/src/annotations.kt | 5 + .../testProject/allOpenSimple/src/test.kt | 13 ++ .../testProject/allOpenSpring/build.gradle | 24 +++ .../springframework/stereotype/Component.java | 60 +++++++ .../testProject/allOpenSpring/src/test.kt | 12 ++ .../kotlin/gradle/util/bytecodeUtils.kt | 4 + 17 files changed, 483 insertions(+) create mode 100755 libraries/tools/kotlin-allopen/pom.xml create mode 100644 libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenExtension.kt create mode 100644 libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt create mode 100644 libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/KotlinSpringSubplugin.kt create mode 100644 libraries/tools/kotlin-allopen/src/main/resources/META-INF/gradle-plugins/kotlin-allopen.properties create mode 100644 libraries/tools/kotlin-allopen/src/main/resources/META-INF/gradle-plugins/kotlin-spring.properties create mode 100644 libraries/tools/kotlin-allopen/src/main/resources/META-INF/services/org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/src/annotations.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/src/test.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/src/org/springframework/stereotype/Component.java create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/src/test.kt diff --git a/libraries/pom.xml b/libraries/pom.xml index d3351cfd68d..8d195b0aa9b 100644 --- a/libraries/pom.xml +++ b/libraries/pom.xml @@ -100,6 +100,7 @@ tools/kotlin-js-tests tools/kotlin-js-tests-junit tools/kotlin-annotation-processing + tools/kotlin-allopen tools/kotlin-gradle-plugin tools/kotlin-gradle-plugin-api diff --git a/libraries/tools/kotlin-allopen/pom.xml b/libraries/tools/kotlin-allopen/pom.xml new file mode 100755 index 00000000000..79702108e65 --- /dev/null +++ b/libraries/tools/kotlin-allopen/pom.xml @@ -0,0 +1,148 @@ + + + + 4.0.0 + + 3.0.4 + ${basedir}/../../../plugins/allopen/src + ${basedir}/src/main/kotlin + ${basedir}/src/main/resources + ${basedir}/target/src/main/kotlin + ${basedir}/target/resource + + + + org.jetbrains.kotlin + kotlin-project + 1.1-SNAPSHOT + ../../pom.xml + + + kotlin-allopen + jar + + All-open plugin for Gradle + + + + jetbrains-utils + http://repository.jetbrains.com/utils + + + + + + org.jetbrains.kotlin + kotlin-stdlib + ${project.version} + + + org.jetbrains.kotlin + kotlin-compiler-embeddable + ${project.version} + provided + + + org.jetbrains.kotlin + kotlin-gradle-plugin-api + ${project.version} + provided + + + org.jetbrains.kotlin + gradle-api + 2.2 + provided + + + + + ${allopen.target-src} + + + ${allopen.target-resources} + + + + + + maven-resources-plugin + 3.0.0 + + + copy-sources + validate + + copy-resources + + + ${allopen.target-src} + + ${allopen.src} + ${allopen.gradle.plugin.src} + + + + + copy-resources + validate + + copy-resources + + + ${allopen.target-resources}/META-INF + + ${allopen.src}/META-INF + ${allopen.gradle.plugin.resources}/META-INF + + + + + + + com.google.code.maven-replacer-plugin + replacer + 1.5.3 + + + generate-sources + + replace + + + + + + ${allopen.target-src}/** + + + + com\.intellij + org.jetbrains.kotlin.com.intellij + + + + + + kotlin-maven-plugin + org.jetbrains.kotlin + ${project.version} + + + + compile + compile + compile + + + ${allopen.target-src} + + + + + + + + diff --git a/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenExtension.kt b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenExtension.kt new file mode 100644 index 00000000000..3cf83b7763a --- /dev/null +++ b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenExtension.kt @@ -0,0 +1,33 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.allopen.gradle + +open class AllOpenExtension { + internal val myAnnotations = mutableListOf() + + open fun annotation(fqName: String) { + myAnnotations.add(fqName) + } + + open fun annotations(fqNames: List) { + myAnnotations.addAll(fqNames) + } + + open fun annotations(vararg fqNames: String) { + myAnnotations.addAll(fqNames) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt new file mode 100644 index 00000000000..ab91c24af24 --- /dev/null +++ b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/AllOpenSubplugin.kt @@ -0,0 +1,70 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.allopen.gradle + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.tasks.SourceSet +import org.gradle.api.tasks.compile.AbstractCompile +import org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin +import org.jetbrains.kotlin.gradle.plugin.SubpluginOption + +class AllOpenGradleSubplugin : Plugin { + companion object { + fun isEnabled(project: Project) = project.plugins.findPlugin(AllOpenGradleSubplugin::class.java) != null + + fun getAllOpenExtension(project: Project): AllOpenExtension { + return project.extensions.getByType(AllOpenExtension::class.java) + } + } + + override fun apply(project: Project) { + project.extensions.create("allOpen", AllOpenExtension::class.java) + } +} + +class AllOpenKotlinGradleSubplugin : KotlinGradleSubplugin { + private companion object { + val ANNOTATIONS_ARG_NAME = "annotation" + } + + override fun isApplicable(project: Project, task: AbstractCompile) = AllOpenGradleSubplugin.isEnabled(project) + + override fun apply( + project: Project, + kotlinCompile: AbstractCompile, + javaCompile: AbstractCompile, + variantData: Any?, + javaSourceSet: SourceSet? + ): List { + if (!AllOpenGradleSubplugin.isEnabled(project)) return emptyList() + + val allOpenExtension = project.extensions.findByType(AllOpenExtension::class.java) ?: return emptyList() + + val options = mutableListOf() + + for (anno in allOpenExtension.myAnnotations) { + options += SubpluginOption(ANNOTATIONS_ARG_NAME, anno) + } + + return options + } + + override fun getArtifactName() = "kotlin-allopen" + override fun getGroupName() = "org.jetbrains.kotlin" + override fun getPluginName() = "org.jetbrains.kotlin.allopen" +} \ No newline at end of file diff --git a/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/KotlinSpringSubplugin.kt b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/KotlinSpringSubplugin.kt new file mode 100644 index 00000000000..20356132b8a --- /dev/null +++ b/libraries/tools/kotlin-allopen/src/main/kotlin/org/jetbrains/kotlin/allopen/gradle/KotlinSpringSubplugin.kt @@ -0,0 +1,31 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.allopen.gradle + +import org.gradle.api.Plugin +import org.gradle.api.Project + +class SpringGradleSubplugin : Plugin { + override fun apply(project: Project) { + project.plugins.apply(AllOpenGradleSubplugin::class.java) + val allOpenExtension = AllOpenGradleSubplugin.getAllOpenExtension(project) + allOpenExtension.annotations("org.springframework.stereotype.Component", + "org.springframework.transaction.annotation.Transactional", + "org.springframework.scheduling.annotation.Async", + "org.springframework.cache.annotation.Cacheable") + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-allopen/src/main/resources/META-INF/gradle-plugins/kotlin-allopen.properties b/libraries/tools/kotlin-allopen/src/main/resources/META-INF/gradle-plugins/kotlin-allopen.properties new file mode 100644 index 00000000000..a454f56564c --- /dev/null +++ b/libraries/tools/kotlin-allopen/src/main/resources/META-INF/gradle-plugins/kotlin-allopen.properties @@ -0,0 +1 @@ +implementation-class=org.jetbrains.kotlin.allopen.gradle.AllOpenGradleSubplugin \ No newline at end of file diff --git a/libraries/tools/kotlin-allopen/src/main/resources/META-INF/gradle-plugins/kotlin-spring.properties b/libraries/tools/kotlin-allopen/src/main/resources/META-INF/gradle-plugins/kotlin-spring.properties new file mode 100644 index 00000000000..32ce0b3cf8a --- /dev/null +++ b/libraries/tools/kotlin-allopen/src/main/resources/META-INF/gradle-plugins/kotlin-spring.properties @@ -0,0 +1 @@ +implementation-class=org.jetbrains.kotlin.allopen.gradle.SpringGradleSubplugin \ No newline at end of file diff --git a/libraries/tools/kotlin-allopen/src/main/resources/META-INF/services/org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin b/libraries/tools/kotlin-allopen/src/main/resources/META-INF/services/org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin new file mode 100644 index 00000000000..5f04def2d18 --- /dev/null +++ b/libraries/tools/kotlin-allopen/src/main/resources/META-INF/services/org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin @@ -0,0 +1 @@ +org.jetbrains.kotlin.allopen.gradle.AllOpenKotlinGradleSubplugin \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/pom.xml b/libraries/tools/kotlin-gradle-plugin-integration-tests/pom.xml index 3c6eafe0def..c1dfa8d1b18 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/pom.xml +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/pom.xml @@ -45,6 +45,12 @@ ${project.version} test + + org.jetbrains.kotlin + kotlin-allopen + ${project.version} + test + org.jetbrains.kotlin kotlin-gradle-subplugin-example diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt index af44201ec1b..87ae90d1567 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/SimpleKotlinGradleIT.kt @@ -1,6 +1,9 @@ package org.jetbrains.kotlin.gradle +import org.jetbrains.kotlin.gradle.util.checkBytecodeContains import org.junit.Test +import java.io.File +import kotlin.test.assertTrue class SimpleKotlinGradleIT : BaseGradleIT() { @@ -99,4 +102,46 @@ class SimpleKotlinGradleIT : BaseGradleIT() { assertContains("GreeterTest PASSED") } } + + @Test + fun testAllOpenPlugin() { + Project("allOpenSimple", GRADLE_VERSION).build("build") { + assertSuccessful() + + val classesDir = File(project.projectDir, "build/classes/main") + val openClass = File(classesDir, "test/OpenClass.class") + val closedClass = File(classesDir, "test/ClosedClass.class") + assertTrue(openClass.exists()) + assertTrue(closedClass.exists()) + + checkBytecodeContains(openClass, + "public class test/OpenClass {", + "public method()V") + + checkBytecodeContains(closedClass, + "public final class test/ClosedClass {", + "public final method()V") + } + } + + @Test + fun testKotlinSpringPlugin() { + Project("allOpenSpring", GRADLE_VERSION).build("build") { + assertSuccessful() + + val classesDir = File(project.projectDir, "build/classes/main") + val openClass = File(classesDir, "test/OpenClass.class") + val closedClass = File(classesDir, "test/ClosedClass.class") + assertTrue(openClass.exists()) + assertTrue(closedClass.exists()) + + checkBytecodeContains(openClass, + "public class test/OpenClass {", + "public method()V") + + checkBytecodeContains(closedClass, + "public final class test/ClosedClass {", + "public final method()V") + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/build.gradle new file mode 100644 index 00000000000..3fe5b66753e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/build.gradle @@ -0,0 +1,28 @@ +buildscript { + repositories { + mavenLocal() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" + } +} + +apply plugin: "kotlin" +apply plugin: "kotlin-allopen" + +repositories { + mavenLocal() +} + +sourceSets { + main.kotlin.srcDir 'src' +} + +allOpen { + annotation("lib.AllOpen") +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/src/annotations.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/src/annotations.kt new file mode 100644 index 00000000000..b3b21ba837a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/src/annotations.kt @@ -0,0 +1,5 @@ +package lib + +annotation class AllOpen + +annotation class AllClose \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/src/test.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/src/test.kt new file mode 100644 index 00000000000..d33c0c3a094 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSimple/src/test.kt @@ -0,0 +1,13 @@ +package test + +import lib.* + +@AllOpen +class OpenClass { + fun method() {} +} + +@AllClose // effectively does nothing +class ClosedClass { + fun method() {} +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/build.gradle new file mode 100644 index 00000000000..85f3bf457cc --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/build.gradle @@ -0,0 +1,24 @@ +buildscript { + repositories { + mavenLocal() + } + dependencies { + classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath "org.jetbrains.kotlin:kotlin-allopen:$kotlin_version" + } +} + +apply plugin: "kotlin" +apply plugin: "kotlin-spring" + +repositories { + mavenLocal() +} + +sourceSets { + main.kotlin.srcDir 'src' +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/src/org/springframework/stereotype/Component.java b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/src/org/springframework/stereotype/Component.java new file mode 100644 index 00000000000..dda67f42e26 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/src/org/springframework/stereotype/Component.java @@ -0,0 +1,60 @@ +/** + * This file was copied from the spring framework: + * https://github.com/spring-projects/spring-framework + */ + +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.stereotype; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Indicates that an annotated class is a "component". + * Such classes are considered as candidates for auto-detection + * when using annotation-based configuration and classpath scanning. + * + *

Other class-level annotations may be considered as identifying + * a component as well, typically a special kind of component: + * e.g. the {@link Repository @Repository} annotation or AspectJ's + * {@link org.aspectj.lang.annotation.Aspect @Aspect} annotation. + * + * @ author Mark Fisher + * @since 2.5 + * @see Repository + * @see Service + * @see Controller + * @see org.springframework.context.annotation.ClassPathBeanDefinitionScanner + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Indexed +public @interface Component { + + /** + * The value may indicate a suggestion for a logical component name, + * to be turned into a Spring bean in case of an autodetected component. + * @return the suggested component name, if any + */ + String value() default ""; + +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/src/test.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/src/test.kt new file mode 100644 index 00000000000..1ed4250b66b --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/allOpenSpring/src/test.kt @@ -0,0 +1,12 @@ +package test + +import org.springframework.stereotype.Component + +@Component +class OpenClass { + fun method() {} +} + +class ClosedClass { + fun method() {} +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/util/bytecodeUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/util/bytecodeUtils.kt index e7d6812924d..126873b1d2d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/util/bytecodeUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/util/bytecodeUtils.kt @@ -13,6 +13,10 @@ fun classFileBytecodeString(classFile: File): String { return out.toString() } +fun checkBytecodeContains(classFile: File, vararg strings: String) { + checkBytecodeContains(classFile, strings.toList()) +} + fun checkBytecodeContains(classFile: File, strings: Iterable) { val bytecode = classFileBytecodeString(classFile) for (string in strings) {