Support backward compatibility with gradle-script-kotlin 0.2.0, some refactoring
This commit is contained in:
@@ -37,10 +37,20 @@ import kotlin.reflect.*
|
|||||||
|
|
||||||
@Target(AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
annotation class ScriptTemplateDefinition(val resolver: KClass<out ScriptDependenciesResolver>,
|
annotation class ScriptTemplateDefinition(val resolver: KClass<out AnnotationBasedScriptDependenciesResolver>,
|
||||||
val scriptFilePattern: String)
|
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<out ScriptDependenciesResolver>)
|
||||||
|
|
||||||
|
interface AnnotationBasedScriptDependenciesResolver {
|
||||||
fun resolve(scriptFile: File?,
|
fun resolve(scriptFile: File?,
|
||||||
annotations: Iterable<Annotation>,
|
annotations: Iterable<Annotation>,
|
||||||
environment: Map<String, Any?>?,
|
environment: Map<String, Any?>?,
|
||||||
@@ -48,13 +58,66 @@ interface ScriptDependenciesResolver {
|
|||||||
): KotlinScriptExternalDependencies? = null
|
): KotlinScriptExternalDependencies? = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated("Use new resolver Ex")
|
||||||
|
interface ScriptDependenciesResolver {
|
||||||
|
fun resolve(projectRoot: File?,
|
||||||
|
scriptFile: File?,
|
||||||
|
annotations: Iterable<KtAnnotationEntry>,
|
||||||
|
context: Any?
|
||||||
|
): KotlinScriptExternalDependencies? = null
|
||||||
|
}
|
||||||
|
|
||||||
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
@Target(AnnotationTarget.FUNCTION, AnnotationTarget.CLASS)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
annotation class AcceptedAnnotations(vararg val supportedAnnotationClasses: KClass<out Annotation>)
|
annotation class AcceptedAnnotations(vararg val supportedAnnotationClasses: KClass<out Annotation>)
|
||||||
|
|
||||||
data class KotlinScriptDefinitionFromTemplate(val template: KClass<out Any>, val environment: Map<String, Any?>?) : KotlinScriptDefinition {
|
data class KotlinScriptDefinitionFromTemplate(val template: KClass<out Any>, val environment: Map<String, Any?>?) : KotlinScriptDefinition {
|
||||||
|
|
||||||
private val definitionAnnotation by lazy { template.annotations.firstIsInstanceOrNull<ScriptTemplateDefinition>() }
|
// TODO: remove this and simplify definitionAnnotation as soon as deprecated annotations will be removed
|
||||||
|
internal class ScriptTemplateDefinitionData(val resolverClass: KClass<out AnnotationBasedScriptDependenciesResolver>,
|
||||||
|
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<AcceptedAnnotations>()
|
||||||
|
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<Annotation>,
|
||||||
|
environment: Map<String, Any?>?,
|
||||||
|
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<ScriptTemplateDefinition>()
|
||||||
|
if (defAnn == null) {
|
||||||
|
val resolverAnn = template.annotations.firstIsInstanceOrNull<ScriptDependencyResolver>()
|
||||||
|
val filePatternAnn = template.annotations.firstIsInstanceOrNull<ScriptFilePattern>()
|
||||||
|
ScriptTemplateDefinitionData(ObsoleteResolverProxy::class, ObsoleteResolverProxy(resolverAnn), filePatternAnn?.pattern)
|
||||||
|
}
|
||||||
|
else ScriptTemplateDefinitionData(defAnn.resolver, defAnn.resolver.primaryConstructor?.call(), defAnn.scriptFilePattern)
|
||||||
|
}
|
||||||
|
|
||||||
override val name = template.simpleName!!
|
override val name = template.simpleName!!
|
||||||
|
|
||||||
@@ -68,45 +131,17 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass<out Any>, val
|
|||||||
getScriptParameters(scriptDescriptor).map { it.name }
|
getScriptParameters(scriptDescriptor).map { it.name }
|
||||||
|
|
||||||
override fun <TF> isScript(file: TF): Boolean =
|
override fun <TF> 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
|
// 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 getScriptName(script: KtScript): Name = ScriptNameUtil.fileNameWithExtensionStripped(script, KotlinParserDefinition.STD_SCRIPT_EXT)
|
||||||
|
|
||||||
private class ResolverWithAcceptedAnnotations(val resolverClass: KClass<out ScriptDependenciesResolver>) {
|
|
||||||
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<AcceptedAnnotations>()
|
|
||||||
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<KClass<out Any>> by lazy {
|
|
||||||
dependenciesResolvers.flatMap { it.acceptedAnnotations }
|
|
||||||
.distinctBy { it.qualifiedName }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? {
|
override fun <TF> getDependenciesFor(file: TF, project: Project, previousDependencies: KotlinScriptExternalDependencies?): KotlinScriptExternalDependencies? {
|
||||||
val fileAnnotations = getAnnotationEntries(file, project)
|
val fileAnnotations = getAnnotationEntries(file, project)
|
||||||
.map { KtAnnotationWrapper(it) }
|
.map { KtAnnotationWrapper(it) }
|
||||||
.mapNotNull { wrappedAnn ->
|
.mapNotNull { wrappedAnn ->
|
||||||
// TODO: consider advanced matching using semantic similar to actual resolving
|
// TODO: consider advanced matching using semantic similar to actual resolving
|
||||||
supportedAnnotationClasses.find {
|
definitionData.acceptedAnnotations.find {
|
||||||
wrappedAnn.name == it.simpleName || wrappedAnn.name == it.qualifiedName
|
wrappedAnn.name == it.simpleName || wrappedAnn.name == it.qualifiedName
|
||||||
}?.let { it to wrappedAnn }
|
}?.let { it to wrappedAnn }
|
||||||
}
|
}
|
||||||
@@ -120,14 +155,12 @@ data class KotlinScriptDefinitionFromTemplate(val template: KClass<out Any>, val
|
|||||||
annClassToWrapper.first to InvalidScriptResolverAnnotation(annClassToWrapper.second.name, annClassToWrapper.second.valueArguments, ex)
|
annClassToWrapper.first to InvalidScriptResolverAnnotation(annClassToWrapper.second.name, annClassToWrapper.second.valueArguments, ex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
val fileDeps = dependenciesResolvers.mapNotNull { resolverWrapper ->
|
val supportedAnnotations = annotations.mapNotNull { annClassToWrapper ->
|
||||||
val supportedAnnotations = annotations.mapNotNull { annClassToWrapper ->
|
val annFQN = annClassToWrapper.first.qualifiedName
|
||||||
val annFQN = annClassToWrapper.first.qualifiedName
|
if (definitionData.acceptedAnnotations.any { it.qualifiedName == annFQN }) annClassToWrapper.second else null
|
||||||
if (resolverWrapper.acceptedAnnotations.any { it.qualifiedName == annFQN }) annClassToWrapper.second else null
|
|
||||||
}
|
|
||||||
resolverWrapper.resolver.resolve(getFile(file), supportedAnnotations, environment, previousDependencies)
|
|
||||||
}
|
}
|
||||||
return KotlinScriptExternalDependenciesUnion(fileDeps)
|
val fileDeps = definitionData.resolver?.resolve(getFile(file), supportedAnnotations, environment, previousDependencies)
|
||||||
|
return fileDeps
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <TF> getAnnotationEntries(file: TF, project: Project): Iterable<KtAnnotationEntry> = when (file) {
|
private fun <TF> getAnnotationEntries(file: TF, project: Project): Iterable<KtAnnotationEntry> = when (file) {
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ class ScriptTest2 {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestKotlinScriptDependenciesResolver : ScriptDependenciesResolver {
|
class TestKotlinScriptDependenciesResolver : AnnotationBasedScriptDependenciesResolver {
|
||||||
|
|
||||||
private val kotlinPaths by lazy { PathUtil.getKotlinPathsForCompiler() }
|
private val kotlinPaths by lazy { PathUtil.getKotlinPathsForCompiler() }
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -35,7 +35,9 @@ class GradleScriptTemplateProvider(project: Project, gim: GradleInstallationMana
|
|||||||
gradleLibsPath?.listFiles { file -> file.extension == "jar" && depLibsPrefixes.any { file.name.startsWith(it) } }
|
gradleLibsPath?.listFiles { file -> file.extension == "jar" && depLibsPrefixes.any { file.name.startsWith(it) } }
|
||||||
?.map { it.canonicalPath }
|
?.map { it.canonicalPath }
|
||||||
?: emptyList()
|
?: emptyList()
|
||||||
override val environment: Map<String, Any?>? = mapOf("gradleHome" to gradleHome)
|
override val environment: Map<String, Any?>? = mapOf(
|
||||||
|
"gradleHome" to gradleHome,
|
||||||
|
"projectRoot" to (project.basePath ?: project.baseDir.canonicalPath )?.let { File(it) })
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val depLibsPrefixes = listOf("gradle-script-kotlin", "gradle-core")
|
private val depLibsPrefixes = listOf("gradle-script-kotlin", "gradle-core")
|
||||||
|
|||||||
Reference in New Issue
Block a user