GradleScriptTemplateProvider: avoid duplicating template loading code

This commit is contained in:
Pavel V. Talanov
2017-07-11 16:43:47 +03:00
parent 6c3ce7adc1
commit 5c18ab750b
3 changed files with 37 additions and 63 deletions
@@ -54,9 +54,6 @@ interface ScriptTemplatesProvider {
val environment: Map<String, Any?>? val environment: Map<String, Any?>?
// for caching already loaded definitions, when needed
val scriptDefinitions: List<KotlinScriptDefinition>? get() = null
companion object { companion object {
val EP_NAME: ExtensionPointName<ScriptTemplatesProvider> = val EP_NAME: ExtensionPointName<ScriptTemplatesProvider> =
ExtensionPointName.create<ScriptTemplatesProvider>("org.jetbrains.kotlin.scriptTemplatesProvider") ExtensionPointName.create<ScriptTemplatesProvider>("org.jetbrains.kotlin.scriptTemplatesProvider")
@@ -75,11 +72,9 @@ fun makeScriptDefsFromTemplatesProviders(providers: Iterable<ScriptTemplatesProv
try { try {
val classpath = provider.dependenciesClasspath + provider.additionalResolverClasspath val classpath = provider.dependenciesClasspath + provider.additionalResolverClasspath
LOG.info("[kts] loading script definitions ${provider.templateClassNames} using cp: ${classpath.joinToString(File.pathSeparator)}") LOG.info("[kts] loading script definitions ${provider.templateClassNames} using cp: ${classpath.joinToString(File.pathSeparator)}")
provider.scriptDefinitions ?: run { val loader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), ScriptTemplatesProvider::class.java.classLoader)
val loader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), ScriptTemplatesProvider::class.java.classLoader) provider.templateClassNames.map {
provider.templateClassNames.map { KotlinScriptDefinitionFromAnnotatedTemplate(loader.loadClass(it).kotlin, provider.resolver, provider.filePattern, provider.environment)
KotlinScriptDefinitionFromAnnotatedTemplate(loader.loadClass(it).kotlin, provider.resolver, provider.filePattern, provider.environment)
}
} }
} }
catch (ex: Throwable) { catch (ex: Throwable) {
@@ -23,16 +23,15 @@ import com.intellij.openapi.project.Project
import org.gradle.tooling.ProjectConnection import org.gradle.tooling.ProjectConnection
import org.jetbrains.kotlin.lexer.KotlinLexer import org.jetbrains.kotlin.lexer.KotlinLexer
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.script.KotlinScriptDefinition
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
import org.jetbrains.kotlin.script.ScriptTemplatesProvider import org.jetbrains.kotlin.script.ScriptTemplatesProvider
import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper
import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings
import java.io.File import java.io.File
import java.net.URLClassLoader
import java.util.* import java.util.*
class GradleScriptTemplatesProvider(project: Project): ScriptTemplatesProvider { abstract class AbstractGradleScriptTemplatesProvider(
project: Project, override val id: String, private val templateClass: String, private val dependencySelector: Regex
): ScriptTemplatesProvider {
private val gradleExeSettings: GradleExecutionSettings? by lazy { private val gradleExeSettings: GradleExecutionSettings? by lazy {
try { try {
@@ -43,7 +42,7 @@ class GradleScriptTemplatesProvider(project: Project): ScriptTemplatesProvider {
} }
catch (e: Throwable) { catch (e: Throwable) {
// TODO: consider displaying the warning to the user // TODO: consider displaying the warning to the user
Logger.getInstance(GradleScriptTemplatesProvider::class.java).warn("[kts] Cannot get gradle execution settings", e) Logger.getInstance(AbstractGradleScriptTemplatesProvider::class.java).warn("[kts] Cannot get gradle execution settings", e)
null null
} }
} }
@@ -57,51 +56,24 @@ class GradleScriptTemplatesProvider(project: Project): ScriptTemplatesProvider {
} ?: emptyList() } ?: emptyList()
} }
override val id: String = "Gradle" override val isValid: Boolean get() = true
override val isValid: Boolean get() = templatesData is TemplateDataOrError.Data
private sealed class TemplateDataOrError { override val templateClassNames get() = listOf(templateClass)
class Data(val templateClassNames: Iterable<String>,
val dependenciesClasspath: List<File>,
val scriptDefinitions: List<KotlinScriptDefinition>) : TemplateDataOrError()
class Error(val message: String) : TemplateDataOrError()
}
private val templatesData: TemplateDataOrError by lazy { override val dependenciesClasspath: List<File>
get() {
val gradleHome = gradleExeSettings?.gradleHome ?: error("Unable to get Gradle home directory")
if (gradleExeSettings?.gradleHome == null) return@lazy TemplateDataOrError.Error("Unable to get Gradle home directory") val gradleLibDir = File(gradleHome, "lib").let {
it.takeIf { it.exists() && it.isDirectory } ?: error("Invalid Gradle libraries directory $it")
val gradleLibDir = File(gradleExeSettings!!.gradleHome, "lib").let {
it.takeIf { it.exists() && it.isDirectory }
?: return@lazy TemplateDataOrError.Error("Invalid Gradle libraries directory $it")
}
for ((template, selector) in templates2DependenciesSelectors) {
val cp = gradleLibDir.listFiles { it /* an inference problem without explicit 'it', TODO: remove when fixed */ -> selector.matches(it.name) }.takeIf { it.isNotEmpty() } ?: continue
val loader = URLClassLoader(cp.map { it.toURI().toURL() }.toTypedArray(), ScriptTemplatesProvider::class.java.classLoader)
try {
val cl = loader.loadClass(template)
val def = KotlinScriptDefinitionFromAnnotatedTemplate(cl.kotlin, resolver, filePattern, environment)
return@lazy TemplateDataOrError.Data(listOf(template), cp.asList(), listOf(def))
} }
catch (e: ClassNotFoundException) {}
catch (e: NoClassDefFoundError) {} return gradleLibDir.listFiles { it ->
/* an inference problem without explicit 'it', TODO: remove when fixed */
dependencySelector.matches(it.name)
}.takeIf { it.isNotEmpty() }?.asList() ?: error("Missing jars in gradle directory")
} }
return@lazy TemplateDataOrError.Error("Unable to find a suitable template in the Gradle libraries directory $gradleLibDir")
}
override val templateClassNames: Iterable<String> get() = when(templatesData) {
is GradleScriptTemplatesProvider.TemplateDataOrError.Data -> (templatesData as TemplateDataOrError.Data).templateClassNames
is GradleScriptTemplatesProvider.TemplateDataOrError.Error -> throw IllegalStateException((templatesData as TemplateDataOrError.Error).message)
}
override val dependenciesClasspath: List<File> get() = when(templatesData) {
is GradleScriptTemplatesProvider.TemplateDataOrError.Data -> (templatesData as TemplateDataOrError.Data).dependenciesClasspath
is GradleScriptTemplatesProvider.TemplateDataOrError.Error -> throw IllegalStateException((templatesData as TemplateDataOrError.Error).message)
}
override val environment: Map<String, Any?>? by lazy { override val environment: Map<String, Any?>? by lazy {
mapOf( mapOf(
"gradleHome" to gradleExeSettings?.gradleHome?.let(::File), "gradleHome" to gradleExeSettings?.gradleHome?.let(::File),
@@ -113,17 +85,22 @@ class GradleScriptTemplatesProvider(project: Project): ScriptTemplatesProvider {
"getScriptSectionTokens" to ::topLevelSectionCodeTextTokens) "getScriptSectionTokens" to ::topLevelSectionCodeTextTokens)
} }
override val scriptDefinitions: List<KotlinScriptDefinition>? get() = when(templatesData) {
is GradleScriptTemplatesProvider.TemplateDataOrError.Data -> (templatesData as TemplateDataOrError.Data).scriptDefinitions
is GradleScriptTemplatesProvider.TemplateDataOrError.Error -> throw IllegalStateException((templatesData as TemplateDataOrError.Error).message)
} }
companion object { class GradleKotlinDSLTemplateProvider(project: Project) : AbstractGradleScriptTemplatesProvider(
private val templates2DependenciesSelectors = listOf( project,
"org.gradle.kotlin.dsl.KotlinBuildScript" to Regex("^gradle-(?:kotlin-dsl|core).*\\.jar\$"), "Gradle Kotlin DSL",
"org.gradle.script.lang.kotlin.KotlinBuildScript" to Regex("^gradle-(?:script-kotlin|core).*\\.jar\$")) "org.gradle.kotlin.dsl.KotlinBuildScript",
} Regex("^gradle-(?:kotlin-dsl|core).*\\.jar\$")
} )
class LegacyGradleScriptKotlinTemplateProvider(project: Project) : AbstractGradleScriptTemplatesProvider(
project,
"Gradle Script Kotlin",
"org.gradle.script.lang.kotlin.KotlinBuildScript",
Regex("^gradle-(?:script-kotlin|core).*\\.jar\$")
)
class TopLevelSectionTokensEnumerator(script: CharSequence, identifier: String) : Enumeration<KotlinLexer> { class TopLevelSectionTokensEnumerator(script: CharSequence, identifier: String) : Enumeration<KotlinLexer> {
+4 -2
View File
@@ -48,7 +48,9 @@
<platformGradleDetector implementation="org.jetbrains.kotlin.idea.inspections.gradle.DefaultPlatformGradleDetector"/> <platformGradleDetector implementation="org.jetbrains.kotlin.idea.inspections.gradle.DefaultPlatformGradleDetector"/>
<scriptTemplatesProvider <scriptTemplatesProvider
id="GradleScriptTemplatesProvider" implementation="org.jetbrains.kotlin.idea.core.script.GradleKotlinDSLTemplateProvider"/>
implementation="org.jetbrains.kotlin.idea.core.script.GradleScriptTemplatesProvider"/>
<scriptTemplatesProvider
implementation="org.jetbrains.kotlin.idea.core.script.LegacyGradleScriptKotlinTemplateProvider"/>
</extensions> </extensions>
</idea-plugin> </idea-plugin>