From df647361926db41be6b667a1d366f600af759976 Mon Sep 17 00:00:00 2001 From: Ilya Chernikov Date: Mon, 1 Aug 2016 13:48:18 +0200 Subject: [PATCH] Refactor script dependnecies template and resolver interfaces: - get rid of obsolete interfaces and annotations - rename actual resolver interface to ScriptDependenciesResolver - make ScriptDependenciesResolverEx interface compatible with the one from 1.1-M01 to be able to support both on the provider side - add possibility to override file patter in the script template provider - construct resolver lazily, if possible --- .../script/scriptDefinitionFromTemplate.kt | 96 ++++++++----------- .../jetbrains/kotlin/script/scriptTemplate.kt | 31 ++---- .../scriptTemplateProviderExtensionPoint.kt | 6 +- .../jetbrains/kotlin/scripts/ScriptTest2.kt | 6 +- 4 files changed, 59 insertions(+), 80 deletions(-) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptDefinitionFromTemplate.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptDefinitionFromTemplate.kt index 0973c37a39d..1db915b5f5c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptDefinitionFromTemplate.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptDefinitionFromTemplate.kt @@ -31,24 +31,25 @@ import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.File -import java.util.concurrent.Future import kotlin.reflect.KClass import kotlin.reflect.memberFunctions import kotlin.reflect.primaryConstructor data class KotlinScriptDefinitionFromTemplate(val template: KClass, - val resolver: ScriptDependenciesResolverEx? = null, + val resolver: ScriptDependenciesResolver? = null, + val scriptFilePattern: String? = null, val environment: Map? = null ) : KotlinScriptDefinition { - private val log = Logger.getInstance(KotlinScriptDefinitionFromTemplate::class.java) - // TODO: remove this and simplify definitionAnnotation as soon as deprecated annotations will be removed - internal class ScriptTemplateDefinitionData(val resolverClass: KClass, - val resolver: ScriptDependenciesResolverEx?, + internal class ScriptTemplateDefinitionData(val resolverClass: KClass, + makeResolver: () -> ScriptDependenciesResolver?, val scriptFilePattern: String?) { + + val resolver: ScriptDependenciesResolver? by lazy(makeResolver) + val acceptedAnnotations: List> by lazy { - val resolveMethod = ScriptDependenciesResolverEx::resolve + val resolveMethod = ScriptDependenciesResolver::resolve val resolverMethodAnnotations = resolverClass.memberFunctions.find { it.name == resolveMethod.name && @@ -64,33 +65,14 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass, } } - internal class ObsoleteResolverProxy(val resolverAnn: ScriptDependencyResolver?) : ScriptDependenciesResolverEx { - private val resolver by lazy { resolverAnn?.resolver?.primaryConstructor?.call() } - override fun resolve(script: ScriptContents, - environment: Map?, - report: (ScriptDependenciesResolverEx.ReportSeverity, String, ScriptContents.Position?) -> Unit, - previousDependencies: KotlinScriptExternalDependencies? - ): Future = - resolver?.resolve( - environment?.get("projectRoot") as? File?, - script.file, - emptyList(), - environment as Any? - ) - .asFuture() - } - private val definitionData by lazy { val defAnn = template.annotations.firstIsInstanceOrNull() - val obsoleteResolverAnn = template.annotations.firstIsInstanceOrNull() - val filePattern = defAnn?.scriptFilePattern ?: - template.annotations.firstIsInstanceOrNull()?.pattern ?: - DEFAULT_SCRIPT_FILE_PATTERN + val filePattern = scriptFilePattern ?: defAnn?.scriptFilePattern ?: DEFAULT_SCRIPT_FILE_PATTERN when { - resolver != null -> ScriptTemplateDefinitionData(resolver.javaClass.kotlin, resolver, filePattern) - defAnn != null -> ScriptTemplateDefinitionData(defAnn.resolver, defAnn.resolver.primaryConstructor?.call(), filePattern) - obsoleteResolverAnn != null -> ScriptTemplateDefinitionData(ObsoleteResolverProxy::class, ObsoleteResolverProxy(obsoleteResolverAnn), filePattern) - else -> ScriptTemplateDefinitionData(BasicScriptDependenciesResolver::class, BasicScriptDependenciesResolver(), filePattern) + resolver != null -> ScriptTemplateDefinitionData(resolver.javaClass.kotlin, { resolver }, filePattern) + // TODO: logScriptDefMessage missing or invalid constructor + defAnn != null -> ScriptTemplateDefinitionData(defAnn.resolver, { defAnn.resolver.primaryConstructor?.call() }, filePattern) + else -> ScriptTemplateDefinitionData(BasicScriptDependenciesResolver::class, ::BasicScriptDependenciesResolver, filePattern) } } @@ -111,30 +93,22 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass, // 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) + override fun getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? { - val script = BasicScriptContents(file) { - val classLoader = (template as Any).javaClass.classLoader - getAnnotationEntries(file, project) - .mapNotNull { psiAnn -> - // TODO: consider advanced matching using semantic similar to actual resolving - definitionData.acceptedAnnotations.find { ann -> - psiAnn.typeName.let { it == ann.simpleName || it == ann.qualifiedName } - }?.let { KtAnnotationWrapper(psiAnn, classLoader.loadClass(it.qualifiedName).kotlin as KClass) } - } - .map { it.getProxy(classLoader) } - } - val reportFn = { reportSeverity: ScriptDependenciesResolverEx.ReportSeverity, s: String, position: ScriptContents.Position? -> - val msg = (position?.run { "[at $line:$col]" } ?: "") + s - when (reportSeverity) { - ScriptDependenciesResolverEx.ReportSeverity.ERROR -> log.error(msg) - ScriptDependenciesResolverEx.ReportSeverity.WARNING -> log.warn(msg) - ScriptDependenciesResolverEx.ReportSeverity.INFO -> log.info(msg) - ScriptDependenciesResolverEx.ReportSeverity.DEBUG -> log.debug(msg) - } - } - - val fileDeps = definitionData.resolver?.resolve(script, environment, reportFn, previousDependencies) + val script = BasicScriptContents(file, getAnnotations = { + val classLoader = (template as Any).javaClass.classLoader + getAnnotationEntries(file, project) + .mapNotNull { psiAnn -> + // TODO: consider advanced matching using semantic similar to actual resolving + definitionData.acceptedAnnotations.find { ann -> + psiAnn.typeName.let { it == ann.simpleName || it == ann.qualifiedName } + }?.let { KtAnnotationWrapper(psiAnn, classLoader.loadClass(it.qualifiedName).kotlin as KClass) } + } + .map { it.getProxy(classLoader) } + }) + val fileDeps = definitionData.resolver?.resolve(script, environment, ::logScriptDefMessage, previousDependencies) + // TODO: use it as a Future return fileDeps?.get() } @@ -164,4 +138,18 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass, override val annotations: Iterable by lazy { getAnnotations() } override val text: CharSequence? by lazy { getFileContents(myFile) } } -} \ No newline at end of file + + companion object { + internal val log = Logger.getInstance(KotlinScriptDefinitionFromTemplate::class.java) + } +} + +internal fun logScriptDefMessage(reportSeverity: ScriptDependenciesResolver.ReportSeverity, s: String, position: ScriptContents.Position?): Unit { + val msg = (position?.run { "[at $line:$col]" } ?: "") + s + when (reportSeverity) { + ScriptDependenciesResolver.ReportSeverity.ERROR -> KotlinScriptDefinitionFromTemplate.log.error(msg) + ScriptDependenciesResolver.ReportSeverity.WARNING -> KotlinScriptDefinitionFromTemplate.log.warn(msg) + ScriptDependenciesResolver.ReportSeverity.INFO -> KotlinScriptDefinitionFromTemplate.log.info(msg) + ScriptDependenciesResolver.ReportSeverity.DEBUG -> KotlinScriptDefinitionFromTemplate.log.debug(msg) + } +} diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt index 443e42c4622..9f4076bc371 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplate.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.script -import org.jetbrains.kotlin.psi.KtAnnotationEntry import java.io.File import java.util.concurrent.Future import java.util.concurrent.TimeUnit @@ -28,19 +27,9 @@ const val DEFAULT_SCRIPT_FILE_PATTERN = ".*\\.kts" @Target(AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) -annotation class ScriptTemplateDefinition(val resolver: KClass = BasicScriptDependenciesResolver::class, +annotation class ScriptTemplateDefinition(val resolver: KClass = BasicScriptDependenciesResolver::class, val scriptFilePattern: String = DEFAULT_SCRIPT_FILE_PATTERN) -@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 ScriptContents { data class Position(val line: Int, val col: Int) @@ -60,8 +49,7 @@ class PseudoFuture(private val value: T): Future { fun KotlinScriptExternalDependencies?.asFuture(): PseudoFuture = PseudoFuture(this) -// TODO: rename to just ScriptDependenciesResolver as soon as current deprecated one will be dropped -interface ScriptDependenciesResolverEx { +interface ScriptDependenciesResolver { enum class ReportSeverity { ERROR, WARNING, INFO, DEBUG } @@ -72,16 +60,17 @@ interface ScriptDependenciesResolverEx { ): Future = PseudoFuture(null) } -@Deprecated("Use new ScriptDependenciesResolverEx") -interface ScriptDependenciesResolver { - fun resolve(projectRoot: File?, - scriptFile: File?, - annotations: Iterable, - context: Any? +@Suppress("unused") // used in gradle-script-kotlin for a moment +@Deprecated("Use new ScriptDependenciesResolver, this one is left for temporary compatibility of new resolvers to kotlin plugin 1.1-M01", + ReplaceWith("ScriptDependenciesResolver")) +interface ScriptDependenciesResolverEx { + fun resolve(script: ScriptContents, + environment: Map?, + previousDependencies: KotlinScriptExternalDependencies? ): KotlinScriptExternalDependencies? = null } -class BasicScriptDependenciesResolver : ScriptDependenciesResolverEx +class BasicScriptDependenciesResolver : ScriptDependenciesResolver @Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS) @Retention(AnnotationRetention.RUNTIME) diff --git a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplateProviderExtensionPoint.kt b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplateProviderExtensionPoint.kt index 6fd5eb3f8e4..524b6db3d33 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplateProviderExtensionPoint.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/script/scriptTemplateProviderExtensionPoint.kt @@ -32,7 +32,9 @@ interface ScriptTemplateProvider { val templateClassName: String - val resolver: ScriptDependenciesResolverEx? get() = null + val resolver: ScriptDependenciesResolver? get() = null + + val filePattern: String? get() = null val dependenciesClasspath: Iterable @@ -58,7 +60,7 @@ fun makeScriptDefsFromTemplateProviders(providers: Iterable? = null, runIsolated: Boolean = true, suppressOutput: Boolean = false): Class<*>? = - compileScriptImpl("compiler/testData/script/" + scriptPath, KotlinScriptDefinitionFromTemplate(scriptBase, null, environment), runIsolated, suppressOutput) + compileScriptImpl("compiler/testData/script/" + scriptPath, KotlinScriptDefinitionFromTemplate(scriptBase, null, null, environment), runIsolated, suppressOutput) private fun compileScriptImpl( scriptPath: String, @@ -126,14 +126,14 @@ class ScriptTest2 { } } -class TestKotlinScriptDependenciesResolver : ScriptDependenciesResolverEx { +class TestKotlinScriptDependenciesResolver : ScriptDependenciesResolver { private val kotlinPaths by lazy { PathUtil.getKotlinPathsForCompiler() } @AcceptedAnnotations(DependsOn::class, DependsOnTwo::class) override fun resolve(script: ScriptContents, environment: Map?, - report: (ScriptDependenciesResolverEx.ReportSeverity, String, ScriptContents.Position?) -> Unit, + report: (ScriptDependenciesResolver.ReportSeverity, String, ScriptContents.Position?) -> Unit, previousDependencies: KotlinScriptExternalDependencies? ): Future {