Optimize ScriptTemplatesFromDependenciesProvider
No needs to convert file.url to VirtualFile because index already has getContainingFiles method Do not iterate through all children of VirtualFile to avoid VFS events initialisation for those files there is no guarantee that file is under source root so is can be not present is vfs at this moment
This commit is contained in:
@@ -1041,6 +1041,10 @@ fun main(args: Array<String>) {
|
||||
testClass<AbstractScratchLineMarkersTest> {
|
||||
model("scratch/lineMarker", testMethod = "doScratchTest", pattern = KT_OR_KTS)
|
||||
}
|
||||
|
||||
testClass<AbstractScriptTemplatesFromDependenciesTest> {
|
||||
model("script/templatesFromDependencies", extension = null, recursive = false)
|
||||
}
|
||||
}
|
||||
|
||||
testGroup("idea/idea-maven/test", "idea/idea-maven/testData") {
|
||||
|
||||
@@ -119,10 +119,7 @@ import org.jetbrains.kotlin.idea.repl.AbstractIdeReplCompletionTest
|
||||
import org.jetbrains.kotlin.idea.resolve.*
|
||||
import org.jetbrains.kotlin.idea.scratch.AbstractScratchLineMarkersTest
|
||||
import org.jetbrains.kotlin.idea.scratch.AbstractScratchRunActionTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationCompletionTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationHighlightingTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationNavigationTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptDefinitionsOrderTest
|
||||
import org.jetbrains.kotlin.idea.script.*
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerLeafGroupingTest
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerNullnessGroupingTest
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerTreeTest
|
||||
@@ -841,20 +838,60 @@ fun main(args: Array<String>) {
|
||||
|
||||
testGroup("idea/scripting-support/test", "idea/scripting-support/testData") {
|
||||
testClass<AbstractScratchRunActionTest> {
|
||||
model("scratch", extension = "kts", testMethod = "doScratchCompilingTest", testClassName = "ScratchCompiling", recursive = false)
|
||||
model(
|
||||
"scratch",
|
||||
extension = "kts",
|
||||
testMethod = "doScratchCompilingTest",
|
||||
testClassName = "ScratchCompiling",
|
||||
recursive = false
|
||||
)
|
||||
model("scratch", extension = "kts", testMethod = "doScratchReplTest", testClassName = "ScratchRepl", recursive = false)
|
||||
model("scratch/multiFile", extension = null, testMethod = "doScratchMultiFileTest", testClassName = "ScratchMultiFile", recursive = false)
|
||||
model(
|
||||
"scratch/multiFile",
|
||||
extension = null,
|
||||
testMethod = "doScratchMultiFileTest",
|
||||
testClassName = "ScratchMultiFile",
|
||||
recursive = false
|
||||
)
|
||||
|
||||
model("worksheet", extension = "ws.kts", testMethod = "doWorksheetCompilingTest", testClassName = "WorksheetCompiling", recursive = false)
|
||||
model("worksheet", extension = "ws.kts", testMethod = "doWorksheetReplTest", testClassName = "WorksheetRepl", recursive = false)
|
||||
model("worksheet/multiFile", extension = null, testMethod = "doWorksheetMultiFileTest", testClassName = "WorksheetMultiFile", recursive = false)
|
||||
model(
|
||||
"worksheet",
|
||||
extension = "ws.kts",
|
||||
testMethod = "doWorksheetCompilingTest",
|
||||
testClassName = "WorksheetCompiling",
|
||||
recursive = false
|
||||
)
|
||||
model(
|
||||
"worksheet",
|
||||
extension = "ws.kts",
|
||||
testMethod = "doWorksheetReplTest",
|
||||
testClassName = "WorksheetRepl",
|
||||
recursive = false
|
||||
)
|
||||
model(
|
||||
"worksheet/multiFile",
|
||||
extension = null,
|
||||
testMethod = "doWorksheetMultiFileTest",
|
||||
testClassName = "WorksheetMultiFile",
|
||||
recursive = false
|
||||
)
|
||||
|
||||
model("scratch/rightPanelOutput", extension = "kts", testMethod = "doRightPreviewPanelOutputTest", testClassName = "ScratchRightPanelOutput", recursive = false)
|
||||
model(
|
||||
"scratch/rightPanelOutput",
|
||||
extension = "kts",
|
||||
testMethod = "doRightPreviewPanelOutputTest",
|
||||
testClassName = "ScratchRightPanelOutput",
|
||||
recursive = false
|
||||
)
|
||||
}
|
||||
|
||||
testClass<AbstractScratchLineMarkersTest> {
|
||||
model("scratch/lineMarker", testMethod = "doScratchTest", pattern = KT_OR_KTS)
|
||||
}
|
||||
|
||||
testClass<AbstractScriptTemplatesFromDependenciesTest> {
|
||||
model("script/templatesFromDependencies", extension = null, recursive = false)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -119,10 +119,7 @@ import org.jetbrains.kotlin.idea.repl.AbstractIdeReplCompletionTest
|
||||
import org.jetbrains.kotlin.idea.resolve.*
|
||||
import org.jetbrains.kotlin.idea.scratch.AbstractScratchLineMarkersTest
|
||||
import org.jetbrains.kotlin.idea.scratch.AbstractScratchRunActionTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationCompletionTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationHighlightingTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptConfigurationNavigationTest
|
||||
import org.jetbrains.kotlin.idea.script.AbstractScriptDefinitionsOrderTest
|
||||
import org.jetbrains.kotlin.idea.script.*
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerLeafGroupingTest
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerNullnessGroupingTest
|
||||
import org.jetbrains.kotlin.idea.slicer.AbstractSlicerTreeTest
|
||||
@@ -841,20 +838,60 @@ fun main(args: Array<String>) {
|
||||
|
||||
testGroup("idea/scripting-support/test", "idea/scripting-support/testData") {
|
||||
testClass<AbstractScratchRunActionTest> {
|
||||
model("scratch", extension = "kts", testMethod = "doScratchCompilingTest", testClassName = "ScratchCompiling", recursive = false)
|
||||
model(
|
||||
"scratch",
|
||||
extension = "kts",
|
||||
testMethod = "doScratchCompilingTest",
|
||||
testClassName = "ScratchCompiling",
|
||||
recursive = false
|
||||
)
|
||||
model("scratch", extension = "kts", testMethod = "doScratchReplTest", testClassName = "ScratchRepl", recursive = false)
|
||||
model("scratch/multiFile", extension = null, testMethod = "doScratchMultiFileTest", testClassName = "ScratchMultiFile", recursive = false)
|
||||
model(
|
||||
"scratch/multiFile",
|
||||
extension = null,
|
||||
testMethod = "doScratchMultiFileTest",
|
||||
testClassName = "ScratchMultiFile",
|
||||
recursive = false
|
||||
)
|
||||
|
||||
model("worksheet", extension = "ws.kts", testMethod = "doWorksheetCompilingTest", testClassName = "WorksheetCompiling", recursive = false)
|
||||
model("worksheet", extension = "ws.kts", testMethod = "doWorksheetReplTest", testClassName = "WorksheetRepl", recursive = false)
|
||||
model("worksheet/multiFile", extension = null, testMethod = "doWorksheetMultiFileTest", testClassName = "WorksheetMultiFile", recursive = false)
|
||||
model(
|
||||
"worksheet",
|
||||
extension = "ws.kts",
|
||||
testMethod = "doWorksheetCompilingTest",
|
||||
testClassName = "WorksheetCompiling",
|
||||
recursive = false
|
||||
)
|
||||
model(
|
||||
"worksheet",
|
||||
extension = "ws.kts",
|
||||
testMethod = "doWorksheetReplTest",
|
||||
testClassName = "WorksheetRepl",
|
||||
recursive = false
|
||||
)
|
||||
model(
|
||||
"worksheet/multiFile",
|
||||
extension = null,
|
||||
testMethod = "doWorksheetMultiFileTest",
|
||||
testClassName = "WorksheetMultiFile",
|
||||
recursive = false
|
||||
)
|
||||
|
||||
model("scratch/rightPanelOutput", extension = "kts", testMethod = "doRightPreviewPanelOutputTest", testClassName = "ScratchRightPanelOutput", recursive = false)
|
||||
model(
|
||||
"scratch/rightPanelOutput",
|
||||
extension = "kts",
|
||||
testMethod = "doRightPreviewPanelOutputTest",
|
||||
testClassName = "ScratchRightPanelOutput",
|
||||
recursive = false
|
||||
)
|
||||
}
|
||||
|
||||
testClass<AbstractScratchLineMarkersTest> {
|
||||
model("scratch/lineMarker", testMethod = "doScratchTest", pattern = KT_OR_KTS)
|
||||
}
|
||||
|
||||
testClass<AbstractScriptTemplatesFromDependenciesTest> {
|
||||
model("script/templatesFromDependencies", extension = null, recursive = false)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.idea.script
|
||||
|
||||
import com.intellij.ide.projectView.actions.MarkRootActionBase
|
||||
import com.intellij.openapi.module.JavaModuleType
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.guessProjectDir
|
||||
import com.intellij.openapi.roots.*
|
||||
import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VfsUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.testFramework.HeavyPlatformTestCase
|
||||
import com.intellij.testFramework.PsiTestUtil
|
||||
import com.intellij.util.indexing.FileBasedIndex
|
||||
import org.jetbrains.jps.model.java.JavaResourceRootType
|
||||
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionContributor
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.test.InTextDirectivesUtils
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInnersForJPS
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.jetbrains.kotlin.test.MockLibraryUtil
|
||||
import org.jetbrains.kotlin.test.util.addDependency
|
||||
import org.jetbrains.kotlin.test.util.jarRoot
|
||||
import org.jetbrains.kotlin.test.util.projectLibrary
|
||||
import org.junit.runner.RunWith
|
||||
import java.io.File
|
||||
|
||||
@RunWith(JUnit3RunnerWithInnersForJPS::class)
|
||||
abstract class AbstractScriptTemplatesFromDependenciesTest : HeavyPlatformTestCase() {
|
||||
|
||||
companion object {
|
||||
private const val testFileName = "test.kts"
|
||||
}
|
||||
|
||||
fun doTest(path: String) {
|
||||
val projectRoot = project.guessProjectDir() ?: return
|
||||
val testDataDir = File(path)
|
||||
|
||||
copyDirContentsTo(
|
||||
LocalFileSystem.getInstance().findFileByIoFile(testDataDir)!!,
|
||||
projectRoot
|
||||
)
|
||||
|
||||
testDataDir
|
||||
.listFiles { f -> f.name.startsWith("module") }
|
||||
?.filter { it.exists() }
|
||||
?.forEach {
|
||||
createTestModule(it)
|
||||
}
|
||||
|
||||
ModuleManager.getInstance(project).modules.forEach { module ->
|
||||
testDataDir
|
||||
.listFiles { f -> f.name.startsWith("jar") }
|
||||
?.map { folder ->
|
||||
ModuleRootManager.getInstance(module).modifiableModel.apply {
|
||||
val vFile = VfsUtil.findFileByIoFile(folder, true)!!
|
||||
MarkRootActionBase.findContentEntry(this, vFile)?.addExcludeFolder(vFile)
|
||||
runWriteAction { this@apply.commit() }
|
||||
}
|
||||
|
||||
packJar(folder)
|
||||
}
|
||||
?.forEach { jar ->
|
||||
module.addDependency(
|
||||
projectLibrary(
|
||||
libraryName = "script-library",
|
||||
classesRoot = jar.jarRoot
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val roots: Collection<VirtualFile> = FileBasedIndex.getInstance().getContainingFiles(
|
||||
ScriptTemplatesClassRootsIndex.KEY,
|
||||
ScriptTemplatesClassRootsIndex.VALUE,
|
||||
GlobalSearchScope.allScope(project)
|
||||
)
|
||||
|
||||
val testFile = File(path, testFileName)
|
||||
val fileText = testFile.readText()
|
||||
|
||||
checkRoots(fileText, roots)
|
||||
|
||||
val provider = ScriptDefinitionContributor.find<ScriptTemplatesFromDependenciesProvider>(project)
|
||||
?: error("Cannot find ScriptTemplatesFromDependenciesProvider")
|
||||
|
||||
val (templates, classpath) = provider.getTemplateClassPath(roots.toList())
|
||||
|
||||
checkTemplateNames(fileText, templates)
|
||||
checkTemplateClasspath(fileText, classpath)
|
||||
}
|
||||
|
||||
private fun String.removeTestDirPrefix(): String = this.substringAfterLast(getTestName(true))
|
||||
|
||||
private fun checkRoots(fileText: String, roots: Collection<VirtualFile>) {
|
||||
val actual = roots.map { it.path.removeTestDirPrefix() }
|
||||
val expected = InTextDirectivesUtils.findListWithPrefixes(fileText, "// ROOT:")
|
||||
|
||||
assertOrderedEquals("Roots are different", actual.sorted(), expected.sorted())
|
||||
}
|
||||
|
||||
private fun checkTemplateNames(fileText: String, names: Collection<String>) {
|
||||
val expected = InTextDirectivesUtils.findListWithPrefixes(fileText, "// NAME:")
|
||||
|
||||
assertOrderedEquals("Template names are different", names.sorted(), expected.sorted())
|
||||
}
|
||||
|
||||
private fun checkTemplateClasspath(fileText: String, classpath: Collection<File>) {
|
||||
val actual = classpath.map {
|
||||
FileUtil.toSystemIndependentName(it.path).removeTestDirPrefix()
|
||||
}
|
||||
|
||||
val expected = InTextDirectivesUtils.findListWithPrefixes(fileText, "// CLASSPATH:")
|
||||
|
||||
assertOrderedEquals("Roots are different", actual.sorted(), expected.sorted())
|
||||
}
|
||||
|
||||
private fun createTestModule(dir: File): Module {
|
||||
val newModule = createModuleAt(name, project, JavaModuleType.getModuleType(), dir.path)
|
||||
|
||||
dir.listFiles()?.forEach {
|
||||
val root = VfsUtil.findFileByIoFile(it, true) ?: return@forEach
|
||||
when (it.name) {
|
||||
"src" -> PsiTestUtil.addSourceRoot(newModule, root)
|
||||
"test" -> PsiTestUtil.addSourceRoot(newModule, root, true)
|
||||
"resources" -> PsiTestUtil.addSourceRoot(newModule, root, JavaResourceRootType.RESOURCE)
|
||||
}
|
||||
}
|
||||
return newModule
|
||||
}
|
||||
|
||||
private fun packJar(dir: File): File {
|
||||
val contentDir = KotlinTestUtils.tmpDirForReusableFolder("folderForLibrary-${getTestName(true)}")
|
||||
return MockLibraryUtil.createJarFile(contentDir, dir, "templates")
|
||||
}
|
||||
}
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.idea.script;
|
||||
|
||||
import com.intellij.testFramework.TestDataPath;
|
||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners;
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||
import org.jetbrains.kotlin.test.TestMetadata;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */
|
||||
@SuppressWarnings("all")
|
||||
@TestMetadata("idea/scripting-support/testData/script/templatesFromDependencies")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public class ScriptTemplatesFromDependenciesTestGenerated extends AbstractScriptTemplatesFromDependenciesTest {
|
||||
private void runTest(String testDataFilePath) throws Exception {
|
||||
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
|
||||
}
|
||||
|
||||
public void testAllFilesPresentInTemplatesFromDependencies() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/scripting-support/testData/script/templatesFromDependencies"), Pattern.compile("^([^\\.]+)$"), null, false);
|
||||
}
|
||||
|
||||
@TestMetadata("inJar")
|
||||
public void testInJar() throws Exception {
|
||||
runTest("idea/scripting-support/testData/script/templatesFromDependencies/inJar/");
|
||||
}
|
||||
|
||||
@TestMetadata("inTests")
|
||||
public void testInTests() throws Exception {
|
||||
runTest("idea/scripting-support/testData/script/templatesFromDependencies/inTests/");
|
||||
}
|
||||
|
||||
@TestMetadata("multipleRoots")
|
||||
public void testMultipleRoots() throws Exception {
|
||||
runTest("idea/scripting-support/testData/script/templatesFromDependencies/multipleRoots/");
|
||||
}
|
||||
|
||||
@TestMetadata("multipleTemplates")
|
||||
public void testMultipleTemplates() throws Exception {
|
||||
runTest("idea/scripting-support/testData/script/templatesFromDependencies/multipleTemplates/");
|
||||
}
|
||||
|
||||
@TestMetadata("outsideRoots")
|
||||
public void testOutsideRoots() throws Exception {
|
||||
runTest("idea/scripting-support/testData/script/templatesFromDependencies/outsideRoots/");
|
||||
}
|
||||
|
||||
@TestMetadata("singleTemplate")
|
||||
public void testSingleTemplate() throws Exception {
|
||||
runTest("idea/scripting-support/testData/script/templatesFromDependencies/singleTemplate/");
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
// needed for module creation
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// ROOT: /templates.jar!/META-INF/kotlin/script/templates/MyTemplate1.classname
|
||||
// ROOT: /templates.jar!/inner/META-INF/kotlin/script/templates/MyTemplate2.classname
|
||||
|
||||
// NAME: MyTemplate1
|
||||
// CLASSPATH: /templates.jar
|
||||
|
||||
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
// ROOT: /module/test/META-INF/kotlin/script/templates/MyTemplate.classname
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// ROOT: /module/resources/META-INF/kotlin/script/templates/MyTemplate1.classname
|
||||
// ROOT: /module/src/foo/META-INF/kotlin/script/templates/MyTemplate2.classname
|
||||
|
||||
|
||||
// NAME: MyTemplate1
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
// ROOT: /module/resources/META-INF/kotlin/script/templates/MyTemplate1.classname
|
||||
// ROOT: /module/resources/META-INF/kotlin/script/templates/MyTemplate2.classname
|
||||
|
||||
// NAME: MyTemplate1
|
||||
// NAME: MyTemplate2
|
||||
+1
@@ -0,0 +1 @@
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
// ROOT: /module/resources/META-INF/kotlin/script/templates/MyTemplate.classname
|
||||
|
||||
// NAME: MyTemplate
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.indexing.*
|
||||
import com.intellij.util.io.IOUtil
|
||||
import com.intellij.util.io.KeyDescriptor
|
||||
import org.jetbrains.kotlin.scripting.definitions.SCRIPT_DEFINITION_MARKERS_EXTENSION_WITH_DOT
|
||||
import org.jetbrains.kotlin.scripting.definitions.SCRIPT_DEFINITION_MARKERS_PATH
|
||||
import java.io.DataInput
|
||||
import java.io.DataOutput
|
||||
@@ -21,6 +22,7 @@ class ScriptTemplatesClassRootsIndex :
|
||||
|
||||
companion object {
|
||||
val KEY = ID.create<String, Void>(ScriptTemplatesClassRootsIndex::class.java.canonicalName)
|
||||
const val VALUE = "MY_VALUE"
|
||||
|
||||
private val suffix = SCRIPT_DEFINITION_MARKERS_PATH.removeSuffix("/")
|
||||
}
|
||||
@@ -37,29 +39,26 @@ class ScriptTemplatesClassRootsIndex :
|
||||
|
||||
override fun getVersion(): Int = 1
|
||||
|
||||
override fun indexDirectories(): Boolean = true
|
||||
override fun indexDirectories(): Boolean = false
|
||||
|
||||
override fun acceptInput(file: VirtualFile): Boolean {
|
||||
return file.isDirectory && file.path.endsWith(suffix)
|
||||
val parent = file.parent ?: return false
|
||||
return parent.isDirectory
|
||||
&& parent.path.endsWith(suffix)
|
||||
&& file.path.endsWith(SCRIPT_DEFINITION_MARKERS_EXTENSION_WITH_DOT)
|
||||
}
|
||||
|
||||
override fun save(out: DataOutput, value: String) {
|
||||
IOUtil.writeUTF(out, value)
|
||||
}
|
||||
override fun save(out: DataOutput, value: String) = IOUtil.writeUTF(out, value)
|
||||
|
||||
override fun read(input: DataInput): String? {
|
||||
return IOUtil.readUTF(input)
|
||||
}
|
||||
override fun read(input: DataInput): String? = IOUtil.readUTF(input)
|
||||
|
||||
override fun getHashCode(value: String): Int {
|
||||
return value.hashCode()
|
||||
}
|
||||
override fun getHashCode(value: String): Int = value.hashCode()
|
||||
|
||||
override fun isEqual(val1: String?, val2: String?): Boolean {
|
||||
return val1 == val2
|
||||
}
|
||||
|
||||
override fun map(inputData: FileContent): Map<String?, Void?> {
|
||||
return Collections.singletonMap(inputData.file.url, null)
|
||||
return Collections.singletonMap(VALUE, null)
|
||||
}
|
||||
}
|
||||
+59
-51
@@ -12,17 +12,16 @@ import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.roots.*
|
||||
import com.intellij.openapi.vfs.*
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import com.intellij.util.concurrency.AppExecutorUtil
|
||||
import com.intellij.util.indexing.FileBasedIndex
|
||||
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.SCRIPT_DEFINITION_MARKERS_EXTENSION_WITH_DOT
|
||||
import org.jetbrains.kotlin.scripting.definitions.SCRIPT_DEFINITION_MARKERS_PATH
|
||||
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition
|
||||
import org.jetbrains.kotlin.scripting.definitions.getEnvironment
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
import java.util.concurrent.locks.ReentrantLock
|
||||
import kotlin.concurrent.withLock
|
||||
import kotlin.script.experimental.host.ScriptingHostConfiguration
|
||||
@@ -104,61 +103,21 @@ class ScriptTemplatesFromDependenciesProvider(private val project: Project) : Sc
|
||||
logger.debug("async script definitions update started")
|
||||
}
|
||||
|
||||
val templates = LinkedHashSet<String>()
|
||||
val classpath = LinkedHashSet<File>()
|
||||
|
||||
ReadAction
|
||||
.nonBlocking<List<VirtualFile>> {
|
||||
val fileManager = VirtualFileManager.getInstance()
|
||||
FileBasedIndex.getInstance().getAllKeys(ScriptTemplatesClassRootsIndex.KEY, project).mapNotNull {
|
||||
val vFile = fileManager.findFileByUrl(it)
|
||||
|
||||
// see SCRIPT_DEFINITION_MARKERS_PATH
|
||||
vFile?.parent?.parent?.parent?.parent
|
||||
}
|
||||
FileBasedIndex.getInstance().getContainingFiles(
|
||||
ScriptTemplatesClassRootsIndex.KEY,
|
||||
ScriptTemplatesClassRootsIndex.VALUE,
|
||||
GlobalSearchScope.allScope(project)
|
||||
).filterNotNull()
|
||||
}
|
||||
.inSmartMode(project)
|
||||
.expireWith(project)
|
||||
.submit(AppExecutorUtil.getAppExecutorService())
|
||||
.onSuccess { roots ->
|
||||
roots.forEach { root ->
|
||||
if (logger.isDebugEnabled) {
|
||||
logger.debug("root matching SCRIPT_DEFINITION_MARKERS_PATH found: ${root.path}")
|
||||
}
|
||||
.onSuccess { files ->
|
||||
val (templates, classpath) = getTemplateClassPath(files)
|
||||
|
||||
val orderEntriesForFile = ProjectFileIndex.getInstance(project).getOrderEntriesForFile(root)
|
||||
.filter {
|
||||
if (it is ModuleSourceOrderEntry) {
|
||||
!ModuleRootManager.getInstance(it.ownerModule).fileIndex.isInTestSourceContent(root)
|
||||
} else {
|
||||
it is LibraryOrSdkOrderEntry
|
||||
}
|
||||
}
|
||||
.takeIf { it.isNotEmpty() } ?: return@forEach
|
||||
|
||||
root.findFileByRelativePath(SCRIPT_DEFINITION_MARKERS_PATH)?.children?.forEach { resourceFile ->
|
||||
if (resourceFile.isValid && !resourceFile.isDirectory) {
|
||||
templates.add(resourceFile.name.removeSuffix(SCRIPT_DEFINITION_MARKERS_EXTENSION_WITH_DOT))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// assuming that all libraries are placed into classes roots
|
||||
// TODO: extract exact library dependencies instead of putting all module dependencies into classpath
|
||||
// minimizing the classpath needed to use the template by taking cp only from modules with new templates found
|
||||
// on the other hand the approach may fail if some module contains a template without proper classpath, while
|
||||
// the other has properly configured classpath, so assuming that the dependencies are set correctly everywhere
|
||||
orderEntriesForFile.forEach {
|
||||
classpath.addAll(
|
||||
OrderEnumerator.orderEntries(it.ownerModule).withoutSdk().classesRoots.mapNotNull {
|
||||
it.canonicalPath?.removeSuffix("!/").let(::File)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onProcessed {
|
||||
if (templates.isEmpty()) return@onProcessed onEarlyEnd()
|
||||
if (templates.isEmpty()) return@onSuccess onEarlyEnd()
|
||||
|
||||
val newTemplates = TemplatesWithCp(templates.toList(), classpath.toList())
|
||||
if (newTemplates == oldTemplates) {
|
||||
@@ -166,7 +125,7 @@ class ScriptTemplatesFromDependenciesProvider(private val project: Project) : Sc
|
||||
inProgress = false
|
||||
}
|
||||
|
||||
return@onProcessed
|
||||
return@onSuccess
|
||||
}
|
||||
|
||||
if (logger.isDebugEnabled) {
|
||||
@@ -219,4 +178,53 @@ class ScriptTemplatesFromDependenciesProvider(private val project: Project) : Sc
|
||||
inProgress = false
|
||||
}
|
||||
}
|
||||
|
||||
// public for tests
|
||||
fun getTemplateClassPath(files: List<VirtualFile>): Pair<Collection<String>, Collection<File>> {
|
||||
val rootDirToTemplates: MutableMap<VirtualFile, MutableList<VirtualFile>> = hashMapOf()
|
||||
for (file in files) {
|
||||
val dir = file.parent?.parent?.parent?.parent?.parent ?: continue
|
||||
rootDirToTemplates.getOrPut(dir) { arrayListOf() }.add(file)
|
||||
}
|
||||
|
||||
val templates = LinkedHashSet<String>()
|
||||
val classpath = LinkedHashSet<File>()
|
||||
|
||||
rootDirToTemplates.forEach { (root, templateFiles) ->
|
||||
if (logger.isDebugEnabled) {
|
||||
logger.debug("root matching SCRIPT_DEFINITION_MARKERS_PATH found: ${root.path}")
|
||||
}
|
||||
|
||||
val orderEntriesForFile = ProjectFileIndex.getInstance(project).getOrderEntriesForFile(root)
|
||||
.filter {
|
||||
if (it is ModuleSourceOrderEntry) {
|
||||
if (ModuleRootManager.getInstance(it.ownerModule).fileIndex.isInTestSourceContent(root)) {
|
||||
return@filter false
|
||||
}
|
||||
|
||||
it.getFiles(OrderRootType.SOURCES).contains(root)
|
||||
} else {
|
||||
it is LibraryOrSdkOrderEntry && it.getFiles(OrderRootType.CLASSES).contains(root)
|
||||
}
|
||||
}
|
||||
.takeIf { it.isNotEmpty() } ?: return@forEach
|
||||
|
||||
templateFiles.forEach {
|
||||
templates.add(it.name.removeSuffix(SCRIPT_DEFINITION_MARKERS_EXTENSION_WITH_DOT))
|
||||
}
|
||||
|
||||
// assuming that all libraries are placed into classes roots
|
||||
// TODO: extract exact library dependencies instead of putting all module dependencies into classpath
|
||||
// minimizing the classpath needed to use the template by taking cp only from modules with new templates found
|
||||
// on the other hand the approach may fail if some module contains a template without proper classpath, while
|
||||
// the other has properly configured classpath, so assuming that the dependencies are set correctly everywhere
|
||||
orderEntriesForFile.flatMap {
|
||||
OrderEnumerator.orderEntries(it.ownerModule).withoutSdk().classesRoots.mapNotNull {
|
||||
classpath.add(it.canonicalPath?.removeSuffix("!/").let(::File))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return templates to classpath
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user