From 2ca4d635ea2026a324469e65fc8fe9be18cf335e Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Mon, 27 Jun 2016 09:17:05 -0700 Subject: [PATCH] Support backward compatibility with gradle-script-kotlin 0.2.0, some refactoring --- .../jetbrains/kotlin/script/scriptTemplate.kt | 113 +++++++++++------- .../jetbrains/kotlin/scripts/ScriptTest2.kt | 2 +- .../script/gradleScriptTemplateProvider.kt | 4 +- 3 files changed, 77 insertions(+), 42 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt index 55e08e549ee..dd401ccd2cf 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt @@ -37,10 +37,20 @@ import kotlin.reflect.* @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) -annotation class ScriptTemplateDefinition(val resolver: KClass, +annotation class ScriptTemplateDefinition(val resolver: KClass, val scriptFilePattern: String) -interface ScriptDependenciesResolver { +@Deprecated("Use ScriptTemplateDefinition") +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class ScriptFilePattern(val pattern: String) + +@Deprecated("Use ScriptTemplateDefinition") +@Target(AnnotationTarget.CLASS) +@Retention(AnnotationRetention.RUNTIME) +annotation class ScriptDependencyResolver(val resolver: KClass) + +interface AnnotationBasedScriptDependenciesResolver { fun resolve(scriptFile: File?, annotations: Iterable, environment: Map?, @@ -48,13 +58,66 @@ interface ScriptDependenciesResolver { ): KotlinScriptExternalDependencies? = null } +@Deprecated("Use new resolver Ex") +interface ScriptDependenciesResolver { + fun resolve(projectRoot: File?, + scriptFile: File?, + annotations: Iterable, + context: Any? + ): KotlinScriptExternalDependencies? = null +} + @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) annotation class AcceptedAnnotations(vararg val supportedAnnotationClasses: KClass) data class KotlinScriptDefinitionFromTemplate(val template: KClass, val environment: Map?) : KotlinScriptDefinition { - private val definitionAnnotation by lazy { template.annotations.firstIsInstanceOrNull() } + // TODO: remove this and simplify definitionAnnotation as soon as deprecated annotations will be removed + internal class ScriptTemplateDefinitionData(val resolverClass: KClass, + val resolver: AnnotationBasedScriptDependenciesResolver?, + val scriptFilePattern: String?) { + val acceptedAnnotations by lazy { + val resolveMethod = AnnotationBasedScriptDependenciesResolver::resolve + val resolverMethodAnnotations = + resolverClass.memberFunctions.find { + it.name == resolveMethod.name && + sameSignature(it, resolveMethod) + } + ?.annotations + ?.filterIsInstance() + resolverMethodAnnotations?.flatMap { + val v = it.supportedAnnotationClasses + v.toList() // TODO: inline after KT-9453 is resolved (now it fails with "java.lang.Class cannot be cast to kotlin.reflect.KClass") + } + ?: emptyList() + } + } + + internal class ObsoleteResolverProxy(val resolverAnn: ScriptDependencyResolver?) : AnnotationBasedScriptDependenciesResolver { + private val resolver by lazy { resolverAnn?.resolver?.primaryConstructor?.call() } + override fun resolve(scriptFile: File?, + annotations: Iterable, + environment: Map?, + previousDependencies: KotlinScriptExternalDependencies? + ): KotlinScriptExternalDependencies? = + resolver?.resolve( + environment?.get("projectRoot") as? File?, + scriptFile, + emptyList(), + environment as Any? + ) + } + + private val definitionData by lazy { + val defAnn = template.annotations.firstIsInstanceOrNull() + if (defAnn == null) { + val resolverAnn = template.annotations.firstIsInstanceOrNull() + val filePatternAnn = template.annotations.firstIsInstanceOrNull() + ScriptTemplateDefinitionData(ObsoleteResolverProxy::class, ObsoleteResolverProxy(resolverAnn), filePatternAnn?.pattern) + } + else ScriptTemplateDefinitionData(defAnn.resolver, defAnn.resolver.primaryConstructor?.call(), defAnn.scriptFilePattern) + } override val name = template.simpleName!! @@ -68,45 +131,17 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass, val getScriptParameters(scriptDescriptor).map { it.name } override fun isScript(file: TF): Boolean = - definitionAnnotation?.let { Regex(it.scriptFilePattern).matches(getFileName(file)) } ?: false + definitionData.scriptFilePattern?.let { Regex(it).matches(getFileName(file)) } ?: false // TODO: implement other strategy - e.g. try to extract something from match with ScriptFilePattern override fun getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, KotlinParserDefinition.STD_SCRIPT_EXT) - private class ResolverWithAcceptedAnnotations(val resolverClass: KClass) { - val resolver by lazy { resolverClass.primaryConstructor!!.call() } - val acceptedAnnotations by lazy { - val resolveMethod = ScriptDependenciesResolver::resolve - val resolverMethodAnnotations = - resolverClass.memberFunctions.find { - it.name == resolveMethod.name && - sameSignature(it, resolveMethod) - } - ?.annotations - ?.filterIsInstance() - resolverMethodAnnotations?.flatMap { - val v = it.supportedAnnotationClasses - v.toList() // TODO: inline after KT-9453 is resolved (now it fails with "java.lang.Class cannot be cast to kotlin.reflect.KClass") - } - ?: emptyList() - } - } - - private val dependenciesResolvers by lazy { - definitionAnnotation?.resolver?.let { listOf(ResolverWithAcceptedAnnotations(it)) } ?: emptyList() - } - - private val supportedAnnotationClasses: List> by lazy { - dependenciesResolvers.flatMap { it.acceptedAnnotations } - .distinctBy { it.qualifiedName } - } - override fun getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? { val fileAnnotations = getAnnotationEntries(file, project) .map { KtAnnotationWrapper(it) } .mapNotNull { wrappedAnn -> // TODO: consider advanced matching using semantic similar to actual resolving - supportedAnnotationClasses.find { + definitionData.acceptedAnnotations.find { wrappedAnn.name == it.simpleName || wrappedAnn.name == it.qualifiedName }?.let { it to wrappedAnn } } @@ -120,14 +155,12 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass, val annClassToWrapper.first to InvalidScriptResolverAnnotation(annClassToWrapper.second.name, annClassToWrapper.second.valueArguments, ex) } } - val fileDeps = dependenciesResolvers.mapNotNull { resolverWrapper -> - val supportedAnnotations = annotations.mapNotNull { annClassToWrapper -> - val annFQN = annClassToWrapper.first.qualifiedName - if (resolverWrapper.acceptedAnnotations.any { it.qualifiedName == annFQN }) annClassToWrapper.second else null - } - resolverWrapper.resolver.resolve(getFile(file), supportedAnnotations, environment, previousDependencies) + val supportedAnnotations = annotations.mapNotNull { annClassToWrapper -> + val annFQN = annClassToWrapper.first.qualifiedName + if (definitionData.acceptedAnnotations.any { it.qualifiedName == annFQN }) annClassToWrapper.second else null } - return KotlinScriptExternalDependenciesUnion(fileDeps) + val fileDeps = definitionData.resolver?.resolve(getFile(file), supportedAnnotations, environment, previousDependencies) + return fileDeps } private fun getAnnotationEntries(file: TF, project: Project): Iterable = when (file) { diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt index d771ed40649..9531bbf7d6d 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest2.kt @@ -118,7 +118,7 @@ class ScriptTest2 { } } -class TestKotlinScriptDependenciesResolver : ScriptDependenciesResolver { +class TestKotlinScriptDependenciesResolver : AnnotationBasedScriptDependenciesResolver { private val kotlinPaths by lazy { PathUtil.getKotlinPathsForCompiler() } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/gradleScriptTemplateProvider.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/gradleScriptTemplateProvider.kt index 6a994ac4880..2ce439973b2 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/gradleScriptTemplateProvider.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/gradleScriptTemplateProvider.kt @@ -35,7 +35,9 @@ class GradleScriptTemplateProvider(project: Project, gim: GradleInstallationMana gradleLibsPath?.listFiles { file -> file.extension == "jar" && depLibsPrefixes.any { file.name.startsWith(it) } } ?.map { it.canonicalPath } ?: emptyList() - override val environment: Map? = mapOf("gradleHome" to gradleHome) + override val environment: Map? = mapOf( + "gradleHome" to gradleHome, + "projectRoot" to (project.basePath ?: project.baseDir.canonicalPath )?.let { File(it) }) companion object { private val depLibsPrefixes = listOf("gradle-script-kotlin", "gradle-core")