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:
Natalia Selezneva
2020-07-02 08:21:41 +03:00
parent 45600830d3
commit 1d45dc8d81
25 changed files with 396 additions and 83 deletions
@@ -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")
}
}
@@ -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/");
}
}
@@ -0,0 +1 @@
// needed for module creation
@@ -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
@@ -0,0 +1 @@
// ROOT: /module/test/META-INF/kotlin/script/templates/MyTemplate.classname
@@ -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
@@ -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
@@ -0,0 +1,4 @@
// ROOT: /module/resources/META-INF/kotlin/script/templates/MyTemplate.classname
// NAME: MyTemplate