Scripting: avoid definitions discovery when compiling regular kotlin
If only regular kotlin .kt (and .java) files are compiled, do not register file extensions that may come from discovered script definitions. Since the discovery is lazy by itself, this should skip jars processing for regular compilation scenarios without scripts. #KT-47816 fixed
This commit is contained in:
@@ -5,6 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.cli.jvm.compiler
|
||||
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.vfs.StandardFileSystems
|
||||
@@ -19,9 +21,11 @@ import org.jetbrains.kotlin.cli.common.messages.MessageCollector
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||
import org.jetbrains.kotlin.config.JVMConfigurationKeys
|
||||
import org.jetbrains.kotlin.extensions.CompilerConfigurationExtension
|
||||
import org.jetbrains.kotlin.extensions.PreprocessedFileCreator
|
||||
import org.jetbrains.kotlin.idea.KotlinFileType
|
||||
import org.jetbrains.kotlin.modules.Module
|
||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
|
||||
import java.io.File
|
||||
@@ -43,6 +47,8 @@ inline fun List<KotlinSourceRoot>.forAllFiles(
|
||||
|
||||
val virtualFileCreator = PreprocessedFileCreator(project)
|
||||
|
||||
var pluginsConfigured = false
|
||||
|
||||
for ((sourceRootPath, isCommon) in this) {
|
||||
val sourceRoot = File(sourceRootPath)
|
||||
val vFile = localFileSystem.findFileByPath(sourceRoot.normalize().path)
|
||||
@@ -59,9 +65,15 @@ inline fun List<KotlinSourceRoot>.forAllFiles(
|
||||
continue
|
||||
}
|
||||
|
||||
if (!vFile.isDirectory && vFile.extension != KotlinFileType.EXTENSION && vFile.fileType != KotlinFileType.INSTANCE) {
|
||||
configuration.report(CompilerMessageSeverity.ERROR, "Source entry is not a Kotlin file: $sourceRootPath", reportLocation)
|
||||
continue
|
||||
if (!vFile.isDirectory && vFile.extension != KotlinFileType.EXTENSION) {
|
||||
if (!pluginsConfigured) {
|
||||
vFile.registerPluginsSuppliedExtensionsIfNeeded(project)
|
||||
pluginsConfigured = true
|
||||
}
|
||||
if (vFile.fileType != KotlinFileType.INSTANCE) {
|
||||
configuration.report(CompilerMessageSeverity.ERROR, "Source entry is not a Kotlin file: $sourceRootPath", reportLocation)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
for (file in sourceRoot.walkTopDown()) {
|
||||
@@ -69,12 +81,29 @@ inline fun List<KotlinSourceRoot>.forAllFiles(
|
||||
|
||||
val virtualFile = localFileSystem.findFileByPath(file.absoluteFile.normalize().path)?.let(virtualFileCreator::create)
|
||||
if (virtualFile != null && processedFiles.add(virtualFile)) {
|
||||
if (!pluginsConfigured) {
|
||||
virtualFile.registerPluginsSuppliedExtensionsIfNeeded(project)
|
||||
pluginsConfigured = true
|
||||
}
|
||||
body(virtualFile, isCommon)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun VirtualFile.registerPluginsSuppliedExtensionsIfNeeded(project: Project) {
|
||||
if (
|
||||
extension == null ||
|
||||
extension == KotlinFileType.EXTENSION ||
|
||||
extension == JavaFileType.INSTANCE.defaultExtension ||
|
||||
extension == JavaClassFileType.INSTANCE.defaultExtension ||
|
||||
fileType == KotlinFileType.INSTANCE
|
||||
) return
|
||||
for (extension in CompilerConfigurationExtension.getInstances(project)) {
|
||||
extension.updateFileRegistry()
|
||||
}
|
||||
}
|
||||
|
||||
fun createSourceFilesFromSourceRoots(
|
||||
configuration: CompilerConfiguration,
|
||||
project: Project,
|
||||
|
||||
+2
@@ -15,4 +15,6 @@ interface CompilerConfigurationExtension {
|
||||
)
|
||||
|
||||
fun updateConfiguration(configuration: CompilerConfiguration)
|
||||
|
||||
fun updateFileRegistry() {}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ build:
|
||||
[kotlin2js] Compiling [[TestData]/root1] => [[Temp]/out.js]
|
||||
[kotlin2js] logging: using Kotlin home directory [KotlinProjectHome]/dist/kotlinc
|
||||
[kotlin2js] logging: exception on loading scripting plugin: java.lang.ClassNotFoundException: org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar
|
||||
[kotlin2js] logging: configure scripting: Added template org.jetbrains.kotlin.mainKts.MainKtsScript from [[CompilerLib]/kotlin-main-kts.jar, [CompilerLib]/kotlin-reflect.jar, [CompilerLib]/kotlin-script-runtime.jar, [CompilerLib]/kotlin-stdlib.jar]
|
||||
[kotlin2js] logging: compiling source files: [TestData]/root1/foo.kt
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
|
||||
@@ -7,7 +7,6 @@ build:
|
||||
[kotlinc] logging: exception on loading scripting plugin: java.lang.ClassNotFoundException: org.jetbrains.kotlin.scripting.compiler.plugin.ScriptingCompilerConfigurationComponentRegistrar
|
||||
[kotlinc] logging: using JVM IR backend
|
||||
[kotlinc] logging: configuring the compilation environment
|
||||
[kotlinc] logging: configure scripting: Added template org.jetbrains.kotlin.mainKts.MainKtsScript from [[CompilerLib]/kotlin-main-kts.jar, [CompilerLib]/kotlin-reflect.jar, [CompilerLib]/kotlin-script-runtime.jar, [CompilerLib]/kotlin-stdlib.jar]
|
||||
|
||||
BUILD SUCCESSFUL
|
||||
Total time: [time]
|
||||
|
||||
+10
-2
@@ -6,10 +6,18 @@
|
||||
package org.jetbrains.kotlin.test
|
||||
|
||||
import kotlin.script.experimental.annotations.*
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.isStandalone
|
||||
|
||||
@KotlinScript(fileExtension = "greet.kts")
|
||||
@KotlinScript(fileExtension = "greet.kts", compilationConfiguration = GreetScriptDefinition::class)
|
||||
abstract class GreetScriptTemplate {
|
||||
fun greet(subject: String) {
|
||||
println("Hello, $subject!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object GreetScriptDefinition : ScriptCompilationConfiguration(
|
||||
{
|
||||
isStandalone(false)
|
||||
}
|
||||
)
|
||||
|
||||
+11
-3
@@ -5,11 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.test
|
||||
|
||||
import kotlin.script.experimental.annotations.*
|
||||
import kotlin.script.experimental.annotations.KotlinScript
|
||||
import kotlin.script.experimental.api.ScriptCompilationConfiguration
|
||||
import kotlin.script.experimental.api.isStandalone
|
||||
|
||||
@KotlinScript(fileExtension = "greet")
|
||||
@KotlinScript(fileExtension = "greet", compilationConfiguration = GreetScriptDefinition::class)
|
||||
abstract class GreetScriptTemplate {
|
||||
fun greet(subject: String) {
|
||||
println("Hello, $subject!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object GreetScriptDefinition : ScriptCompilationConfiguration(
|
||||
{
|
||||
isStandalone(false)
|
||||
}
|
||||
)
|
||||
|
||||
+1
@@ -39,6 +39,7 @@ class ScriptDefinitionsFromClasspathDiscoverySource(
|
||||
|
||||
private const val MANIFEST_RESOURCE_NAME = "/META-INF/MANIFEST.MF"
|
||||
|
||||
@Suppress("unused") // TODO: remove if really unused
|
||||
fun discoverScriptTemplatesInClassLoader(
|
||||
classLoader: ClassLoader,
|
||||
hostConfiguration: ScriptingHostConfiguration,
|
||||
|
||||
+2
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.scripting.definitions
|
||||
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.ide.highlighter.JavaFileType
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.fileTypes.FileTypeRegistry
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -56,6 +57,7 @@ fun findScriptDefinition(project: Project, script: SourceCode): ScriptDefinition
|
||||
fun VirtualFile.isNonScript(): Boolean =
|
||||
isDirectory ||
|
||||
extension == KotlinFileType.EXTENSION ||
|
||||
extension == JavaFileType.INSTANCE.defaultExtension ||
|
||||
extension == JavaClassFileType.INSTANCE.defaultExtension ||
|
||||
!this.isKotlinFileType()
|
||||
|
||||
|
||||
+13
-7
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.scripting.compiler.plugin.impl.reporter
|
||||
import org.jetbrains.kotlin.scripting.configuration.ScriptingConfigurationKeys
|
||||
import org.jetbrains.kotlin.scripting.definitions.*
|
||||
import java.io.File
|
||||
import java.util.concurrent.atomic.AtomicBoolean
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
|
||||
class ScriptingCompilerConfigurationExtension(
|
||||
@@ -88,15 +89,20 @@ class ScriptingCompilerConfigurationExtension(
|
||||
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
|
||||
override fun updateFileRegistry() {
|
||||
val scriptDefinitionProvider = ScriptDefinitionProvider.getInstance(project) as? CliScriptDefinitionProvider
|
||||
if (scriptDefinitionProvider != null) {
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
|
||||
fun main() {
|
||||
println("OK")
|
||||
}
|
||||
+27
@@ -240,6 +240,33 @@ class ScriptingWithCliCompilerTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testScriptMainKtsDiscovery() {
|
||||
withTempDir { tmpdir ->
|
||||
|
||||
fun compileSuccessfullyGetStdErr(fileArg: String): List<String> {
|
||||
val (_, err, ret) = captureOutErrRet {
|
||||
CLITool.doMainNoExit(
|
||||
K2JVMCompiler(),
|
||||
arrayOf(
|
||||
"-P", "plugin:kotlin.scripting:disable-script-definitions-autoloading=true",
|
||||
"-cp", getMainKtsClassPath().joinToString(File.pathSeparator), "-d", tmpdir.path, "-verbose", fileArg)
|
||||
)
|
||||
}
|
||||
Assert.assertEquals(0, ret.code)
|
||||
return err.linesSplitTrim()
|
||||
}
|
||||
|
||||
val loadMainKtsMessage = "logging: configure scripting: loading script definition class org.jetbrains.kotlin.mainKts.MainKtsScript using classpath"
|
||||
|
||||
val res1 = compileSuccessfullyGetStdErr("$TEST_DATA_DIR/compiler/mixedCompilation/nonScript.kt")
|
||||
Assert.assertTrue(res1.none { it.startsWith(loadMainKtsMessage) })
|
||||
|
||||
val res2 = compileSuccessfullyGetStdErr("$TEST_DATA_DIR/compiler/mixedCompilation/simpleScript.main.kts")
|
||||
Assert.assertTrue(res2.any { it.startsWith(loadMainKtsMessage) })
|
||||
}
|
||||
}
|
||||
|
||||
private fun getMainKtsClassPath(): List<File> {
|
||||
return listOf(
|
||||
File("dist/kotlinc/lib/kotlin-main-kts.jar").also {
|
||||
|
||||
Reference in New Issue
Block a user