proper enforcing of url class loader in stub generator

This commit is contained in:
Dennis Ushakov
2018-06-09 17:36:40 +03:00
parent ded03fb0d8
commit 4ffda7026f
4 changed files with 74 additions and 49 deletions
-1
View File
@@ -16,6 +16,5 @@
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="module" module-name="intellij.tools.index" />
<orderEntry type="module" module-name="intellij.pycharm.community" exported="" scope="RUNTIME" />
<orderEntry type="module" module-name="intellij.platform.bootstrap" />
</component>
</module>
@@ -1,7 +1,6 @@
// Copyright 2000-2017 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.jetbrains.python.tools
import com.intellij.ide.BootstrapClassLoaderUtil
import com.intellij.idea.IdeaTestApplication
import com.intellij.index.PrebuiltIndexAwareIdIndexer
import com.intellij.openapi.application.PathManager
@@ -15,60 +14,67 @@ import com.intellij.util.io.ZipUtil
import com.intellij.util.ui.UIUtil
import com.jetbrains.python.psi.impl.stubs.PyPrebuiltStubsProvider
import org.jetbrains.index.id.IdIndexGenerator
import org.jetbrains.index.stubs.StubGeneratorBootstrap
import org.jetbrains.index.stubs.bootstrapAndRun
import java.io.File
import java.util.*
fun main(args: Array<String>) {
buildIndices(args[0], "${args[1]}/${PyPrebuiltStubsProvider.NAME}")
bootstrapAndRun(args, PyPrebuiltIndicesGeneratorBootstrap::class.java.name)
}
fun buildIndices(root: String, outputPath: String) {
val app = createApp()
try {
FileUtil.delete(File(outputPath))
val roots = unzipArchivesToRoots(root)
val rootFiles = ArrayList(roots.map { it -> LocalFileSystem.getInstance().findFileByIoFile(it)!! })
PyStubsGenerator("$outputPath/${PrebuiltStubsProviderBase.SDK_STUBS_STORAGE_NAME}").buildStubsForRoots(rootFiles)
IdIndexGenerator("$outputPath/${PrebuiltIndexAwareIdIndexer.ID_INDEX_FILE_NAME}").buildIdIndexForRoots(rootFiles)
class PyPrebuiltIndicesGeneratorBootstrap : StubGeneratorBootstrap {
override fun run(args: Array<String>) {
buildIndices(args[0], "${args[1]}/${PyPrebuiltStubsProvider.NAME}")
}
catch (e: Throwable) {
e.printStackTrace()
private fun buildIndices(root: String, outputPath: String) {
val app = createApp()
try {
FileUtil.delete(File(outputPath))
val roots = unzipArchivesToRoots(root)
val rootFiles = ArrayList(roots.map { it -> LocalFileSystem.getInstance().findFileByIoFile(it)!! })
PyStubsGenerator("$outputPath/${PrebuiltStubsProviderBase.SDK_STUBS_STORAGE_NAME}").buildStubsForRoots(rootFiles)
IdIndexGenerator("$outputPath/${PrebuiltIndexAwareIdIndexer.ID_INDEX_FILE_NAME}").buildIdIndexForRoots(rootFiles)
}
catch (e: Throwable) {
e.printStackTrace()
}
finally {
UIUtil.invokeAndWaitIfNeeded(Runnable {
WriteAction.run<Throwable> {
app.dispose()
}
})
FileUtil.delete(File(System.getProperty(PathManager.PROPERTY_PLUGINS_PATH)))
FileUtil.delete(File(System.getProperty(PathManager.PROPERTY_SYSTEM_PATH)))
System.exit(0)
}
}
finally {
UIUtil.invokeAndWaitIfNeeded(Runnable {
WriteAction.run<Throwable> {
app.dispose()
}
})
FileUtil.delete(File(System.getProperty(PathManager.PROPERTY_PLUGINS_PATH)))
FileUtil.delete(File(System.getProperty(PathManager.PROPERTY_SYSTEM_PATH)))
System.exit(0)
private fun unzipArchivesToRoots(root: String): List<File> {
val dir = File(root)
if (!dir.exists() || !dir.isDirectory) {
throw IllegalStateException("$root doesn't exist or isn't a directory")
}
return dir.listFiles { _, name -> name.endsWith(".zip") }.map { zip ->
val unzipRoot = File(root, zip.nameWithoutExtension)
println("Extracting $zip")
ZipUtil.extract(zip, unzipRoot, null)
unzipRoot
}
}
private fun createApp(): IdeaTestApplication {
val candidates = ReflectionUtil.getField(PlatformTestCase::class.java, null, Array<String>::class.java, "PREFIX_CANDIDATES")
candidates[0] = "PyCharm"
System.setProperty(PathManager.PROPERTY_PLUGINS_PATH, FileUtil.createTempDirectory("pystubs", "plugins").absolutePath)
System.setProperty(PathManager.PROPERTY_SYSTEM_PATH, FileUtil.createTempDirectory("pystubs", "system").absolutePath)
System.setProperty(PathManager.PROPERTY_CONFIG_PATH, FileUtil.createTempDirectory("pystubs", "config").absolutePath)
return IdeaTestApplication.getInstance()
}
}
fun unzipArchivesToRoots(root: String): List<File> {
val dir = File(root)
if (!dir.exists() || !dir.isDirectory) {
throw IllegalStateException("$root doesn't exist or isn't a directory")
}
return dir.listFiles { _, name -> name.endsWith(".zip") }.map { zip ->
val unzipRoot = File(root, zip.nameWithoutExtension)
println("Extracting $zip")
ZipUtil.extract(zip, unzipRoot, null)
unzipRoot
}
}
private fun createApp(): IdeaTestApplication {
val candidates = ReflectionUtil.getField(PlatformTestCase::class.java, null, Array<String>::class.java, "PREFIX_CANDIDATES")
candidates[0] = "PyCharm"
System.setProperty(PathManager.PROPERTY_PLUGINS_PATH, FileUtil.createTempDirectory("pystubs", "plugins").absolutePath)
System.setProperty(PathManager.PROPERTY_SYSTEM_PATH, FileUtil.createTempDirectory("pystubs", "system").absolutePath)
System.setProperty(PathManager.PROPERTY_CONFIG_PATH, FileUtil.createTempDirectory("pystubs", "config").absolutePath)
Thread.currentThread().contextClassLoader = BootstrapClassLoaderUtil.initClassLoader()
return IdeaTestApplication.getInstance()
}
@@ -11,5 +11,6 @@
<orderEntry type="module" module-name="intellij.platform.lang.impl" />
<orderEntry type="library" name="Guava" level="project" />
<orderEntry type="module" module-name="intellij.platform.testFramework" />
<orderEntry type="module" module-name="intellij.platform.bootstrap" />
</component>
</module>
@@ -0,0 +1,19 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.index.stubs
import com.intellij.ide.BootstrapClassLoaderUtil
interface StubGeneratorBootstrap {
fun run(args: Array<String>)
fun <T> Array<out T>.secondOrNull() = if (size < 2) null else this[1]
}
fun bootstrapAndRun(args: Array<String>, className: String?) {
val newClassLoader = BootstrapClassLoaderUtil.initClassLoader()
Thread.currentThread().contextClassLoader = newClassLoader
val klass = Class.forName(className, true, newClassLoader)
val instance = klass.newInstance()
val method = klass.getDeclaredMethod("run", Array<String>::class.java)
method.invoke(instance, args)
}