Refactor script definitions loading
Make ScriptDefinitionProvider an interface
and provide different implementation for cli and IDEA
Rework ide extension point to a simpler interface (ScriptDefinitionContributor)
Move template loading logic into a top level function
Allow script definitions to be reloaded in IDE
This commit is contained in:
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.cli.common.script
|
||||
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.StandardScriptDefinition
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
class CliScriptDefinitionProvider : ScriptDefinitionProvider {
|
||||
private val definitions: MutableList<KotlinScriptDefinition> = arrayListOf(StandardScriptDefinition)
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
|
||||
override fun findScriptDefinition(fileName: String) = lock.read {
|
||||
definitions.firstOrNull { it.isScript(fileName) }
|
||||
}
|
||||
|
||||
override fun isScript(fileName: String) = lock.read {
|
||||
definitions.any { it.isScript(fileName) }
|
||||
}
|
||||
|
||||
fun setScriptDefinitions(newDefinitions: List<KotlinScriptDefinition>) {
|
||||
lock.write {
|
||||
definitions.clear()
|
||||
definitions.addAll(newDefinitions)
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -19,9 +19,9 @@ package org.jetbrains.kotlin.cli.common.script
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.script.ScriptContentLoader
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import java.io.File
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
@@ -30,7 +30,7 @@ import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
class CliScriptDependenciesProvider(
|
||||
project: Project,
|
||||
private val scriptDefinitionProvider: KotlinScriptDefinitionProvider
|
||||
private val scriptDefinitionProvider: ScriptDefinitionProvider
|
||||
) : ScriptDependenciesProvider {
|
||||
|
||||
private val cacheLock = ReentrantReadWriteLock()
|
||||
|
||||
@@ -47,7 +47,7 @@ import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.StandardScriptDefinition
|
||||
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
@@ -166,7 +166,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
val environment = createEnvironmentWithScriptingSupport(rootDisposable, configuration, arguments, messageCollector)
|
||||
?: return COMPILATION_ERROR
|
||||
|
||||
val scriptDefinitionProvider = KotlinScriptDefinitionProvider.getInstance(environment.project)!!
|
||||
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(environment.project)!!
|
||||
val scriptFile = File(sourcePath)
|
||||
if (scriptFile.isDirectory || !scriptDefinitionProvider.isScript(scriptFile.name)) {
|
||||
val extensionHint =
|
||||
@@ -460,7 +460,7 @@ class K2JVMCompiler : CLICompiler<K2JVMCompilerArguments>() {
|
||||
for (template in scriptTemplates) {
|
||||
try {
|
||||
val cls = classloader.loadClass(template)
|
||||
val def = KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, null, null, scriptResolverEnv)
|
||||
val def = KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, scriptResolverEnv)
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, def)
|
||||
messageCollector.report(
|
||||
INFO,
|
||||
|
||||
@@ -29,7 +29,6 @@ import com.intellij.ide.plugins.PluginManagerCore
|
||||
import com.intellij.lang.MetaLanguage
|
||||
import com.intellij.lang.java.JavaParserDefinition
|
||||
import com.intellij.openapi.Disposable
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.TransactionGuard
|
||||
import com.intellij.openapi.application.TransactionGuardImpl
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
@@ -39,7 +38,6 @@ import com.intellij.openapi.fileTypes.FileTypeExtensionPoint
|
||||
import com.intellij.openapi.fileTypes.PlainTextFileType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.util.Disposer
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.*
|
||||
@@ -71,6 +69,7 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.STRONG_WARNING
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.cli.common.script.CliScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.cli.common.script.CliScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.cli.common.script.CliScriptReportSink
|
||||
import org.jetbrains.kotlin.cli.common.toBooleanLenient
|
||||
@@ -104,7 +103,7 @@ import org.jetbrains.kotlin.resolve.jvm.extensions.PackageFragmentProviderExtens
|
||||
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.CliDeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProviderFactoryService
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.script.ScriptReportSink
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
@@ -191,7 +190,8 @@ class KotlinCoreEnvironment private constructor(
|
||||
})
|
||||
sourceFiles.sortBy { it.virtualFile.path }
|
||||
|
||||
KotlinScriptDefinitionProvider.getInstance(project)?.let { scriptDefinitionProvider ->
|
||||
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
|
||||
if (scriptDefinitionProvider != null) {
|
||||
scriptDefinitionProvider.setScriptDefinitions(
|
||||
configuration.getList(JVMConfigurationKeys.SCRIPT_DEFINITIONS))
|
||||
|
||||
@@ -554,9 +554,9 @@ class KotlinCoreEnvironment private constructor(
|
||||
@JvmStatic
|
||||
fun registerProjectServices(projectEnvironment: JavaCoreProjectEnvironment, messageCollector: MessageCollector?) {
|
||||
with (projectEnvironment.project) {
|
||||
val kotlinScriptDefinitionProvider = KotlinScriptDefinitionProvider()
|
||||
registerService(KotlinScriptDefinitionProvider::class.java, kotlinScriptDefinitionProvider)
|
||||
registerService(ScriptDependenciesProvider::class.java, CliScriptDependenciesProvider(projectEnvironment.project, kotlinScriptDefinitionProvider))
|
||||
val scriptDefinitionProvider = CliScriptDefinitionProvider()
|
||||
registerService(ScriptDefinitionProvider::class.java, scriptDefinitionProvider)
|
||||
registerService(ScriptDependenciesProvider::class.java, CliScriptDependenciesProvider(projectEnvironment.project, scriptDefinitionProvider))
|
||||
registerService(KotlinJavaPsiFacade::class.java, KotlinJavaPsiFacade(this))
|
||||
registerService(KtLightClassForFacade.FacadeStubCache::class.java, KtLightClassForFacade.FacadeStubCache(this))
|
||||
if (messageCollector != null) {
|
||||
|
||||
@@ -63,7 +63,7 @@ open class KotlinJvmReplService(
|
||||
|
||||
try {
|
||||
val cls = classloader.loadClass(templateClassName)
|
||||
val def = KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, null, null, emptyMap())
|
||||
val def = KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, emptyMap())
|
||||
messageCollector.report(INFO, "New script definition $templateClassName: files pattern = \"${def.scriptFilePattern}\", " +
|
||||
"resolver = ${def.dependencyResolver.javaClass.name}")
|
||||
return def
|
||||
|
||||
+1
-5
@@ -35,21 +35,17 @@ import kotlin.script.templates.AcceptedAnnotations
|
||||
|
||||
open class KotlinScriptDefinitionFromAnnotatedTemplate(
|
||||
template: KClass<out Any>,
|
||||
providedResolver: DependenciesResolver? = null,
|
||||
providedScriptFilePattern: String? = null,
|
||||
val environment: Map<String, Any?>? = null,
|
||||
val templateClasspath: List<File> = emptyList()
|
||||
) : KotlinScriptDefinition(template) {
|
||||
|
||||
val scriptFilePattern by lazy {
|
||||
providedScriptFilePattern
|
||||
?: takeUnlessError { template.annotations.firstIsInstanceOrNull<kotlin.script.templates.ScriptTemplateDefinition>()?.scriptFilePattern }
|
||||
takeUnlessError { template.annotations.firstIsInstanceOrNull<kotlin.script.templates.ScriptTemplateDefinition>()?.scriptFilePattern }
|
||||
?: takeUnlessError { template.annotations.firstIsInstanceOrNull<org.jetbrains.kotlin.script.ScriptTemplateDefinition>()?.scriptFilePattern }
|
||||
?: DEFAULT_SCRIPT_FILE_PATTERN
|
||||
}
|
||||
|
||||
override val dependencyResolver: DependenciesResolver by lazy {
|
||||
providedResolver ?:
|
||||
resolverFromAnnotation(template) ?:
|
||||
resolverFromLegacyAnnotation(template) ?:
|
||||
DependenciesResolver.NoDependencies
|
||||
|
||||
-95
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.script
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.project.Project
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
|
||||
interface ScriptTemplatesProvider {
|
||||
|
||||
// for resolving ambiguities
|
||||
val id: String
|
||||
|
||||
@Deprecated("Parameter isn't used for resolving priorities anymore. " +
|
||||
"com.intellij.openapi.extensions.LoadingOrder constants can be used to order providers when registered from Intellij plugin.",
|
||||
ReplaceWith("0"))
|
||||
val version: Int get() = 0
|
||||
|
||||
val isValid: Boolean
|
||||
|
||||
val templateClassNames: Iterable<String>
|
||||
|
||||
val resolver: DependenciesResolver? get() = null
|
||||
|
||||
val filePattern: String? get() = null
|
||||
|
||||
val templateClasspath: List<File>
|
||||
|
||||
// TODO: need to provide a way to specify this in compiler/repl .. etc
|
||||
/*
|
||||
* Allows to specify additional jars needed for DependenciesResolver (and not script template).
|
||||
* Script template dependencies naturally become (part of) dependencies of the script which is not always desired for resolver dependencies.
|
||||
* i.e. gradle resolver may depend on some jars that 'built.gradle.kts' files should not depend on.
|
||||
*/
|
||||
val additionalResolverClasspath: List<File> get() = emptyList()
|
||||
|
||||
val environment: Map<String, Any?>?
|
||||
|
||||
companion object {
|
||||
val EP_NAME: ExtensionPointName<ScriptTemplatesProvider> =
|
||||
ExtensionPointName.create<ScriptTemplatesProvider>("org.jetbrains.kotlin.scriptTemplatesProvider")
|
||||
}
|
||||
}
|
||||
|
||||
fun makeScriptDefsFromTemplatesProviderExtensions(project: Project,
|
||||
errorsHandler: ((ScriptTemplatesProvider, Throwable) -> Unit)
|
||||
): List<KotlinScriptDefinition> =
|
||||
makeScriptDefsFromTemplatesProviders(Extensions.getArea(project).getExtensionPoint(ScriptTemplatesProvider.EP_NAME).extensions.asIterable(),
|
||||
errorsHandler)
|
||||
|
||||
fun makeScriptDefsFromTemplatesProviders(providers: Iterable<ScriptTemplatesProvider>,
|
||||
errorsHandler: ((ScriptTemplatesProvider, Throwable) -> Unit) = { _, ex -> throw ex }
|
||||
): List<KotlinScriptDefinition> = providers.flatMap { provider ->
|
||||
try {
|
||||
val loader = createClassLoader(provider)
|
||||
provider.templateClassNames.map {
|
||||
KotlinScriptDefinitionFromAnnotatedTemplate(
|
||||
loader.loadClass(it).kotlin, provider.resolver,
|
||||
provider.filePattern, provider.environment, provider.templateClasspath
|
||||
)
|
||||
}
|
||||
}
|
||||
catch (ex: Throwable) {
|
||||
LOG.info("Templates provider ${provider.id} is invalid: ${ex.message}")
|
||||
errorsHandler(provider, ex)
|
||||
emptyList<KotlinScriptDefinition>()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createClassLoader(provider: ScriptTemplatesProvider): ClassLoader {
|
||||
val classpath = provider.templateClasspath + provider.additionalResolverClasspath
|
||||
LOG.info("[kts] loading script definitions ${provider.templateClassNames} using cp: ${classpath.joinToString(File.pathSeparator)}")
|
||||
val baseLoader = ScriptTemplatesProvider::class.java.classLoader
|
||||
return if (classpath.isEmpty()) baseLoader else URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), baseLoader)
|
||||
}
|
||||
|
||||
private val LOG = Logger.getInstance("ScriptTemplatesProviders")
|
||||
@@ -23,14 +23,14 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.tree.IElementType;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider;
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider;
|
||||
|
||||
public class KotlinParser implements PsiParser {
|
||||
|
||||
private final KotlinScriptDefinitionProvider scriptDefinitionProvider;
|
||||
private final ScriptDefinitionProvider scriptDefinitionProvider;
|
||||
|
||||
public KotlinParser(Project project) {
|
||||
scriptDefinitionProvider = KotlinScriptDefinitionProvider.getInstance(project);
|
||||
scriptDefinitionProvider = ScriptDefinitionProvider.Companion.getInstance(project);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+7
-51
@@ -17,67 +17,23 @@
|
||||
package org.jetbrains.kotlin.script
|
||||
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiFile
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
|
||||
class KotlinScriptDefinitionProvider {
|
||||
|
||||
private val definitions: MutableList<KotlinScriptDefinition> = arrayListOf(StandardScriptDefinition)
|
||||
private val definitionsLock = java.util.concurrent.locks.ReentrantReadWriteLock()
|
||||
|
||||
fun setScriptDefinitions(newDefinitions: List<KotlinScriptDefinition>): Boolean {
|
||||
var changed = false
|
||||
definitionsLock.read {
|
||||
if (newDefinitions != definitions) {
|
||||
definitionsLock.write {
|
||||
definitions.clear()
|
||||
definitions.addAll(newDefinitions)
|
||||
}
|
||||
changed = true
|
||||
}
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
interface ScriptDefinitionProvider {
|
||||
fun findScriptDefinition(fileName: String): KotlinScriptDefinition?
|
||||
fun isScript(fileName: String): Boolean
|
||||
fun findScriptDefinition(file: VirtualFile): KotlinScriptDefinition? = findScriptDefinition(file.name)
|
||||
|
||||
fun findScriptDefinition(fileName: String): KotlinScriptDefinition? = definitionsLock.read {
|
||||
definitions.firstOrNull { it.isScript(fileName) }
|
||||
}
|
||||
|
||||
fun isScript(fileName: String): Boolean = definitionsLock.read {
|
||||
definitions.any { it.isScript(fileName) }
|
||||
}
|
||||
|
||||
fun addScriptDefinition(scriptDefinition: KotlinScriptDefinition) {
|
||||
definitionsLock.write {
|
||||
definitions.add(0, scriptDefinition)
|
||||
}
|
||||
}
|
||||
|
||||
fun removeScriptDefinition(scriptDefinition: KotlinScriptDefinition) {
|
||||
definitionsLock.write {
|
||||
definitions.remove(scriptDefinition)
|
||||
}
|
||||
}
|
||||
|
||||
fun getAllKnownFileTypes(): Iterable<LanguageFileType> = definitionsLock.read {
|
||||
definitions.map { it.fileType }.distinct()
|
||||
}
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun getInstance(project: Project): KotlinScriptDefinitionProvider? =
|
||||
ServiceManager.getService(project, KotlinScriptDefinitionProvider::class.java)
|
||||
fun getInstance(project: Project): ScriptDefinitionProvider =
|
||||
ServiceManager.getService(project, ScriptDefinitionProvider::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
fun getScriptDefinition(file: VirtualFile, project: Project): KotlinScriptDefinition? =
|
||||
KotlinScriptDefinitionProvider.getInstance(project)?.findScriptDefinition(file)
|
||||
ScriptDefinitionProvider.getInstance(project).findScriptDefinition(file)
|
||||
|
||||
fun getScriptDefinition(psiFile: PsiFile): KotlinScriptDefinition? =
|
||||
KotlinScriptDefinitionProvider.getInstance(psiFile.project)?.findScriptDefinition(psiFile.name)
|
||||
ScriptDefinitionProvider.getInstance(psiFile.project).findScriptDefinition(psiFile.name)
|
||||
|
||||
@@ -25,8 +25,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.checkers.CheckerTestUtil;
|
||||
import org.jetbrains.kotlin.psi.KtFile;
|
||||
import org.jetbrains.kotlin.resolve.AnalyzingUtils;
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider;
|
||||
import org.jetbrains.kotlin.script.StandardScriptDefinition;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -133,10 +131,6 @@ public class CodegenTestFiles {
|
||||
}
|
||||
}
|
||||
|
||||
KotlinScriptDefinitionProvider scriptDefinitionProvider = KotlinScriptDefinitionProvider.getInstance(project);
|
||||
assert scriptDefinitionProvider != null;
|
||||
scriptDefinitionProvider.addScriptDefinition(StandardScriptDefinition.INSTANCE);
|
||||
|
||||
return new CodegenTestFiles(Collections.singletonList(file), expectedValues, scriptParameterValues);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ internal class TestRepl(
|
||||
private fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition {
|
||||
val classloader = URLClassLoader(templateClasspath.map { it.toURI().toURL() }.toTypedArray(), this::class.java.classLoader)
|
||||
val cls = classloader.loadClass(templateClassName)
|
||||
return KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, null, null, emptyMap())
|
||||
return KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, emptyMap())
|
||||
}
|
||||
|
||||
private val scriptDef = makeScriptDefinition(templateClasspath, templateClassName)
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys
|
||||
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
|
||||
import org.jetbrains.kotlin.cli.common.messages.PrintingMessageCollector
|
||||
@@ -26,16 +25,18 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.addKotlinSourceRoots
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.scripts.ScriptWithIntParam
|
||||
import org.jetbrains.kotlin.scripts.TestKotlinScriptDependenciesResolver
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import java.io.File
|
||||
import kotlin.script.templates.ScriptTemplateDefinition
|
||||
|
||||
class ScriptGenTest : CodegenTestCase() {
|
||||
companion object {
|
||||
private val FIB_SCRIPT_DEFINITION = KotlinScriptDefinitionFromAnnotatedTemplate(ScriptWithIntParam::class, providedScriptFilePattern = ".*\\.lang\\.kt")
|
||||
private val NO_PARAM_SCRIPT_DEFINITION = KotlinScriptDefinitionFromAnnotatedTemplate(Any::class, providedScriptFilePattern = ".*\\.kts")
|
||||
private val FIB_SCRIPT_DEFINITION = KotlinScriptDefinitionFromAnnotatedTemplate(ScriptWithIntParam::class)
|
||||
private val NO_PARAM_SCRIPT_DEFINITION = KotlinScriptDefinitionFromAnnotatedTemplate(Any::class)
|
||||
}
|
||||
|
||||
override fun setUp() {
|
||||
@@ -124,3 +125,8 @@ class ScriptGenTest : CodegenTestCase() {
|
||||
loadFiles(*sourcePaths.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
@ScriptTemplateDefinition(
|
||||
scriptFilePattern =".*\\.lang\\.kt",
|
||||
resolver = TestKotlinScriptDependenciesResolver::class)
|
||||
abstract class ScriptWithIntParam(val num: Int)
|
||||
@@ -28,8 +28,9 @@ import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.PathUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.KtNodeTypes;
|
||||
import org.jetbrains.kotlin.cli.common.script.CliScriptDefinitionProvider;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider;
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.testFramework.KtParsingTestCase;
|
||||
|
||||
@@ -41,7 +42,7 @@ public abstract class AbstractParsingTest extends KtParsingTestCase {
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
getProject().registerService(KotlinScriptDefinitionProvider.class);
|
||||
getProject().registerService(ScriptDefinitionProvider.class, CliScriptDefinitionProvider.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -333,7 +333,7 @@ class ScriptTemplateTest : KtUsefulTestCase() {
|
||||
includeKotlinRuntime: Boolean = true
|
||||
): Class<*>? =
|
||||
compileScriptImpl("compiler/testData/script/" + scriptPath, KotlinScriptDefinitionFromAnnotatedTemplate(
|
||||
scriptTemplate, null, null, environment
|
||||
scriptTemplate, environment
|
||||
), runIsolated, messageCollector, includeKotlinRuntime)
|
||||
|
||||
private fun compileScriptImpl(
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.idea.core.script
|
||||
|
||||
import com.intellij.openapi.components.service
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.extensions.ExtensionPointName
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.JavaSdk
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.projectRoots.ex.PathUtilEx
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.flattenTo
|
||||
import java.io.File
|
||||
import java.net.URLClassLoader
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
import kotlin.concurrent.write
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.dependencies.ScriptContents
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
import kotlin.script.experimental.dependencies.asSuccess
|
||||
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
||||
|
||||
class ScriptDefinitionsManager(private val project: Project): ScriptDefinitionProvider {
|
||||
private val lock = ReentrantReadWriteLock()
|
||||
private var definitionsByContributor = mutableMapOf<ScriptDefinitionContributor, List<KotlinScriptDefinition>>()
|
||||
private var definitions: List<KotlinScriptDefinition> = emptyList()
|
||||
|
||||
fun reloadDefinitionsBy(contributor: ScriptDefinitionContributor) = lock.write {
|
||||
currentDefinitions() //force definitions to be computed
|
||||
|
||||
if (contributor !in definitionsByContributor) error("Unknown contributor: ${contributor.id}")
|
||||
|
||||
definitionsByContributor[contributor] = contributor.safeGetDefinitions()
|
||||
updateDefinitions()
|
||||
}
|
||||
|
||||
private fun currentDefinitions(): List<KotlinScriptDefinition> {
|
||||
val hasDefinitions = definitions.isNotEmpty()
|
||||
when {
|
||||
hasDefinitions -> return definitions
|
||||
else -> {
|
||||
reloadScriptDefinitions()
|
||||
return definitions
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun findScriptDefinition(fileName: String): KotlinScriptDefinition? = lock.read {
|
||||
currentDefinitions().firstOrNull { it.isScript(fileName) }
|
||||
}
|
||||
|
||||
override fun isScript(fileName: String) = lock.read {
|
||||
currentDefinitions().any { it.isScript(fileName) }
|
||||
}
|
||||
|
||||
private fun getContributors(): List<ScriptDefinitionContributor> =
|
||||
Extensions.getArea(project).getExtensionPoint(ScriptDefinitionContributor.EP_NAME).extensions.toList()
|
||||
|
||||
fun reloadScriptDefinitions() = lock.write {
|
||||
definitionsByContributor = getContributors().associateByTo(mutableMapOf(), { it }, { it.safeGetDefinitions() })
|
||||
updateDefinitions()
|
||||
}
|
||||
|
||||
private fun updateDefinitions() {
|
||||
definitions = definitionsByContributor.values.flattenTo(mutableListOf())
|
||||
// TODO: clear by script type/definition
|
||||
project.service<ScriptDependenciesUpdater>().clear()
|
||||
}
|
||||
|
||||
private fun ScriptDefinitionContributor.safeGetDefinitions(): List<KotlinScriptDefinition> {
|
||||
return try {
|
||||
getDefinitions()
|
||||
}
|
||||
catch (t: Throwable) {
|
||||
// TODO: review exception handling
|
||||
// possibly log, see KT-19276
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getInstance(project: Project): ScriptDefinitionsManager = project.service<ScriptDefinitionProvider>() as ScriptDefinitionsManager
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private val LOG = Logger.getInstance("ScriptTemplatesProviders")
|
||||
|
||||
fun loadDefinitionsFromTemplates(
|
||||
templateClassNames: List<String>,
|
||||
templateClasspath: List<File>,
|
||||
environment: Environment = emptyMap(),
|
||||
// TODO: need to provide a way to specify this in compiler/repl .. etc
|
||||
/*
|
||||
* Allows to specify additional jars needed for DependenciesResolver (and not script template).
|
||||
* Script template dependencies naturally become (part of) dependencies of the script which is not always desired for resolver dependencies.
|
||||
* i.e. gradle resolver may depend on some jars that 'built.gradle.kts' files should not depend on.
|
||||
*/
|
||||
additionalResolverClasspath: List<File> = emptyList()
|
||||
): List<KotlinScriptDefinitionFromAnnotatedTemplate> = try {
|
||||
val classpath = templateClasspath + additionalResolverClasspath
|
||||
LOG.info("[kts] loading script definitions $templateClassNames using cp: ${classpath.joinToString(File.pathSeparator)}")
|
||||
val baseLoader = ScriptDefinitionContributor::class.java.classLoader
|
||||
val loader = if (classpath.isEmpty()) baseLoader else URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), baseLoader)
|
||||
|
||||
templateClassNames.map {
|
||||
KotlinScriptDefinitionFromAnnotatedTemplate(
|
||||
loader.loadClass(it).kotlin,
|
||||
environment,
|
||||
templateClasspath
|
||||
)
|
||||
}
|
||||
}
|
||||
catch (ex: Throwable) {
|
||||
// TODO: review exception handling
|
||||
emptyList()
|
||||
}
|
||||
|
||||
interface ScriptDefinitionContributor {
|
||||
val id: String
|
||||
|
||||
fun getDefinitions(): List<KotlinScriptDefinition>
|
||||
|
||||
companion object {
|
||||
val EP_NAME: ExtensionPointName<ScriptDefinitionContributor> =
|
||||
ExtensionPointName.create<ScriptDefinitionContributor>("org.jetbrains.kotlin.scriptDefinitionContributor")
|
||||
|
||||
inline fun <reified T> find(project: Project) =
|
||||
Extensions.getArea(project).getExtensionPoint(ScriptDefinitionContributor.EP_NAME).extensions.filterIsInstance<T>().firstOrNull()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class StandardScriptDefinitionContributor(private val project: Project) : ScriptDefinitionContributor {
|
||||
override fun getDefinitions() = listOf(StandardIdeScriptDefinition(project))
|
||||
|
||||
override val id: String = "StandardKotlinScript"
|
||||
}
|
||||
|
||||
|
||||
class StandardIdeScriptDefinition(project: Project) : KotlinScriptDefinition(ScriptTemplateWithArgs::class) {
|
||||
override val dependencyResolver = BundledKotlinScriptDependenciesResolver(project)
|
||||
}
|
||||
|
||||
class BundledKotlinScriptDependenciesResolver(private val project: Project) : DependenciesResolver {
|
||||
override fun resolve(
|
||||
scriptContents: ScriptContents,
|
||||
environment: Environment
|
||||
): DependenciesResolver.ResolveResult {
|
||||
val javaHome = getScriptSDK(project)
|
||||
val dependencies = ScriptDependencies(
|
||||
javaHome = javaHome?.let(::File),
|
||||
classpath = with(PathUtil.kotlinPathsForIdeaPlugin) {
|
||||
listOf(
|
||||
reflectPath,
|
||||
stdlibPath,
|
||||
scriptRuntimePath
|
||||
)
|
||||
}
|
||||
)
|
||||
return dependencies.asSuccess()
|
||||
}
|
||||
|
||||
private fun getScriptSDK(project: Project): String? {
|
||||
val jdk = ProjectJdkTable.getInstance().allJdks.firstOrNull { sdk -> sdk.sdkType is JavaSdk } ?: PathUtilEx.getAnyJdk(project)
|
||||
return jdk?.homePath
|
||||
}
|
||||
}
|
||||
|
||||
+17
-16
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.idea.core.script
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.extensions.Extensions
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
@@ -27,6 +26,7 @@ import com.intellij.psi.search.NonClasspathDirectoriesScope
|
||||
import com.intellij.util.containers.SLRUMap
|
||||
import kotlinx.coroutines.experimental.launch
|
||||
import org.jetbrains.kotlin.idea.core.util.EDT
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import java.io.File
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock
|
||||
import kotlin.concurrent.read
|
||||
@@ -37,11 +37,11 @@ import kotlin.reflect.KProperty0
|
||||
import kotlin.reflect.jvm.isAccessible
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
private const val MAX_SCRIPTS_CACHED = 15
|
||||
private const val MAX_SCRIPTS_CACHED = 10
|
||||
|
||||
class ScriptDependenciesCache(private val project: Project) {
|
||||
private val cacheLock = ReentrantReadWriteLock()
|
||||
private val cache = SLRUMap<VirtualFile, ScriptDependencies>(0, MAX_SCRIPTS_CACHED)
|
||||
private val cache = SLRUMap<VirtualFile, ScriptDependencies>(MAX_SCRIPTS_CACHED, MAX_SCRIPTS_CACHED)
|
||||
|
||||
operator fun get(virtualFile: VirtualFile): ScriptDependencies? = cacheLock.read { cache[virtualFile] }
|
||||
|
||||
@@ -62,7 +62,7 @@ class ScriptDependenciesCache(private val project: Project) {
|
||||
NonClasspathDirectoriesScope(allLibrarySources)
|
||||
}
|
||||
|
||||
private fun onChange(file: VirtualFile?) {
|
||||
private fun onChange(files: List<VirtualFile>) {
|
||||
this::allScriptsClasspath.clearValue()
|
||||
this::allScriptsClasspathScope.clearValue()
|
||||
this::allLibrarySources.clearValue()
|
||||
@@ -74,22 +74,18 @@ class ScriptDependenciesCache(private val project: Project) {
|
||||
.single()
|
||||
|
||||
kotlinScriptDependenciesClassFinder.clearCache()
|
||||
updateHighlighting(file)
|
||||
updateHighlighting(files)
|
||||
}
|
||||
|
||||
private fun updateHighlighting(file: VirtualFile?) {
|
||||
private fun updateHighlighting(files: List<VirtualFile>) {
|
||||
ScriptDependenciesModificationTracker.getInstance(project).incModificationCount()
|
||||
|
||||
launch(EDT(project)) {
|
||||
if (file != null) {
|
||||
file.let { PsiManager.getInstance(project).findFile(it) }?.let { psiFile ->
|
||||
files.forEach {
|
||||
PsiManager.getInstance(project).findFile(it)?.let { psiFile ->
|
||||
DaemonCodeAnalyzer.getInstance(project).restart(psiFile)
|
||||
}
|
||||
}
|
||||
else {
|
||||
assert(ApplicationManager.getApplication().isUnitTestMode)
|
||||
DaemonCodeAnalyzer.getInstance(project).restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -99,8 +95,13 @@ class ScriptDependenciesCache(private val project: Project) {
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
cacheLock.write(cache::clear)
|
||||
onChange(null)
|
||||
val keys = cacheLock.read {
|
||||
val keys = mutableListOf<VirtualFile>()
|
||||
cache.iterateKeys { keys.addIfNotNull(it) }
|
||||
cacheLock.write(cache::clear)
|
||||
keys
|
||||
}
|
||||
onChange(keys)
|
||||
}
|
||||
|
||||
fun save(virtualFile: VirtualFile, new: ScriptDependencies): Boolean {
|
||||
@@ -111,7 +112,7 @@ class ScriptDependenciesCache(private val project: Project) {
|
||||
}
|
||||
val changed = new != old
|
||||
if (changed) {
|
||||
onChange(virtualFile)
|
||||
onChange(listOf(virtualFile))
|
||||
}
|
||||
|
||||
return changed
|
||||
@@ -122,7 +123,7 @@ class ScriptDependenciesCache(private val project: Project) {
|
||||
cache.remove(virtualFile) != null
|
||||
}
|
||||
if (changed) {
|
||||
onChange(virtualFile)
|
||||
onChange(listOf(virtualFile))
|
||||
}
|
||||
return changed
|
||||
}
|
||||
|
||||
+2
-24
@@ -23,9 +23,8 @@ import com.intellij.openapi.vfs.StandardFileSystems
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.io.URLUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.ScriptDependenciesProvider
|
||||
import org.jetbrains.kotlin.script.makeScriptDefsFromTemplatesProviderExtensions
|
||||
import java.io.File
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
@@ -41,25 +40,12 @@ class IdeScriptDependenciesProvider(
|
||||
}
|
||||
|
||||
class ScriptDependenciesManager internal constructor(
|
||||
private val project: Project,
|
||||
private val scriptDefinitionProvider: KotlinScriptDefinitionProvider,
|
||||
private val cacheUpdater: ScriptDependenciesUpdater,
|
||||
private val cache: ScriptDependenciesCache
|
||||
) {
|
||||
init {
|
||||
reloadScriptDefinitions()
|
||||
}
|
||||
|
||||
fun getScriptClasspath(file: VirtualFile): List<VirtualFile> = toVfsRoots(cacheUpdater.getCurrentDependencies(file).classpath)
|
||||
fun getScriptDependencies(file: VirtualFile): ScriptDependencies = cacheUpdater.getCurrentDependencies(file)
|
||||
|
||||
private fun reloadScriptDefinitions() {
|
||||
val def = makeScriptDefsFromTemplatesProviderExtensions(
|
||||
project, { ep, ex -> /* do nothing, logging these exception creates too much noise*/}
|
||||
)
|
||||
scriptDefinitionProvider.setScriptDefinitions(def)
|
||||
}
|
||||
|
||||
fun getAllScriptsClasspathScope() = cache.allScriptsClasspathScope
|
||||
fun getAllLibrarySourcesScope() = cache.allLibrarySourcesScope
|
||||
fun getAllLibrarySources() = cache.allLibrarySources
|
||||
@@ -90,18 +76,10 @@ class ScriptDependenciesManager internal constructor(
|
||||
@TestOnly
|
||||
fun updateScriptDependenciesSynchronously(virtualFile: VirtualFile, project: Project) {
|
||||
with(getInstance(project)) {
|
||||
val scriptDefinition = KotlinScriptDefinitionProvider.getInstance(project)!!.findScriptDefinition(virtualFile)!!
|
||||
val scriptDefinition = ScriptDefinitionProvider.getInstance(project).findScriptDefinition(virtualFile)!!
|
||||
cacheUpdater.updateSync(virtualFile, scriptDefinition)
|
||||
cacheUpdater.notifyRootsChanged()
|
||||
}
|
||||
}
|
||||
|
||||
@TestOnly
|
||||
fun reloadScriptDefinitions(project: Project) {
|
||||
with(getInstance(project)) {
|
||||
reloadScriptDefinitions()
|
||||
cacheUpdater.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -47,10 +47,10 @@ import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
internal class ScriptDependenciesUpdater(
|
||||
class ScriptDependenciesUpdater(
|
||||
private val project: Project,
|
||||
private val cache: ScriptDependenciesCache,
|
||||
private val scriptDefinitionProvider: KotlinScriptDefinitionProvider
|
||||
private val scriptDefinitionProvider: ScriptDefinitionProvider
|
||||
) {
|
||||
private val requests = ConcurrentHashMap<String, ModStampedRequest>()
|
||||
private val contentLoader = ScriptContentLoader(project)
|
||||
|
||||
+4
-10
@@ -21,28 +21,22 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.ResolveScopeProvider
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager
|
||||
import org.jetbrains.kotlin.idea.core.script.StandardIdeScriptDefinition
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.script.getScriptDefinition
|
||||
|
||||
class KotlinScriptResolveScopeProvider : ResolveScopeProvider() {
|
||||
companion object {
|
||||
val USE_NULL_RESOLVE_SCOPE = "USE_NULL_RESOLVE_SCOPE"
|
||||
}
|
||||
|
||||
override fun getResolveScope(file: VirtualFile, project: Project): GlobalSearchScope? {
|
||||
val scriptDefinition = getScriptDefinition(file, project)
|
||||
// TODO: this should get this particular scripts dependencies
|
||||
return when {
|
||||
scriptDefinition == null -> null
|
||||
// This is a workaround for completion in scripts and REPL to provide module dependencies
|
||||
// This is a workaround for completion in scripts and REPL to provide module dependencies
|
||||
scriptDefinition.template == Any::class -> null
|
||||
scriptDefinition is StandardIdeScriptDefinition -> null
|
||||
scriptDefinition is KotlinScriptDefinitionFromAnnotatedTemplate -> // TODO: should include the file itself
|
||||
if (scriptDefinition.environment?.containsKey(USE_NULL_RESOLVE_SCOPE) ?: false) {
|
||||
null
|
||||
}
|
||||
else {
|
||||
ScriptDependenciesManager.getInstance(project).getAllScriptsClasspathScope()
|
||||
}
|
||||
ScriptDependenciesManager.getInstance(project).getAllScriptsClasspathScope()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
+50
-37
@@ -24,23 +24,51 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.gradle.tooling.ProjectConnection
|
||||
import org.jetbrains.kotlin.lexer.KotlinLexer
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.script.ScriptTemplatesProvider
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper
|
||||
import org.jetbrains.plugins.gradle.settings.GradleExecutionSettings
|
||||
import org.jetbrains.plugins.gradle.util.GradleConstants
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
|
||||
abstract class AbstractGradleScriptTemplatesProvider(
|
||||
project: Project, override val id: String, private val templateClass: String, private val dependencySelector: Regex
|
||||
): ScriptTemplatesProvider {
|
||||
private val project: Project,
|
||||
override val id: String,
|
||||
private val templateClass: String,
|
||||
private val dependencySelector: Regex
|
||||
): ScriptDefinitionContributor {
|
||||
|
||||
private val gradleExeSettings: GradleExecutionSettings? by lazy {
|
||||
try {
|
||||
ExternalSystemApiUtil.getExecutionSettings<GradleExecutionSettings>(
|
||||
override fun getDefinitions(): List<KotlinScriptDefinition> {
|
||||
val gradleExeSettings = getExeSettings() ?: return emptyList()
|
||||
|
||||
val gradleHome = gradleExeSettings.gradleHome ?: 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 templateClasspath = 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 loadDefinitionsFromTemplates(
|
||||
listOf(templateClass),
|
||||
templateClasspath,
|
||||
createEnvironment(gradleExeSettings),
|
||||
additionalResolverClasspath(gradleLibDir)
|
||||
)
|
||||
}
|
||||
|
||||
open fun additionalResolverClasspath(gradleLibDir: File): List<File> = emptyList()
|
||||
|
||||
private fun getExeSettings(): GradleExecutionSettings? {
|
||||
return try {
|
||||
ExternalSystemApiUtil.getExecutionSettings(
|
||||
project,
|
||||
com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil.toCanonicalPath(project.basePath!!),
|
||||
org.jetbrains.plugins.gradle.util.GradleConstants.SYSTEM_ID)
|
||||
ExternalSystemApiUtil.toCanonicalPath(project.basePath!!),
|
||||
GradleConstants.SYSTEM_ID)
|
||||
}
|
||||
catch (e: Throwable) {
|
||||
// TODO: consider displaying the warning to the user
|
||||
@@ -49,44 +77,26 @@ abstract class AbstractGradleScriptTemplatesProvider(
|
||||
}
|
||||
}
|
||||
|
||||
private val gradleJvmOptions: List<String> by lazy {
|
||||
gradleExeSettings?.daemonVmOptions?.let { vmOptions ->
|
||||
private fun createEnvironment(gradleExeSettings: GradleExecutionSettings): Environment {
|
||||
val gradleJvmOptions = gradleExeSettings.daemonVmOptions?.let { vmOptions ->
|
||||
CommandLineTokenizer(vmOptions).toList()
|
||||
.mapNotNull { it?.let { it as? String } }
|
||||
.filterNot(String::isBlank)
|
||||
.distinct()
|
||||
} ?: emptyList()
|
||||
}
|
||||
|
||||
internal val gradleLibDir: File by lazy {
|
||||
val gradleHome = gradleExeSettings?.gradleHome ?: error("Unable to get Gradle home directory")
|
||||
|
||||
File(gradleHome, "lib").let {
|
||||
it.takeIf { it.exists() && it.isDirectory } ?: error("Invalid Gradle libraries directory $it")
|
||||
}
|
||||
}
|
||||
|
||||
override val isValid: Boolean get() = true
|
||||
|
||||
override val templateClassNames get() = listOf(templateClass)
|
||||
|
||||
override val templateClasspath: List<File> get() {
|
||||
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")
|
||||
}
|
||||
|
||||
override val environment: Map<String, Any?>? by lazy {
|
||||
mapOf(
|
||||
"gradleHome" to gradleExeSettings?.gradleHome?.let(::File),
|
||||
return mapOf(
|
||||
"gradleHome" to gradleExeSettings.gradleHome?.let(::File),
|
||||
"projectRoot" to (project.basePath ?: project.baseDir.canonicalPath)?.let(::File),
|
||||
"gradleWithConnection" to { action: (ProjectConnection) -> Unit ->
|
||||
GradleExecutionHelper().execute(project.basePath!!, null) { action(it) } },
|
||||
"gradleJavaHome" to gradleExeSettings?.javaHome,
|
||||
GradleExecutionHelper().execute(project.basePath!!, null) { action(it) }
|
||||
},
|
||||
"gradleJavaHome" to gradleExeSettings.javaHome,
|
||||
"gradleJvmOptions" to gradleJvmOptions,
|
||||
"getScriptSectionTokens" to ::topLevelSectionCodeTextTokens
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,11 +107,14 @@ abstract class AbstractGradleKotlinDSLTemplateProvider(project: Project, private
|
||||
templateClass,
|
||||
Regex("^gradle-(?:kotlin-dsl|core).*\\.jar\$")
|
||||
) {
|
||||
|
||||
// TODO_R: check this against kotlin-dsl branch that uses daemon
|
||||
override val additionalResolverClasspath: List<File> get() =
|
||||
// additionally need compiler jar to load gradle resolver
|
||||
gradleLibDir.listFiles { file -> file.name.startsWith("kotlin-compiler-embeddable") || file.name.startsWith("kotlin-stdlib") }
|
||||
override fun additionalResolverClasspath(gradleLibDir: File): List<File> {
|
||||
// additionally need compiler jar to load gradle resolver
|
||||
return gradleLibDir.listFiles { file -> file.name.startsWith("kotlin-compiler-embeddable") || file.name.startsWith("kotlin-stdlib") }
|
||||
.firstOrNull()?.let(::listOf).orEmpty()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class GradleSettingsKotlinDSLTemplateProvider(project: Project)
|
||||
|
||||
@@ -46,6 +46,7 @@ import com.intellij.psi.PsiFileFactory
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.impl.PsiFileFactoryImpl
|
||||
import com.intellij.testFramework.LightVirtualFile
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import org.jetbrains.annotations.TestOnly
|
||||
import org.jetbrains.kotlin.console.actions.BuildAndRestartConsoleAction
|
||||
import org.jetbrains.kotlin.console.actions.KtExecuteCommandAction
|
||||
@@ -54,7 +55,12 @@ import org.jetbrains.kotlin.console.gutter.ConsoleIndicatorRenderer
|
||||
import org.jetbrains.kotlin.console.gutter.IconWithTooltip
|
||||
import org.jetbrains.kotlin.console.gutter.ReplIcons
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.NotUnderContentRootModuleInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.productionSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.testSourceInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
||||
import org.jetbrains.kotlin.idea.project.KOTLIN_CONSOLE_KEY
|
||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
@@ -66,7 +72,6 @@ import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil
|
||||
import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
||||
import org.jetbrains.kotlin.resolve.repl.ReplState
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||
import java.awt.Color
|
||||
import java.awt.Font
|
||||
import java.util.concurrent.CountDownLatch
|
||||
@@ -89,7 +94,9 @@ class KotlinConsoleRunner(
|
||||
|
||||
override fun finishConsole() {
|
||||
KotlinConsoleKeeper.getInstance(project).removeConsole(consoleView.virtualFile)
|
||||
KotlinScriptDefinitionProvider.getInstance(project)!!.removeScriptDefinition(consoleScriptDefinition)
|
||||
val consoleContributor = ScriptDefinitionContributor.find<ConsoleScriptDefinitionContributor>(project)!!
|
||||
consoleContributor.unregisterDefinition(consoleScriptDefinition)
|
||||
ScriptDefinitionsManager.getInstance(project).reloadDefinitionsBy(consoleContributor)
|
||||
|
||||
if (ApplicationManager.getApplication().isUnitTestMode) {
|
||||
consoleTerminated.countDown()
|
||||
@@ -151,7 +158,10 @@ class KotlinConsoleRunner(
|
||||
val executeAction = KtExecuteCommandAction(consoleView.virtualFile)
|
||||
executeAction.registerCustomShortcutSet(CommonShortcuts.CTRL_ENTER, consoleView.consoleEditor.component)
|
||||
|
||||
KotlinScriptDefinitionProvider.getInstance(project)!!.addScriptDefinition(consoleScriptDefinition)
|
||||
val consoleContributor = ScriptDefinitionContributor.find<ConsoleScriptDefinitionContributor>(project)!!
|
||||
consoleContributor.registerDefinition(consoleScriptDefinition)
|
||||
ScriptDefinitionsManager.getInstance(project).reloadDefinitionsBy(consoleContributor)
|
||||
|
||||
enableCompletion(consoleView)
|
||||
|
||||
return consoleView
|
||||
@@ -285,4 +295,22 @@ class KotlinConsoleRunner(
|
||||
private fun configureFileDependencies(psiFile: KtFile) {
|
||||
psiFile.moduleInfo = module.testSourceInfo() ?: module.productionSourceInfo() ?: NotUnderContentRootModuleInfo
|
||||
}
|
||||
}
|
||||
|
||||
class ConsoleScriptDefinitionContributor: ScriptDefinitionContributor {
|
||||
private val definitions = ContainerUtil.newConcurrentSet<KotlinScriptDefinition>()
|
||||
|
||||
override val id: String = "IDEA Console"
|
||||
|
||||
override fun getDefinitions(): List<KotlinScriptDefinition> {
|
||||
return definitions.toList()
|
||||
}
|
||||
|
||||
fun registerDefinition(definition: KotlinScriptDefinition) {
|
||||
definitions.add(definition)
|
||||
}
|
||||
|
||||
fun unregisterDefinition(definition: KotlinScriptDefinition) {
|
||||
definitions.remove(definition)
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,8 @@
|
||||
<extensionPoint name="storageComponentContainerContributor"
|
||||
interface="org.jetbrains.kotlin.extensions.StorageComponentContainerContributor"
|
||||
area="IDEA_PROJECT"/>
|
||||
<extensionPoint name="scriptTemplatesProvider"
|
||||
interface="org.jetbrains.kotlin.script.ScriptTemplatesProvider"
|
||||
<extensionPoint name="scriptDefinitionContributor"
|
||||
interface="org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor"
|
||||
area="IDEA_PROJECT"/>
|
||||
<extensionPoint name="facetConfigurationExtension"
|
||||
interface="org.jetbrains.kotlin.idea.facet.KotlinFacetConfigurationExtension"/>
|
||||
|
||||
@@ -25,13 +25,16 @@
|
||||
<!-- diagnosticSuppressor decelerated in common.xml -->
|
||||
<diagnosticSuppressor implementation="org.jetbrains.kotlin.idea.debugger.DiagnosticSuppressorForDebugger"/>
|
||||
|
||||
<scriptTemplatesProvider
|
||||
<scriptDefinitionContributor
|
||||
id="ScriptTemplatesFromCompilerSettingsProvider"
|
||||
implementation="org.jetbrains.kotlin.idea.script.ScriptTemplatesFromCompilerSettingsProvider"/>
|
||||
|
||||
<scriptTemplatesProvider id="StandardKotlinScriptTemplateProvider"
|
||||
<scriptDefinitionContributor id="StandardScriptDefinitionContributor"
|
||||
order="last"
|
||||
implementation="org.jetbrains.kotlin.idea.script.StandardKotlinScriptTemplateProvider"/>
|
||||
implementation="org.jetbrains.kotlin.idea.core.script.StandardScriptDefinitionContributor"/>
|
||||
|
||||
<scriptDefinitionContributor id="ConsoleScriptDefinitionContributor"
|
||||
implementation="org.jetbrains.kotlin.console.ConsoleScriptDefinitionContributor"/>
|
||||
|
||||
<idePlatformSupport implementation="org.jetbrains.kotlin.caches.resolve.JvmPlatformSupport"/>
|
||||
<idePlatformSupport implementation="org.jetbrains.kotlin.caches.resolve.JsPlatformSupport"/>
|
||||
|
||||
@@ -280,8 +280,8 @@
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.resolve.CodeAnalyzerInitializer"
|
||||
serviceImplementation="org.jetbrains.kotlin.resolve.DummyCodeAnalyzerInitializer"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider"
|
||||
serviceImplementation="org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider"/>
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.script.ScriptDefinitionProvider"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager"/>
|
||||
|
||||
<projectService serviceInterface="org.jetbrains.kotlin.script.ScriptDependenciesProvider"
|
||||
serviceImplementation="org.jetbrains.kotlin.idea.core.script.IdeScriptDependenciesProvider"/>
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
* 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.idea.script
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.projectRoots.JavaSdk
|
||||
import com.intellij.openapi.projectRoots.ProjectJdkTable
|
||||
import com.intellij.openapi.projectRoots.ex.PathUtilEx
|
||||
import org.jetbrains.kotlin.idea.core.script.dependencies.KotlinScriptResolveScopeProvider
|
||||
import org.jetbrains.kotlin.script.ScriptTemplatesProvider
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
import java.io.File
|
||||
import kotlin.script.dependencies.*
|
||||
import kotlin.script.experimental.dependencies.*
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult
|
||||
import kotlin.script.templates.standard.ScriptTemplateWithArgs
|
||||
|
||||
class StandardKotlinScriptTemplateProvider(val project: Project) : ScriptTemplatesProvider {
|
||||
override val id: String = "StandardKotlinScriptTemplateProvider"
|
||||
override val isValid: Boolean = true
|
||||
|
||||
override val templateClassNames: Iterable<String> get() = listOf(ScriptTemplateWithArgs::class.qualifiedName!!)
|
||||
override val templateClasspath get() = emptyList<File>()
|
||||
|
||||
override val environment: Map<String, Any?>? get() {
|
||||
return mapOf(
|
||||
KotlinScriptResolveScopeProvider.USE_NULL_RESOLVE_SCOPE to true,
|
||||
"sdk" to getScriptSDK(project)
|
||||
)
|
||||
}
|
||||
|
||||
override val resolver: DependenciesResolver = BundledKotlinScriptDependenciesResolver()
|
||||
|
||||
private fun getScriptSDK(project: Project): String? {
|
||||
val jdk = PathUtilEx.getAnyJdk(project) ?:
|
||||
ProjectJdkTable.getInstance().allJdks.firstOrNull { sdk -> sdk.sdkType is JavaSdk }
|
||||
|
||||
return jdk?.homePath
|
||||
}
|
||||
}
|
||||
|
||||
class BundledKotlinScriptDependenciesResolver : DependenciesResolver {
|
||||
override fun resolve(
|
||||
scriptContents: ScriptContents,
|
||||
environment: Environment
|
||||
): ResolveResult {
|
||||
val javaHome = environment.get("sdk") as String?
|
||||
val dependencies = ScriptDependencies(
|
||||
javaHome = javaHome?.let(::File),
|
||||
classpath = with(PathUtil.kotlinPathsForIdeaPlugin) {
|
||||
listOf(
|
||||
reflectPath,
|
||||
stdlibPath,
|
||||
scriptRuntimePath
|
||||
)
|
||||
}
|
||||
)
|
||||
return dependencies.asSuccess()
|
||||
}
|
||||
}
|
||||
@@ -18,20 +18,23 @@ package org.jetbrains.kotlin.idea.script
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings
|
||||
import org.jetbrains.kotlin.script.ScriptTemplatesProvider
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor
|
||||
import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import java.io.File
|
||||
|
||||
class ScriptTemplatesFromCompilerSettingsProvider(project: Project): ScriptTemplatesProvider
|
||||
{
|
||||
private val kotlinSettings = KotlinCompilerSettings.getInstance(project).settings
|
||||
class ScriptTemplatesFromCompilerSettingsProvider(private val project: Project) : ScriptDefinitionContributor {
|
||||
override fun getDefinitions(): List<KotlinScriptDefinition> {
|
||||
val kotlinSettings = KotlinCompilerSettings.getInstance(project).settings
|
||||
return loadDefinitionsFromTemplates(
|
||||
templateClassNames = kotlinSettings.scriptTemplates.split(',', ' '),
|
||||
templateClasspath = kotlinSettings.scriptTemplatesClasspath.split(File.pathSeparator).map(::File),
|
||||
environment = mapOf(
|
||||
"projectRoot" to (project.basePath ?: project.baseDir.canonicalPath)?.let(::File))
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
override val id: String = "KotlinCompilerScriptTemplatesSettings"
|
||||
override val isValid: Boolean = kotlinSettings.scriptTemplates.isNotBlank()
|
||||
|
||||
override val templateClassNames: Iterable<String> get() = kotlinSettings.scriptTemplates.split(',', ' ')
|
||||
override val templateClasspath get() = kotlinSettings.scriptTemplatesClasspath.split(File.pathSeparator).map(::File)
|
||||
override val environment: Map<String, Any?>? by lazy { mapOf(
|
||||
"projectRoot" to (project.basePath ?: project.baseDir.canonicalPath)?.let(::File))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -24,10 +24,10 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.testFramework.PlatformTestUtil
|
||||
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime
|
||||
import org.jetbrains.kotlin.idea.KotlinDaemonAnalyzerTestCase
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager.Companion.updateScriptDependenciesSynchronously
|
||||
import org.jetbrains.kotlin.idea.navigation.GotoCheck
|
||||
import org.jetbrains.kotlin.script.ScriptTemplatesProvider
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.MockLibraryUtil
|
||||
@@ -39,12 +39,6 @@ import org.junit.Assert
|
||||
import java.io.File
|
||||
import java.util.regex.Pattern
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.dependencies.ScriptContents
|
||||
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
import kotlin.script.experimental.dependencies.asSuccess
|
||||
import kotlin.script.templates.ScriptTemplateDefinition
|
||||
|
||||
|
||||
abstract class AbstractScriptConfigurationHighlightingTest : AbstractScriptConfigurationTest() {
|
||||
@@ -182,44 +176,10 @@ abstract class AbstractScriptConfigurationTest : KotlinDaemonAnalyzerTestCase()
|
||||
|
||||
PlatformTestUtil.registerExtension(
|
||||
Extensions.getArea(project),
|
||||
ScriptTemplatesProvider.EP_NAME,
|
||||
ScriptDefinitionContributor.EP_NAME,
|
||||
provider,
|
||||
testRootDisposable
|
||||
)
|
||||
ScriptDependenciesManager.reloadScriptDefinitions(project)
|
||||
ScriptDefinitionsManager.getInstance(project).reloadScriptDefinitions()
|
||||
}
|
||||
}
|
||||
|
||||
class CustomScriptTemplateProvider(
|
||||
override val environment: Map<String, Any?>
|
||||
) : ScriptTemplatesProvider {
|
||||
override val id = "Test"
|
||||
override val isValid = true
|
||||
override val templateClassNames = listOf("custom.scriptDefinition.Template")
|
||||
override val templateClasspath = listOfNotNull(environment["template-classes"] as? File)
|
||||
}
|
||||
|
||||
class FromTextTemplateProvider(
|
||||
override val environment: Map<String, Any?>
|
||||
) : ScriptTemplatesProvider {
|
||||
override val id = "Test"
|
||||
override val isValid = true
|
||||
override val templateClassNames = listOf("org.jetbrains.kotlin.idea.script.Template")
|
||||
override val templateClasspath get() = emptyList<File>()
|
||||
}
|
||||
|
||||
|
||||
class FromTextDependenciesResolver : AsyncDependenciesResolver {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
suspend override fun resolveAsync(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult {
|
||||
return ScriptDependencies(
|
||||
classpath = (environment["classpath"] as? List<File>).orEmpty(),
|
||||
imports = (environment["imports"] as? List<String>).orEmpty(),
|
||||
sources = (environment["sources"] as? List<File>).orEmpty()
|
||||
).asSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@ScriptTemplateDefinition(FromTextDependenciesResolver::class, scriptFilePattern = "script.kts")
|
||||
class Template
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.idea.script
|
||||
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor
|
||||
import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates
|
||||
import java.io.File
|
||||
import kotlin.script.dependencies.Environment
|
||||
import kotlin.script.dependencies.ScriptContents
|
||||
import kotlin.script.experimental.dependencies.AsyncDependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.DependenciesResolver
|
||||
import kotlin.script.experimental.dependencies.ScriptDependencies
|
||||
import kotlin.script.experimental.dependencies.asSuccess
|
||||
import kotlin.script.templates.ScriptTemplateDefinition
|
||||
|
||||
|
||||
class CustomScriptTemplateProvider(
|
||||
val environment: Environment
|
||||
) : ScriptDefinitionContributor {
|
||||
override val id = "Test"
|
||||
|
||||
override fun getDefinitions() = loadDefinitionsFromTemplates(
|
||||
templateClassNames = listOf("custom.scriptDefinition.Template"),
|
||||
templateClasspath = listOfNotNull(environment["template-classes"] as? File),
|
||||
environment = environment
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
class FromTextTemplateProvider(
|
||||
val environment: Map<String, Any?>
|
||||
) : ScriptDefinitionContributor {
|
||||
override val id = "Test"
|
||||
override fun getDefinitions() = loadDefinitionsFromTemplates(
|
||||
templateClassNames = listOf("org.jetbrains.kotlin.idea.script.Template"),
|
||||
templateClasspath = emptyList(),
|
||||
environment = environment
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
class FromTextDependenciesResolver : AsyncDependenciesResolver {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
suspend override fun resolveAsync(scriptContents: ScriptContents, environment: Environment): DependenciesResolver.ResolveResult {
|
||||
return ScriptDependencies(
|
||||
classpath = (environment["classpath"] as? List<File>).orEmpty(),
|
||||
imports = (environment["imports"] as? List<String>).orEmpty(),
|
||||
sources = (environment["sources"] as? List<File>).orEmpty()
|
||||
).asSuccess()
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@ScriptTemplateDefinition(FromTextDependenciesResolver::class, scriptFilePattern = "script.kts")
|
||||
class Template
|
||||
+1
-2
@@ -23,7 +23,6 @@ import org.jetbrains.kotlin.cli.common.repl.*
|
||||
import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots
|
||||
import org.jetbrains.kotlin.cli.jvm.repl.GenericReplCompiler
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmMetadataVersion
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinition
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionFromAnnotatedTemplate
|
||||
import org.jetbrains.kotlin.utils.PathUtil
|
||||
@@ -64,7 +63,7 @@ class KotlinJsr223JvmLocalScriptEngine(
|
||||
private fun makeScriptDefinition(templateClasspath: List<File>, templateClassName: String): KotlinScriptDefinition {
|
||||
val classloader = URLClassLoader(templateClasspath.map { it.toURI().toURL() }.toTypedArray(), this.javaClass.classLoader)
|
||||
val cls = classloader.loadClass(templateClassName)
|
||||
return KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, null, null, emptyMap())
|
||||
return KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, emptyMap())
|
||||
}
|
||||
|
||||
private fun makeCompilerConfiguration() = CompilerConfiguration().apply {
|
||||
|
||||
+1
-1
@@ -115,7 +115,7 @@ done
|
||||
suppressOutput: Boolean = false
|
||||
): Class<*>? =
|
||||
compileScriptImpl("src/test/resources/scripts/" + scriptFileName,
|
||||
KotlinScriptDefinitionFromAnnotatedTemplate(scriptTemplate, null, null, environment), suppressOutput)
|
||||
KotlinScriptDefinitionFromAnnotatedTemplate(scriptTemplate, environment), suppressOutput)
|
||||
|
||||
private fun compileScriptImpl(
|
||||
scriptPath: String,
|
||||
|
||||
+1
-1
@@ -31,7 +31,7 @@ abstract class AbstractSamWithReceiverScriptTest : AbstractDiagnosticsTest() {
|
||||
|
||||
override fun createEnvironment(file: File) = super.createEnvironment(file).apply {
|
||||
StorageComponentContainerContributor.registerExtension(project, CliSamWithReceiverComponentContributor(TEST_ANNOTATIONS))
|
||||
val def = KotlinScriptDefinitionFromAnnotatedTemplate(ScriptForSamWithReceivers::class, null, null, emptyMap())
|
||||
val def = KotlinScriptDefinitionFromAnnotatedTemplate(ScriptForSamWithReceivers::class, emptyMap())
|
||||
configuration.add(JVMConfigurationKeys.SCRIPT_DEFINITIONS, def)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,8 +19,6 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.addKotlinSourceRoot
|
||||
import org.jetbrains.kotlin.resolve.jvm.extensions.AnalysisHandlerExtension
|
||||
import org.jetbrains.kotlin.script.KotlinScriptDefinitionProvider
|
||||
import org.jetbrains.kotlin.script.StandardScriptDefinition
|
||||
import org.jetbrains.kotlin.test.ConfigurationKind
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.TestJdkKind
|
||||
@@ -51,8 +49,6 @@ abstract class AbstractKotlinUastTest : AbstractUastTest() {
|
||||
|
||||
initializeKotlinEnvironment()
|
||||
|
||||
KotlinScriptDefinitionProvider.getInstance(project)?.addScriptDefinition(StandardScriptDefinition)
|
||||
|
||||
val trace = CliLightClassGenerationSupport.NoScopeRecordCliBindingTrace()
|
||||
|
||||
val environment = kotlinCoreEnvironment!!
|
||||
|
||||
Reference in New Issue
Block a user