diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestCase.java b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestCase.java index d3f2c59eb96..626d3abfd31 100644 --- a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestCase.java +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/CodegenTestCase.java @@ -13,7 +13,7 @@ import com.intellij.testFramework.TestDataFile; import kotlin.collections.ArraysKt; import kotlin.collections.CollectionsKt; import kotlin.io.FilesKt; -import kotlin.script.experimental.dependencies.ScriptDependencies; +import kotlin.script.experimental.api.ErrorHandlingKt; import kotlin.text.Charsets; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider; +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper; import org.jetbrains.kotlin.test.ConfigurationKind; import org.jetbrains.kotlin.test.InTextDirectivesUtils; import org.jetbrains.kotlin.test.KotlinTestUtils; @@ -433,9 +434,9 @@ public abstract class CodegenTestCase extends KtUsefulTestCase { if (externalImportsProvider != null) { myEnvironment.getSourceFiles().forEach( file -> { - ScriptDependencies dependencies = externalImportsProvider.getScriptDependencies(file); - if (dependencies != null) { - files.addAll(dependencies.getClasspath()); + ScriptCompilationConfigurationWrapper refinedConfiguration = ErrorHandlingKt.valueOrNull(externalImportsProvider.getScriptConfigurationResult(file)); + if (refinedConfiguration != null) { + files.addAll(refinedConfiguration.getDependenciesClassPath()); } } ); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt b/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt index feda4bf0831..33e0f000277 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/AbstractCustomScriptCodegenTest.kt @@ -24,6 +24,7 @@ import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.api.implicitReceivers import kotlin.script.experimental.api.providedProperties +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContextOrStdlib abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() { @@ -37,7 +38,9 @@ abstract class AbstractCustomScriptCodegenTest : CodegenTestCase() { override fun updateConfiguration(configuration: CompilerConfiguration) { if (scriptDefinitions.isNotEmpty()) { - configureScriptDefinitions(scriptDefinitions, configuration, this::class.java.classLoader, MessageCollector.NONE, emptyMap()) + configureScriptDefinitions( + scriptDefinitions, configuration, this::class.java.classLoader, MessageCollector.NONE, defaultJvmScriptingHostConfiguration + ) } configuration.addJvmClasspathRoots(additionalDependencies.orEmpty()) diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/CustomScriptCodegenTest.kt b/compiler/tests/org/jetbrains/kotlin/codegen/CustomScriptCodegenTest.kt index d6037a7d59b..3afd882b7be 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/CustomScriptCodegenTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/CustomScriptCodegenTest.kt @@ -21,6 +21,7 @@ import java.io.File import java.lang.reflect.Constructor import kotlin.reflect.KClass import kotlin.script.experimental.annotations.KotlinScript +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContextOrStdlib class CustomScriptCodegenTest : CodegenTestCase() { @@ -65,7 +66,8 @@ class CustomScriptCodegenTest : CodegenTestCase() { if (scriptDefinitions.isNotEmpty()) { configureScriptDefinitions( - scriptDefinitions.asList(), configuration, this::class.java.classLoader, MessageCollector.NONE, emptyMap() + scriptDefinitions.asList(), configuration, this::class.java.classLoader, + MessageCollector.NONE, defaultJvmScriptingHostConfiguration ) } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ScriptGenTest.kt b/compiler/tests/org/jetbrains/kotlin/codegen/ScriptGenTest.kt index d1b91300081..d1d4cd15b7a 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ScriptGenTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ScriptGenTest.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.cli.jvm.config.addJvmClasspathRoots import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.script.loadScriptingPlugin import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate import org.jetbrains.kotlin.scripts.TestKotlinScriptDependenciesResolver import org.jetbrains.kotlin.test.ConfigurationKind @@ -33,14 +34,21 @@ 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.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.templates.ScriptTemplateDefinition class ScriptGenTest : CodegenTestCase() { companion object { private val FIB_SCRIPT_DEFINITION = - KotlinScriptDefinitionFromAnnotatedTemplate(ScriptWithIntParam::class) + ScriptDefinition.FromLegacy( + defaultJvmScriptingHostConfiguration, + KotlinScriptDefinitionFromAnnotatedTemplate(ScriptWithIntParam::class) + ) private val NO_PARAM_SCRIPT_DEFINITION = - KotlinScriptDefinitionFromAnnotatedTemplate(Any::class) + ScriptDefinition.FromLegacy( + defaultJvmScriptingHostConfiguration, + KotlinScriptDefinitionFromAnnotatedTemplate(Any::class) + ) } override fun setUp() { diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/CollectScriptCompilationDependenciesTest.kt b/compiler/tests/org/jetbrains/kotlin/scripts/CollectScriptCompilationDependenciesTest.kt index 1674c563990..7523e0a47e0 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/CollectScriptCompilationDependenciesTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/CollectScriptCompilationDependenciesTest.kt @@ -12,16 +12,13 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.script.loadScriptingPlugin import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinitionAdapterFromNewAPI +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase import java.io.File -import kotlin.script.experimental.api.KotlinType import kotlin.script.experimental.host.ScriptingHostConfiguration -import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration private const val testDataPath = "compiler/testData/script/collectDependencies" @@ -58,15 +55,14 @@ class CollectScriptCompilationDependenciesTest : KtUsefulTestCase() { private fun runTest(scriptFile: String, expectedDependencies: List, classPath: List = emptyList()) { val configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.NO_KOTLIN_REFLECT, TestJdkKind.MOCK_JDK).apply { - val hostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) - val scriptDefinition = KotlinScriptDefinitionAdapterFromNewAPI( - createCompilationConfigurationFromTemplate( - KotlinType(TestScriptWithRequire::class), - hostConfiguration, KotlinScriptDefinition::class - ), - hostConfiguration + add( + ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, + ScriptDefinition.FromTemplate( + ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration), + TestScriptWithRequire::class, + ScriptDefinition::class + ) ) - add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) addKotlinSourceRoot(File(testDataPath, scriptFile).path) diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptCliCompilationTest.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptCliCompilationTest.kt index 3af01e5e091..7c273264f83 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptCliCompilationTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptCliCompilationTest.kt @@ -15,8 +15,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler import org.jetbrains.kotlin.daemon.TestMessageCollector import org.jetbrains.kotlin.script.loadScriptingPlugin import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinitionAdapterFromNewAPI +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.TestJdkKind @@ -27,10 +26,10 @@ import java.io.File import kotlin.reflect.KClass import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.* +import kotlin.script.experimental.host.FileBasedScriptSource import kotlin.script.experimental.host.FileScriptSource import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.host.configurationDependencies -import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate import kotlin.script.experimental.jvm.* private const val testDataPath = "compiler/testData/script/cliCompilation" @@ -75,14 +74,10 @@ class ScriptCliCompilationTest : KtUsefulTestCase() { val hostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { configurationDependencies(JvmDependency(classpath)) } - val scriptDefinition = KotlinScriptDefinitionAdapterFromNewAPI( - createCompilationConfigurationFromTemplate( - KotlinType(scriptDef), - hostConfiguration, KotlinScriptDefinition::class - ), - hostConfiguration + add( + ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, + ScriptDefinition.FromTemplate(hostConfiguration, scriptDef, ScriptDefinition::class) ) - add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) } loadScriptingPlugin(this) } @@ -122,7 +117,7 @@ object TestScriptWithRequireConfiguration : ScriptCompilationConfiguration( } refineConfiguration { onAnnotations(Import::class, DependsOn::class) { context: ScriptConfigurationRefinementContext -> - val scriptBaseDir = (context.script as? FileScriptSource)?.file?.parentFile + val scriptBaseDir = (context.script as? FileBasedScriptSource)?.file?.parentFile val sources = context.collectedData?.get(ScriptCollectedData.foundAnnotations) ?.flatMap { (it as? Import)?.sources?.map { sourceName -> diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTemplateTest.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTemplateTest.kt index 04a30e5661f..f6c145a02be 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTemplateTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTemplateTest.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.daemon.toFile import org.jetbrains.kotlin.script.loadScriptingPlugin import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.resolve.InvalidScriptResolverAnnotation import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate import org.jetbrains.kotlin.test.ConfigurationKind @@ -50,6 +51,7 @@ import kotlin.reflect.KClass import kotlin.script.dependencies.* import kotlin.script.experimental.dependencies.* import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.templates.AcceptedAnnotations import kotlin.script.templates.ScriptTemplateDefinition import kotlin.script.templates.standard.ScriptTemplateWithArgs @@ -348,7 +350,13 @@ class ScriptTemplateTest : KtUsefulTestCase() { *additionalClasspath) configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) configuration.addKotlinSourceRoot(scriptPath) - configuration.add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + configuration.add( + ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, + ScriptDefinition.FromLegacy( + defaultJvmScriptingHostConfiguration, + scriptDefinition + ) + ) configuration.put(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION, true) configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) diff --git a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt index 87cd157cbbb..f7bbeee91c3 100644 --- a/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt +++ b/compiler/tests/org/jetbrains/kotlin/scripts/ScriptTest.kt @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.script.loadScriptingPlugin import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.StandardScriptDefinition import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.KotlinTestUtils @@ -37,6 +38,7 @@ import org.jetbrains.kotlin.utils.tryConstructClassFromStringArgs import org.junit.Assert import java.io.File import java.net.URLClassLoader +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration class ScriptTest : KtUsefulTestCase() { fun testStandardScriptWithParams() { @@ -102,7 +104,13 @@ class ScriptTest : KtUsefulTestCase() { val configuration = KotlinTestUtils.newConfiguration(ConfigurationKind.ALL, TestJdkKind.FULL_JDK) configuration.put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) configuration.addKotlinSourceRoot("compiler/testData/script/$scriptPath") - configuration.add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + configuration.add( + ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, + ScriptDefinition.FromLegacy( + defaultJvmScriptingHostConfiguration, + scriptDefinition + ) + ) configuration.put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) if (saveClassesDir != null) { configuration.put(JVMConfigurationKeys.OUTPUT_DIRECTORY, saveClassesDir) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/ScriptModuleInfos.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/ScriptModuleInfos.kt index 7ee04c45b66..8765cf0a268 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/ScriptModuleInfos.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/ScriptModuleInfos.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager import org.jetbrains.kotlin.idea.core.script.dependencies.ScriptAdditionalIdeaDependenciesProvider import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.jvm.JvmPlatforms @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices data class ScriptModuleInfo( val project: Project, val scriptFile: VirtualFile, - val scriptDefinition: KotlinScriptDefinition + val scriptDefinition: ScriptDefinition ) : IdeaModuleInfo { override val moduleOrigin: ModuleOrigin get() = ModuleOrigin.OTHER @@ -85,7 +85,7 @@ sealed class ScriptDependenciesInfo(val project: Project) : IdeaModuleInfo, Bina class ForFile( project: Project, val scriptFile: VirtualFile, - val scriptDefinition: KotlinScriptDefinition + val scriptDefinition: ScriptDefinition ) : ScriptDependenciesInfo(project) { override val sdk: Sdk? get() { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt index 2392ea73580..cda63161254 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/getModuleInfo.kt @@ -27,7 +27,7 @@ import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected import org.jetbrains.kotlin.idea.util.isKotlinBinary import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getParentOfType -import org.jetbrains.kotlin.scripting.definitions.scriptDefinitionByFileName +import org.jetbrains.kotlin.scripting.definitions.findScriptDefinitionByFileName import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.sure import org.jetbrains.kotlin.utils.yieldIfNotNull @@ -174,7 +174,7 @@ private fun PsiElement.collectInfos(c: ModuleInfoCollector): T { return c.onResult(it) } containingKtFile.script?.let { - val definition = scriptDefinitionByFileName(project, containingKtFile.name) + val definition = findScriptDefinitionByFileName(project, containingKtFile.name) return c.onResult(ScriptModuleInfo(project, virtualFile, definition)) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt index 23f40adbd2c..98debbe7be0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/compiler/IDELanguageSettingsProvider.kt @@ -37,7 +37,7 @@ import org.jetbrains.kotlin.idea.caches.project.* import org.jetbrains.kotlin.idea.project.getLanguageVersionSettings import org.jetbrains.kotlin.idea.project.languageVersionSettings import org.jetbrains.kotlin.idea.project.platform -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.platform.jvm.JdkPlatform import org.jetbrains.kotlin.platform.subplatformOfType import org.jetbrains.kotlin.utils.Jsr305State @@ -92,8 +92,8 @@ private data class ScriptLanguageSettings( private val SCRIPT_LANGUAGE_SETTINGS = Key.create>("SCRIPT_LANGUAGE_SETTINGS") -private fun getLanguageSettingsForScripts(project: Project, scriptDefinition: KotlinScriptDefinition): ScriptLanguageSettings { - val args = scriptDefinition.additionalCompilerArguments +private fun getLanguageSettingsForScripts(project: Project, scriptDefinition: ScriptDefinition): ScriptLanguageSettings { + val args = scriptDefinition.compilerOptions return if (args == null || args.none()) { ScriptLanguageSettings(project.getLanguageVersionSettings(), TargetPlatformVersion.NoVersion) } else { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt index 25cd9a9934e..0ad1338e000 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinHighlightingUtil.kt @@ -22,7 +22,7 @@ import org.jetbrains.kotlin.idea.caches.project.NotUnderContentRootModuleInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager -import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesUpdater +import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.isRunningInCidrIde import org.jetbrains.kotlin.psi.KtCodeFragment @@ -70,7 +70,7 @@ object KotlinHighlightingUtil { @Suppress("DEPRECATION") private fun shouldHighlightScript(ktFile: KtFile): Boolean { if (isRunningInCidrIde) return false // There is no Java support in CIDR. So do not highlight errors in KTS if running in CIDR. - if (!ScriptDependenciesUpdater.areDependenciesCached(ktFile)) return false + if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(ktFile)) return false if (ktFile.virtualFile.getUserData(IdeScriptReportSink.Reports)?.any { it.severity == ScriptReport.Severity.FATAL } == true) { return false } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt index 28a78968c5b..3ae4c5b4186 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/ScriptExternalHighlightingPass.kt @@ -39,9 +39,8 @@ import com.intellij.util.ui.UIUtil import org.jetbrains.kotlin.idea.core.script.IdeScriptReportSink import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager -import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesUpdater +import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater import org.jetbrains.kotlin.psi.KtFile -import kotlin.script.experimental.dependencies.ScriptDependencies import kotlin.script.experimental.dependencies.ScriptReport class ScriptExternalHighlightingPass( @@ -62,9 +61,10 @@ class ScriptExternalHighlightingPass( ) } - if (!ScriptDependenciesUpdater.areDependenciesCached(file)) { - val scriptDependencies = ScriptDependenciesManager.getInstance(file.project).getScriptDependencies(file.virtualFile) - if (scriptDependencies == ScriptDependencies.Empty) { + if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(file)) { + // initiate configuration refinement, if needed + ScriptDependenciesManager.getInstance(file.project).getRefinedCompilationConfiguration(file.virtualFile) + if (!ScriptsCompilationConfigurationUpdater.areDependenciesCached(file)) { showNotification( file, "Highlighting in scripts is not available until all Script Dependencies are loaded" diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/TargetPlatformDetector.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/TargetPlatformDetector.java index b7c0d24874d..d2ff0d2e469 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/TargetPlatformDetector.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/TargetPlatformDetector.java @@ -33,7 +33,7 @@ import org.jetbrains.kotlin.psi.KtPsiFactoryKt; import org.jetbrains.kotlin.platform.TargetPlatform; import org.jetbrains.kotlin.platform.SimplePlatform; import org.jetbrains.kotlin.scripting.definitions.DefinitionsKt; -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition; +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition; public class TargetPlatformDetector { public static final TargetPlatformDetector INSTANCE = new TargetPlatformDetector(); @@ -62,7 +62,7 @@ public class TargetPlatformDetector { } if (file.isScript()) { - KotlinScriptDefinition scriptDefinition = DefinitionsKt.scriptDefinition(file); + ScriptDefinition scriptDefinition = DefinitionsKt.findScriptDefinition(file); if (scriptDefinition != null) { String platformNameFromScriptDefinition = scriptDefinition.getPlatform(); for (TargetPlatform compilerPlatform : IdePlatformKind.Companion.getAll_PLATFORMS()) { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt index 561cf482583..15e4347c84a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt @@ -71,7 +71,8 @@ object ProjectRootsUtil { ): Boolean { val scriptDefinition = file.findScriptDefinition(project) if (scriptDefinition != null) { - val scriptScope = scriptDefinition.scriptExpectedLocations + // TODO: rewrite to ScriptAcceptedLocation and without legacyDefinition + val scriptScope = scriptDefinition.legacyDefinition.scriptExpectedLocations val includeAll = scriptScope.contains(ScriptExpectedLocation.Everywhere) || scriptScope.contains(ScriptExpectedLocation.Project) || ScratchUtil.isScratch(file) @@ -115,7 +116,8 @@ object ProjectRootsUtil { if (ProjectRootManager.getInstance(project).fileIndex.isInContent(file) || ScratchUtil.isScratch(file)) { return true } - return file.findScriptDefinition(project)?.scriptExpectedLocations?.contains(ScriptExpectedLocation.Everywhere) == true + // TODO: rewrite to ScriptAcceptedLocation and without legacyDefinition + return file.findScriptDefinition(project)?.legacyDefinition?.scriptExpectedLocations?.contains(ScriptExpectedLocation.Everywhere) == true } if (!includeLibraryClasses && !includeLibrarySource) return false diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt index e3577e16f84..215b513ac98 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDefinitionsManager.kt @@ -39,11 +39,7 @@ import org.jetbrains.kotlin.idea.caches.project.SdkInfo import org.jetbrains.kotlin.idea.caches.project.getScriptRelatedModuleInfo import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings import org.jetbrains.kotlin.script.ScriptTemplatesProvider -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinitionAdapterFromNewAPI -import org.jetbrains.kotlin.scripting.definitions.LazyScriptDefinitionProvider -import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider -import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate +import org.jetbrains.kotlin.scripting.definitions.* import org.jetbrains.kotlin.utils.PathUtil import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.flattenTo @@ -53,35 +49,33 @@ import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.write import kotlin.script.dependencies.Environment import kotlin.script.dependencies.ScriptContents -import kotlin.script.experimental.api.KotlinType import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.dependencies.ScriptDependencies import kotlin.script.experimental.dependencies.asSuccess import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.host.configurationDependencies -import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate import kotlin.script.experimental.jvm.JvmDependency import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.jvm.util.scriptCompilationClasspathFromContextOrStdlib import kotlin.script.templates.standard.ScriptTemplateWithArgs class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinitionProvider() { - private var definitionsByContributor = mutableMapOf>() - private var definitions: List? = null + private var definitionsBySource = mutableMapOf>() + private var definitions: List? = null private val failedContributorsHashes = HashSet() private val scriptDefinitionsCacheLock = ReentrantReadWriteLock() - private val scriptDefinitionsCache = SLRUMap(10, 10) + private val scriptDefinitionsCache = SLRUMap(10, 10) - override fun findScriptDefinition(fileName: String): KotlinScriptDefinition? { + override fun findDefinition(fileName: String): ScriptDefinition? { if (nonScriptFileName(fileName)) return null if (!isReady()) return null val cached = scriptDefinitionsCacheLock.write { scriptDefinitionsCache.get(fileName) } if (cached != null) return cached - val definition = super.findScriptDefinition(fileName) ?: return null + val definition = super.findDefinition(fileName) ?: return null scriptDefinitionsCacheLock.write { scriptDefinitionsCache.put(fileName, definition) @@ -90,48 +84,43 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit return definition } - fun reloadDefinitionsBy(contributor: ScriptDefinitionContributor) = lock.write { + override fun findScriptDefinition(fileName: String): KotlinScriptDefinition? = findDefinition(fileName)?.legacyDefinition + + fun reloadDefinitionsBy(source: ScriptDefinitionsSource) = lock.write { if (definitions == null) return // not loaded yet - if (contributor !in definitionsByContributor) error("Unknown contributor: ${contributor.id}") + if (source !in definitionsBySource) error("Unknown script definition source: $source") - definitionsByContributor[contributor] = contributor.safeGetDefinitions() + definitionsBySource[source] = source.safeGetDefinitions() - definitions = definitionsByContributor.values.flattenTo(mutableListOf()) + definitions = definitionsBySource.values.flattenTo(mutableListOf()) updateDefinitions() } - fun getDefinitionsBy(contributor: ScriptDefinitionContributor): List = lock.write { - if (definitions == null) return emptyList() // not loaded yet - - if (contributor !in definitionsByContributor) error("Unknown contributor: ${contributor.id}") - - return definitionsByContributor[contributor] ?: emptyList() - } - - override val currentDefinitions: Sequence + override val currentDefinitions get() = (definitions ?: kotlin.run { reloadScriptDefinitions() definitions!! }).asSequence().filter { KotlinScriptingSettings.getInstance(project).isScriptDefinitionEnabled(it) } - private fun getContributors(): List { + private fun getSources(): List { @Suppress("DEPRECATION") val fromDeprecatedEP = Extensions.getArea(project).getExtensionPoint(ScriptTemplatesProvider.EP_NAME).extensions.toList() - .map(::ScriptTemplatesProviderAdapter) + .map { ScriptTemplatesProviderAdapter(it).asSource() } val fromNewEp = Extensions.getArea(project).getExtensionPoint(ScriptDefinitionContributor.EP_NAME).extensions.toList() + .map { it.asSource() } return fromNewEp.dropLast(1) + fromDeprecatedEP + fromNewEp.last() } fun reloadScriptDefinitions() = lock.write { - for (contributor in getContributors()) { - val definitions = contributor.safeGetDefinitions() - definitionsByContributor[contributor] = definitions + for (source in getSources()) { + val definitions = source.safeGetDefinitions() + definitionsBySource[source] = definitions } - definitions = definitionsByContributor.values.flattenTo(mutableListOf()) + definitions = definitionsBySource.values.flattenTo(mutableListOf()) updateDefinitions() } @@ -140,7 +129,7 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit updateDefinitions() } - fun getAllDefinitions(): List { + fun getAllDefinitions(): List { return definitions ?: kotlin.run { reloadScriptDefinitions() definitions!! @@ -148,15 +137,16 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit } fun isReady(): Boolean { - return definitionsByContributor.keys.all { contributor -> - contributor.isReady() + return definitionsBySource.keys.all { source -> + // TODO: implement another API for readiness checking + (source as? ScriptDefinitionContributor)?.isReady() != false } } - override fun getDefaultScriptDefinition(): KotlinScriptDefinition { + override fun getDefaultDefinition(): ScriptDefinition { val standardScriptDefinitionContributor = ScriptDefinitionContributor.find(project) ?: error("StandardScriptDefinitionContributor should be registered is plugin.xml") - return standardScriptDefinitionContributor.getDefinitions().last() + return ScriptDefinition.FromLegacy(getScriptingHostConfiguration(), standardScriptDefinitionContributor.getDefinitions().last()) } private fun updateDefinitions() { @@ -187,7 +177,7 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit scriptDefinitionsCacheLock.write { scriptDefinitionsCache.clear() } // TODO: clear by script type/definition - ServiceManager.getService(project, ScriptDependenciesCache::class.java).clear() + ServiceManager.getService(project, ScriptsCompilationConfigurationCache::class.java).clear() ApplicationManager.getApplication().invokeLater { if (!project.isDisposed) { @@ -196,9 +186,9 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit } } - private fun ScriptDefinitionContributor.safeGetDefinitions(): List { + private fun ScriptDefinitionsSource.safeGetDefinitions(): List { if (!failedContributorsHashes.contains(this@safeGetDefinitions.hashCode())) try { - return getDefinitions() + return definitions.toList() } catch (t: Throwable) { // reporting failed loading only once LOG.error("[kts] cannot load script definitions using $this", t) @@ -207,6 +197,15 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit return emptyList() } + @Suppress("unused") // used in the 182/as33 bunches + fun getDefinitionsBy(source: ScriptDefinitionsSource): List = lock.write { + if (definitions == null) return emptyList() // not loaded yet + + if (source !in definitionsBySource) error("Unknown source: ${source::class.java.name}") + + return definitionsBySource[source] ?: emptyList() + } + companion object { fun getInstance(project: Project): ScriptDefinitionsManager = ServiceManager.getService(project, ScriptDefinitionProvider::class.java) as ScriptDefinitionsManager @@ -216,10 +215,11 @@ class ScriptDefinitionsManager(private val project: Project) : LazyScriptDefinit private val LOG = Logger.getInstance("ScriptTemplatesProviders") +// TODO: consider rewriting to return sequence fun loadDefinitionsFromTemplates( templateClassNames: List, templateClasspath: List, - environment: Environment = emptyMap(), + baseHostConfiguration: ScriptingHostConfiguration, // 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). @@ -227,7 +227,7 @@ fun loadDefinitionsFromTemplates( * i.e. gradle resolver may depend on some jars that 'built.gradle.kts' files should not depend on. */ additionalResolverClasspath: List = emptyList() -): List { +): List { val classpath = templateClasspath + additionalResolverClasspath LOG.info("[kts] loading script definitions $templateClassNames using cp: ${classpath.joinToString(File.pathSeparator)}") val baseLoader = ScriptDefinitionContributor::class.java.classLoader @@ -240,24 +240,13 @@ fun loadDefinitionsFromTemplates( val template = loader.loadClass(templateClassName).kotlin when { template.annotations.firstIsInstanceOrNull() != null -> { - KotlinScriptDefinitionFromAnnotatedTemplate( - template, - environment, - templateClasspath - ) + ScriptDefinition.FromLegacyTemplate(baseHostConfiguration, template, templateClasspath) } template.annotations.firstIsInstanceOrNull() != null -> { - val hostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + val hostConfiguration = ScriptingHostConfiguration(baseHostConfiguration) { configurationDependencies(JvmDependency(classpath)) } - KotlinScriptDefinitionAdapterFromNewAPI( - createCompilationConfigurationFromTemplate( - KotlinType( - template - ), hostConfiguration, KotlinScriptDefinition::class - ), - hostConfiguration - ) + ScriptDefinition.FromTemplate(hostConfiguration, template, ScriptDefinition::class) } else -> { LOG.warn("[kts] cannot find a valid script definition annotation on the class $template") @@ -276,10 +265,16 @@ fun loadDefinitionsFromTemplates( } } +@Deprecated("migrating to new configuration refinement: use ScriptDefinitionsSource internally and kotlin.script.experimental.intellij.ScriptDefinitionsProvider as a providing extension point") interface ScriptDefinitionContributor { + + @Deprecated("migrating to new configuration refinement: drop usages") val id: String + @Deprecated("migrating to new configuration refinement: use ScriptDefinitionsSource instead") fun getDefinitions(): List + + @Deprecated("migrating to new configuration refinement: drop usages") fun isReady() = true companion object { @@ -289,9 +284,29 @@ interface ScriptDefinitionContributor { inline fun find(project: Project) = Extensions.getArea(project).getExtensionPoint(ScriptDefinitionContributor.EP_NAME).extensions.filterIsInstance().firstOrNull() } - } +@Deprecated("migrating to new configuration refinement: use ScriptDefinitionsSource directly instead") +interface ScriptDefinitionSourceAsContributor : ScriptDefinitionContributor, ScriptDefinitionsSource { + + override fun getDefinitions(): List = definitions.map { it.legacyDefinition }.toList() +} + +@Deprecated("migrating to new configuration refinement: convert all contributors to ScriptDefinitionsSource/ScriptDefinitionsProvider") +class ScriptDefinitionSourceFromContributor( + val contributor: ScriptDefinitionContributor, + val hostConfiguration: ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration +) : ScriptDefinitionsSource { + override val definitions: Sequence + get() = + if (contributor is ScriptDefinitionsSource) contributor.definitions + else contributor.getDefinitions().asSequence().map { ScriptDefinition.FromLegacy(hostConfiguration, it) } +} + +fun ScriptDefinitionContributor.asSource(): ScriptDefinitionsSource = + if (this is ScriptDefinitionsSource) this + else ScriptDefinitionSourceFromContributor(this) + class StandardScriptDefinitionContributor(project: Project) : ScriptDefinitionContributor { private val standardIdeScriptDefinition = StandardIdeScriptDefinition(project) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesFileAttribute.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesFileAttribute.kt index 9890a87584e..86c2339ac94 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesFileAttribute.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesFileAttribute.kt @@ -18,8 +18,9 @@ package org.jetbrains.kotlin.idea.core.script import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.idea.core.util.* -import java.io.DataInput -import java.io.DataOutput +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper +import java.io.* +import kotlin.script.experimental.api.ScriptCompilationConfiguration import kotlin.script.experimental.dependencies.ScriptDependencies var VirtualFile.scriptDependencies: ScriptDependencies? by cachedFileAttribute( @@ -43,4 +44,27 @@ var VirtualFile.scriptDependencies: ScriptDependencies? by cachedFileAttribute( writeFileList(sources) } } -) \ No newline at end of file +) + +var VirtualFile.scriptCompilationConfiguration: ScriptCompilationConfiguration? by cachedFileAttribute( + name = "kotlin-script-compilation-configuration", + version = 1, + read = { + val size = readInt() + val bytes = ByteArray(size) + read(bytes, 0, size) + val bis = ByteArrayInputStream(bytes) + ObjectInputStream(bis).use { ois -> + ois.readObject() as ScriptCompilationConfiguration + } + }, + write = { + val os = ByteArrayOutputStream() + ObjectOutputStream(os).use { oos -> + oos.writeObject((it as? ScriptCompilationConfigurationWrapper.FromCompilationConfiguration)?.configuration) + } + val bytes = os.toByteArray() + writeInt(bytes.size) + write(bytes) + } +) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesManager.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesManager.kt index 185d96c6695..37a58c74c5d 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesManager.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesManager.kt @@ -30,8 +30,10 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.idea.caches.project.getAllProjectSdks import org.jetbrains.kotlin.idea.core.script.dependencies.SyncScriptDependenciesLoader import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper import java.io.File -import kotlin.script.experimental.dependencies.ScriptDependencies +import kotlin.script.experimental.api.valueOrNull // NOTE: this service exists exclusively because ScriptDependencyManager @@ -39,18 +41,21 @@ import kotlin.script.experimental.dependencies.ScriptDependencies class IdeScriptDependenciesProvider( private val scriptDependenciesManager: ScriptDependenciesManager ) : ScriptDependenciesProvider { - override fun getScriptDependencies(file: VirtualFile): ScriptDependencies? { - return scriptDependenciesManager.getScriptDependencies(file) - } + override fun getScriptConfigurationResult(file: VirtualFile): ScriptCompilationConfigurationResult? = scriptDependenciesManager.getRefinedCompilationConfiguration(file) } +// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore class ScriptDependenciesManager internal constructor( - private val cacheUpdater: ScriptDependenciesUpdater, - private val cache: ScriptDependenciesCache + private val cacheUpdater: ScriptsCompilationConfigurationUpdater, + private val cache: ScriptsCompilationConfigurationCache ) { - fun getScriptClasspath(file: VirtualFile): List = toVfsRoots(cacheUpdater.getCurrentDependencies(file).classpath) - fun getScriptDependencies(file: VirtualFile): ScriptDependencies = cacheUpdater.getCurrentDependencies(file) - fun getScriptSdk(file: VirtualFile): Sdk? = getScriptSdk(getScriptDependencies(file)) + fun getScriptClasspath(file: VirtualFile): List = + toVfsRoots(cacheUpdater.getCurrentCompilationConfiguration(file)?.valueOrNull()?.dependenciesClassPath.orEmpty()) + + fun getRefinedCompilationConfiguration(file: VirtualFile): ScriptCompilationConfigurationResult? = + cacheUpdater.getCurrentCompilationConfiguration(file) + + fun getScriptSdk(file: VirtualFile): Sdk? = Companion.getScriptSdk(getRefinedCompilationConfiguration(file)?.valueOrNull()) fun getScriptDependenciesClassFilesScope(file: VirtualFile) = cache.scriptDependenciesClassFilesScope(file) @@ -67,35 +72,29 @@ class ScriptDependenciesManager internal constructor( fun getInstance(project: Project): ScriptDependenciesManager = ServiceManager.getService(project, ScriptDependenciesManager::class.java) - fun getScriptSdk(dependencies: ScriptDependencies): Sdk? { + fun getScriptSdk(compilationConfiguration: ScriptCompilationConfigurationWrapper?): Sdk? { // workaround for mismatched gradle wrapper and plugin version - try { - val javaHome = dependencies.javaHome - ?.let { VfsUtil.findFileByIoFile(it, true) } - ?: return null - - return getAllProjectSdks().find { it.homeDirectory == javaHome } + val javaHome = try { + compilationConfiguration?.javaHome?.let { VfsUtil.findFileByIoFile(it, true) } } catch (e: Throwable) { - return null - } + null + } ?: return null + + return getAllProjectSdks().find { it.homeDirectory == javaHome } } - fun getScriptDefaultSdk(project: Project): Sdk? { - val projectSdk = getProjectSdk(project) - if (projectSdk != null) return projectSdk - val anyJavaSdk = getAllProjectSdks().find { it.canBeUsedForScript() } - if (anyJavaSdk != null) { - return anyJavaSdk - } - - log.warn( - "Default Script SDK is null: " + - "projectSdk = ${ProjectRootManager.getInstance(project).projectSdk}, " + - "all sdks = ${getAllProjectSdks().joinToString("\n")}" - ) - return null - } + fun getScriptDefaultSdk(project: Project): Sdk? = + getProjectSdk(project) + ?: getAllProjectSdks().find { it.canBeUsedForScript() } + ?: run { + log.warn( + "Default Script SDK is null: " + + "projectSdk = ${ProjectRootManager.getInstance(project).projectSdk}, " + + "all sdks = ${getAllProjectSdks().joinToString("; ")}" + ) + null + } fun getProjectSdk(project: Project) = ProjectRootManager.getInstance(project).projectSdk?.takeIf { it.canBeUsedForScript() } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptNewDependenciesNotification.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptNewDependenciesNotification.kt index 433788f35d1..0c50a1dc733 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptNewDependenciesNotification.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptNewDependenciesNotification.kt @@ -16,7 +16,7 @@ import com.intellij.ui.EditorNotificationPanel import com.intellij.ui.HyperlinkLabel import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings import org.jetbrains.kotlin.psi.UserDataProperty -import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult fun VirtualFile.removeScriptDependenciesNotificationPanel(project: Project) { withSelectedEditor(project) { manager -> @@ -28,14 +28,14 @@ fun VirtualFile.removeScriptDependenciesNotificationPanel(project: Project) { } fun VirtualFile.addScriptDependenciesNotificationPanel( - resolveResult: ResolveResult, + compilationConfigurationResult: ScriptCompilationConfigurationResult?, project: Project, - onClick: (ResolveResult) -> Unit + onClick: (ScriptCompilationConfigurationResult?) -> Unit ) { withSelectedEditor(project) { manager -> val existingPanel = notificationPanel if (existingPanel != null) { - if (existingPanel.resolveResult.dependencies == resolveResult.dependencies) { + if (existingPanel.compilationConfigurationResult == compilationConfigurationResult) { return@withSelectedEditor } notificationPanel?.let { @@ -43,7 +43,7 @@ fun VirtualFile.addScriptDependenciesNotificationPanel( } } - val panel = NewScriptDependenciesNotificationPanel(onClick, resolveResult, project) + val panel = NewScriptDependenciesNotificationPanel(onClick, compilationConfigurationResult, project) notificationPanel = panel manager.addTopComponent(this, panel) } @@ -61,19 +61,19 @@ private fun VirtualFile.withSelectedEditor(project: Project, f: FileEditor.(File private var FileEditor.notificationPanel: NewScriptDependenciesNotificationPanel? by UserDataProperty(Key.create("script.dependencies.panel")) private class NewScriptDependenciesNotificationPanel( - onClick: (ResolveResult) -> Unit, - val resolveResult: ResolveResult, + onClick: (ScriptCompilationConfigurationResult?) -> Unit, + val compilationConfigurationResult: ScriptCompilationConfigurationResult?, project: Project ) : EditorNotificationPanel() { init { - setText("There are new script dependencies available.") - createComponentActionLabel("Apply dependencies") { - onClick(resolveResult) + setText("There is a new script context available.") + createComponentActionLabel("Apply context") { + onClick(compilationConfigurationResult) } createComponentActionLabel("Enable auto-reload") { - onClick(resolveResult) + onClick(compilationConfigurationResult) KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled = true } } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTemplatesProviderAdapter.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTemplatesProviderAdapter.kt index 95612875288..7e031a325ac 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTemplatesProviderAdapter.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptTemplatesProviderAdapter.kt @@ -6,17 +6,25 @@ package org.jetbrains.kotlin.idea.core.script import org.jetbrains.kotlin.script.ScriptTemplatesProvider -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.getEnvironment +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration + +class ScriptTemplatesProviderAdapter(private val templatesProvider: ScriptTemplatesProvider) : ScriptDefinitionSourceAsContributor { -class ScriptTemplatesProviderAdapter(private val templatesProvider: ScriptTemplatesProvider) : - ScriptDefinitionContributor { override val id: String get() = templatesProvider.id - override fun getDefinitions(): List { - return loadDefinitionsFromTemplates( - templatesProvider.templateClassNames.toList(), templatesProvider.templateClasspath, - templatesProvider.environment.orEmpty(), templatesProvider.additionalResolverClasspath - ) - } + override val definitions: Sequence + get() = + loadDefinitionsFromTemplates( + templatesProvider.templateClassNames.toList(), templatesProvider.templateClasspath, + ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + getEnvironment { + templatesProvider.environment + } + }, + templatesProvider.additionalResolverClasspath + ).asSequence() } \ No newline at end of file diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesCache.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptsCompilationConfigurationCache.kt similarity index 83% rename from idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesCache.kt rename to idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptsCompilationConfigurationCache.kt index f9fe9741de5..579895a76c0 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesCache.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptsCompilationConfigurationCache.kt @@ -29,15 +29,17 @@ import com.intellij.util.containers.SLRUMap import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import org.jetbrains.kotlin.idea.core.util.EDT +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.write import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty import kotlin.reflect.KProperty0 import kotlin.reflect.jvm.isAccessible -import kotlin.script.experimental.dependencies.ScriptDependencies +import kotlin.script.experimental.api.valueOrNull -class ScriptDependenciesCache(private val project: Project) { +class ScriptsCompilationConfigurationCache(private val project: Project) { companion object { const val MAX_SCRIPTS_CACHED = 50 @@ -45,10 +47,10 @@ class ScriptDependenciesCache(private val project: Project) { private val cacheLock = ReentrantReadWriteLock() - private val scriptDependenciesCache = SLRUCacheWithLock() + private val scriptDependenciesCache = SLRUCacheWithLock() private val scriptsModificationStampsCache = SLRUCacheWithLock() - operator fun get(virtualFile: VirtualFile): ScriptDependencies? = scriptDependenciesCache.get(virtualFile) + operator fun get(virtualFile: VirtualFile): ScriptCompilationConfigurationResult? = scriptDependenciesCache.get(virtualFile) fun shouldRunDependenciesUpdate(file: VirtualFile): Boolean { return scriptsModificationStampsCache.replace(file, file.modificationStamp) != file.modificationStamp @@ -58,10 +60,10 @@ class ScriptDependenciesCache(private val project: Project) { fun scriptDependenciesClassFilesScope(file: VirtualFile): GlobalSearchScope { return scriptsDependenciesClasspathScopeCache.getOrPut(file) { - val dependencies = scriptDependenciesCache.get(file) ?: return@getOrPut GlobalSearchScope.EMPTY_SCOPE - val roots = dependencies.classpath + val compilationConfiguration = scriptDependenciesCache.get(file)?.valueOrNull() ?: return@getOrPut GlobalSearchScope.EMPTY_SCOPE + val roots = compilationConfiguration.dependenciesClassPath - val sdk = ScriptDependenciesManager.getScriptSdk(dependencies) + val sdk = ScriptDependenciesManager.getScriptSdk(compilationConfiguration) @Suppress("FoldInitializerAndIfToElvis") if (sdk == null) { @@ -86,7 +88,8 @@ class ScriptDependenciesCache(private val project: Project) { .filter { it != ScriptDependenciesManager.getProjectSdk(project) } .flatMap { it.rootProvider.getFiles(OrderRootType.CLASSES).toList() } - val scriptDependenciesClasspath = scriptDependenciesCache.getAll().flatMap { it.value.classpath }.distinct() + val scriptDependenciesClasspath = scriptDependenciesCache.getAll() + .flatMap { it.value.valueOrNull()?.dependenciesClassPath ?: emptyList() }.distinct() sdkFiles + ScriptDependenciesManager.toVfsRoots(scriptDependenciesClasspath) } @@ -96,7 +99,8 @@ class ScriptDependenciesCache(private val project: Project) { .filter { it != ScriptDependenciesManager.getProjectSdk(project) } .flatMap { it.rootProvider.getFiles(OrderRootType.SOURCES).toList() } - val scriptDependenciesSources = scriptDependenciesCache.getAll().flatMap { it.value.sources }.distinct() + val scriptDependenciesSources = scriptDependenciesCache.getAll() + .flatMap { it.value.valueOrNull()?.dependenciesSources ?: emptyList() }.distinct() sdkSources + ScriptDependenciesManager.toVfsRoots(scriptDependenciesSources) } @@ -140,11 +144,10 @@ class ScriptDependenciesCache(private val project: Project) { } } - fun hasNotCachedRoots(scriptDependencies: ScriptDependencies): Boolean { - return !allSdks.contains(ScriptDependenciesManager.getScriptSdk(scriptDependencies)) || - !allDependenciesClassFiles.containsAll(ScriptDependenciesManager.toVfsRoots(scriptDependencies.classpath)) || - !allDependenciesSources.containsAll(ScriptDependenciesManager.toVfsRoots(scriptDependencies.sources)) - + fun hasNotCachedRoots(compilationConfiguration: ScriptCompilationConfigurationWrapper): Boolean { + return !allSdks.contains(ScriptDependenciesManager.getScriptSdk(compilationConfiguration)) || + !allDependenciesClassFiles.containsAll(ScriptDependenciesManager.toVfsRoots(compilationConfiguration.dependenciesClassPath)) || + !allDependenciesSources.containsAll(ScriptDependenciesManager.toVfsRoots(compilationConfiguration.dependenciesSources)) } fun clear() { @@ -155,7 +158,7 @@ class ScriptDependenciesCache(private val project: Project) { onChange(keys) } - fun save(virtualFile: VirtualFile, new: ScriptDependencies): Boolean { + fun save(virtualFile: VirtualFile, new: ScriptCompilationConfigurationResult): Boolean { val old = scriptDependenciesCache.replace(virtualFile, new) val changed = new != old if (changed) { @@ -207,8 +210,8 @@ private class SLRUCacheWithLock { private val lock = ReentrantReadWriteLock() val cache = SLRUMap( - ScriptDependenciesCache.MAX_SCRIPTS_CACHED, - ScriptDependenciesCache.MAX_SCRIPTS_CACHED + ScriptsCompilationConfigurationCache.MAX_SCRIPTS_CACHED, + ScriptsCompilationConfigurationCache.MAX_SCRIPTS_CACHED ) fun get(value: VirtualFile): T? = lock.write { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptsCompilationConfigurationUpdater.kt similarity index 89% rename from idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt rename to idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptsCompilationConfigurationUpdater.kt index 6498939bb03..e3bffac148c 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptDependenciesUpdater.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/ScriptsCompilationConfigurationUpdater.kt @@ -41,14 +41,15 @@ import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.NotNullableUserDataProperty import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.resolve.LegacyResolverWrapper +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult import kotlin.script.experimental.dependencies.AsyncDependenciesResolver -import kotlin.script.experimental.dependencies.ScriptDependencies -class ScriptDependenciesUpdater( +class ScriptsCompilationConfigurationUpdater( private val project: Project, - private val cache: ScriptDependenciesCache + private val cache: ScriptsCompilationConfigurationCache ) { private val scriptsQueue = Alarm(Alarm.ThreadToUse.SWING_THREAD, project) private val scriptChangesListenerDelay = 1400 @@ -64,13 +65,13 @@ class ScriptDependenciesUpdater( listenForChangesInScripts() } - fun getCurrentDependencies(file: VirtualFile): ScriptDependencies { + fun getCurrentCompilationConfiguration(file: VirtualFile): ScriptCompilationConfigurationResult? { cache[file]?.let { return it } updateDependencies(file) makeRootsChangeIfNeeded() - return cache[file] ?: ScriptDependencies.Empty + return cache[file] } fun updateDependenciesIfNeeded(files: List): Boolean { @@ -174,15 +175,15 @@ class ScriptDependenciesUpdater( return cache[file] != null || file.scriptDependencies != null } - fun isAsyncDependencyResolver(scriptDef: KotlinScriptDefinition): Boolean { - val dependencyResolver = scriptDef.dependencyResolver - return dependencyResolver is AsyncDependenciesResolver || dependencyResolver is LegacyResolverWrapper - } + fun isAsyncDependencyResolver(scriptDef: ScriptDefinition): Boolean = + scriptDef.asLegacyOrNull()?.dependencyResolver?.let { + it is AsyncDependenciesResolver || it is LegacyResolverWrapper + } ?: false companion object { @JvmStatic - fun getInstance(project: Project): ScriptDependenciesUpdater = - ServiceManager.getService(project, ScriptDependenciesUpdater::class.java) + fun getInstance(project: Project): ScriptsCompilationConfigurationUpdater = + ServiceManager.getService(project, ScriptsCompilationConfigurationUpdater::class.java) fun areDependenciesCached(file: KtFile): Boolean { return getInstance(file.project).areDependenciesCached(file.virtualFile) diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/AsyncScriptDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/AsyncScriptDependenciesLoader.kt index 44c5b575a9c..4893ef1d213 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/AsyncScriptDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/AsyncScriptDependenciesLoader.kt @@ -5,7 +5,6 @@ package org.jetbrains.kotlin.idea.core.script.dependencies -import com.intellij.openapi.application.runReadAction import com.intellij.openapi.progress.EmptyProgressIndicator import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.Task @@ -13,18 +12,16 @@ import com.intellij.openapi.progress.util.BackgroundTaskUtil import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import kotlinx.coroutines.Runnable -import kotlinx.coroutines.runBlocking -import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesUpdater +import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition -import org.jetbrains.kotlin.scripting.resolve.asResolveFailure +import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource +import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration import java.util.concurrent.ConcurrentLinkedQueue import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.write -import kotlin.script.experimental.dependencies.AsyncDependenciesResolver -import kotlin.script.experimental.dependencies.DependenciesResolver +// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore class AsyncScriptDependenciesLoader internal constructor(project: Project) : ScriptDependenciesLoader(project) { private val lock = ReentrantReadWriteLock() @@ -33,7 +30,7 @@ class AsyncScriptDependenciesLoader internal constructor(project: Project) : Scr override fun isApplicable(file: VirtualFile): Boolean { val scriptDefinition = file.findScriptDefinition(project) ?: return false - return ScriptDependenciesUpdater.getInstance(project).isAsyncDependencyResolver(scriptDefinition) + return ScriptsCompilationConfigurationUpdater.getInstance(project).isAsyncDependencyResolver(scriptDefinition) } override fun loadDependencies(file: VirtualFile) { @@ -73,35 +70,15 @@ class AsyncScriptDependenciesLoader internal constructor(project: Project) : Scr } private fun runDependenciesUpdate(file: VirtualFile) { - val scriptDef = runReadAction { file.findScriptDefinition(project) } ?: return + val scriptDef = file.findScriptDefinition(project) ?: return debug(file) { "start async dependencies loading" } - // runBlocking is using there to avoid loading dependencies asynchronously - // because it leads to starting more than one gradle daemon in case of resolving dependencies in build.gradle.kts - // It is more efficient to use one hot daemon consistently than multiple daemon in parallel - val result = runBlocking { - try { - resolveDependencies(file, scriptDef) - } catch (t: Throwable) { - t.asResolveFailure(scriptDef) - } - } + + val result = refineScriptCompilationConfiguration(VirtualFileScriptSource(file), scriptDef, project) debug(file) { "finish async dependencies loading" } - processResult(result, file, scriptDef) - } - - private suspend fun resolveDependencies(file: VirtualFile, scriptDef: KotlinScriptDefinition): DependenciesResolver.ResolveResult { - val dependenciesResolver = scriptDef.dependencyResolver - val scriptContents = contentLoader.getScriptContents(scriptDef, file) - val environment = contentLoader.getEnvironment(scriptDef) - return if (dependenciesResolver is AsyncDependenciesResolver) { - dependenciesResolver.resolveAsync(scriptContents, environment) - } else { - // TODO: shouldn't come here after dropping legacy resolvers, refactor accordingly - dependenciesResolver.resolve(scriptContents, environment) - } + processRefinedConfiguration(result, file) } private inner class LoaderBackgroundTask { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt index edecea6e352..726e0e0cd78 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/FromFileAttributeScriptDependenciesLoader.kt @@ -7,8 +7,13 @@ package org.jetbrains.kotlin.idea.core.script.dependencies import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.idea.core.script.scriptCompilationConfiguration import org.jetbrains.kotlin.idea.core.script.scriptDependencies +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper +import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource +import kotlin.script.experimental.api.asSuccess +// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore class FromFileAttributeScriptDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) { override fun isApplicable(file: VirtualFile): Boolean { @@ -16,9 +21,17 @@ class FromFileAttributeScriptDependenciesLoader(project: Project) : ScriptDepend } override fun loadDependencies(file: VirtualFile) { - val deserializedDependencies = file.scriptDependencies ?: return - debug(file) { "dependencies from fileAttributes = $deserializedDependencies" } - saveToCache(file, deserializedDependencies) + file.scriptCompilationConfiguration?.let { + ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(VirtualFileScriptSource(file), it).apply { + debug(file) { "refined configuration from fileAttributes = $it" } + } + } ?: file.scriptDependencies?.let { + ScriptCompilationConfigurationWrapper.FromLegacy(VirtualFileScriptSource(file), it).apply { + debug(file) { "dependencies from fileAttributes = $it" } + } + }?.let { + saveToCache(file, it.asSuccess(), skipSaveToAttributes = true) + } } override fun shouldShowNotification(): Boolean = false diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/KotlinScriptResolveScopeProvider.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/KotlinScriptResolveScopeProvider.kt index b6336f6de28..a808ac6c0a5 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/KotlinScriptResolveScopeProvider.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/KotlinScriptResolveScopeProvider.kt @@ -22,6 +22,7 @@ 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.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate @@ -36,11 +37,13 @@ class KotlinScriptResolveScopeProvider : ResolveScopeProvider() { // 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 - scriptDefinition.template == Any::class -> null - scriptDefinition is StandardIdeScriptDefinition -> null - scriptDefinition is KotlinScriptDefinitionFromAnnotatedTemplate -> // TODO: should include the file itself + // This is a workaround for completion in scripts and REPL to provide module dependencies + scriptDefinition.baseClassType.fromClass == Any::class -> null + scriptDefinition.asLegacyOrNull() != null -> null + scriptDefinition is ScriptDefinition.FromConfigurations || scriptDefinition.asLegacyOrNull() != null -> { + // TODO: should include the file itself ScriptDependenciesManager.getInstance(project).getAllScriptsDependenciesClassFilesScope() + } else -> null } } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/OutsiderFileDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/OutsiderFileDependenciesLoader.kt index 1a06df0c247..1af075a99ee 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/OutsiderFileDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/OutsiderFileDependenciesLoader.kt @@ -18,9 +18,8 @@ class OutsiderFileDependenciesLoader(project: Project) : ScriptDependenciesLoade override fun loadDependencies(file: VirtualFile) { val fileOrigin = OutsidersPsiFileSupportUtils.getOutsiderFileOrigin(project, file) ?: return - val originDependencies = ScriptDependenciesManager.getInstance(project).getScriptDependencies(fileOrigin) - debug(file) { "dependencies for outsider file = $originDependencies" } - saveToCache(file, originDependencies) + val compilationConfiguration = ScriptDependenciesManager.getInstance(project).getRefinedCompilationConfiguration(fileOrigin) ?: return + saveToCache(file, compilationConfiguration) } override fun shouldShowNotification(): Boolean = false diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/ScriptDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/ScriptDependenciesLoader.kt index ca8dd16190f..293a1af3eb2 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/ScriptDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/ScriptDependenciesLoader.kt @@ -15,13 +15,14 @@ import com.intellij.openapi.util.EmptyRunnable import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.idea.core.script.* import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition -import org.jetbrains.kotlin.scripting.resolve.ScriptContentLoader +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationWrapper import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink -import org.jetbrains.kotlin.scripting.resolve.adjustByDefinition -import kotlin.script.experimental.dependencies.DependenciesResolver -import kotlin.script.experimental.dependencies.ScriptDependencies +import kotlin.script.experimental.api.ResultWithDiagnostics +import kotlin.script.experimental.api.valueOrNull +import kotlin.script.experimental.jvm.compat.mapToLegacyReports +// TODO: rename and provide alias for compatibility - this is not only about dependencies anymore abstract class ScriptDependenciesLoader(protected val project: Project) { abstract fun isApplicable(file: VirtualFile): Boolean @@ -31,40 +32,40 @@ abstract class ScriptDependenciesLoader(protected val project: Project) { protected var shouldNotifyRootsChanged = false - protected val contentLoader = ScriptContentLoader(project) - protected val cache: ScriptDependenciesCache = ServiceManager.getService(project, ScriptDependenciesCache::class.java) + protected val cache: ScriptsCompilationConfigurationCache = ServiceManager.getService(project, ScriptsCompilationConfigurationCache::class.java) private val reporter: ScriptReportSink = ServiceManager.getService(project, ScriptReportSink::class.java) - protected fun processResult(result: DependenciesResolver.ResolveResult, file: VirtualFile, scriptDef: KotlinScriptDefinition) { - debug(file) { "dependencies from ${this.javaClass} received = $result" } + protected fun processRefinedConfiguration(result: ScriptCompilationConfigurationResult, file: VirtualFile) { + debug(file) { "refined script compilation configuration from ${this.javaClass} received = $result" } - if (cache[file] == null) { - saveDependencies(result, file, scriptDef) - attachReportsIfChanged(result, file, scriptDef) + val oldResult = cache[file] + + if (oldResult == null) { + save(result, file) + attachReportsIfChanged(result, file) return } - val newDependencies = result.dependencies?.adjustByDefinition(scriptDef) - if (cache[file] != newDependencies) { + if (oldResult != result) { if (shouldShowNotification() && !ApplicationManager.getApplication().isUnitTestMode) { debug(file) { - "dependencies changed, notification was shown: old = ${cache[file]}, new = $newDependencies" + "dependencies changed, notification is shown: old = $oldResult, new = $result" } file.addScriptDependenciesNotificationPanel(result, project) { - saveDependencies(it, file, scriptDef) - attachReportsIfChanged(it, file, scriptDef) + save(it, file) + attachReportsIfChanged(result, file) submitMakeRootsChange() } } else { debug(file) { - "dependencies changed, new dependencies were applied automatically: old = ${cache[file]}, new = $newDependencies" + "dependencies changed, new dependencies are applied automatically: old = $oldResult, new = $result" } - saveDependencies(result, file, scriptDef) - attachReportsIfChanged(result, file, scriptDef) + save(result, file) + attachReportsIfChanged(result, file) } } else { - attachReportsIfChanged(result, file, scriptDef) + attachReportsIfChanged(result, file) if (shouldShowNotification()) { file.removeScriptDependenciesNotificationPanel(project) @@ -72,28 +73,36 @@ abstract class ScriptDependenciesLoader(protected val project: Project) { } } - private fun attachReportsIfChanged(result: DependenciesResolver.ResolveResult, file: VirtualFile, scriptDef: KotlinScriptDefinition) { + private fun attachReportsIfChanged(result: ResultWithDiagnostics<*>, file: VirtualFile) { if (file.getUserData(IdeScriptReportSink.Reports) != result.reports.takeIf { it.isNotEmpty() }) { - reporter.attachReports(file, result.reports) + reporter.attachReports(file, result.reports.mapToLegacyReports()) } } - private fun saveDependencies(result: DependenciesResolver.ResolveResult, file: VirtualFile, scriptDef: KotlinScriptDefinition) { + private fun save(compilationConfigurationResult: ScriptCompilationConfigurationResult?, file: VirtualFile) { if (shouldShowNotification()) { file.removeScriptDependenciesNotificationPanel(project) } - - val dependencies = result.dependencies?.adjustByDefinition(scriptDef) ?: return - saveToCache(file, dependencies) + if (compilationConfigurationResult != null) { + saveToCache(file, compilationConfigurationResult) + } } - protected fun saveToCache(file: VirtualFile, dependencies: ScriptDependencies) { - val rootsChanged = cache.hasNotCachedRoots(dependencies) - if (cache.save(file, dependencies)) { + protected fun saveToCache( + file: VirtualFile, compilationConfigurationResult: ScriptCompilationConfigurationResult, skipSaveToAttributes: Boolean = false + ) { + val rootsChanged = compilationConfigurationResult.valueOrNull()?.let { cache.hasNotCachedRoots(it) } ?: false + if (cache.save(file, compilationConfigurationResult) + && !skipSaveToAttributes + && compilationConfigurationResult is ResultWithDiagnostics.Success + ) { debug(file) { - "dependencies were saved to file attributes: dependencies = $dependencies" + "refined configuration is saved to file attributes: $compilationConfigurationResult" } - file.scriptDependencies = dependencies + if (compilationConfigurationResult.value is ScriptCompilationConfigurationWrapper.FromLegacy) + file.scriptDependencies = compilationConfigurationResult.value.legacyDependencies + else + file.scriptCompilationConfiguration = compilationConfigurationResult.value.configuration } if (rootsChanged) { @@ -101,6 +110,7 @@ abstract class ScriptDependenciesLoader(protected val project: Project) { } } + open fun notifyRootsChanged(): Boolean = submitMakeRootsChange() protected fun submitMakeRootsChange(): Boolean { diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/SyncScriptDependenciesLoader.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/SyncScriptDependenciesLoader.kt index 473d0794eeb..eba6d376fd3 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/SyncScriptDependenciesLoader.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/dependencies/SyncScriptDependenciesLoader.kt @@ -7,21 +7,23 @@ package org.jetbrains.kotlin.idea.core.script.dependencies import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile -import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesUpdater +import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition +import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource +import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration -class SyncScriptDependenciesLoader internal constructor(project: Project) : ScriptDependenciesLoader(project) { +class SyncScriptDependenciesLoader(project: Project) : ScriptDependenciesLoader(project) { override fun isApplicable(file: VirtualFile): Boolean { val scriptDefinition = file.findScriptDefinition(project) ?: return false - return !ScriptDependenciesUpdater.getInstance(project).isAsyncDependencyResolver(scriptDefinition) + return !ScriptsCompilationConfigurationUpdater.getInstance(project).isAsyncDependencyResolver(scriptDefinition) } override fun loadDependencies(file: VirtualFile) { val scriptDef = file.findScriptDefinition(project) ?: return debug(file) { "start sync dependencies loading" } - val result = contentLoader.loadContentsAndResolveDependencies(scriptDef, file) + val result = refineScriptCompilationConfiguration(VirtualFileScriptSource(file), scriptDef, project) debug(file) { "finish sync dependencies loading" } - processResult(result, file, scriptDef) + processRefinedConfiguration(result, file) } override fun shouldShowNotification(): Boolean = false diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/settings/KotlinScriptingSettings.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/settings/KotlinScriptingSettings.kt index 6445fea1547..c626bad157a 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/settings/KotlinScriptingSettings.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/script/settings/KotlinScriptingSettings.kt @@ -14,7 +14,7 @@ import com.intellij.util.addOptionTag import com.intellij.util.attribute import com.intellij.util.getAttributeBooleanValue import org.jdom.Element -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition @State( name = "KotlinScriptingSettings", @@ -72,22 +72,22 @@ class KotlinScriptingSettings : PersistentStateComponent { } } - fun setOrder(scriptDefinition: KotlinScriptDefinition, order: Int) { + fun setOrder(scriptDefinition: ScriptDefinition, order: Int) { scriptDefinitions[scriptDefinition.toKey()] = scriptDefinitions[scriptDefinition.toKey()]?.copy(order = order) ?: KotlinScriptDefinitionValue(order) } - fun setEnabled(scriptDefinition: KotlinScriptDefinition, isEnabled: Boolean) { + fun setEnabled(scriptDefinition: ScriptDefinition, isEnabled: Boolean) { scriptDefinitions[scriptDefinition.toKey()] = scriptDefinitions[scriptDefinition.toKey()]?.copy(isEnabled = isEnabled) ?: KotlinScriptDefinitionValue(scriptDefinitions.size, isEnabled) } - fun getScriptDefinitionOrder(scriptDefinition: KotlinScriptDefinition): Int { + fun getScriptDefinitionOrder(scriptDefinition: ScriptDefinition): Int { return scriptDefinitions[scriptDefinition.toKey()]?.order ?: Integer.MAX_VALUE } - fun isScriptDefinitionEnabled(scriptDefinition: KotlinScriptDefinition): Boolean { + fun isScriptDefinitionEnabled(scriptDefinition: ScriptDefinition): Boolean { return scriptDefinitions[scriptDefinition.toKey()]?.isEnabled ?: true } @@ -99,8 +99,8 @@ class KotlinScriptingSettings : PersistentStateComponent { getAttributeValue(KotlinScriptDefinitionKey::className.name) ) - private fun KotlinScriptDefinition.toKey() = - KotlinScriptDefinitionKey(this.name, this::class.qualifiedName ?: "unknown") + private fun ScriptDefinition.toKey() = + KotlinScriptDefinitionKey(this.name, this.definitionId) private fun Element.addScriptDefinitionContentElement(definition: KotlinScriptDefinitionKey, settings: KotlinScriptDefinitionValue) { addElement(SCRIPT_DEFINITION_TAG).apply { diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/core/script/GradleScriptTemplateProvider.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/core/script/GradleScriptTemplateProvider.kt index d0477ec69e3..bccfea3879e 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/core/script/GradleScriptTemplateProvider.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/core/script/GradleScriptTemplateProvider.kt @@ -27,8 +27,9 @@ import com.intellij.util.EnvironmentUtil import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID import org.jetbrains.kotlin.lexer.KotlinLexer import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinitionAdapterFromNewAPIBase +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.getEnvironment import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate import org.jetbrains.plugins.gradle.config.GradleSettingsListenerAdapter import org.jetbrains.plugins.gradle.service.execution.GradleExecutionHelper @@ -38,10 +39,8 @@ import org.jetbrains.plugins.gradle.settings.GradleProjectSettings import org.jetbrains.plugins.gradle.settings.GradleSettingsListener import org.jetbrains.plugins.gradle.util.GradleConstants import java.io.File -import java.lang.IllegalStateException import java.util.* import java.util.concurrent.atomic.AtomicBoolean -import kotlin.collections.LinkedHashSet import kotlin.reflect.KClass import kotlin.script.dependencies.Environment import kotlin.script.dependencies.ScriptContents @@ -54,7 +53,7 @@ import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.experimental.location.ScriptExpectedLocation import kotlin.script.templates.standard.ScriptTemplateWithArgs -class GradleScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionContributor { +class GradleScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionSourceAsContributor { override val id: String = "Gradle Kotlin DSL" private val failedToLoad = AtomicBoolean(false) @@ -86,55 +85,52 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD initializeScriptModificationListener(project) } - override fun getDefinitions(): List { - return loadDefinitions() - } - // NOTE: control flow here depends on suppressing exceptions from loadGradleTemplates calls // TODO: possibly combine exceptions from every loadGradleTemplates call, be mindful of KT-19276 - private fun loadDefinitions(): List { - val kotlinDslDependencySelector = Regex("^gradle-(?:kotlin-dsl|core).*\\.jar\$") - val kotlinDslAdditionalResolverCp = ::kotlinStdlibAndCompiler + override val definitions: Sequence + get() { + val kotlinDslDependencySelector = Regex("^gradle-(?:kotlin-dsl|core).*\\.jar\$") + val kotlinDslAdditionalResolverCp = ::kotlinStdlibAndCompiler - failedToLoad.set(false) + failedToLoad.set(false) - val kotlinDslTemplates = LinkedHashSet() + val kotlinDslTemplates = LinkedHashSet() - loadGradleTemplates( - templateClass = "org.gradle.kotlin.dsl.KotlinInitScript", - dependencySelector = kotlinDslDependencySelector, - additionalResolverClasspath = kotlinDslAdditionalResolverCp + loadGradleTemplates( + templateClass = "org.gradle.kotlin.dsl.KotlinInitScript", + dependencySelector = kotlinDslDependencySelector, + additionalResolverClasspath = kotlinDslAdditionalResolverCp - ).let { kotlinDslTemplates.addAll(it) } + ).let { kotlinDslTemplates.addAll(it) } - loadGradleTemplates( - templateClass = "org.gradle.kotlin.dsl.KotlinSettingsScript", - dependencySelector = kotlinDslDependencySelector, - additionalResolverClasspath = kotlinDslAdditionalResolverCp + loadGradleTemplates( + templateClass = "org.gradle.kotlin.dsl.KotlinSettingsScript", + dependencySelector = kotlinDslDependencySelector, + additionalResolverClasspath = kotlinDslAdditionalResolverCp - ).let { kotlinDslTemplates.addAll(it) } + ).let { kotlinDslTemplates.addAll(it) } - // KotlinBuildScript should be last because it has wide scriptFilePattern - loadGradleTemplates( - templateClass = "org.gradle.kotlin.dsl.KotlinBuildScript", - dependencySelector = kotlinDslDependencySelector, - additionalResolverClasspath = kotlinDslAdditionalResolverCp - ).let { kotlinDslTemplates.addAll(it) } + // KotlinBuildScript should be last because it has wide scriptFilePattern + loadGradleTemplates( + templateClass = "org.gradle.kotlin.dsl.KotlinBuildScript", + dependencySelector = kotlinDslDependencySelector, + additionalResolverClasspath = kotlinDslAdditionalResolverCp + ).let { kotlinDslTemplates.addAll(it) } - if (kotlinDslTemplates.isNotEmpty()) { - return kotlinDslTemplates.toList() + if (kotlinDslTemplates.isNotEmpty()) { + return kotlinDslTemplates.asSequence() + } + + val default = tryToLoadOldBuildScriptDefinition() + if (default.isNotEmpty()) { + return default.asSequence() + } + + return sequenceOf(ErrorGradleScriptDefinition()) } - val default = tryToLoadOldBuildScriptDefinition() - if (default.isNotEmpty()) { - return default - } - - return listOf(ErrorGradleScriptDefinition()) - } - - private fun tryToLoadOldBuildScriptDefinition(): List { + private fun tryToLoadOldBuildScriptDefinition(): List { failedToLoad.set(false) return loadGradleTemplates( @@ -154,7 +150,7 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD private fun loadGradleTemplates( templateClass: String, dependencySelector: Regex, additionalResolverClasspath: (gradleLibDir: File) -> List - ): List = try { + ): List = try { doLoadGradleTemplates(templateClass, dependencySelector, additionalResolverClasspath) } catch (t: Throwable) { // TODO: review exception handling @@ -170,11 +166,11 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD private fun doLoadGradleTemplates( templateClass: String, dependencySelector: Regex, additionalResolverClasspath: (gradleLibDir: File) -> List - ): List { - fun createEnvironment( + ): List { + fun createHostConfiguration( gradleExeSettings: GradleExecutionSettings, projectSettings: GradleProjectSettings - ): Environment { + ): ScriptingHostConfiguration { val gradleJvmOptions = gradleExeSettings.daemonVmOptions?.let { vmOptions -> CommandLineTokenizer(vmOptions).toList() .mapNotNull { it?.let { it as? String } } @@ -182,7 +178,8 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD .distinct() } ?: emptyList() - return mapOf( + + val environment = mapOf( "gradleHome" to gradleExeSettings.gradleHome?.let(::File), "gradleJavaHome" to gradleExeSettings.javaHome, @@ -194,6 +191,9 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD "getScriptSectionTokens" to ::topLevelSectionCodeTextTokens ) + return ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + getEnvironment { environment } + } } val gradleSettings = ExternalSystemApiUtil.getSettings(project, GradleConstants.SYSTEM_ID) @@ -221,14 +221,17 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD return loadDefinitionsFromTemplates( listOf(templateClass), templateClasspath, - createEnvironment(gradleExeSettings, projectSettings), + createHostConfiguration(gradleExeSettings, projectSettings), additionalResolverClasspath(gradleLibDir) ).map { - // Expand scope for old gradle script definition - if (it is KotlinScriptDefinitionFromAnnotatedTemplate && !it.scriptExpectedLocations.contains(ScriptExpectedLocation.Project)) - GradleKotlinScriptDefinitionFromAnnotatedTemplate(it) - else - it + it.asLegacyOrNull()?.let { legacyDef -> + @Suppress("DEPRECATION") + if (legacyDef.scriptExpectedLocations.contains(ScriptExpectedLocation.Project)) null + else { + // Expand scope for old gradle script definition + ScriptDefinition.FromLegacy(it.hostConfiguration, GradleKotlinScriptDefinitionFromAnnotatedTemplate(legacyDef)) + } + } ?: it } } @@ -242,23 +245,28 @@ class GradleScriptDefinitionsContributor(private val project: Project) : ScriptD ScriptDefinitionsManager.getInstance(project).reloadDefinitionsBy(this) } - private class ErrorGradleScriptDefinition(message: String? = null) : KotlinScriptDefinitionAdapterFromNewAPIBase() { - companion object { - private const val KOTLIN_DSL_SCRIPT_EXTENSION = "gradle.kts" + // TODO: refactor - minimize + private class ErrorGradleScriptDefinition(message: String? = null) : + ScriptDefinition.FromLegacy(ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration), LegacyDefinition(message)) { + + private class LegacyDefinition(message: String?) : KotlinScriptDefinitionAdapterFromNewAPIBase() { + companion object { + private const val KOTLIN_DSL_SCRIPT_EXTENSION = "gradle.kts" + } + + override val name: String = "Default Kotlin Gradle Script" + override val fileExtension: String = KOTLIN_DSL_SCRIPT_EXTENSION + + override val scriptCompilationConfiguration: ScriptCompilationConfiguration = ScriptCompilationConfiguration.Default + override val hostConfiguration: ScriptingHostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) + override val baseClass: KClass<*> = ScriptTemplateWithArgs::class + + override val dependencyResolver: DependenciesResolver = ErrorScriptDependenciesResolver(message) + + override fun toString(): String = "ErrorGradleScriptDefinition" + override fun equals(other: Any?): Boolean = other is ErrorGradleScriptDefinition + override fun hashCode(): Int = name.hashCode() } - - override val name: String = "Default Kotlin Gradle Script" - override val fileExtension: String = KOTLIN_DSL_SCRIPT_EXTENSION - - override val scriptCompilationConfiguration: ScriptCompilationConfiguration = ScriptCompilationConfiguration.Default - override val hostConfiguration: ScriptingHostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) - override val baseClass: KClass<*> = ScriptTemplateWithArgs::class - - override val dependencyResolver: DependenciesResolver = ErrorScriptDependenciesResolver(message) - - override fun toString(): String = "ErrorGradleScriptDefinition" - override fun equals(other: Any?): Boolean = other is ErrorGradleScriptDefinition - override fun hashCode(): Int = name.hashCode() } private class ErrorScriptDependenciesResolver(private val message: String? = null) : DependenciesResolver { @@ -280,6 +288,7 @@ internal class GradleSyncState { class GradleKotlinScriptDefinitionFromAnnotatedTemplate( base: KotlinScriptDefinitionFromAnnotatedTemplate ) : KotlinScriptDefinitionFromAnnotatedTemplate(base.template, base.environment, base.templateClasspath) { + @Suppress("DEPRECATION") override val scriptExpectedLocations: List get() = listOf(ScriptExpectedLocation.Project) } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtCompilingExecutor.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtCompilingExecutor.kt index a44e212973f..c5b0e39a94a 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtCompilingExecutor.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/scratch/compile/KtCompilingExecutor.kt @@ -48,6 +48,7 @@ import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext import org.jetbrains.kotlin.resolve.AnalyzingUtils import java.io.File +import kotlin.script.experimental.api.valueOrNull class KtCompilingExecutor(file: ScratchFile) : ScratchExecutor(file) { companion object { @@ -186,8 +187,10 @@ class KtCompilingExecutor(file: ScratchFile) : ScratchExecutor(file) { javaParameters.classPath.addAll(JavaParametersBuilder.getModuleDependencies(module)) } - val scriptDependencies = ScriptDependenciesManager.getInstance(originalFile.project).getScriptDependencies(originalFile.virtualFile) - javaParameters.classPath.addAll(scriptDependencies.classpath.map { it.absolutePath }) + ScriptDependenciesManager.getInstance(originalFile.project) + .getRefinedCompilationConfiguration(originalFile.virtualFile)?.valueOrNull()?.let { + javaParameters.classPath.addAll(it.dependenciesClassPath.map { f -> f.absolutePath }) + } return javaParameters.toCommandLine() } diff --git a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt index d3a70c64068..d9c03a7636f 100644 --- a/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt +++ b/idea/idea-repl/src/org/jetbrains/kotlin/console/KotlinConsoleRunner.kt @@ -62,6 +62,7 @@ import org.jetbrains.kotlin.idea.caches.project.productionSourceInfo import org.jetbrains.kotlin.idea.caches.project.testSourceInfo import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor +import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionSourceAsContributor 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 @@ -72,11 +73,13 @@ import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil import org.jetbrains.kotlin.resolve.repl.ReplState import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import java.awt.Color import java.awt.Font import java.util.concurrent.CountDownLatch import java.util.concurrent.TimeUnit import kotlin.properties.Delegates +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration private val KOTLIN_SHELL_EXECUTE_ACTION_ID = "KotlinShellExecute" @@ -305,20 +308,21 @@ class KotlinConsoleRunner( } } -class ConsoleScriptDefinitionContributor: ScriptDefinitionContributor { - private val definitions = ContainerUtil.newConcurrentSet() +class ConsoleScriptDefinitionContributor: ScriptDefinitionSourceAsContributor { + + val definitionsSet = ContainerUtil.newConcurrentSet() + + override val definitions: Sequence + get() = definitionsSet.asSequence() override val id: String = "IDEA Console" - override fun getDefinitions(): List { - return definitions.toList() - } - + // TODO: rewrite to ScriptDefinition fun registerDefinition(definition: KotlinScriptDefinition) { - definitions.add(definition) + definitionsSet.add(ScriptDefinition.FromLegacy(defaultJvmScriptingHostConfiguration, definition)) } fun unregisterDefinition(definition: KotlinScriptDefinition) { - definitions.remove(definition) + definitionsSet.removeIf { it.asLegacyOrNull() == definition } } } \ No newline at end of file diff --git a/idea/resources/META-INF/plugin-common.xml b/idea/resources/META-INF/plugin-common.xml index 629ed9e5309..87c1b290969 100644 --- a/idea/resources/META-INF/plugin-common.xml +++ b/idea/resources/META-INF/plugin-common.xml @@ -284,11 +284,11 @@ - + - + diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt index 884dd105f5a..af911a0939d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/UnusedSymbolInspection.kt @@ -43,7 +43,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.core.isInheritable -import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesUpdater +import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdater import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.findUsages.KotlinFindUsagesHandlerFactory import org.jetbrains.kotlin.idea.findUsages.handlers.KotlinFindClassUsagesHandler @@ -127,7 +127,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() { val usedScripts = findScriptsWithUsages(declaration) if (usedScripts.isNotEmpty()) { - if (ScriptDependenciesUpdater.getInstance(declaration.project).updateDependenciesIfNeeded(usedScripts)) { + if (ScriptsCompilationConfigurationUpdater.getInstance(declaration.project).updateDependenciesIfNeeded(usedScripts)) { return TOO_MANY_OCCURRENCES } } diff --git a/idea/src/org/jetbrains/kotlin/idea/script/AsyncScriptDefinitionsContributor.kt b/idea/src/org/jetbrains/kotlin/idea/script/AsyncScriptDefinitionsContributor.kt index 142c6316a27..eaf965a82b5 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/AsyncScriptDefinitionsContributor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/script/AsyncScriptDefinitionsContributor.kt @@ -9,29 +9,30 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.progress.ProgressIndicator import com.intellij.openapi.progress.Task import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor +import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionSourceAsContributor import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.read import kotlin.concurrent.write -abstract class AsyncScriptDefinitionsContributor(protected val project: Project) : ScriptDefinitionContributor { +abstract class AsyncScriptDefinitionsContributor(protected val project: Project) : ScriptDefinitionSourceAsContributor { abstract val progressMessage: String - override fun isReady(): Boolean = definitions != null + override fun isReady(): Boolean = _definitions != null - override fun getDefinitions(): List { - definitionsLock.read { - if (definitions != null) { - return definitions!! + override val definitions: Sequence + get() { + definitionsLock.read { + if (_definitions != null) { + return _definitions!!.asSequence() + } } - } - forceStartUpdate = false - asyncRunUpdateScriptTemplates() - return emptyList() - } + forceStartUpdate = false + asyncRunUpdateScriptTemplates() + return emptySequence() + } protected fun asyncRunUpdateScriptTemplates() { val backgroundTask = inProgressLock.write { @@ -50,9 +51,9 @@ abstract class AsyncScriptDefinitionsContributor(protected val project: Project) } } - protected abstract fun loadScriptDefinitions(previous: List?): List + protected abstract fun loadScriptDefinitions(previous: List?): List - private var definitions: List? = null + private var _definitions: List? = null private val definitionsLock = ReentrantReadWriteLock() protected var forceStartUpdate = false @@ -77,10 +78,10 @@ abstract class AsyncScriptDefinitionsContributor(protected val project: Project) val wasRunning = definitionsLock.isWriteLocked val needReload = definitionsLock.write { - if (wasRunning && !forceStartUpdate && definitions != null) return@write false - val newDefinitions = loadScriptDefinitions(definitions) - if (newDefinitions != definitions) { - definitions = newDefinitions + if (wasRunning && !forceStartUpdate && _definitions != null) return@write false + val newDefinitions = loadScriptDefinitions(_definitions) + if (newDefinitions != _definitions) { + _definitions = newDefinitions return@write true } return@write false diff --git a/idea/src/org/jetbrains/kotlin/idea/script/BridgeDefinitionsContributor.kt b/idea/src/org/jetbrains/kotlin/idea/script/BridgeDefinitionsContributor.kt index 37375a6cb2d..c22f19df649 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/BridgeDefinitionsContributor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/script/BridgeDefinitionsContributor.kt @@ -11,35 +11,38 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.cli.common.messages.CompilerMessageLocation import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity import org.jetbrains.kotlin.cli.common.messages.MessageCollector -import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor +import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionSourceAsContributor import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource import org.jetbrains.kotlin.scripting.definitions.reporter import kotlin.script.experimental.intellij.ScriptDefinitionsProvider +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration -class BridgeScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionContributor { +class BridgeScriptDefinitionsContributor(private val project: Project) : ScriptDefinitionSourceAsContributor { override val id: String = "BridgeScriptDefinitionsContributor" - override fun getDefinitions(): List { - val extensions = Extensions.getArea(project).getExtensionPoint(ScriptDefinitionsProvider.EP_NAME).extensions - val messageCollector = LoggingMessageCollector() - return extensions.flatMap { provider -> - val explicitClasses = provider.getDefinitionClasses().toList() - val classPath = provider.getDefinitionsClassPath().toList() - val explicitDefinitions = - if (explicitClasses.isNotEmpty()) loadDefinitionsFromTemplates(explicitClasses, classPath) - else emptyList() - val discoveredDefinitions = - if (provider.useDiscovery()) emptySequence() - else ScriptDefinitionsFromClasspathDiscoverySource( - classPath, - emptyMap(), - messageCollector.reporter - ).definitions - explicitDefinitions + discoveredDefinitions + override val definitions: Sequence + get() { + val extensions = Extensions.getArea(project).getExtensionPoint(ScriptDefinitionsProvider.EP_NAME).extensions + val messageCollector = LoggingMessageCollector() + return extensions.asSequence().flatMap { provider -> + val explicitClasses = provider.getDefinitionClasses().toList() + val classPath = provider.getDefinitionsClassPath().toList() + val hostConfiguration = defaultJvmScriptingHostConfiguration + val explicitDefinitions = + if (explicitClasses.isEmpty()) emptySequence() + else loadDefinitionsFromTemplates(explicitClasses, classPath, hostConfiguration).asSequence() + val discoveredDefinitions = + if (provider.useDiscovery()) emptySequence() + else ScriptDefinitionsFromClasspathDiscoverySource( + classPath, + hostConfiguration, + messageCollector.reporter + ).definitions + explicitDefinitions + discoveredDefinitions + } } - } } private class LoggingMessageCollector : MessageCollector { diff --git a/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptDefinitionsModel.kt b/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptDefinitionsModel.kt index e1765717dfb..4d150907524 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptDefinitionsModel.kt +++ b/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptDefinitionsModel.kt @@ -12,11 +12,10 @@ import com.intellij.util.ui.ListTableModel import org.jetbrains.kotlin.idea.core.script.StandardIdeScriptDefinition import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings import org.jetbrains.kotlin.parsing.KotlinParserDefinition -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinitionAdapterFromNewAPIBase +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate -class KotlinScriptDefinitionsModelDescriptor(val definition: KotlinScriptDefinition, var isEnabled: Boolean) +class KotlinScriptDefinitionsModelDescriptor(val definition: ScriptDefinition, var isEnabled: Boolean) class KotlinScriptDefinitionsModel private constructor(definitions: MutableList) : ListTableModel( @@ -30,7 +29,7 @@ class KotlinScriptDefinitionsModel private constructor(definitions: MutableList< ) { fun getDefinitions() = items.map { it.definition } - fun setDefinitions(definitions: List, settings: KotlinScriptingSettings) { + fun setDefinitions(definitions: List, settings: KotlinScriptingSettings) { items = definitions.mapTo(arrayListOf()) { KotlinScriptDefinitionsModelDescriptor(it, settings.isScriptDefinitionEnabled(it)) } } @@ -41,12 +40,9 @@ class KotlinScriptDefinitionsModel private constructor(definitions: MutableList< private class ScriptDefinitionPattern : ColumnInfo("Pattern/Extension") { override fun valueOf(item: KotlinScriptDefinitionsModelDescriptor): String { val definition = item.definition - return when (definition) { - is KotlinScriptDefinitionFromAnnotatedTemplate -> definition.scriptFilePattern.pattern - is KotlinScriptDefinitionAdapterFromNewAPIBase -> definition.fileExtension - is StandardIdeScriptDefinition -> KotlinParserDefinition.STD_SCRIPT_EXT - else -> "" - } + return definition.asLegacyOrNull()?.scriptFilePattern?.pattern + ?: definition.asLegacyOrNull()?.let { KotlinParserDefinition.STD_SCRIPT_EXT } + ?: definition.fileExtension } } @@ -58,11 +54,12 @@ class KotlinScriptDefinitionsModel private constructor(definitions: MutableList< override fun getEditor(item: KotlinScriptDefinitionsModelDescriptor?) = BooleanTableCellEditor() override fun getRenderer(item: KotlinScriptDefinitionsModelDescriptor?) = BooleanTableCellRenderer() - override fun isCellEditable(item: KotlinScriptDefinitionsModelDescriptor) = item.definition !is StandardIdeScriptDefinition + override fun isCellEditable(item: KotlinScriptDefinitionsModelDescriptor) = + item.definition.asLegacyOrNull() == null } companion object { - fun createModel(definitions: List, settings: KotlinScriptingSettings): KotlinScriptDefinitionsModel { + fun createModel(definitions: List, settings: KotlinScriptingSettings): KotlinScriptDefinitionsModel { return KotlinScriptDefinitionsModel(definitions.mapTo(arrayListOf()) { KotlinScriptDefinitionsModelDescriptor( it, diff --git a/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptingSettingsConfigurable.java b/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptingSettingsConfigurable.java index ff1717ad833..742000555a1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptingSettingsConfigurable.java +++ b/idea/src/org/jetbrains/kotlin/idea/script/configuration/KotlinScriptingSettingsConfigurable.java @@ -14,7 +14,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager; import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings; -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition; +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition; import javax.swing.*; import java.awt.*; @@ -64,7 +64,7 @@ public class KotlinScriptingSettingsConfigurable implements SearchableConfigurab if (isScriptDefinitionsChanged()) { for (KotlinScriptDefinitionsModelDescriptor item : model.getItems()) { - KotlinScriptDefinition definition = item.getDefinition(); + ScriptDefinition definition = item.getDefinition(); settings.setOrder(definition, model.getItems().indexOf(item)); settings.setEnabled(definition, item.isEnabled()); } diff --git a/idea/src/org/jetbrains/kotlin/idea/script/configuration/MultipleScriptDefinitionsChecker.kt b/idea/src/org/jetbrains/kotlin/idea/script/configuration/MultipleScriptDefinitionsChecker.kt index 436fe25ba94..0fa943b1269 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/configuration/MultipleScriptDefinitionsChecker.kt +++ b/idea/src/org/jetbrains/kotlin/idea/script/configuration/MultipleScriptDefinitionsChecker.kt @@ -23,8 +23,7 @@ import org.jetbrains.kotlin.idea.core.script.StandardIdeScriptDefinition import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings import org.jetbrains.kotlin.parsing.KotlinParserDefinition import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinitionAdapterFromNewAPIBase +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate class MultipleScriptDefinitionsChecker(private val project: Project) : EditorNotifications.Provider() { @@ -42,8 +41,7 @@ class MultipleScriptDefinitionsChecker(private val project: Project) : EditorNot val allApplicableDefinitions = ScriptDefinitionsManager.getInstance(project) .getAllDefinitions() .filter { - it !is StandardIdeScriptDefinition && - it.isScript(ktFile.name) && + it.asLegacyOrNull() == null && it.isScript(ktFile.name) && KotlinScriptingSettings.getInstance(project).isScriptDefinitionEnabled(it) } .toList() @@ -56,10 +54,10 @@ class MultipleScriptDefinitionsChecker(private val project: Project) : EditorNot ) } - private fun areDefinitionsForGradleKts(allApplicableDefinitions: List): Boolean { + private fun areDefinitionsForGradleKts(allApplicableDefinitions: List): Boolean { if (allApplicableDefinitions.size == 2) { - return (allApplicableDefinitions[0] as? KotlinScriptDefinitionFromAnnotatedTemplate)?.scriptFilePattern?.pattern == "^(settings|.+\\.settings)\\.gradle\\.kts\$" - && (allApplicableDefinitions[1] as? KotlinScriptDefinitionFromAnnotatedTemplate)?.scriptFilePattern?.pattern == ".*\\.gradle\\.kts" + return allApplicableDefinitions[0].asLegacyOrNull()?.scriptFilePattern?.pattern == "^(settings|.+\\.settings)\\.gradle\\.kts\$" + && allApplicableDefinitions[1].asLegacyOrNull()?.scriptFilePattern?.pattern == ".*\\.gradle\\.kts" } return false } @@ -67,25 +65,18 @@ class MultipleScriptDefinitionsChecker(private val project: Project) : EditorNot companion object { private val KEY = Key.create("MultipleScriptDefinitionsChecker") - private fun createNotification(psiFile: KtFile, defs: List): EditorNotificationPanel { + private fun createNotification(psiFile: KtFile, defs: List): EditorNotificationPanel { return EditorNotificationPanel().apply { setText("Multiple script definitions are applicable for this script. ${defs.first().name} is used") createComponentActionLabel("Show all") { val list = JBPopupFactory.getInstance().createListPopup( - object : BaseListPopupStep(null, defs) { - override fun getTextFor(value: KotlinScriptDefinition): String { - return when (value) { - is KotlinScriptDefinitionFromAnnotatedTemplate -> { - value.name + " (${value.scriptFilePattern})" - } - is KotlinScriptDefinitionAdapterFromNewAPIBase -> { - value.name + " (${value.fileExtension})" - } - is StandardIdeScriptDefinition -> { - value.name + " (${KotlinParserDefinition.STD_SCRIPT_EXT})" - } - else -> value.name - } + object : BaseListPopupStep(null, defs) { + override fun getTextFor(value: ScriptDefinition): String { + return value.asLegacyOrNull()?.let { + it.name + " (${it.scriptFilePattern})" + } ?: value.asLegacyOrNull()?.let { + it.name + " (${KotlinParserDefinition.STD_SCRIPT_EXT})" + } ?: value.name + " (${value.fileExtension})" } } ) diff --git a/idea/src/org/jetbrains/kotlin/idea/script/scriptTemplatesFromCompilerSettings.kt b/idea/src/org/jetbrains/kotlin/idea/script/scriptTemplatesFromCompilerSettings.kt index 2202e4178ac..9d2fb72dcc4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/scriptTemplatesFromCompilerSettings.kt +++ b/idea/src/org/jetbrains/kotlin/idea/script/scriptTemplatesFromCompilerSettings.kt @@ -20,16 +20,19 @@ import com.intellij.openapi.project.Project import org.jetbrains.kotlin.config.CompilerSettings import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettingsListener -import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor +import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionSourceAsContributor import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.getEnvironment import java.io.File +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration class ScriptTemplatesFromCompilerSettingsProvider( private val project: Project, private val compilerSettings: KotlinCompilerSettings -) : ScriptDefinitionContributor { +) : ScriptDefinitionSourceAsContributor { init { project.messageBus.connect().subscribe(KotlinCompilerSettingsListener.TOPIC, object : KotlinCompilerSettingsListener { @@ -41,17 +44,22 @@ class ScriptTemplatesFromCompilerSettingsProvider( }) } - override fun getDefinitions(): List { - val kotlinSettings = compilerSettings.settings - return if (kotlinSettings.scriptTemplates.isBlank()) emptyList() - else 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 definitions: Sequence + get() { + val kotlinSettings = compilerSettings.settings + return if (kotlinSettings.scriptTemplates.isBlank()) emptySequence() + else loadDefinitionsFromTemplates( + templateClassNames = kotlinSettings.scriptTemplates.split(',', ' '), + templateClasspath = kotlinSettings.scriptTemplatesClasspath.split(File.pathSeparator).map(::File), + baseHostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + getEnvironment { + mapOf( + "projectRoot" to (project.basePath ?: project.baseDir.canonicalPath)?.let(::File) + ) + } + } + ).asSequence() + } override val id: String = "KotlinCompilerScriptTemplatesSettings" } diff --git a/idea/src/org/jetbrains/kotlin/idea/script/scriptsTemplatesFromDependencies.kt b/idea/src/org/jetbrains/kotlin/idea/script/scriptsTemplatesFromDependencies.kt index 7c35ab240f7..0ee7fbb439d 100644 --- a/idea/src/org/jetbrains/kotlin/idea/script/scriptsTemplatesFromDependencies.kt +++ b/idea/src/org/jetbrains/kotlin/idea/script/scriptsTemplatesFromDependencies.kt @@ -14,12 +14,12 @@ import com.intellij.openapi.vfs.JarFileSystem import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates import org.jetbrains.kotlin.idea.util.projectStructure.allModules -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition -import org.jetbrains.kotlin.scripting.definitions.SCRIPT_DEFINITION_MARKERS_EXTENSION_WITH_DOT -import org.jetbrains.kotlin.scripting.definitions.SCRIPT_DEFINITION_MARKERS_PATH +import org.jetbrains.kotlin.scripting.definitions.* import java.io.File import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.write +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration class ScriptTemplatesFromDependenciesProvider(project: Project) : AsyncScriptDefinitionsContributor(project) { @@ -41,7 +41,7 @@ class ScriptTemplatesFromDependenciesProvider(project: Project) : AsyncScriptDef override val id = "ScriptTemplatesFromDependenciesProvider" override val progressMessage = "Kotlin: scanning dependencies for script definitions..." - override fun loadScriptDefinitions(previous: List?): List { + override fun loadScriptDefinitions(previous: List?): List { val templatesCopy = templatesLock.write { val newTemplates = scriptDefinitionsFromDependencies(project) if (newTemplates != templates) { @@ -51,12 +51,17 @@ class ScriptTemplatesFromDependenciesProvider(project: Project) : AsyncScriptDef return@write null } if (templatesCopy != null) { + val hostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + getEnvironment { + mapOf( + "projectRoot" to (project.basePath ?: project.baseDir.canonicalPath)?.let(::File) + ) + } + } return loadDefinitionsFromTemplates( templateClassNames = templatesCopy.templates, templateClasspath = templatesCopy.classpath, - environment = mapOf( - "projectRoot" to (project.basePath ?: project.baseDir.canonicalPath)?.let(::File) - ) + baseHostConfiguration = hostConfiguration ) } return previous ?: emptyList() diff --git a/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt b/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt index dd50d92fe1b..cba13e052dd 100644 --- a/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/util/ImportInsertHelperImpl.kt @@ -49,6 +49,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.findVariable import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.utils.addIfNotNull import java.util.* +import kotlin.script.experimental.api.valueOrNull class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper() { @@ -64,8 +65,9 @@ class ImportInsertHelperImpl(private val project: Project) : ImportInsertHelper( val allDefaultImports = platform.findAnalyzerServices.getDefaultImports(languageVersionSettings, includeLowPriorityImports = true) val scriptExtraImports = contextFile.takeIf { it.isScript() }?.let { ktFile -> - val scriptDependencies = ScriptDependenciesProvider.getInstance(ktFile.project)?.getScriptDependencies(ktFile.originalFile) - scriptDependencies?.imports?.map { ImportPath.fromString(it) } + val scriptDependencies = + ScriptDependenciesProvider.getInstance(ktFile.project)?.getScriptConfigurationResult(ktFile.originalFile)?.valueOrNull() + scriptDependencies?.defaultImports?.map { ImportPath.fromString(it) } }.orEmpty() return importPath.isImported(allDefaultImports + scriptExtraImports, platform.findAnalyzerServices.excludedImports) diff --git a/idea/testData/script/definition/highlighting/throwingResolver/script.kts b/idea/testData/script/definition/highlighting/throwingResolver/script.kts index 4b09b3b0a64..d993c29740a 100644 --- a/idea/testData/script/definition/highlighting/throwingResolver/script.kts +++ b/idea/testData/script/definition/highlighting/throwingResolver/script.kts @@ -1,4 +1,3 @@ - + val s = 3 val g = 4 \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureProjectByChangingFileTest.java b/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureProjectByChangingFileTest.java index baf5e9e5ded..43c81bb775b 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureProjectByChangingFileTest.java +++ b/idea/tests/org/jetbrains/kotlin/idea/configuration/AbstractConfigureProjectByChangingFileTest.java @@ -22,7 +22,7 @@ import com.intellij.testFramework.LightProjectDescriptor; import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesUpdaterKt; +import org.jetbrains.kotlin.idea.core.script.ScriptsCompilationConfigurationUpdaterKt; import org.jetbrains.kotlin.test.InTextDirectivesUtils; import org.jetbrains.kotlin.test.KotlinTestUtils; import org.jetbrains.plugins.groovy.GroovyFileType; @@ -42,12 +42,12 @@ public abstract class AbstractConfigureProjectByChangingFileTest FileTypeManager.getInstance().associateExtension(GroovyFileType.GROOVY_FILE_TYPE, "gradle") ); - ScriptDependenciesUpdaterKt.setScriptDependenciesUpdaterDisabled(ApplicationManager.getApplication(), true); + ScriptsCompilationConfigurationUpdaterKt.setScriptDependenciesUpdaterDisabled(ApplicationManager.getApplication(), true); } @Override protected void tearDown() throws Exception { - ScriptDependenciesUpdaterKt.setScriptDependenciesUpdaterDisabled(ApplicationManager.getApplication(), false); + ScriptsCompilationConfigurationUpdaterKt.setScriptDependenciesUpdaterDisabled(ApplicationManager.getApplication(), false); moduleInfoFile = null; super.tearDown(); } diff --git a/idea/tests/org/jetbrains/kotlin/idea/script/TestScriptDefinitionContributors.kt b/idea/tests/org/jetbrains/kotlin/idea/script/TestScriptDefinitionContributors.kt index 2414ab60ce0..5d3b00e7403 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/script/TestScriptDefinitionContributors.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/script/TestScriptDefinitionContributors.kt @@ -5,32 +5,41 @@ package org.jetbrains.kotlin.idea.script -import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor +import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionSourceAsContributor import org.jetbrains.kotlin.idea.core.script.loadDefinitionsFromTemplates +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.getEnvironment import java.io.File import kotlin.script.dependencies.Environment +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration -class CustomScriptTemplateProvider( - val environment: Environment -) : ScriptDefinitionContributor { +class CustomScriptTemplateProvider(val environment: Environment) : ScriptDefinitionSourceAsContributor { + override val id = "Test" - override fun getDefinitions() = loadDefinitionsFromTemplates( + override val definitions: Sequence + get() = loadDefinitionsFromTemplates( templateClassNames = environment["template-classes-names"] as List, templateClasspath = listOfNotNull(environment["template-classes"] as? File), - environment = environment - ) + baseHostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + getEnvironment { environment } + } + ).asSequence() } -class FromTextTemplateProvider( - val environment: Map -) : ScriptDefinitionContributor { +class FromTextTemplateProvider(val environment: Map) : ScriptDefinitionSourceAsContributor { + override val id = "Test" - override fun getDefinitions() = loadDefinitionsFromTemplates( + + override val definitions: Sequence + get() = loadDefinitionsFromTemplates( templateClassNames = listOf("org.jetbrains.kotlin.idea.script.Template"), templateClasspath = listOfNotNull(environment["template-classes"] as? File), - environment = environment - ) + baseHostConfiguration = ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + getEnvironment { environment } + } + ).asSequence() } \ No newline at end of file diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt index 692d804cd94..fe3de5bd9b3 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/errorHandling.kt @@ -76,6 +76,10 @@ sealed class ResultWithDiagnostics { ) : ResultWithDiagnostics() { constructor(vararg reports: ScriptDiagnostic) : this(reports.asList()) } + + override fun equals(other: Any?): Boolean = this === other || (other is ResultWithDiagnostics<*> && this.reports == other.reports) + + override fun hashCode(): Int = reports.hashCode() } /** @@ -162,9 +166,10 @@ fun makeFailureResult(message: String, path: String? = null, location: SourceCod fun Throwable.asDiagnostics( customMessage: String? = null, path: String? = null, - location: SourceCode.Location? = null + location: SourceCode.Location? = null, + severity: ScriptDiagnostic.Severity = ScriptDiagnostic.Severity.ERROR ): ScriptDiagnostic = - ScriptDiagnostic(customMessage ?: message ?: "$this", ScriptDiagnostic.Severity.ERROR, path, location, this) + ScriptDiagnostic(customMessage ?: message ?: "$this", severity, path, location, this) /** * Converts the receiver String to error diagnostic report with optional [path] and [location] @@ -175,7 +180,7 @@ fun String.asErrorDiagnostics(path: String? = null, location: SourceCode.Locatio /** * Extracts the result value from the receiver wrapper or null if receiver represents a Failure */ -fun ResultWithDiagnostics.resultOrNull(): R? = when (this) { +fun ResultWithDiagnostics.valueOrNull(): R? = when (this) { is ResultWithDiagnostics.Success -> value else -> null } @@ -183,7 +188,7 @@ fun ResultWithDiagnostics.resultOrNull(): R? = when (this) { /** * Extracts the result value from the receiver wrapper or run non-returning lambda if receiver represents a Failure */ -inline fun ResultWithDiagnostics.resultOr(body: (ResultWithDiagnostics.Failure) -> Nothing): R = when (this) { +inline fun ResultWithDiagnostics.valueOr(body: (ResultWithDiagnostics.Failure) -> Nothing): R = when (this) { is ResultWithDiagnostics.Success -> value is ResultWithDiagnostics.Failure -> body(this) } diff --git a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt index 4d9ee725835..e8900ea1130 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/api/scriptCompilation.kt @@ -59,7 +59,7 @@ val ScriptCompilationConfigurationKeys.fileExtension by PropertiesCollection.key /** * The superclass for target script class */ -val ScriptCompilationConfigurationKeys.baseClass by PropertiesCollection.key() // script base class +val ScriptCompilationConfigurationKeys.baseClass by PropertiesCollection.key(KotlinType(Any::class)) // script base class /** * The list of classes that will be used as implicit receivers in the script body, as if the whole body is wrapped with "with" calls: diff --git a/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt b/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt index 76764c49256..8d0e100aa46 100644 --- a/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt +++ b/libraries/scripting/common/src/kotlin/script/experimental/host/scriptHostUtil.kt @@ -41,10 +41,14 @@ fun getMergedScriptText(script: SourceCode, configuration: ScriptCompilationConf } } +abstract class FileBasedScriptSource() : ExternalSourceCode { + abstract val file: File +} + /** * The implementation of the SourceCode for a script located in a file */ -open class FileScriptSource(val file: File, private val preloadedText: String? = null) : ExternalSourceCode { +open class FileScriptSource(override val file: File, private val preloadedText: String? = null) : FileBasedScriptSource() { override val externalLocation: URL get() = file.toURI().toURL() override val text: String by lazy { preloadedText ?: file.readText() } override val name: String? get() = file.name diff --git a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ScriptingHostTest.kt b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ScriptingHostTest.kt index da10b5baf0f..8c317085574 100644 --- a/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ScriptingHostTest.kt +++ b/libraries/scripting/jvm-host-test/test/kotlin/script/experimental/jvmhost/test/ScriptingHostTest.kt @@ -18,13 +18,13 @@ import java.util.jar.JarFile import kotlin.reflect.KClass import kotlin.script.experimental.api.* import kotlin.script.experimental.host.BasicScriptingHost -import kotlin.script.experimental.host.FileScriptSource +import kotlin.script.experimental.host.FileBasedScriptSource import kotlin.script.experimental.host.toScriptSource import kotlin.script.experimental.jvm.BasicJvmScriptEvaluator import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration +import kotlin.script.experimental.jvm.impl.KJvmCompiledScript import kotlin.script.experimental.jvmhost.* import kotlin.script.experimental.jvmhost.impl.CompiledScriptClassLoader -import kotlin.script.experimental.jvm.impl.KJvmCompiledScript import kotlin.script.templates.standard.SimpleScriptTemplate class ScriptingHostTest : TestCase() { @@ -86,7 +86,7 @@ class ScriptingHostTest : TestCase() { val scriptName = "SavedRunnableScript" val compiledScript = runBlocking { compiler("println(\"$greeting\")".toScriptSource(name = "$scriptName.kts"), compilationConfiguration).throwOnFailure() - .resultOrNull()!! + .valueOrNull()!! } val saver = BasicJvmScriptJarGenerator(outJar) runBlocking { @@ -353,8 +353,8 @@ class ScriptingHostTest : TestCase() { val compiledScriptClassRes = runBlocking { compiledScript!!.getClass(null) } val cachedScriptClassRes = runBlocking { cachedScript!!.getClass(null) } - val compiledScriptClass = compiledScriptClassRes.resultOrNull() - val cachedScriptClass = cachedScriptClassRes.resultOrNull() + val compiledScriptClass = compiledScriptClassRes.valueOrNull() + val cachedScriptClass = cachedScriptClassRes.valueOrNull() Assert.assertEquals(compiledScriptClass!!.qualifiedName, cachedScriptClass!!.qualifiedName) Assert.assertEquals(compiledScriptClass!!.supertypes, cachedScriptClass!!.supertypes) @@ -380,7 +380,7 @@ class ScriptingHostTest : TestCase() { val res = compiler(script.toScriptSource(), scriptCompilationConfiguration).throwOnFailure() (res as ResultWithDiagnostics.Success>).value } - val compiledScriptClass = runBlocking { compiledScript.getClass(null).throwOnFailure().resultOrNull()!! as KClass<*> } + val compiledScriptClass = runBlocking { compiledScript.getClass(null).throwOnFailure().valueOrNull()!! as KClass<*> } val classLoader = compiledScriptClass.java.classLoader Assert.assertTrue(classLoader is CompiledScriptClassLoader) @@ -463,7 +463,7 @@ private fun ScriptCompilationConfiguration.Builder.makeSimpleConfigurationWithTe refineConfiguration { beforeCompiling { ctx -> val importedScript = File(ScriptingHostTest.TEST_DATA_DIR, "importTest/helloWithVal.kts") - if ((ctx.script as? FileScriptSource)?.file?.canonicalFile == importedScript.canonicalFile) { + if ((ctx.script as? FileBasedScriptSource)?.file?.canonicalFile == importedScript.canonicalFile) { ctx.compilationConfiguration } else { ScriptCompilationConfiguration(ctx.compilationConfiguration) { diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompilerImpl.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompilerImpl.kt index d49e5d9cb6b..577fd5e5292 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompilerImpl.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmCompilerImpl.kt @@ -33,7 +33,7 @@ class KJvmCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : KJvm val mainKtFile = getScriptKtFile(script, context.baseScriptCompilationConfiguration, context.environment.project, messageCollector) - .resultOr { return it } + .valueOr { return it } context.scriptCompilationState.configureFor(script, context.baseScriptCompilationConfiguration) diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmReplCompilerImpl.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmReplCompilerImpl.kt index e873597d64e..6bb7bf9d79f 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmReplCompilerImpl.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/KJvmReplCompilerImpl.kt @@ -31,7 +31,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : override fun createReplCompilationState(scriptCompilationConfiguration: ScriptCompilationConfiguration): JvmReplCompilerState.Compilation { val context = withMessageCollectorAndDisposable(disposeOnSuccess = false) { messageCollector, disposable -> createSharedCompilationContext(scriptCompilationConfiguration, hostConfiguration, messageCollector, disposable).asSuccess() - }.resultOr { throw IllegalStateException("Unable to initialize repl compiler:\n ${it.reports.joinToString("\n ")}") } + }.valueOr { throw IllegalStateException("Unable to initialize repl compiler:\n ${it.reports.joinToString("\n ")}") } return ReplCompilationState(context) } @@ -42,7 +42,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : ): ResultWithDiagnostics = withMessageCollector(script) { messageCollector -> val ktFile = getScriptKtFile(script, scriptCompilationConfiguration, project, messageCollector) - .resultOr { return it } + .valueOr { return it } val errorHolder = object : MessageCollectorBasedReporter { override val messageCollector = messageCollector } @@ -80,7 +80,7 @@ class KJvmReplCompilerImpl(val hostConfiguration: ScriptingHostConfiguration) : val snippetKtFile = getScriptKtFile(snippet, context.baseScriptCompilationConfiguration, context.environment.project, messageCollector) - .resultOr { return it } + .valueOr { return it } val (sourceFiles, sourceDependencies) = collectRefinedSourcesAndUpdateEnvironment(context, snippetKtFile, messageCollector) diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/compilationContext.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/compilationContext.kt index b41b913e261..f65be6d13d3 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/compilationContext.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/compilationContext.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.dependencies.ScriptsCompilationDependencies import org.jetbrains.kotlin.scripting.dependencies.collectScriptsCompilationDependencies import kotlin.script.experimental.api.ScriptCompilationConfiguration @@ -88,10 +89,13 @@ internal fun createInitialConfigurations( kotlinCompilerConfiguration.add( ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, - BridgeScriptDefinition( - scriptCompilationConfiguration, + ScriptDefinition.FromLegacy( hostConfiguration, - scriptCompilationState + BridgeScriptDefinition( + scriptCompilationConfiguration, + hostConfiguration, + scriptCompilationState + ) ) ) diff --git a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/jvmCompilationUtil.kt b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/jvmCompilationUtil.kt index ae555fd0d8a..aeb8822ae85 100644 --- a/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/jvmCompilationUtil.kt +++ b/libraries/scripting/jvm-host/src/kotlin/script/experimental/jvmhost/impl/jvmCompilationUtil.kt @@ -8,11 +8,8 @@ package kotlin.script.experimental.jvmhost.impl import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer -import com.intellij.openapi.util.text.StringUtil -import com.intellij.openapi.vfs.CharsetToolkit import com.intellij.psi.PsiFileFactory import com.intellij.psi.impl.PsiFileFactoryImpl -import com.intellij.testFramework.LightVirtualFile import org.jetbrains.kotlin.cli.common.environment.setIdeaIoUseFallback import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.idea.KotlinLanguage @@ -20,24 +17,15 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.renderer.DescriptorRenderer import org.jetbrains.kotlin.scripting.dependencies.ScriptsCompilationDependencies +import org.jetbrains.kotlin.scripting.resolve.ScriptLightVirtualFile import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.util.* import kotlin.script.experimental.api.* +import kotlin.script.experimental.host.FileBasedScriptSource import kotlin.script.experimental.host.FileScriptSource import kotlin.script.experimental.host.getMergedScriptText import kotlin.script.experimental.jvm.impl.KJvmCompiledScript -internal class ScriptLightVirtualFile(name: String, private val _path: String?, text: String) : - LightVirtualFile(name, KotlinLanguage.INSTANCE, StringUtil.convertLineSeparators(text)) { - - init { - charset = CharsetToolkit.UTF8_CHARSET - } - - override fun getPath(): String = _path ?: super.getPath() - override fun getCanonicalPath(): String? = path -} - internal fun makeCompiledModule(generationState: GenerationState) = KJvmCompiledModuleInMemory( generationState.factory.asList() @@ -98,7 +86,7 @@ internal fun getScriptKtFile( val scriptText = getMergedScriptText(script, scriptCompilationConfiguration) val virtualFile = ScriptLightVirtualFile( script.scriptFileName(script, scriptCompilationConfiguration), - (script as? FileScriptSource)?.file?.path, + (script as? FileBasedScriptSource)?.file?.path, scriptText ) val ktFile = psiFileFactory.trySetupPsiForFile(virtualFile, KotlinLanguage.INSTANCE, true, false) as KtFile? diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/BasicJvmScriptEvaluator.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/BasicJvmScriptEvaluator.kt index ed86b05011e..f74fbfc2bdb 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/BasicJvmScriptEvaluator.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/BasicJvmScriptEvaluator.kt @@ -40,7 +40,7 @@ open class BasicJvmScriptEvaluator : ScriptEvaluator { ?.onFailure { return@invoke ResultWithDiagnostics.Failure(it.reports) } - ?.resultOrNull() + ?.valueOrNull() ?: configuration val instance = diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/compat/diagnosticsUtil.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/compat/diagnosticsUtil.kt index d4e034d793b..3398356fd85 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/compat/diagnosticsUtil.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/compat/diagnosticsUtil.kt @@ -48,8 +48,13 @@ fun mapLegacyScriptPosition(pos: ScriptReport.Position?): SourceCode.Location? = } fun mapToLegacyScriptReportPosition(pos: SourceCode.Location?): ScriptReport.Position? = - pos?.let { ScriptReport.Position(pos.start.line, pos.start.col) } + pos?.let { ScriptReport.Position(pos.start.line, pos.start.col, pos.end?.line, pos.end?.col) } -fun Iterable.mapToDiagnostics(): List = map { (message, severity, position: ScriptReport.Position?) -> +fun Iterable.mapToDiagnostics(): List = map { (message, severity, position) -> ScriptDiagnostic(message, mapLegacyDiagnosticSeverity(severity), null, mapLegacyScriptPosition(position)) } + +fun Iterable.mapToLegacyReports(): List = map { (message, severity, _, location, exception) -> + val reportMessage = if (exception == null) message else "$message ($exception)" + ScriptReport(reportMessage, mapToLegacyScriptReportSeverity(severity), mapToLegacyScriptReportPosition(location)) +} diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt index a939151cc39..1956ab9fc1d 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/impl/BridgeDependenciesResolver.kt @@ -41,16 +41,6 @@ class BridgeDependenciesResolver( ) ) - val defaultImports = scriptCompilationConfiguration[ScriptCompilationConfiguration.defaultImports]?.toList() ?: emptyList() - - fun ScriptCompilationConfiguration.toDependencies(classpath: List): ScriptDependencies = - ScriptDependencies( - classpath = classpath, - sources = this[ScriptCompilationConfiguration.ide.dependenciesSources].toClassPathOrEmpty(), - imports = defaultImports, - scripts = this[ScriptCompilationConfiguration.importScripts].toFilesOrEmpty() - ) - val script = getScriptSource(scriptContents) ?: scriptContents.toScriptSource() val refineResults = scriptCompilationConfiguration.refineWith( @@ -92,6 +82,17 @@ class BridgeDependenciesResolver( } } +fun ScriptCompilationConfiguration.toDependencies(classpath: List): ScriptDependencies { + val defaultImports = this[ScriptCompilationConfiguration.defaultImports]?.toList() ?: emptyList() + + return ScriptDependencies( + classpath = classpath, + sources = this[ScriptCompilationConfiguration.ide.dependenciesSources].toClassPathOrEmpty(), + imports = defaultImports, + scripts = this[ScriptCompilationConfiguration.importScripts].toFilesOrEmpty() + ) +} + internal fun List.mapScriptReportsToDiagnostics() = map { ScriptReport(it.message, mapToLegacyScriptReportSeverity(it.severity), mapToLegacyScriptReportPosition(it.location)) } @@ -101,7 +102,7 @@ internal fun ScriptContents.toScriptSource(): SourceCode = when { else -> throw IllegalArgumentException("Unable to convert script contents $this into script source") } -internal fun List?.toClassPathOrEmpty() = this?.flatMap { (it as JvmDependency).classpath } ?: emptyList() +fun List?.toClassPathOrEmpty() = this?.flatMap { (it as JvmDependency).classpath } ?: emptyList() internal fun List?.toFilesOrEmpty() = this?.map { val externalSource = it as? ExternalSourceCode diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt index f59d06f01b1..b69c1153284 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptEvaluation.kt @@ -9,6 +9,7 @@ package kotlin.script.experimental.jvm import kotlin.reflect.KClass import kotlin.script.experimental.api.* +import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.util.PropertiesCollection interface JvmScriptEvaluationConfigurationKeys @@ -21,7 +22,10 @@ open class JvmScriptEvaluationConfigurationBuilder : PropertiesCollection.Builde /** * The base classloader to use for script classes loading */ -val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key(Thread.currentThread().contextClassLoader) +val JvmScriptEvaluationConfigurationKeys.baseClassLoader by PropertiesCollection.key { + get(ScriptEvaluationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jvm.baseClassLoader) + ?: Thread.currentThread().contextClassLoader +} /** * Load script dependencies before evaluation, true by default diff --git a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptingHostConfiguration.kt b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptingHostConfiguration.kt index d6b02d8ad96..ff2c546a37e 100644 --- a/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptingHostConfiguration.kt +++ b/libraries/scripting/jvm/src/kotlin/script/experimental/jvm/jvmScriptingHostConfiguration.kt @@ -11,6 +11,7 @@ import java.net.URLClassLoader import kotlin.reflect.KClass import kotlin.script.experimental.api.* import kotlin.script.experimental.host.* +import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty import kotlin.script.experimental.util.PropertiesCollection interface JvmScriptingHostConfigurationKeys @@ -25,6 +26,12 @@ val JvmScriptingHostConfigurationKeys.javaHome by PropertiesCollection.key val JvmScriptingHostConfigurationKeys.jdkHome by PropertiesCollection.key() +val JvmScriptingHostConfigurationKeys.baseClassLoader by PropertiesCollection.key { + get(ScriptingHostConfiguration.configurationDependencies)?.let { + URLClassLoader(it.toClassPathOrEmpty().map { f -> f.toURI().toURL() }.toTypedArray()) + } +} + @Suppress("unused") val ScriptingHostConfigurationKeys.jvm get() = JvmScriptingHostConfigurationBuilder() @@ -49,15 +56,17 @@ class JvmGetScriptingClass : GetScriptingClass, Serializable { @Transient private var baseClassLoader: ClassLoader? = null + override fun invoke(classType: KotlinType, contextClass: KClass<*>, hostConfiguration: ScriptingHostConfiguration): KClass<*> = + invoke(classType, contextClass.java.classLoader, hostConfiguration) + @Synchronized - override fun invoke(classType: KotlinType, contextClass: KClass<*>, hostConfiguration: ScriptingHostConfiguration): KClass<*> { + operator fun invoke(classType: KotlinType, contextClassLoader: ClassLoader?, hostConfiguration: ScriptingHostConfiguration): KClass<*> { // checking if class already loaded in the same context - val contextClassloader = contextClass.java.classLoader val fromClass = classType.fromClass if (fromClass != null) { if (fromClass.java.classLoader == null) return fromClass // root classloader - val actualClassLoadersChain = generateSequence(contextClassloader) { it.parent } + val actualClassLoadersChain = generateSequence(contextClassLoader) { it.parent } if (actualClassLoadersChain.any { it == fromClass.java.classLoader }) return fromClass } @@ -71,7 +80,7 @@ class JvmGetScriptingClass : GetScriptingClass, Serializable { } if (baseClassLoaderIsInitialized != true) { - baseClassLoader = contextClassloader + baseClassLoader = contextClassLoader baseClassLoaderIsInitialized = true } // TODO: this check breaks testLazyScriptDefinition, find out the reason and fix @@ -88,12 +97,12 @@ class JvmGetScriptingClass : GetScriptingClass, Serializable { } } classLoader = - if (classpath == null || classpath.isEmpty()) baseClassLoader - else URLClassLoader(classpath.toTypedArray(), baseClassLoader) + if (classpath == null || classpath.isEmpty()) baseClassLoader + else URLClassLoader(classpath.toTypedArray(), baseClassLoader) } return try { - classLoader!!.loadClass(classType.typeName).kotlin + (classLoader ?: ClassLoader.getSystemClassLoader()).loadClass(classType.typeName).kotlin } catch (e: Throwable) { throw IllegalArgumentException("unable to load class $classType", e) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/scripting/internal/ScriptingGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/scripting/internal/ScriptingGradleSubplugin.kt index 29a694b7718..9de6e47d6c7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/scripting/internal/ScriptingGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/scripting/internal/ScriptingGradleSubplugin.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource import org.jetbrains.kotlin.scripting.definitions.reporter import java.io.File +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration private const val MIN_SUPPORTED_GRADLE_MAJOR_VERSION = 5 private const val MIN_SUPPORTED_GRADLE_MINOR_VERSION = 0 @@ -166,7 +167,8 @@ internal class DiscoverScriptExtensionsTransform : ArtifactTransform() { override fun transform(input: File): List { val definitions = ScriptDefinitionsFromClasspathDiscoverySource( - listOf(input), emptyMap(), + listOf(input), + defaultJvmScriptingHostConfiguration, PrintingMessageCollector(System.out, MessageRenderer.WITHOUT_PATHS, false).reporter ).definitions val extensions = definitions.mapTo(arrayListOf()) { it.fileExtension } diff --git a/libraries/tools/kotlin-main-kts/src/org/jetbrains/kotlin/mainKts/scriptDef.kt b/libraries/tools/kotlin-main-kts/src/org/jetbrains/kotlin/mainKts/scriptDef.kt index aa3551967b9..63d00386c21 100644 --- a/libraries/tools/kotlin-main-kts/src/org/jetbrains/kotlin/mainKts/scriptDef.kt +++ b/libraries/tools/kotlin-main-kts/src/org/jetbrains/kotlin/mainKts/scriptDef.kt @@ -14,6 +14,7 @@ import kotlin.script.dependencies.ScriptContents import kotlin.script.dependencies.ScriptDependenciesResolver import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.* +import kotlin.script.experimental.host.FileBasedScriptSource import kotlin.script.experimental.host.FileScriptSource import kotlin.script.experimental.jvm.compat.mapLegacyDiagnosticSeverity import kotlin.script.experimental.jvm.compat.mapLegacyScriptPosition @@ -59,7 +60,7 @@ class MainKtsConfigurator : RefineScriptCompilationConfigurationHandler { val annotations = context.collectedData?.get(ScriptCollectedData.foundAnnotations)?.takeIf { it.isNotEmpty() } ?: return context.compilationConfiguration.asSuccess() - val scriptBaseDir = (context.script as? FileScriptSource)?.file?.parentFile + val scriptBaseDir = (context.script as? FileBasedScriptSource)?.file?.parentFile val importedSources = annotations.flatMap { (it as? Import)?.paths?.map { sourceName -> FileScriptSource(scriptBaseDir?.resolve(sourceName) ?: File(sourceName)) diff --git a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/ExecuteKotlinScriptMojo.java b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/ExecuteKotlinScriptMojo.java index bf65d872fa0..ef8d8c854dd 100644 --- a/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/ExecuteKotlinScriptMojo.java +++ b/libraries/tools/kotlin-maven-plugin/src/main/java/org/jetbrains/kotlin/maven/ExecuteKotlinScriptMojo.java @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.maven; import com.intellij.openapi.Disposable; import com.intellij.openapi.util.Disposer; +import kotlin.script.experimental.jvm.JvmScriptingHostConfigurationKt; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.DefaultArtifact; import org.apache.maven.artifact.handler.ArtifactHandler; @@ -188,7 +189,8 @@ public class ExecuteKotlinScriptMojo extends AbstractMojo { configuration.put(CommonConfigurationKeys.MODULE_NAME, JvmProtoBufUtil.DEFAULT_MODULE_NAME); ConfigurationKt.configureScriptDefinitions( - scriptTemplates, configuration, this.getClass().getClassLoader(), messageCollector, new HashMap<>() + scriptTemplates, configuration, this.getClass().getClassLoader(), messageCollector, + JvmScriptingHostConfigurationKt.getDefaultJvmScriptingHostConfiguration() ); KotlinCoreEnvironment environment = KotlinCoreEnvironment.createForProduction(rootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES); diff --git a/libraries/tools/kotlin-script-util/src/test/kotlin/org/jetbrains/kotlin/script/util/ScriptUtilIT.kt b/libraries/tools/kotlin-script-util/src/test/kotlin/org/jetbrains/kotlin/script/util/ScriptUtilIT.kt index 9bff86d57ec..50a24c2a329 100644 --- a/libraries/tools/kotlin-script-util/src/test/kotlin/org/jetbrains/kotlin/script/util/ScriptUtilIT.kt +++ b/libraries/tools/kotlin-script-util/src/test/kotlin/org/jetbrains/kotlin/script/util/ScriptUtilIT.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.script.util.templates.StandardArgsScriptTemplateWith import org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate import org.jetbrains.kotlin.utils.PathUtil.getResourcePathForClass import org.junit.Assert @@ -44,6 +45,7 @@ import java.io.ByteArrayOutputStream import java.io.OutputStream import java.io.PrintStream import kotlin.reflect.KClass +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration const val KOTLIN_JAVA_RUNTIME_JAR = "kotlin-stdlib.jar" @@ -155,7 +157,12 @@ done } } put(CommonConfigurationKeys.MODULE_NAME, "kotlin-script-util-test") - add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + add( + ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, + ScriptDefinition.FromLegacy( + defaultJvmScriptingHostConfiguration, scriptDefinition + ) + ) put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, ScriptingCompilerConfigurationComponentRegistrar()) diff --git a/plugins/sam-with-receiver/sam-with-receiver-cli/test/org/jetbrains/kotlin/samWithReceiver/AbstractSamWithReceiverScriptTest.kt b/plugins/sam-with-receiver/sam-with-receiver-cli/test/org/jetbrains/kotlin/samWithReceiver/AbstractSamWithReceiverScriptTest.kt index 0f91316d860..4a129247cc9 100644 --- a/plugins/sam-with-receiver/sam-with-receiver-cli/test/org/jetbrains/kotlin/samWithReceiver/AbstractSamWithReceiverScriptTest.kt +++ b/plugins/sam-with-receiver/sam-with-receiver-cli/test/org/jetbrains/kotlin/samWithReceiver/AbstractSamWithReceiverScriptTest.kt @@ -19,8 +19,10 @@ package org.jetbrains.kotlin.samWithReceiver import org.jetbrains.kotlin.checkers.AbstractDiagnosticsTest import org.jetbrains.kotlin.extensions.StorageComponentContainerContributor import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate import java.io.File +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.extensions.SamWithReceiverAnnotations import kotlin.script.templates.ScriptTemplateDefinition @@ -31,7 +33,10 @@ abstract class AbstractSamWithReceiverScriptTest : AbstractDiagnosticsTest() { override fun createEnvironment(file: File) = super.createEnvironment(file).apply { StorageComponentContainerContributor.registerExtension(project, CliSamWithReceiverComponentContributor(TEST_ANNOTATIONS)) - val def = KotlinScriptDefinitionFromAnnotatedTemplate(ScriptForSamWithReceivers::class, emptyMap()) + val def = ScriptDefinition.FromLegacy( + defaultJvmScriptingHostConfiguration, + KotlinScriptDefinitionFromAnnotatedTemplate(ScriptForSamWithReceivers::class, emptyMap()) + ) configuration.add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, def) } } diff --git a/plugins/sam-with-receiver/sam-with-receiver-ide/src/IdeSamWithReceiverComponentContributor.kt b/plugins/sam-with-receiver/sam-with-receiver-ide/src/IdeSamWithReceiverComponentContributor.kt index 88efe8510b8..1f3e4e16254 100644 --- a/plugins/sam-with-receiver/sam-with-receiver-ide/src/IdeSamWithReceiverComponentContributor.kt +++ b/plugins/sam-with-receiver/sam-with-receiver-ide/src/IdeSamWithReceiverComponentContributor.kt @@ -65,12 +65,12 @@ class IdeSamWithReceiverComponentContributor(val project: Project) : StorageComp val moduleInfo = moduleDescriptor.getCapability(ModuleInfo.Capability) val annotations = - when (moduleInfo) { - is ScriptModuleInfo -> moduleInfo.scriptDefinition.annotationsForSamWithReceivers - is ScriptDependenciesInfo.ForFile -> moduleInfo.scriptDefinition.annotationsForSamWithReceivers - is ModuleProductionSourceInfo -> getAnnotationsForModule(moduleInfo.module) - else -> null - } ?: return + when (moduleInfo) { + is ScriptModuleInfo -> moduleInfo.scriptDefinition.legacyDefinition.annotationsForSamWithReceivers + is ScriptDependenciesInfo.ForFile -> moduleInfo.scriptDefinition.legacyDefinition.annotationsForSamWithReceivers + is ModuleProductionSourceInfo -> getAnnotationsForModule(moduleInfo.module) + else -> null + } ?: return container.useInstance(SamWithReceiverResolverExtension(annotations)) } diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/configuration/ScriptingConfigurationKeys.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/configuration/ScriptingConfigurationKeys.kt index 070ef0796f4..ce3b9c3cc94 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/configuration/ScriptingConfigurationKeys.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/configuration/ScriptingConfigurationKeys.kt @@ -6,13 +6,13 @@ package org.jetbrains.kotlin.scripting.configuration import org.jetbrains.kotlin.config.CompilerConfigurationKey -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource import java.io.File object ScriptingConfigurationKeys { - val SCRIPT_DEFINITIONS = CompilerConfigurationKey.create>("script definitions") + val SCRIPT_DEFINITIONS = CompilerConfigurationKey.create>("script definitions") val SCRIPT_DEFINITIONS_SOURCES = CompilerConfigurationKey.create>("script definitions sources") diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/configuration/configuration.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/configuration/configuration.kt index ce0bcdb8c21..ff2092a17ee 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/configuration/configuration.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/configuration/configuration.kt @@ -5,11 +5,14 @@ package org.jetbrains.kotlin.scripting.configuration +import com.intellij.openapi.project.Project import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.scripting.definitions.loadScriptTemplatesFromClasspath import org.jetbrains.kotlin.scripting.definitions.reporter +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration const val KOTLIN_SCRIPTING_PLUGIN_ID = "kotlin.scripting" @@ -18,12 +21,16 @@ fun configureScriptDefinitions( configuration: CompilerConfiguration, baseClassloader: ClassLoader, messageCollector: MessageCollector, - scriptResolverEnv: Map + hostConfiguration: ScriptingHostConfiguration ) { // TODO: consider using escaping to allow kotlin escaped names in class names val templatesFromClasspath = loadScriptTemplatesFromClasspath( - scriptTemplates, configuration.jvmClasspathRoots, emptyList(), baseClassloader, scriptResolverEnv, messageCollector.reporter + scriptTemplates, configuration.jvmClasspathRoots, emptyList(), baseClassloader, hostConfiguration, messageCollector.reporter ) configuration.addAll(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, templatesFromClasspath.toList()) } +fun makeHostConfiguration(project: Project, configuration: CompilerConfiguration): ScriptingHostConfiguration = + ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + // TODO: add jdk path and other params if needed + } \ No newline at end of file diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinition.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinition.kt index 1cb1ebf7070..ffcc3f34f7f 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinition.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinition.kt @@ -17,6 +17,8 @@ import kotlin.reflect.KType import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.templates.standard.ScriptTemplateWithArgs +// Legacy definition, will be obsolete soon +// TODO: make deprecated and drop usages where possible open class KotlinScriptDefinition(open val template: KClass) : UserDataHolderBase() { open val name: String = "Kotlin Script" diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionAdapterFromNewAPI.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionAdapterFromNewAPI.kt index ad6d72c9145..f804e3b7532 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionAdapterFromNewAPI.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionAdapterFromNewAPI.kt @@ -17,6 +17,7 @@ import kotlin.script.experimental.api.* import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.host.getScriptingClass +import kotlin.script.experimental.jvm.compat.mapToLegacyExpectedLocations import kotlin.script.experimental.jvm.impl.BridgeDependenciesResolver import kotlin.script.experimental.location.ScriptExpectedLocation import kotlin.script.experimental.util.getOrError @@ -80,15 +81,8 @@ abstract class KotlinScriptDefinitionAdapterFromNewAPIBase : KotlinScriptDefinit @Suppress("DEPRECATION") override val scriptExpectedLocations: List - get() = scriptCompilationConfiguration[ScriptCompilationConfiguration.ide.acceptedLocations]?.map { - when (it) { - ScriptAcceptedLocation.Sources -> ScriptExpectedLocation.SourcesOnly - ScriptAcceptedLocation.Tests -> ScriptExpectedLocation.TestsOnly - ScriptAcceptedLocation.Libraries -> ScriptExpectedLocation.Libraries - ScriptAcceptedLocation.Project -> ScriptExpectedLocation.Project - ScriptAcceptedLocation.Everywhere -> ScriptExpectedLocation.Everywhere - } - } ?: listOf(ScriptExpectedLocation.SourcesOnly, ScriptExpectedLocation.TestsOnly) + get() = scriptCompilationConfiguration[ScriptCompilationConfiguration.ide.acceptedLocations]?.mapToLegacyExpectedLocations() + ?: listOf(ScriptExpectedLocation.SourcesOnly, ScriptExpectedLocation.TestsOnly) private val scriptingClassGetter by lazy(LazyThreadSafetyMode.PUBLICATION) { hostConfiguration[ScriptingHostConfiguration.getScriptingClass] diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionProvider.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionProvider.kt index 958af70dc93..3aacba360bb 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionProvider.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/KotlinScriptDefinitionProvider.kt @@ -9,10 +9,17 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project interface ScriptDefinitionProvider { + @Deprecated("Migrating to configuration refinement", level = DeprecationLevel.ERROR) fun findScriptDefinition(fileName: String): KotlinScriptDefinition? - fun isScript(fileName: String): Boolean + + @Deprecated("Migrating to configuration refinement", level = DeprecationLevel.ERROR) fun getDefaultScriptDefinition(): KotlinScriptDefinition + fun isScript(fileName: String): Boolean + + fun findDefinition(fileName: String): ScriptDefinition? + fun getDefaultDefinition(): ScriptDefinition + fun getKnownFilenameExtensions(): Sequence companion object { @@ -21,4 +28,3 @@ interface ScriptDefinitionProvider { } } - diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/LazyScriptDefinitionFromDiscoveredClass.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/LazyScriptDefinitionFromDiscoveredClass.kt index 67865e8c1a1..6661bae16c4 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/LazyScriptDefinitionFromDiscoveredClass.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/LazyScriptDefinitionFromDiscoveredClass.kt @@ -10,44 +10,56 @@ import java.io.File import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.KotlinType import kotlin.script.experimental.api.ScriptCompilationConfiguration +import kotlin.script.experimental.api.ScriptEvaluationConfiguration import kotlin.script.experimental.api.fileExtension import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.host.configurationDependencies import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate +import kotlin.script.experimental.host.createEvaluationConfigurationFromTemplate import kotlin.script.experimental.jvm.JvmDependency import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration class LazyScriptDefinitionFromDiscoveredClass internal constructor( + baseHostConfiguration: ScriptingHostConfiguration, private val annotationsFromAsm: ArrayList, private val className: String, private val classpath: List, private val messageReporter: MessageReporter -) : KotlinScriptDefinitionAdapterFromNewAPIBase() { +) : ScriptDefinition.FromConfigurationsBase() { constructor( + baseHostConfiguration: ScriptingHostConfiguration, classBytes: ByteArray, className: String, classpath: List, messageReporter: MessageReporter - ) : this(loadAnnotationsFromClass(classBytes), className, classpath, messageReporter) + ) : this(baseHostConfiguration, loadAnnotationsFromClass(classBytes), className, classpath, messageReporter) override val hostConfiguration: ScriptingHostConfiguration by lazy(LazyThreadSafetyMode.PUBLICATION) { - ScriptingHostConfiguration(defaultJvmScriptingHostConfiguration) { + ScriptingHostConfiguration(baseHostConfiguration) { configurationDependencies.append(JvmDependency(classpath)) } } - override val scriptCompilationConfiguration: ScriptCompilationConfiguration by lazy(LazyThreadSafetyMode.PUBLICATION) { + private val configurations by lazy(LazyThreadSafetyMode.PUBLICATION) { messageReporter( CompilerMessageSeverity.LOGGING, "Configure scripting: loading script definition class $className using classpath $classpath\n. ${Thread.currentThread().stackTrace}" ) try { - createCompilationConfigurationFromTemplate( - KotlinType(className), - hostConfiguration, - LazyScriptDefinitionFromDiscoveredClass::class - ) + val compileCfg = + createCompilationConfigurationFromTemplate( + KotlinType(className), + hostConfiguration, + LazyScriptDefinitionFromDiscoveredClass::class + ) + val evalCfg = + createEvaluationConfigurationFromTemplate( + KotlinType(className), + hostConfiguration, + LazyScriptDefinitionFromDiscoveredClass::class + ) + compileCfg to evalCfg } catch (ex: ClassNotFoundException) { messageReporter(CompilerMessageSeverity.ERROR, "Cannot find script definition class $className") InvalidScriptDefinition @@ -60,10 +72,13 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor( } } + override val compilationConfiguration: ScriptCompilationConfiguration get() = configurations.first + override val evaluationConfiguration: ScriptEvaluationConfiguration get() = configurations.second + override val fileExtension: String by lazy(LazyThreadSafetyMode.PUBLICATION) { annotationsFromAsm.find { it.name == KotlinScript::class.simpleName }?.args ?.find { it.name == "fileExtension" }?.value - ?: scriptCompilationConfiguration.let { + ?: compilationConfiguration.let { it[ScriptCompilationConfiguration.fileExtension] ?: super.fileExtension } } @@ -74,4 +89,4 @@ class LazyScriptDefinitionFromDiscoveredClass internal constructor( } } -val InvalidScriptDefinition = ScriptCompilationConfiguration() +val InvalidScriptDefinition = ScriptCompilationConfiguration() to ScriptEvaluationConfiguration() diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/LazyScriptDefinitionProvider.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/LazyScriptDefinitionProvider.kt index 921d991088a..f3ac8e21376 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/LazyScriptDefinitionProvider.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/LazyScriptDefinitionProvider.kt @@ -10,15 +10,22 @@ import org.jetbrains.kotlin.idea.KotlinFileType import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.read import kotlin.concurrent.write +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration abstract class LazyScriptDefinitionProvider : ScriptDefinitionProvider { protected val lock = ReentrantReadWriteLock() - protected abstract val currentDefinitions: Sequence + protected abstract val currentDefinitions: Sequence - private var _cachedDefinitions: Sequence? = null - private val cachedDefinitions: Sequence + protected open fun getScriptingHostConfiguration(): ScriptingHostConfiguration = defaultJvmScriptingHostConfiguration + + override fun getDefaultDefinition(): ScriptDefinition = + ScriptDefinition.FromLegacy(getScriptingHostConfiguration(), StandardScriptDefinition) + + private var _cachedDefinitions: Sequence? = null + private val cachedDefinitions: Sequence get() { assert(lock.readLockCount > 0) { "cachedDefinitions should only be used under the read lock" } if (_cachedDefinitions == null) lock.write { @@ -37,18 +44,22 @@ abstract class LazyScriptDefinitionProvider : ScriptDefinitionProvider { fileName.endsWith(it, ignoreCase = true) } - override fun findScriptDefinition(fileName: String): KotlinScriptDefinition? = + override fun findDefinition(fileName: String): ScriptDefinition? = if (nonScriptFileName(fileName)) null else lock.read { cachedDefinitions.firstOrNull { it.isScript(fileName) } } - override fun isScript(fileName: String) = findScriptDefinition(fileName) != null + override fun findScriptDefinition(fileName: String): KotlinScriptDefinition? = findDefinition(fileName)?.legacyDefinition + + override fun isScript(fileName: String) = findDefinition(fileName) != null override fun getKnownFilenameExtensions(): Sequence = lock.read { cachedDefinitions.map { it.fileExtension } } + override fun getDefaultScriptDefinition(): KotlinScriptDefinition = getDefaultDefinition().legacyDefinition + companion object { // TODO: find a common place for storing kotlin-related extensions and reuse values from it everywhere protected val nonScriptFilenameSuffixes = arrayOf(".${KotlinFileType.EXTENSION}", ".${JavaFileType.DEFAULT_EXTENSION}") diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptCompilationConfigurationFromDefinition.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptCompilationConfigurationFromDefinition.kt new file mode 100644 index 00000000000..1beba5cbcad --- /dev/null +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptCompilationConfigurationFromDefinition.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.scripting.definitions + +import java.io.File +import kotlin.script.dependencies.Environment +import kotlin.script.dependencies.ScriptContents +import kotlin.script.experimental.api.* +import kotlin.script.experimental.dependencies.DependenciesResolver +import kotlin.script.experimental.host.FileBasedScriptSource +import kotlin.script.experimental.host.FileScriptSource +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.host.ScriptingHostConfigurationKeys +import kotlin.script.experimental.jvm.JvmDependency +import kotlin.script.experimental.jvm.compat.mapLegacyDiagnosticSeverity +import kotlin.script.experimental.jvm.compat.mapLegacyExpectedLocations +import kotlin.script.experimental.jvm.jdkHome +import kotlin.script.experimental.jvm.jvm +import kotlin.script.experimental.util.PropertiesCollection + +class ScriptCompilationConfigurationFromDefinition( + val hostConfiguration: ScriptingHostConfiguration, + val scriptDefinition: KotlinScriptDefinition +) : ScriptCompilationConfiguration( + { + hostConfiguration(hostConfiguration) + displayName(scriptDefinition.name) + fileExtension(scriptDefinition.fileExtension) + baseClass(KotlinType(scriptDefinition.template)) + implicitReceivers.putIfAny(scriptDefinition.implicitReceivers.map(::KotlinType)) + providedProperties.putIfAny(scriptDefinition.providedProperties.map { it.first to KotlinType(it.second) }) + annotationsForSamWithReceivers.put(scriptDefinition.annotationsForSamWithReceivers.map(::KotlinType)) + platform(scriptDefinition.platform) + compilerOptions.putIfAny(scriptDefinition.additionalCompilerArguments) + ide { + acceptedLocations.put(scriptDefinition.scriptExpectedLocations.mapLegacyExpectedLocations()) + } + if (scriptDefinition.dependencyResolver != DependenciesResolver.NoDependencies) { + refineConfiguration { + onAnnotations(scriptDefinition.acceptedAnnotations.map(::KotlinType)) { context -> + + val resolveResult: DependenciesResolver.ResolveResult = scriptDefinition.dependencyResolver.resolve( + ScriptContentsFromRefinementContext(context), + context.compilationConfiguration[ScriptCompilationConfiguration.hostConfiguration]?.let { + it[ScriptingHostConfiguration.getEnvironment]?.invoke() + }.orEmpty() + ) + + val reports = resolveResult.reports.map { ScriptDiagnostic(it.message, mapLegacyDiagnosticSeverity(it.severity)) } + val resolvedDeps = (resolveResult as? DependenciesResolver.ResolveResult.Success)?.dependencies + + if (resolvedDeps == null) ResultWithDiagnostics.Failure(reports) + else ScriptCompilationConfiguration(context.compilationConfiguration) { + if (resolvedDeps.classpath.isNotEmpty()) { + dependencies.append(JvmDependency(resolvedDeps.classpath)) + } + defaultImports.append(resolvedDeps.imports) + importScripts.append(resolvedDeps.scripts.map { FileScriptSource(it) }) + jvm { + jdkHome.putIfNotNull(resolvedDeps.javaHome) // TODO: check if it is correct to supply javaHome as jdkHome + } + if (resolvedDeps.sources.isNotEmpty()) { + ide { + dependenciesSources.append(JvmDependency(resolvedDeps.sources)) + } + } + }.asSuccess(reports) + } + } + } + } +) + +private class ScriptContentsFromRefinementContext(val context: ScriptConfigurationRefinementContext) : ScriptContents { + override val file: File? + get() = (context.script as? FileBasedScriptSource)?.file + override val annotations: Iterable + get() = context.collectedData?.get(ScriptCollectedData.foundAnnotations) ?: emptyList() + override val text: CharSequence? + get() = context.script.text +} + +val ScriptCompilationConfigurationKeys.annotationsForSamWithReceivers by PropertiesCollection.key>() + +val ScriptCompilationConfigurationKeys.platform by PropertiesCollection.key() + +val ScriptingHostConfigurationKeys.getEnvironment by PropertiesCollection.key<() -> Environment?>() \ No newline at end of file diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt new file mode 100644 index 00000000000..990f1d74ccb --- /dev/null +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinition.kt @@ -0,0 +1,164 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.scripting.definitions + +import com.intellij.openapi.util.UserDataHolderBase +import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotatedTemplate +import java.io.File +import kotlin.reflect.KClass +import kotlin.script.experimental.api.* +import kotlin.script.experimental.host.ScriptingHostConfiguration +import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate +import kotlin.script.experimental.host.createEvaluationConfigurationFromTemplate +import kotlin.script.experimental.jvm.baseClassLoader +import kotlin.script.experimental.jvm.jvm + +// Transitional class/implementation - migrating to the new API +// TODO: deprecate KotlinScriptDefinition +// TODO: name could be confused with KotlinScriptDefinition, discuss naming +abstract class ScriptDefinition : UserDataHolderBase() { + + abstract val legacyDefinition: KotlinScriptDefinition + abstract val hostConfiguration: ScriptingHostConfiguration + abstract val compilationConfiguration: ScriptCompilationConfiguration + abstract val evaluationConfiguration: ScriptEvaluationConfiguration + + abstract fun isScript(fileName: String): Boolean + abstract val fileExtension: String + abstract val name: String + // TODO: used in settings, find out the reason and refactor accordingly + abstract val definitionId: String + + abstract val contextClassLoader: ClassLoader? + + // Target platform for script, ex. "JVM", "JS", "NATIVE" + open val platform: String + get() = "JVM" + + open val isDefault = false + + abstract val baseClassType: KotlinType + abstract val compilerOptions: Iterable + + inline fun asLegacyOrNull(): T? = + if (this is FromLegacy) legacyDefinition as? T else null + + open class FromLegacy( + override val hostConfiguration: ScriptingHostConfiguration, + override val legacyDefinition: KotlinScriptDefinition + ) : ScriptDefinition() { + + override val compilationConfiguration by lazy { + ScriptCompilationConfigurationFromDefinition( + hostConfiguration, + legacyDefinition + ) + } + + override val evaluationConfiguration by lazy { + ScriptEvaluationConfigurationFromDefinition( + hostConfiguration, + legacyDefinition + ) + } + + override fun isScript(fileName: String): Boolean = legacyDefinition.isScript(fileName) + + override val fileExtension: String get() = legacyDefinition.fileExtension + + override val name: String get() = legacyDefinition.name + + override val definitionId: String get() = legacyDefinition::class.qualifiedName ?: "unknown" + + override val platform: String + get() = legacyDefinition.platform + + override val contextClassLoader: ClassLoader? + get() = legacyDefinition.template.java.classLoader + + override val baseClassType: KotlinType + get() = KotlinType(legacyDefinition.template) + + override val compilerOptions: Iterable + get() = legacyDefinition.additionalCompilerArguments ?: emptyList() + + override fun equals(other: Any?): Boolean = this === other || legacyDefinition == (other as? FromLegacy)?.legacyDefinition + + override fun hashCode(): Int = legacyDefinition.hashCode() + } + + open class FromLegacyTemplate( + hostConfiguration: ScriptingHostConfiguration, + template: KClass<*>, + templateClasspath: List = emptyList() + ) : FromLegacy( + hostConfiguration, + KotlinScriptDefinitionFromAnnotatedTemplate( + template, + hostConfiguration[ScriptingHostConfiguration.getEnvironment]?.invoke(), + templateClasspath + ) + ) + + abstract class FromConfigurationsBase : ScriptDefinition() { + + override val legacyDefinition by lazy { + KotlinScriptDefinitionAdapterFromNewAPI( + compilationConfiguration, + hostConfiguration + ) + } + + override fun isScript(fileName: String): Boolean = fileName.endsWith(".$fileExtension") + + override val fileExtension: String get() = compilationConfiguration[ScriptCompilationConfiguration.fileExtension]!! + + override val name: String get() = compilationConfiguration[ScriptCompilationConfiguration.displayName]!! + + override val definitionId: String get() = compilationConfiguration[ScriptCompilationConfiguration.baseClass]!!.typeName + + override val contextClassLoader: ClassLoader? by lazy { + compilationConfiguration[ScriptCompilationConfiguration.baseClass]?.fromClass?.java?.classLoader + ?: hostConfiguration[ScriptingHostConfiguration.jvm.baseClassLoader] + } + + override val baseClassType: KotlinType + get() = compilationConfiguration[ScriptCompilationConfiguration.baseClass]!! + + override val compilerOptions: Iterable + get() = compilationConfiguration[ScriptCompilationConfiguration.compilerOptions].orEmpty() + + override fun equals(other: Any?): Boolean = this === other || + (other as? FromConfigurations)?.let { + compilationConfiguration == it.compilationConfiguration && evaluationConfiguration == it.evaluationConfiguration + } == true + + override fun hashCode(): Int = compilationConfiguration.hashCode() + 37 * evaluationConfiguration.hashCode() + } + + open class FromConfigurations( + override val hostConfiguration: ScriptingHostConfiguration, + override val compilationConfiguration: ScriptCompilationConfiguration, + override val evaluationConfiguration: ScriptEvaluationConfiguration + ) : FromConfigurationsBase() + + open class FromTemplate( + hostConfiguration: ScriptingHostConfiguration, + template: KClass<*>, + contextClass: KClass<*> = ScriptCompilationConfiguration::class + ) : FromConfigurations( + hostConfiguration, + createCompilationConfigurationFromTemplate(KotlinType(template), hostConfiguration, contextClass), + createEvaluationConfigurationFromTemplate(KotlinType(template), hostConfiguration, contextClass) + ) + + companion object { + fun getDefault(hostConfiguration: ScriptingHostConfiguration) = + object : FromLegacy(hostConfiguration, StandardScriptDefinition) { + override val isDefault = true + } + } +} \ No newline at end of file diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinitionsSource.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinitionsSource.kt index 4eda939f443..a0d2bd7134a 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinitionsSource.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDefinitionsSource.kt @@ -7,5 +7,5 @@ package org.jetbrains.kotlin.scripting.definitions interface ScriptDefinitionsSource { - val definitions: Sequence + val definitions: Sequence } \ No newline at end of file diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDependenciesProvider.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDependenciesProvider.kt index 06274600bdb..b791c96929e 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDependenciesProvider.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptDependenciesProvider.kt @@ -9,11 +9,24 @@ import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiFile +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult +import kotlin.script.experimental.api.valueOrNull import kotlin.script.experimental.dependencies.ScriptDependencies interface ScriptDependenciesProvider { - fun getScriptDependencies(file: VirtualFile): ScriptDependencies? - fun getScriptDependencies(file: PsiFile) = getScriptDependencies(file.virtualFile ?: file.originalFile.virtualFile) + + @Deprecated("Migrating to configuration refinement", level = DeprecationLevel.ERROR) + fun getScriptDependencies(file: VirtualFile): ScriptDependencies? = + getScriptConfigurationResult(file)?.valueOrNull()?.legacyDependencies + + @Deprecated("Migrating to configuration refinement", level = DeprecationLevel.ERROR) + fun getScriptDependencies(file: PsiFile): ScriptDependencies? = + getScriptConfigurationResult(file.virtualFile ?: file.originalFile.virtualFile)?.valueOrNull()?.legacyDependencies + + fun getScriptConfigurationResult(file: VirtualFile): ScriptCompilationConfigurationResult? = null + + fun getScriptConfigurationResult(file: PsiFile): ScriptCompilationConfigurationResult? = + getScriptConfigurationResult(file.virtualFile ?: file.originalFile.virtualFile) companion object { fun getInstance(project: Project): ScriptDependenciesProvider? = diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptEvaluationConfigurationFromDefinition.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptEvaluationConfigurationFromDefinition.kt new file mode 100644 index 00000000000..ed40b00f517 --- /dev/null +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptEvaluationConfigurationFromDefinition.kt @@ -0,0 +1,19 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.scripting.definitions + +import kotlin.script.experimental.api.ScriptEvaluationConfiguration +import kotlin.script.experimental.api.hostConfiguration +import kotlin.script.experimental.host.ScriptingHostConfiguration + +class ScriptEvaluationConfigurationFromDefinition( + val hostConfiguration: ScriptingHostConfiguration, + val scriptDefinition: KotlinScriptDefinition +) : ScriptEvaluationConfiguration( + { + hostConfiguration(hostConfiguration) + } +) diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptiDefinitionsFromClasspathDiscoverySource.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptiDefinitionsFromClasspathDiscoverySource.kt index 346fb1a66de..29979b8afc0 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptiDefinitionsFromClasspathDiscoverySource.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/ScriptiDefinitionsFromClasspathDiscoverySource.kt @@ -11,13 +11,13 @@ import org.jetbrains.kotlin.scripting.resolve.KotlinScriptDefinitionFromAnnotate import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.File import java.io.IOException -import java.lang.IllegalArgumentException import java.net.URLClassLoader import java.util.jar.JarFile import kotlin.script.experimental.annotations.KotlinScript import kotlin.script.experimental.api.KotlinType +import kotlin.script.experimental.host.ScriptingHostConfiguration import kotlin.script.experimental.host.createCompilationConfigurationFromTemplate -import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration +import kotlin.script.experimental.host.createEvaluationConfigurationFromTemplate import kotlin.script.templates.ScriptTemplateDefinition const val SCRIPT_DEFINITION_MARKERS_PATH = "META-INF/kotlin/script/templates/" @@ -32,15 +32,15 @@ val MessageCollector.reporter: MessageReporter class ScriptDefinitionsFromClasspathDiscoverySource( private val classpath: List, - private val scriptResolverEnv: Map, + private val hostConfiguration: ScriptingHostConfiguration, private val messageReporter: MessageReporter ) : ScriptDefinitionsSource { - override val definitions: Sequence = run { + override val definitions: Sequence = run { discoverScriptTemplatesInClasspath( classpath, this::class.java.classLoader, - scriptResolverEnv, + hostConfiguration, messageReporter ) } @@ -50,9 +50,9 @@ private const val MANIFEST_RESOURCE_NAME = "/META-INF/MANIFEST.MF" fun discoverScriptTemplatesInClassLoader( classLoader: ClassLoader, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, messageReporter: MessageReporter -): Sequence { +): Sequence { val classpath = classLoader.getResources(MANIFEST_RESOURCE_NAME).asSequence().mapNotNull { try { File(it.toURI()).takeIf(File::exists) @@ -61,26 +61,26 @@ fun discoverScriptTemplatesInClassLoader( } } val classpathWithLoader = SimpleClasspathWithClassLoader(classpath.toList(), classLoader) - return scriptTemplatesDiscoverySequence(classpathWithLoader, scriptResolverEnv, messageReporter) + return scriptTemplatesDiscoverySequence(classpathWithLoader, hostConfiguration, messageReporter) } fun discoverScriptTemplatesInClasspath( classpath: List, baseClassLoader: ClassLoader?, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, messageReporter: MessageReporter -): Sequence { +): Sequence { // TODO: try to find a way to reduce classpath (and classloader) to minimal one needed to load script definition and its dependencies val classpathWithLoader = LazyClasspathWithClassLoader(baseClassLoader) { classpath } - return scriptTemplatesDiscoverySequence(classpathWithLoader, scriptResolverEnv, messageReporter) + return scriptTemplatesDiscoverySequence(classpathWithLoader, hostConfiguration, messageReporter) } private fun scriptTemplatesDiscoverySequence( classpathWithLoader: ClasspathWithClassLoader, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, messageReporter: MessageReporter -): Sequence { +): Sequence { return sequence { // for jar files the definition class is expected in the same jar as the discovery file // in case of directories, the class output may come separate from the resources, so some candidates should be deffered and processed later @@ -102,7 +102,7 @@ private fun scriptTemplatesDiscoverySequence( definitionNames.partitionLoadJarDefinitions( jar, classpathWithLoader, - scriptResolverEnv, + hostConfiguration, messageReporter ) if (notFoundClasses.isNotEmpty()) { @@ -122,7 +122,7 @@ private fun scriptTemplatesDiscoverySequence( val discoveryMarkers = File(dep, SCRIPT_DEFINITION_MARKERS_PATH).listFiles() if (discoveryMarkers?.isEmpty() == false) { val (foundDefinitionClasses, notFoundDefinitions) = discoveryMarkers.map { it.name } - .partitionLoadDirDefinitions(dep, classpathWithLoader, scriptResolverEnv, messageReporter) + .partitionLoadDirDefinitions(dep, classpathWithLoader, hostConfiguration, messageReporter) foundDefinitionClasses.forEach { yield(it) } @@ -145,7 +145,7 @@ private fun scriptTemplatesDiscoverySequence( if (remainingDefinitionCandidates.isEmpty()) break try { val (foundDefinitionClasses, notFoundDefinitions) = - remainingDefinitionCandidates.partitionLoadDirDefinitions(dep, classpathWithLoader, scriptResolverEnv, messageReporter) + remainingDefinitionCandidates.partitionLoadDirDefinitions(dep, classpathWithLoader, hostConfiguration, messageReporter) foundDefinitionClasses.forEach { yield(it) } @@ -170,9 +170,9 @@ fun loadScriptTemplatesFromClasspath( classpath: List, dependenciesClasspath: List, baseClassLoader: ClassLoader, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, messageReporter: MessageReporter -): Sequence = +): Sequence = if (scriptTemplates.isEmpty()) emptySequence() else sequence { // trying the direct classloading from baseClassloader first, since this is the most performant variant @@ -180,7 +180,7 @@ fun loadScriptTemplatesFromClasspath( loadScriptDefinition( baseClassLoader, it, - scriptResolverEnv, + hostConfiguration, messageReporter ) } @@ -199,11 +199,11 @@ fun loadScriptTemplatesFromClasspath( val (loadedDefinitions, notFoundTemplates) = when { dep.isFile && dep.extension == "jar" -> { // checking for extension is the compiler current behaviour, so the same logic is implemented here JarFile(dep).use { jar -> - remainingTemplates.partitionLoadJarDefinitions(jar, classpathWithLoader, scriptResolverEnv, messageReporter) + remainingTemplates.partitionLoadJarDefinitions(jar, classpathWithLoader, hostConfiguration, messageReporter) } } dep.isDirectory -> { - remainingTemplates.partitionLoadDirDefinitions(dep, classpathWithLoader, scriptResolverEnv, messageReporter) + remainingTemplates.partitionLoadDirDefinitions(dep, classpathWithLoader, hostConfiguration, messageReporter) } else -> { // assuming that invalid classpath entries will be reported elsewhere anyway, so do not spam user with additional warnings here @@ -237,17 +237,17 @@ fun loadScriptTemplatesFromClasspath( } private data class DefinitionsLoadPartitionResult( - val loaded: List, + val loaded: List, val notFound: List ) private inline fun List.partitionLoadDefinitions( classpathWithLoader: ClasspathWithClassLoader, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, noinline messageReporter: MessageReporter, getBytes: (String) -> ByteArray? ): DefinitionsLoadPartitionResult { - val loaded = ArrayList() + val loaded = ArrayList() val notFound = ArrayList() for (definitionName in this) { val classBytes = getBytes(definitionName) @@ -256,7 +256,7 @@ private inline fun List.partitionLoadDefinitions( it, definitionName, classpathWithLoader, - scriptResolverEnv, + hostConfiguration, messageReporter ) } @@ -273,18 +273,18 @@ private inline fun List.partitionLoadDefinitions( private fun List.partitionLoadJarDefinitions( jar: JarFile, classpathWithLoader: ClasspathWithClassLoader, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, messageReporter: MessageReporter -): DefinitionsLoadPartitionResult = partitionLoadDefinitions(classpathWithLoader, scriptResolverEnv, messageReporter) { definitionName -> +): DefinitionsLoadPartitionResult = partitionLoadDefinitions(classpathWithLoader, hostConfiguration, messageReporter) { definitionName -> jar.getJarEntry("${definitionName.replace('.', '/')}.class")?.let { jar.getInputStream(it).readBytes() } } private fun List.partitionLoadDirDefinitions( dir: File, classpathWithLoader: ClasspathWithClassLoader, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, messageReporter: MessageReporter -): DefinitionsLoadPartitionResult = partitionLoadDefinitions(classpathWithLoader, scriptResolverEnv, messageReporter) { definitionName -> +): DefinitionsLoadPartitionResult = partitionLoadDefinitions(classpathWithLoader, hostConfiguration, messageReporter) { definitionName -> File(dir, "${definitionName.replace('.', '/')}.class").takeIf { it.exists() && it.isFile }?.readBytes() } @@ -292,14 +292,15 @@ private fun loadScriptDefinition( templateClassBytes: ByteArray, templateClassName: String, classpathWithLoader: ClasspathWithClassLoader, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, messageReporter: MessageReporter -): KotlinScriptDefinition? { +): ScriptDefinition? { val anns = loadAnnotationsFromClass(templateClassBytes) for (ann in anns) { - var def: KotlinScriptDefinition? = null + var def: ScriptDefinition? = null if (ann.name == KotlinScript::class.simpleName) { def = LazyScriptDefinitionFromDiscoveredClass( + hostConfiguration, anns, templateClassName, classpathWithLoader.classpath, @@ -307,7 +308,14 @@ private fun loadScriptDefinition( ) } else if (ann.name == ScriptTemplateDefinition::class.simpleName) { val templateClass = classpathWithLoader.classLoader.loadClass(templateClassName).kotlin - def = KotlinScriptDefinitionFromAnnotatedTemplate(templateClass, scriptResolverEnv, classpathWithLoader.classpath) + def = ScriptDefinition.FromLegacy( + hostConfiguration, + KotlinScriptDefinitionFromAnnotatedTemplate( + templateClass, + hostConfiguration[ScriptingHostConfiguration.getEnvironment]?.invoke().orEmpty(), + classpathWithLoader.classpath + ) + ) } if (def != null) { messageReporter( @@ -327,29 +335,20 @@ private fun loadScriptDefinition( private fun loadScriptDefinition( classLoader: ClassLoader, template: String, - scriptResolverEnv: Map, + hostConfiguration: ScriptingHostConfiguration, messageReporter: MessageReporter -): KotlinScriptDefinition? { +): ScriptDefinition? { try { val cls = classLoader.loadClass(template) val def = if (cls.annotations.firstIsInstanceOrNull() != null) { - val environment = defaultJvmScriptingHostConfiguration - KotlinScriptDefinitionAdapterFromNewAPI( - createCompilationConfigurationFromTemplate( - KotlinType(cls.kotlin), - environment, - KotlinScriptDefinition::class - ), - environment - ) + ScriptDefinition.FromTemplate(hostConfiguration, cls.kotlin, ScriptDefinition::class) } else { - KotlinScriptDefinitionFromAnnotatedTemplate(cls.kotlin, scriptResolverEnv) + ScriptDefinition.FromLegacyTemplate(hostConfiguration, cls.kotlin) } messageReporter( CompilerMessageSeverity.INFO, - "Added script definition $template to configuration: name = ${def.name}, " + - "resolver = ${def.dependencyResolver.javaClass.name}" + "Added script definition $template to configuration: name = ${def.name}" ) return def } catch (ex: ClassNotFoundException) { diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt index 9055fa969a9..ae565dd1592 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/definitions/definitions.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.scripting.definitions import com.intellij.ide.highlighter.JavaClassFileType +import com.intellij.openapi.application.runReadAction import com.intellij.openapi.fileTypes.FileTypeRegistry import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile @@ -14,30 +15,31 @@ import com.intellij.psi.PsiManager import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.psi.KtFile -fun PsiFile.scriptDefinition(): KotlinScriptDefinition? { +fun PsiFile.findScriptDefinition(): ScriptDefinition? { // Do not use psiFile.script, see comments in findScriptDefinition if (this !is KtFile/* || this.script == null*/) return null val file = virtualFile ?: originalFile.virtualFile ?: return null if (file.isNonScript()) return null - return scriptDefinitionByFileName(project, file.name) + return findScriptDefinitionByFileName(project, file.name) } -fun VirtualFile.findScriptDefinition(project: Project): KotlinScriptDefinition? { +fun VirtualFile.findScriptDefinition(project: Project): ScriptDefinition? { if (!isValid || isNonScript()) return null // Do not use psiFile.script here because this method can be called during indexes access // and accessing stubs may cause deadlock // TODO: measure performance effect and if necessary consider detecting indexing here or using separate logic for non-IDE operations to speed up filtering - if ((PsiManager.getInstance(project).findFile(this) as? KtFile)/*?.script*/ == null) return null - return scriptDefinitionByFileName(project, name) + if (runReadAction { PsiManager.getInstance(project).findFile(this) as? KtFile }/*?.script*/ == null) return null + + return findScriptDefinitionByFileName(project, name) } -fun scriptDefinitionByFileName(project: Project, fileName: String): KotlinScriptDefinition { +fun findScriptDefinitionByFileName(project: Project, fileName: String): ScriptDefinition { val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) ?: return null ?: throw IllegalStateException("Unable to get script definition: ScriptDefinitionProvider is not configured.") - return scriptDefinitionProvider.findScriptDefinition(fileName) ?: scriptDefinitionProvider.getDefaultScriptDefinition() + return scriptDefinitionProvider.findDefinition(fileName) ?: scriptDefinitionProvider.getDefaultDefinition() } private fun VirtualFile.isNonScript(): Boolean = diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/dependencies/ScriptsCompilationDependencies.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/dependencies/ScriptsCompilationDependencies.kt index 750f1ce8f85..72703cd30fe 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/dependencies/ScriptsCompilationDependencies.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/dependencies/ScriptsCompilationDependencies.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import java.io.File +import kotlin.script.experimental.api.valueOrNull data class ScriptsCompilationDependencies( val classpath: List, @@ -41,11 +42,11 @@ fun collectScriptsCompilationDependencies( while (true) { val newRemainingSources = ArrayList() for (source in remainingSources) { - val dependencies = importsProvider.getScriptDependencies(source) - if (dependencies != null) { - collectedClassPath.addAll(dependencies.classpath) + val refinedConfiguration = importsProvider.getScriptConfigurationResult(source)?.valueOrNull() + if (refinedConfiguration != null) { + collectedClassPath.addAll(refinedConfiguration.dependenciesClassPath) - val sourceDependenciesRoots = dependencies.scripts.map { + val sourceDependenciesRoots = refinedConfiguration.importedScripts.map { KotlinSourceRoot(it.path, false) } val sourceDependencies = diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/extensions/ScriptExtraImportsProviderExtension.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/extensions/ScriptExtraImportsProviderExtension.kt index 3f024fecd76..b8b4fdb01f1 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/extensions/ScriptExtraImportsProviderExtension.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/extensions/ScriptExtraImportsProviderExtension.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.psi.KtImportInfo import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.extensions.ExtraImportsProviderExtension import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider +import kotlin.script.experimental.api.valueOrNull class ScriptExtraImportsProviderExtension : ExtraImportsProviderExtension { @@ -28,8 +29,8 @@ class ScriptExtraImportsProviderExtension : ExtraImportsProviderExtension { override fun getExtraImports(ktFile: KtFile): Collection = ktFile.takeIf { it.isScript() }?.let { file -> - val scriptDependencies = ScriptDependenciesProvider.getInstance(file.project)?.getScriptDependencies(file.originalFile) - scriptDependencies?.imports?.map { + val refinedConfiguration = ScriptDependenciesProvider.getInstance(file.project)?.getScriptConfigurationResult(file.originalFile)?.valueOrNull() + refinedConfiguration?.defaultImports?.map { ScriptExtraImportImpl( ImportPath.fromString(it) ) diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/repl/GenericReplChecker.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/repl/GenericReplChecker.kt index 7dcc651d953..78bf3724ac4 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/repl/GenericReplChecker.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/repl/GenericReplChecker.kt @@ -25,8 +25,10 @@ import org.jetbrains.kotlin.parsing.KotlinParserDefinition import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.repl.messages.ConsoleDiagnosticMessageHolder import kotlin.concurrent.write +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration const val KOTLIN_REPL_JVM_TARGET_PROPERTY = "kotlin.repl.jvm.target" @@ -39,7 +41,7 @@ open class GenericReplChecker( internal val environment = run { compilerConfiguration.apply { - add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, scriptDefinition) + add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, ScriptDefinition.FromLegacy(defaultJvmScriptingHostConfiguration, scriptDefinition)) put(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, messageCollector) put(JVMConfigurationKeys.RETAIN_OUTPUT_IN_MEMORY, true) diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/repl/GenericReplCompiler.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/repl/GenericReplCompiler.kt index 98309aafcae..1fe24a87366 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/repl/GenericReplCompiler.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/repl/GenericReplCompiler.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import java.io.File import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.write +import kotlin.script.experimental.api.valueOrNull // WARNING: not thread safe, assuming external synchronization @@ -64,7 +65,9 @@ open class GenericReplCompiler( Pair(compilerState.lastLineState!!.psiFile, compilerState.lastLineState!!.errorHolder) } - val newDependencies = ScriptDependenciesProvider.getInstance(checker.environment.project)?.getScriptDependencies(psiFile) + val newDependencies = + ScriptDependenciesProvider.getInstance(checker.environment.project)?.getScriptConfigurationResult(psiFile)?.valueOrNull() + ?.legacyDependencies var classpathAddendum: List? = null if (compilerState.lastDependencies != newDependencies) { compilerState.lastDependencies = newDependencies diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt index a0e00e17a03..148c651800e 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/LazyScriptDescriptor.kt @@ -33,10 +33,10 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScopeImpl import org.jetbrains.kotlin.resolve.scopes.LexicalScopeKind import org.jetbrains.kotlin.resolve.source.toSourceElement -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.definitions.ScriptPriorities -import org.jetbrains.kotlin.scripting.definitions.scriptDefinitionByFileName +import org.jetbrains.kotlin.scripting.definitions.findScriptDefinitionByFileName import org.jetbrains.kotlin.types.TypeSubstitutor import org.jetbrains.kotlin.types.typeUtil.isNothing import org.jetbrains.kotlin.types.typeUtil.isUnit @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import java.io.File import kotlin.reflect.KClass import kotlin.reflect.KType +import kotlin.script.experimental.api.valueOrNull class LazyScriptDescriptor( @@ -104,8 +105,9 @@ class LazyScriptDescriptor( override fun getPriority() = priority - val scriptDefinition: () -> KotlinScriptDefinition = resolveSession.storageManager.createLazyValue { - scriptDefinitionByFileName( + // rewrite without using legacyDefinition below + val scriptDefinition: () -> ScriptDefinition = resolveSession.storageManager.createLazyValue { + findScriptDefinitionByFileName( resolveSession.project, scriptInfo.script.containingKtFile.name ) @@ -128,7 +130,7 @@ class LazyScriptDescriptor( override fun getUnsubstitutedPrimaryConstructor() = super.getUnsubstitutedPrimaryConstructor()!! internal val baseClassDescriptor: () -> ClassDescriptor? = resolveSession.storageManager.createNullableLazyValue { - val template = scriptDefinition().template + val template = scriptDefinition().legacyDefinition.template findTypeDescriptor( template, if (template.qualifiedName?.startsWith("kotlin.script.templates.standard") == true) Errors.MISSING_SCRIPT_STANDARD_TEMPLATE @@ -167,7 +169,7 @@ class LazyScriptDescriptor( val res = ArrayList() val importedScriptsFiles = ScriptDependenciesProvider.getInstance(scriptInfo.script.project) - ?.getScriptDependencies(scriptInfo.script.containingKtFile)?.scripts + ?.getScriptConfigurationResult(scriptInfo.script.containingKtFile)?.valueOrNull()?.importedScripts if (importedScriptsFiles != null) { val findImportedScriptDescriptor = ImportedScriptDescriptorsFinder() importedScriptsFiles.mapNotNullTo(res) { @@ -175,7 +177,7 @@ class LazyScriptDescriptor( } } - scriptDefinition().implicitReceivers.mapNotNullTo(res) { receiver -> + scriptDefinition().legacyDefinition.implicitReceivers.mapNotNullTo(res) { receiver -> findTypeDescriptor(receiver, Errors.MISSING_SCRIPT_RECEIVER_CLASS) } @@ -222,7 +224,7 @@ class LazyScriptDescriptor( private val scriptOuterScope: () -> LexicalScope = resolveSession.storageManager.createLazyValue { var outerScope = super.getOuterScope() val outerScopeReceivers = implicitReceivers.let { - if (scriptDefinition().providedProperties.isEmpty()) { + if (scriptDefinition().legacyDefinition.providedProperties.isEmpty()) { it } else { it + ScriptProvidedPropertiesDescriptor(this) diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptContentLoader.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptContentLoader.kt index 70c62bdccaf..cdcbcffb216 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptContentLoader.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptContentLoader.kt @@ -5,16 +5,10 @@ package org.jetbrains.kotlin.scripting.resolve -import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiManager -import org.jetbrains.kotlin.psi.KtAnnotationEntry -import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition import java.io.File -import kotlin.reflect.KClass import kotlin.script.dependencies.ScriptContents import kotlin.script.experimental.dependencies.DependenciesResolver import kotlin.script.experimental.dependencies.DependenciesResolver.ResolveResult.Failure @@ -22,43 +16,20 @@ import kotlin.script.experimental.dependencies.ScriptDependencies import kotlin.script.experimental.dependencies.ScriptReport class ScriptContentLoader(private val project: Project) { - fun getScriptContents(scriptDefinition: KotlinScriptDefinition, file: VirtualFile) - = BasicScriptContents( - file, - getAnnotations = { loadAnnotations(scriptDefinition, file) }) - - private fun loadAnnotations(scriptDefinition: KotlinScriptDefinition, file: VirtualFile): List { - val classLoader = scriptDefinition.template.java.classLoader - // TODO_R: report error on failure to load annotation class - return ApplicationManager.getApplication().runReadAction> { - getAnnotationEntries(file, project) - .mapNotNull { psiAnn -> - // TODO: consider advanced matching using semantic similar to actual resolving - scriptDefinition.acceptedAnnotations.find { ann -> - psiAnn.typeName.let { it == ann.simpleName || it == ann.qualifiedName } - }?.let { - @Suppress("UNCHECKED_CAST") - constructAnnotation( - psiAnn, - classLoader.loadClass(it.qualifiedName).kotlin as KClass, - project - ) - } - } - } - } - - private fun getAnnotationEntries(file: VirtualFile, project: Project): Iterable { - val psiFile: PsiFile = PsiManager.getInstance(project).findFile(file) - ?: throw IllegalArgumentException("Unable to load PSI from ${file.canonicalPath}") - return (psiFile as? KtFile)?.annotationEntries - ?: throw IllegalArgumentException("Unable to extract kotlin annotations from ${file.name} (${file.fileType})") - } + fun getScriptContents(scriptDefinition: KotlinScriptDefinition, file: VirtualFile) = + makeScriptContents( + file, + scriptDefinition, + project, + scriptDefinition.template::class.java.classLoader + ) class BasicScriptContents(virtualFile: VirtualFile, getAnnotations: () -> Iterable) : ScriptContents { override val file: File = File(virtualFile.path) override val annotations: Iterable by lazy(LazyThreadSafetyMode.PUBLICATION) { getAnnotations() } - override val text: CharSequence? by lazy(LazyThreadSafetyMode.PUBLICATION) { virtualFile.inputStream.reader(charset = virtualFile.charset).readText() } + override val text: CharSequence? by lazy(LazyThreadSafetyMode.PUBLICATION) { + virtualFile.inputStream.reader(charset = virtualFile.charset).readText() + } } fun loadContentsAndResolveDependencies( @@ -80,11 +51,11 @@ class ScriptContentLoader(private val project: Project) { } fun getEnvironment(scriptDef: KotlinScriptDefinition) = - (scriptDef as? KotlinScriptDefinitionFromAnnotatedTemplate)?.environment.orEmpty() + (scriptDef as? KotlinScriptDefinitionFromAnnotatedTemplate)?.environment.orEmpty() } fun ScriptDependencies.adjustByDefinition( - scriptDef: KotlinScriptDefinition + scriptDef: KotlinScriptDefinition ): ScriptDependencies { val additionalClasspath = (scriptDef as? KotlinScriptDefinitionFromAnnotatedTemplate)?.templateClasspath ?: return this if (additionalClasspath.isEmpty()) return this diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptProvidedPropertiesDescriptor.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptProvidedPropertiesDescriptor.kt index 0f20b7839eb..f17e7dea96f 100644 --- a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptProvidedPropertiesDescriptor.kt +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/ScriptProvidedPropertiesDescriptor.kt @@ -42,7 +42,7 @@ class ScriptProvidedPropertiesDescriptor(script: LazyScriptDescriptor) : override fun getUnsubstitutedMemberScope(): MemberScope = memberScope() val properties: () -> List = script.resolveSession.storageManager.createLazyValue { - script.scriptDefinition().providedProperties.mapNotNull { (name, type) -> + script.scriptDefinition().legacyDefinition.providedProperties.mapNotNull { (name, type) -> script.findTypeDescriptor(type, Errors.MISSING_SCRIPT_PROVIDED_PROPERTY_CLASS)?.let { name to it } diff --git a/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/refineCompilationConfiguration.kt b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/refineCompilationConfiguration.kt new file mode 100644 index 00000000000..5d8475458ed --- /dev/null +++ b/plugins/scripting/scripting-compiler-impl/src/org/jetbrains/kotlin/scripting/resolve/refineCompilationConfiguration.kt @@ -0,0 +1,338 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.scripting.resolve + +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.text.StringUtil +import com.intellij.openapi.vfs.CharsetToolkit +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import com.intellij.testFramework.LightVirtualFile +import kotlinx.coroutines.runBlocking +import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.psi.KtAnnotationEntry +import org.jetbrains.kotlin.psi.KtFile +import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition +import java.io.File +import java.net.URL +import kotlin.reflect.KClass +import kotlin.script.experimental.api.* +import kotlin.script.experimental.dependencies.AsyncDependenciesResolver +import kotlin.script.experimental.dependencies.DependenciesResolver +import kotlin.script.experimental.dependencies.ScriptDependencies +import kotlin.script.experimental.host.* +import kotlin.script.experimental.jvm.JvmGetScriptingClass +import kotlin.script.experimental.jvm.compat.mapToDiagnostics +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration +import kotlin.script.experimental.jvm.impl.refineWith +import kotlin.script.experimental.jvm.impl.toClassPathOrEmpty +import kotlin.script.experimental.jvm.impl.toDependencies +import kotlin.script.experimental.jvm.jdkHome +import kotlin.script.experimental.jvm.jvm + +internal fun VirtualFile.loadAnnotations( + acceptedAnnotations: List>, + project: Project, + classLoader: ClassLoader? +): List = +// TODO_R: report error on failure to load annotation class + ApplicationManager.getApplication().runReadAction> { + this.getAnnotationEntries(project).construct(classLoader, acceptedAnnotations, project) + } + +internal fun VirtualFile.getAnnotationEntries(project: Project): Iterable { + val psiFile: PsiFile = PsiManager.getInstance(project).findFile(this) + ?: throw IllegalArgumentException("Unable to load PSI from $canonicalPath") + return (psiFile as? KtFile)?.annotationEntries + ?: throw IllegalArgumentException("Unable to extract kotlin annotations from $name ($fileType)") +} + +/** + * The implementation of the SourceCode for a script located in a virtual file + */ +open class VirtualFileScriptSource(val virtualFile: VirtualFile, private val preloadedText: String? = null) : + FileBasedScriptSource() +{ + override val file: File get() = File(virtualFile.path) + override val externalLocation: URL get() = URL(virtualFile.url) + override val text: String by lazy { preloadedText ?: virtualFile.inputStream.bufferedReader().readText() } + override val name: String? get() = virtualFile.name + override val locationId: String? get() = virtualFile.path + + override fun equals(other: Any?): Boolean = + this === other || (other as? VirtualFileScriptSource)?.let { virtualFile == it.virtualFile } == true + + override fun hashCode(): Int = virtualFile.hashCode() +} + +/** + * The implementation of the SourceCode for a script located in a KtFile + */ +open class KtFileScriptSource(val ktFile: KtFile, preloadedText: String? = null) : + VirtualFileScriptSource(ktFile.virtualFile ?: ktFile.originalFile.virtualFile, preloadedText) { + + override val text: String by lazy { preloadedText ?: ktFile.text } + override val name: String? get() = ktFile.name + + override fun equals(other: Any?): Boolean = + this === other + || (other as? KtFileScriptSource)?.let { ktFile == it.ktFile } == true + || super.equals(other) + + override fun hashCode(): Int = ktFile.hashCode() +} + +class ScriptLightVirtualFile(name: String, private val _path: String?, text: String) : + LightVirtualFile( + name, + KotlinLanguage.INSTANCE, + StringUtil.convertLineSeparators(text) + ) { + + init { + charset = CharsetToolkit.UTF8_CHARSET + } + + override fun getPath(): String = _path ?: super.getPath() + override fun getCanonicalPath(): String? = path +} + +abstract class ScriptCompilationConfigurationWrapper(val script: SourceCode) { + abstract val configuration: ScriptCompilationConfiguration? + + @Deprecated("Use configuration collection instead") + abstract val legacyDependencies: ScriptDependencies? + + // optimizing most common ops for the IDE + // TODO: consider dropping after complete migration + abstract val dependenciesClassPath: List + abstract val dependenciesSources: List + abstract val javaHome: File? + abstract val defaultImports: List + abstract val importedScripts: List + + override fun equals(other: Any?): Boolean = script == (other as? ScriptCompilationConfigurationWrapper)?.script + + override fun hashCode(): Int = script.hashCode() + + class FromCompilationConfiguration( + script: SourceCode, + override val configuration: ScriptCompilationConfiguration? + ) : ScriptCompilationConfigurationWrapper(script) { + + // TODO: check whether implemented optimization for frequent calls makes sense here + override val dependenciesClassPath: List by lazy { + configuration?.get(ScriptCompilationConfiguration.dependencies).toClassPathOrEmpty() + } + + // TODO: check whether implemented optimization for frequent calls makes sense here + override val dependenciesSources: List by lazy { + configuration?.get(ScriptCompilationConfiguration.ide.dependenciesSources).toClassPathOrEmpty() + } + + override val javaHome: File? + get() = configuration?.get(ScriptCompilationConfiguration.hostConfiguration)?.get(ScriptingHostConfiguration.jvm.jdkHome) + + override val defaultImports: List + get() = configuration?.get(ScriptCompilationConfiguration.defaultImports).orEmpty() + + override val importedScripts: List + get() = configuration?.get(ScriptCompilationConfiguration.importScripts) + ?.mapNotNull { (it as? FileBasedScriptSource)?.file }.orEmpty() + + override val legacyDependencies: ScriptDependencies? + get() = configuration?.toDependencies(dependenciesClassPath) + + override fun equals(other: Any?): Boolean = + super.equals(other) && other is FromCompilationConfiguration && configuration == other.configuration + + override fun hashCode(): Int = super.hashCode() + 23 * (configuration?.hashCode() ?: 1) + } + + class FromLegacy( + script: SourceCode, + override val legacyDependencies: ScriptDependencies? + ) : ScriptCompilationConfigurationWrapper(script) { + + override val dependenciesClassPath: List + get() = legacyDependencies?.classpath.orEmpty() + + override val dependenciesSources: List + get() = legacyDependencies?.sources.orEmpty() + + override val javaHome: File? + get() = legacyDependencies?.javaHome + + override val defaultImports: List + get() = legacyDependencies?.imports.orEmpty() + + override val importedScripts: List + get() = legacyDependencies?.scripts.orEmpty() + + override val configuration: ScriptCompilationConfiguration? + get() = legacyDependencies?.let { + TODO("drop or implement") + } + + override fun equals(other: Any?): Boolean = + super.equals(other) && other is FromLegacy && legacyDependencies == other.legacyDependencies + + override fun hashCode(): Int = super.hashCode() + 31 * (legacyDependencies?.hashCode() ?: 1) + } +} + +typealias ScriptCompilationConfigurationResult = ResultWithDiagnostics + +fun refineScriptCompilationConfiguration( + script: SourceCode, + definition: ScriptDefinition, + project: Project +): ScriptCompilationConfigurationResult { + val ktFileSource = script.toKtFileSource(definition, project) + val legacyDefinition = definition.asLegacyOrNull() + if (legacyDefinition == null) { + val compilationConfiguration = definition.compilationConfiguration + val collectedData = + getScriptCollectedData(ktFileSource.ktFile, compilationConfiguration, project, definition.contextClassLoader) + + return compilationConfiguration.refineWith( + compilationConfiguration[ScriptCompilationConfiguration.refineConfigurationOnAnnotations]?.handler, collectedData, script + ).onSuccess { + it.refineWith( + compilationConfiguration[ScriptCompilationConfiguration.refineConfigurationBeforeCompiling]?.handler, collectedData, script + ) + }.onSuccess { + ScriptCompilationConfigurationWrapper.FromCompilationConfiguration(ktFileSource, it).asSuccess() + } + } else { + val file = script.getVirtualFile(definition) + val scriptContents = + makeScriptContents(file, legacyDefinition, project, definition.contextClassLoader) + val environment = (legacyDefinition as? KotlinScriptDefinitionFromAnnotatedTemplate)?.environment.orEmpty() + + val result: DependenciesResolver.ResolveResult = try { + val resolver = legacyDefinition.dependencyResolver + if (resolver is AsyncDependenciesResolver) { + // since the only known async resolver is gradle, the following logic is taken from AsyncScriptDependenciesLoader + // runBlocking is using there to avoid loading dependencies asynchronously + // because it leads to starting more than one gradle daemon in case of resolving dependencies in build.gradle.kts + // It is more efficient to use one hot daemon consistently than multiple daemon in parallel + runBlocking { + resolver.resolveAsync(scriptContents, environment) + } + } else { + resolver.resolve(scriptContents, environment) + } + } catch (e: Throwable) { + return makeFailureResult(e.asDiagnostics(severity = ScriptDiagnostic.Severity.FATAL)) + } + return if (result is DependenciesResolver.ResolveResult.Failure) + makeFailureResult( + result.reports.mapToDiagnostics() + ) + else + ScriptCompilationConfigurationWrapper.FromLegacy( + ktFileSource, + result.dependencies?.adjustByDefinition(definition.legacyDefinition) + ).asSuccess(result.reports.mapToDiagnostics()) + } +} + +internal fun makeScriptContents( + file: VirtualFile, + legacyDefinition: KotlinScriptDefinition, + project: Project, + classLoader: ClassLoader? +): ScriptContentLoader.BasicScriptContents = + ScriptContentLoader.BasicScriptContents( + file, + getAnnotations = { + file.loadAnnotations(legacyDefinition.acceptedAnnotations, project, classLoader) + }) + +fun SourceCode.getVirtualFile(definition: ScriptDefinition): VirtualFile { + if (this is VirtualFileScriptSource) return virtualFile + if (this is KtFileScriptSource) { + val vFile = virtualFile + if (vFile != null) return vFile + } + if (this is FileScriptSource) { + val vFile = LocalFileSystem.getInstance().findFileByIoFile(file) + if (vFile != null) return vFile + } + val scriptName = name ?: "script.${definition.fileExtension}" + val scriptPath = when (this) { + is FileScriptSource -> file.path + is ExternalSourceCode -> externalLocation.toString() + else -> null + } + val scriptText = definition.asLegacyOrNull()?.let { text } + ?: getMergedScriptText(this, definition.compilationConfiguration) + + return ScriptLightVirtualFile(scriptName, scriptPath, scriptText) +} + +fun SourceCode.getKtFile(definition: ScriptDefinition, project: Project): KtFile = + if (this is KtFileScriptSource) ktFile + else { + val file = getVirtualFile(definition) + ApplicationManager.getApplication().runReadAction { + val psiFile: PsiFile = PsiManager.getInstance(project).findFile(file) + ?: throw IllegalArgumentException("Unable to load PSI from ${file.path}") + (psiFile as? KtFile) + ?: throw IllegalArgumentException("Not a kotlin file ${file.path} (${file.fileType})") + } + } + +fun SourceCode.toKtFileSource(definition: ScriptDefinition, project: Project): KtFileScriptSource = + if (this is KtFileScriptSource) this + else { + KtFileScriptSource(this.getKtFile(definition, project)) + } + +fun getScriptCollectedData( + scriptFile: KtFile, + compilationConfiguration: ScriptCompilationConfiguration, + project: Project, + contextClassLoader: ClassLoader? +): ScriptCollectedData { + val hostConfiguration = + compilationConfiguration[ScriptCompilationConfiguration.hostConfiguration] ?: defaultJvmScriptingHostConfiguration + val getScriptingClass = hostConfiguration[ScriptingHostConfiguration.getScriptingClass] + val jvmGetScriptingClass = (getScriptingClass as? JvmGetScriptingClass) + ?: throw IllegalArgumentException("Expecting JvmGetScriptingClass in the hostConfiguration[getScriptingClass], got $getScriptingClass") + val acceptedAnnotations = + compilationConfiguration[ScriptCompilationConfiguration.refineConfigurationOnAnnotations]?.annotations?.mapNotNull { + jvmGetScriptingClass(it, contextClassLoader, hostConfiguration) as? KClass // TODO errors + }.orEmpty() + val annotations = scriptFile.annotationEntries.construct(contextClassLoader, acceptedAnnotations, project) + return ScriptCollectedData( + mapOf( + ScriptCollectedData.foundAnnotations to annotations + ) + ) +} + +private fun Iterable.construct( + classLoader: ClassLoader?, acceptedAnnotations: List>, project: Project +): List = + mapNotNull { psiAnn -> + // TODO: consider advanced matching using semantic similar to actual resolving + acceptedAnnotations.find { ann -> + psiAnn.typeName.let { it == ann.simpleName || it == ann.qualifiedName } + }?.let { + @Suppress("UNCHECKED_CAST") + (constructAnnotation( + psiAnn, + (classLoader ?: ClassLoader.getSystemClassLoader()).loadClass(it.qualifiedName).kotlin as KClass, + project + )) + } + } \ No newline at end of file diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JvmCliScriptEvaluationExtension.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JvmCliScriptEvaluationExtension.kt index cafe14dda2f..e2fbc8f1b52 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JvmCliScriptEvaluationExtension.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/JvmCliScriptEvaluationExtension.kt @@ -43,7 +43,7 @@ class JvmCliScriptEvaluationExtension : ScriptEvaluationExtension { val scriptFile = File(sourcePath) if (scriptFile.isDirectory || !scriptDefinitionProvider.isScript(scriptFile.name)) { val extensionHint = - if (configuration.get(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS) == listOf(StandardScriptDefinition)) " (.kts)" + if (configuration.get(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS)?.let { it.size == 1 && it.first().isDefault } == true) " (.kts)" else "" messageCollector.report(ERROR, "Specify path to the script file$extensionHint as the first argument") return COMPILATION_ERROR diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt index ec8be9821dd..f5e0582a8ec 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerConfigurationExtension.kt @@ -18,13 +18,14 @@ import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDefinitionProvider import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys import org.jetbrains.kotlin.scripting.configuration.configureScriptDefinitions -import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider -import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsFromClasspathDiscoverySource -import org.jetbrains.kotlin.scripting.definitions.StandardScriptDefinition -import org.jetbrains.kotlin.scripting.definitions.reporter +import org.jetbrains.kotlin.scripting.definitions.* import java.io.File +import kotlin.script.experimental.host.ScriptingHostConfiguration -class ScriptingCompilerConfigurationExtension(val project: MockProject) : CompilerConfigurationExtension { +class ScriptingCompilerConfigurationExtension( + val project: MockProject, + val baseHostConfiguration: ScriptingHostConfiguration +) : CompilerConfigurationExtension { override fun updateConfiguration(configuration: CompilerConfiguration) { @@ -39,7 +40,11 @@ class ScriptingCompilerConfigurationExtension(val project: MockProject) : Compil projectRoot ) } - val scriptResolverEnv = configuration.getMap(ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION) + val hostConfiguration = ScriptingHostConfiguration(baseHostConfiguration) { + getEnvironment { + configuration.getMap(ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION) + } + } val explicitScriptDefinitions = configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_CLASSES) @@ -49,16 +54,16 @@ class ScriptingCompilerConfigurationExtension(val project: MockProject) : Compil configuration, this::class.java.classLoader, messageCollector, - scriptResolverEnv + hostConfiguration ) } // If not disabled explicitly, we should always support at least the standard script definition if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) && - !configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS).contains(StandardScriptDefinition) + configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS).none { it.isDefault } ) { configuration.add( ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, - StandardScriptDefinition + ScriptDefinition.getDefault(hostConfiguration) ) } @@ -66,37 +71,26 @@ class ScriptingCompilerConfigurationExtension(val project: MockProject) : Compil ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_SOURCES, ScriptDefinitionsFromClasspathDiscoverySource( configuration.jvmClasspathRoots, - configuration.get(ScriptingConfigurationKeys.LEGACY_SCRIPT_RESOLVER_ENVIRONMENT_OPTION) ?: emptyMap(), + hostConfiguration, messageCollector.reporter ) ) - } - // If not disabled explicitly, we should always support at least the standard script definition - if (!configuration.getBoolean(JVMConfigurationKeys.DISABLE_STANDARD_SCRIPT_DEFINITION) && - StandardScriptDefinition !in configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS) - ) { - configuration.add( - ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, - StandardScriptDefinition - ) - } + val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider + if (scriptDefinitionProvider != null) { + scriptDefinitionProvider.setScriptDefinitionsSources(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_SOURCES)) + scriptDefinitionProvider.setScriptDefinitions(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS)) - val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider - if (scriptDefinitionProvider != null) { - scriptDefinitionProvider.setScriptDefinitionsSources(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS_SOURCES)) - scriptDefinitionProvider.setScriptDefinitions(configuration.getList(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS)) + // Register new file extensions + val fileTypeRegistry = FileTypeRegistry.getInstance() as CoreFileTypeRegistry - // Register new file extensions - val fileTypeRegistry = FileTypeRegistry.getInstance() as CoreFileTypeRegistry - - scriptDefinitionProvider.getKnownFilenameExtensions().filter { - fileTypeRegistry.getFileTypeByExtension(it) != KotlinFileType.INSTANCE - }.forEach { - fileTypeRegistry.registerFileType(KotlinFileType.INSTANCE, it) + scriptDefinitionProvider.getKnownFilenameExtensions().filter { + fileTypeRegistry.getFileTypeByExtension(it) != KotlinFileType.INSTANCE + }.forEach { + fileTypeRegistry.registerFileType(KotlinFileType.INSTANCE, it) + } } } - } } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/definitions/CliScriptDefinitionProvider.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/definitions/CliScriptDefinitionProvider.kt index b4b9e6291d9..28b33009c47 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/definitions/CliScriptDefinitionProvider.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/definitions/CliScriptDefinitionProvider.kt @@ -5,33 +5,29 @@ package org.jetbrains.kotlin.scripting.compiler.plugin.definitions -import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition import org.jetbrains.kotlin.scripting.definitions.LazyScriptDefinitionProvider +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource -import org.jetbrains.kotlin.scripting.definitions.StandardScriptDefinition import kotlin.concurrent.write open class CliScriptDefinitionProvider : LazyScriptDefinitionProvider() { - private val definitionsFromSources: MutableList> = arrayListOf() - private val definitions: MutableList = arrayListOf() - private var hasStandardDefinition = true + private val definitionsFromSources: MutableList> = arrayListOf() + private val definitions: MutableList = arrayListOf() + private var defaultDefinition: ScriptDefinition? = null - override val currentDefinitions: Sequence + override val currentDefinitions: Sequence get() { val base = definitions.asSequence() + definitionsFromSources.asSequence().flatMap { it } - return if (hasStandardDefinition) base + getDefaultScriptDefinition() else base + return base + getDefaultDefinition() } - override fun getDefaultScriptDefinition(): KotlinScriptDefinition { - return StandardScriptDefinition - } - - fun setScriptDefinitions(newDefinitions: List) { + fun setScriptDefinitions(newDefinitions: List) { lock.write { definitions.clear() - val (withoutStdDef, stdDef) = newDefinitions.partition { it != getDefaultScriptDefinition() } + val (withoutStdDef, stdDef) = newDefinitions.partition { !it.isDefault } definitions.addAll(withoutStdDef) - hasStandardDefinition = stdDef.isNotEmpty() + // TODO: consider reporting an error when several default definitions are supplied + defaultDefinition = stdDef.firstOrNull() } } @@ -43,4 +39,6 @@ open class CliScriptDefinitionProvider : LazyScriptDefinitionProvider() { } } } + + override fun getDefaultDefinition(): ScriptDefinition = defaultDefinition ?: super.getDefaultDefinition() } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/definitions/CliScriptDependenciesProvider.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/definitions/CliScriptDependenciesProvider.kt index 3f06594765f..f5d14313e6e 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/definitions/CliScriptDependenciesProvider.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/definitions/CliScriptDependenciesProvider.kt @@ -11,44 +11,45 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.definitions.findScriptDefinition -import org.jetbrains.kotlin.scripting.resolve.ScriptContentLoader +import org.jetbrains.kotlin.scripting.resolve.ScriptCompilationConfigurationResult import org.jetbrains.kotlin.scripting.resolve.ScriptReportSink -import org.jetbrains.kotlin.scripting.resolve.adjustByDefinition +import org.jetbrains.kotlin.scripting.resolve.VirtualFileScriptSource +import org.jetbrains.kotlin.scripting.resolve.refineScriptCompilationConfiguration import java.io.File import java.util.concurrent.locks.ReentrantReadWriteLock import kotlin.concurrent.read import kotlin.concurrent.write -import kotlin.script.experimental.dependencies.ScriptDependencies +import kotlin.script.experimental.api.ResultWithDiagnostics +import kotlin.script.experimental.jvm.compat.mapToLegacyReports class CliScriptDependenciesProvider(private val project: Project) : ScriptDependenciesProvider { private val cacheLock = ReentrantReadWriteLock() - private val cache = hashMapOf() - private val scriptContentLoader = ScriptContentLoader(project) + private val cache = hashMapOf() - override fun getScriptDependencies(file: VirtualFile): ScriptDependencies? = cacheLock.read { - calculateExternalDependencies(file) + override fun getScriptConfigurationResult(file: VirtualFile): ScriptCompilationConfigurationResult? = cacheLock.read { + calculateRefinedConfiguration(file) } - private fun calculateExternalDependencies(file: VirtualFile): ScriptDependencies? { + private fun calculateRefinedConfiguration(file: VirtualFile): ScriptCompilationConfigurationResult? { val path = file.path val cached = cache[path] return if (cached != null) cached else { val scriptDef = file.findScriptDefinition(project) if (scriptDef != null) { - val result = scriptContentLoader.loadContentsAndResolveDependencies(scriptDef, file) + val result = refineScriptCompilationConfiguration(VirtualFileScriptSource(file), scriptDef, project) - ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports) + ServiceManager.getService(project, ScriptReportSink::class.java)?.attachReports(file, result.reports.mapToLegacyReports()) - val deps = result.dependencies?.adjustByDefinition(scriptDef) - - if (deps != null) { - log.info("[kts] new cached deps for $path: ${deps.classpath.joinToString(File.pathSeparator)}") + if (result is ResultWithDiagnostics.Success) { + log.info("[kts] new cached deps for $path: ${result.value.dependenciesClassPath.joinToString(File.pathSeparator)}") + } else { + log.info("[kts] new cached errors for $path:\n ${result.reports.joinToString("\n ") { it.message + if (it.exception == null) "" else ": ${it.exception}" }}") } cacheLock.write { - cache.put(path, deps) + cache.put(path, result) } - deps + result } else null } } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt index a6728ca45de..3c2f05853ed 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/pluginRegisrar.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.resolve.extensions.SyntheticResolveExtension import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDefinitionProvider import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDependenciesProvider import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptReportSink +import org.jetbrains.kotlin.scripting.configuration.makeHostConfiguration import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionProvider import org.jetbrains.kotlin.scripting.definitions.ScriptDependenciesProvider import org.jetbrains.kotlin.scripting.extensions.* @@ -39,8 +40,9 @@ private fun ProjectExtensionDescriptor.registerExtensionIfRequired(projec class ScriptingCompilerConfigurationComponentRegistrar : ComponentRegistrar { override fun registerProjectComponents(project: MockProject, configuration: CompilerConfiguration) { val messageCollector = configuration.get(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) + val hostConfiguration = makeHostConfiguration(project, configuration) withClassloadingProblemsReporting(messageCollector) { - CompilerConfigurationExtension.registerExtension(project, ScriptingCompilerConfigurationExtension(project)) + CompilerConfigurationExtension.registerExtension(project, ScriptingCompilerConfigurationExtension(project, hostConfiguration)) CollectAdditionalSourcesExtension.registerExtension(project, ScriptingCollectAdditionalSourcesExtension(project)) ScriptEvaluationExtension.registerExtensionIfRequired(project, JvmCliScriptEvaluationExtension()) ShellExtension.registerExtensionIfRequired(project, JvmCliReplShellExtension()) diff --git a/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptProviderTest.kt b/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptProviderTest.kt index 2ff5e67c819..857788ab8ac 100644 --- a/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptProviderTest.kt +++ b/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptProviderTest.kt @@ -7,11 +7,13 @@ package org.jetbrains.kotlin.scripting.compiler.plugin import org.jetbrains.kotlin.scripting.compiler.plugin.definitions.CliScriptDefinitionProvider import org.jetbrains.kotlin.scripting.definitions.KotlinScriptDefinition +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.ScriptDefinitionsSource import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase import org.junit.Assert import org.junit.Test import java.util.concurrent.atomic.AtomicInteger +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration import kotlin.script.templates.standard.ScriptTemplateWithArgs class ScriptProviderTest : KtUsefulTestCase() { @@ -64,11 +66,16 @@ class ScriptProviderTest : KtUsefulTestCase() { } } -private open class FakeScriptDefinition(val suffix: String = ".kts") : KotlinScriptDefinition(ScriptTemplateWithArgs::class) { +private open class FakeScriptDefinition(val suffix: String = ".kts") : + ScriptDefinition.FromLegacy(defaultJvmScriptingHostConfiguration, KotlinScriptDefinition(ScriptTemplateWithArgs::class)) +{ val matchCounter = AtomicInteger() override fun isScript(fileName: String): Boolean = fileName.endsWith(suffix).also { if (it) matchCounter.incrementAndGet() } + + override val isDefault: Boolean + get() = suffix == ".kts" } private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens: Iterable<() -> FakeScriptDefinition>) : @@ -80,7 +87,7 @@ private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens ) } }) - override val definitions: Sequence = sequence { + override val definitions: Sequence = sequence { for (gen in defGens) { counter.incrementAndGet() yield(gen()) @@ -88,6 +95,6 @@ private class TestScriptDefinitionSource(val counter: AtomicInteger, val defGens } } -private class TestCliScriptDefinitionProvider(private val standardDef: KotlinScriptDefinition) : CliScriptDefinitionProvider() { - override fun getDefaultScriptDefinition(): KotlinScriptDefinition = standardDef +private class TestCliScriptDefinitionProvider(private val standardDef: ScriptDefinition) : CliScriptDefinitionProvider() { + override fun getDefaultScriptDefinition(): KotlinScriptDefinition = standardDef.legacyDefinition } \ No newline at end of file diff --git a/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerPluginTest.kt b/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerPluginTest.kt index 9827d64c68a..00e61e59532 100644 --- a/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerPluginTest.kt +++ b/plugins/scripting/scripting-compiler/tests/org/jetbrains/kotlin/scripting/compiler/plugin/ScriptingCompilerPluginTest.kt @@ -35,6 +35,7 @@ import org.jetbrains.kotlin.utils.KotlinPaths import org.jetbrains.kotlin.utils.PathUtil import org.junit.Assert import java.io.File +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration class ScriptingCompilerPluginTest : TestCaseWithTmpdir() { @@ -116,7 +117,7 @@ class ScriptingCompilerPluginTest : TestCaseWithTmpdir() { loadScriptTemplatesFromClasspath( listOf("TestScriptWithReceivers", "TestScriptWithSimpleEnvVars"), - listOf(defsOut), emptyList(), this::class.java.classLoader, emptyMap(), messageCollector.reporter + listOf(defsOut), emptyList(), this::class.java.classLoader, defaultJvmScriptingHostConfiguration, messageCollector.reporter ).toList() for (def in defClasses) { @@ -141,7 +142,7 @@ class ScriptingCompilerPluginTest : TestCaseWithTmpdir() { discoverScriptTemplatesInClasspath( listOf(defsOut), this::class.java.classLoader, - emptyMap(), + defaultJvmScriptingHostConfiguration, messageCollector.reporter ) @@ -212,7 +213,7 @@ class ScriptingCompilerPluginTest : TestCaseWithTmpdir() { discoverScriptTemplatesInClasspath( listOf(defsOut), this::class.java.classLoader, - emptyMap(), + defaultJvmScriptingHostConfiguration, messageCollector.reporter ).toList() diff --git a/plugins/source-sections/source-sections-compiler/tests/org/jetbrains/kotlin/sourceSections/SourceSectionsTest.kt b/plugins/source-sections/source-sections-compiler/tests/org/jetbrains/kotlin/sourceSections/SourceSectionsTest.kt index cf4cce17c52..3a236734e74 100644 --- a/plugins/source-sections/source-sections-compiler/tests/org/jetbrains/kotlin/sourceSections/SourceSectionsTest.kt +++ b/plugins/source-sections/source-sections-compiler/tests/org/jetbrains/kotlin/sourceSections/SourceSectionsTest.kt @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.daemon.common.* import org.jetbrains.kotlin.integration.KotlinIntegrationTestBase.getKotlinPaths import org.jetbrains.kotlin.script.loadScriptingPlugin import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys +import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition import org.jetbrains.kotlin.scripting.definitions.StandardScriptDefinition import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.KotlinTestUtils @@ -46,6 +47,7 @@ import java.lang.management.ManagementFactory import java.net.URLClassLoader import java.nio.charset.Charset import java.util.concurrent.TimeUnit +import kotlin.script.experimental.jvm.defaultJvmScriptingHostConfiguration class SourceSectionsTest : TestCaseWithTmpdir() { @@ -73,7 +75,7 @@ class SourceSectionsTest : TestCaseWithTmpdir() { CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY, PrintingMessageCollector(System.err, MessageRenderer.PLAIN_FULL_PATHS, false) ) - configuration.add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, StandardScriptDefinition) + configuration.add(ScriptingConfigurationKeys.SCRIPT_DEFINITIONS, ScriptDefinition.getDefault(defaultJvmScriptingHostConfiguration)) if (withSourceSectionsPlugin) { configuration.addAll(SourceSectionsConfigurationKeys.SECTIONS_OPTION, TEST_ALLOWED_SECTIONS) configuration.add(ComponentRegistrar.PLUGIN_COMPONENT_REGISTRARS, SourceSectionsComponentRegistrar())