mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[gui-tests] Greenify compiler
This commit is contained in:
+11
-39
@@ -15,10 +15,8 @@
|
||||
*/
|
||||
package com.intellij.testGuiFramework.recorder.compile
|
||||
|
||||
import com.intellij.ide.plugins.PluginManager
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.components.ServiceManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.testGuiFramework.recorder.actions.PerformScriptAction
|
||||
import java.io.File
|
||||
import java.net.URL
|
||||
@@ -26,31 +24,21 @@ import java.nio.file.Paths
|
||||
|
||||
object KotlinCompileUtil {
|
||||
|
||||
private val LOG by lazy { Logger.getInstance("#${KotlinCompileUtil::class.qualifiedName}") }
|
||||
|
||||
private val localCompiler: LocalCompiler by lazy { LocalCompiler() }
|
||||
|
||||
fun compile(codeString: String) {
|
||||
localCompiler.compileOnPooledThread(ScriptWrapper.wrapScript(codeString), getAllUrls().map { Paths.get(it.toURI()).toFile().path })
|
||||
}
|
||||
|
||||
fun compileAndRun(codeString: String) {
|
||||
localCompiler.compileAndRunOnPooledThread(ScriptWrapper.wrapScript(codeString),
|
||||
getAllUrls().map { Paths.get(it.toURI()).toFile().path })
|
||||
}
|
||||
|
||||
fun getAllUrls(): List<URL> {
|
||||
private fun getAllUrls(): List<URL> {
|
||||
if (ServiceManager::class.java.classLoader.javaClass.name.contains("Launcher\$AppClassLoader")) {
|
||||
//lets substitute jars with a common lib dir to avoid Windows long path error
|
||||
val urls = ServiceManager::class.java.classLoader.forcedUrls()
|
||||
val libUrl = urls.filter { url ->
|
||||
val libUrl = urls.first { url ->
|
||||
(url.file.endsWith("idea.jar") && File(url.path).parentFile.name == "lib")
|
||||
}.firstOrNull()!!.getParentURL()
|
||||
}.getParentURL()
|
||||
urls.filter { url -> !url.file.startsWith(libUrl.file) }.plus(libUrl).toSet()
|
||||
|
||||
//add git4idea urls to allow git configuration from local runner
|
||||
// if (System.getenv("TEAMCITY_VERSION") != null) urls.plus(getGit4IdeaUrls())
|
||||
|
||||
if (!ApplicationManager.getApplication().isUnitTestMode)
|
||||
urls.plus(ServiceManager::class.java.classLoader.forcedBaseUrls())
|
||||
return urls.toList()
|
||||
@@ -63,27 +51,13 @@ object KotlinCompileUtil {
|
||||
return list
|
||||
}
|
||||
|
||||
fun getGit4IdeaUrls(): List<URL> {
|
||||
val git4IdeaPluginClassLoader = PluginManager.getPlugins().filter { pluginDescriptor -> pluginDescriptor.name.toLowerCase() == "git integration" }.firstOrNull()!!.pluginClassLoader
|
||||
val urls = git4IdeaPluginClassLoader.forcedUrls()
|
||||
val libUrl = urls.filter { url ->
|
||||
(url.file.endsWith("git4idea.jar") && File(url.path).parentFile.name == "lib")
|
||||
}.firstOrNull()!!.getParentURL()
|
||||
urls.filter { url -> !url.file.startsWith(libUrl.file) }.plus(libUrl).toSet()
|
||||
return urls
|
||||
}
|
||||
private fun URL.getParentURL() = File(this.file).parentFile.toURI().toURL()!!
|
||||
|
||||
private fun ClassLoader.forcedUrls(): List<URL> {
|
||||
var methodName = "getUrls"
|
||||
val methodAlternativeName = "getURLs"
|
||||
|
||||
fun URL.getParentURL() = File(this.file).parentFile.toURI().toURL()
|
||||
|
||||
fun ClassLoader.forcedUrls(): List<URL> {
|
||||
|
||||
val METHOD_DEFAULT_NAME: String = "getUrls"
|
||||
val METHOD_ALTERNATIVE_NAME: String = "getURLs"
|
||||
|
||||
var methodName: String = METHOD_DEFAULT_NAME
|
||||
|
||||
if (this.javaClass.methods.any { mtd -> mtd.name == METHOD_ALTERNATIVE_NAME }) methodName = METHOD_ALTERNATIVE_NAME
|
||||
if (this.javaClass.methods.any { mtd -> mtd.name == methodAlternativeName }) methodName = methodAlternativeName
|
||||
val method = this.javaClass.getMethod(methodName)
|
||||
method.isAccessible
|
||||
val methodResult = method.invoke(this)
|
||||
@@ -91,17 +65,15 @@ object KotlinCompileUtil {
|
||||
return myList.filterIsInstance(URL::class.java)
|
||||
}
|
||||
|
||||
fun ClassLoader.forcedBaseUrls(): List<URL> {
|
||||
private fun ClassLoader.forcedBaseUrls(): List<URL> {
|
||||
try {
|
||||
return ((this.javaClass.getMethod("getBaseUrls").invoke(
|
||||
this) as? List<*>)!!.filter { it is URL && it.protocol == "file" && !it.file.endsWith("jar!") }) as List<URL>
|
||||
return ((this.javaClass.getMethod("getBaseUrls").invoke(this) as? List<*>)!!.
|
||||
filter { it is URL && it.protocol == "file" && !it.file.endsWith("jar!") }) as List<URL>
|
||||
|
||||
}
|
||||
catch (e: NoSuchMethodException) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+42
-110
@@ -25,13 +25,11 @@ import com.intellij.openapi.util.io.FileUtil
|
||||
import com.intellij.testGuiFramework.recorder.components.GuiRecorderComponent
|
||||
import com.intellij.testGuiFramework.recorder.ui.Notifier
|
||||
import com.intellij.util.download.DownloadableFileService
|
||||
import com.intellij.util.lang.UrlClassLoader
|
||||
import java.io.BufferedReader
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import java.io.InputStreamReader
|
||||
import java.util.*
|
||||
import java.util.concurrent.Callable
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.stream.Collectors
|
||||
|
||||
@@ -42,19 +40,17 @@ class LocalCompiler {
|
||||
|
||||
private val LOG by lazy { Logger.getInstance("#${LocalCompiler::class.qualifiedName}") }
|
||||
|
||||
var codeHash: Int? = null
|
||||
private var codeHash: Int? = null
|
||||
|
||||
val TEST_CLASS_NAME = "CurrentTest"
|
||||
private val TEST_CLASS_NAME = "CurrentTest"
|
||||
|
||||
val helloKtText = "fun main(args: Array<String>) { \n println(\"Hello, World!\") \n }"
|
||||
val kotlinCompilerJarUrl = "http://central.maven.org/maven2/org/jetbrains/kotlin/kotlin-compiler/1.0.6/kotlin-compiler-1.0.6.jar"
|
||||
val kotlinCompilerJarName = "kotlin-compiler-1.0.6.jar"
|
||||
private val helloKtText = "fun main(args: Array<String>) { \n println(\"Hello, World!\") \n }"
|
||||
private val kotlinCompilerJarUrl = "http://central.maven.org/maven2/org/jetbrains/kotlin/kotlin-compiler/1.0.6/kotlin-compiler-1.0.6.jar"
|
||||
private val kotlinCompilerJarName = "kotlin-compiler-1.0.6.jar"
|
||||
|
||||
val KOTLINC_PLUGIN_DIR = "kotlinc"
|
||||
|
||||
val tempDir by lazy { FileUtil.createTempDirectory("kotlin-compiler-tmp", null, true) }
|
||||
val helloKt by lazy { createTempFile(helloKtText) }
|
||||
var tempFile: File? = null
|
||||
private val tempDir by lazy { FileUtil.createTempDirectory("kotlin-compiler-tmp", null, true) }
|
||||
private val helloKt by lazy { createTempFile(helloKtText) }
|
||||
private var tempFile: File? = null
|
||||
|
||||
private fun createTempFile(content: String, fileName: String = TEST_CLASS_NAME, extension: String = ".kt"): File {
|
||||
val tempFile = FileUtil.createTempFile(fileName, extension, true)
|
||||
@@ -64,25 +60,25 @@ class LocalCompiler {
|
||||
}
|
||||
|
||||
fun compileAndRunOnPooledThread(code: String, classpath: List<String>) {
|
||||
val taskFuture = ApplicationManager.getApplication().executeOnPooledThread({
|
||||
try {
|
||||
if (codeHash == null || codeHash != code.hashCode()) {
|
||||
compile(code, classpath)
|
||||
codeHash = code.hashCode()
|
||||
}
|
||||
run2()
|
||||
}
|
||||
catch (ce: CompilationException) {
|
||||
LOG.error(ce.message)
|
||||
}
|
||||
})
|
||||
val taskFuture = ApplicationManager.getApplication().executeOnPooledThread(
|
||||
{
|
||||
try {
|
||||
if (codeHash == null || codeHash != code.hashCode()) {
|
||||
compile(code, classpath)
|
||||
codeHash = code.hashCode()
|
||||
}
|
||||
run()
|
||||
}
|
||||
catch (ce: CompilationException) {
|
||||
LOG.error(ce.message)
|
||||
}
|
||||
})
|
||||
GuiRecorderComponent.currentTask = taskFuture
|
||||
|
||||
}
|
||||
|
||||
|
||||
//alternative way to run compiled code with pluginClassloader built especially for this file
|
||||
private fun run2() {
|
||||
private fun run() {
|
||||
Notifier.updateStatus("${Notifier.LONG_OPERATION_PREFIX}Script running...")
|
||||
val testUrl = tempDir.toURI().toURL()
|
||||
var classLoadersArray: Array<ClassLoader>
|
||||
@@ -113,52 +109,9 @@ class LocalCompiler {
|
||||
|
||||
}
|
||||
|
||||
private fun run(classpath: List<String>) {
|
||||
|
||||
//TODO: add case for Gradle test
|
||||
if (tempFile == null) throw Exception("Unable to find tempFile")
|
||||
// findClass
|
||||
if (!tempDir.listFiles().any { file -> (file.name.contains(TEST_CLASS_NAME) && file.extension == "class") }) throw Exception(
|
||||
"Unable to locate compiled class files")
|
||||
// val pluginClassLoader = this.javaClass.classLoader as PluginClassLoader
|
||||
// pluginClassLoader.addLibDirectories(listOf(tempDir.path))
|
||||
|
||||
//create a copy of a plugin classloader
|
||||
val urlClassLoader = UrlClassLoader.build().parent(ApplicationManager::class.java.classLoader).urls(
|
||||
classpath.map { it -> File(it).toURI().toURL() }.plus(tempDir.toURI().toURL())).get()
|
||||
val currentTest = urlClassLoader.loadClass(TEST_CLASS_NAME) ?: throw Exception(
|
||||
"Unable to load by pluginClassLoader $TEST_CLASS_NAME.class file")
|
||||
val testCase = currentTest.newInstance()
|
||||
val setUpMethod = currentTest.getMethod("setUp")
|
||||
val testMethod = currentTest.getMethod(ScriptWrapper.TEST_METHOD_NAME)
|
||||
Notifier.updateStatus("${Notifier.LONG_OPERATION_PREFIX}Script running...")
|
||||
GuiRecorderComponent.state = GuiRecorderComponent.States.RUNNING
|
||||
try {
|
||||
setUpMethod.invoke(testCase)
|
||||
testMethod.invoke(testCase)
|
||||
Notifier.updateStatus("Script stopped")
|
||||
GuiRecorderComponent.state = GuiRecorderComponent.States.IDLE
|
||||
}
|
||||
catch (throwable: Throwable) {
|
||||
GuiRecorderComponent.state = GuiRecorderComponent.States.RUNNING_ERROR
|
||||
Notifier.updateStatus("Running error, please see idea.log")
|
||||
throw throwable
|
||||
}
|
||||
}
|
||||
|
||||
fun compileOnPooledThread(code: String, classpath: List<String>) {
|
||||
ApplicationManager.getApplication().executeOnPooledThread(Callable<Boolean> {
|
||||
compile(code, classpath)
|
||||
})
|
||||
}
|
||||
|
||||
fun compile(code: String, classpath: List<String>): Boolean {
|
||||
val tempFile = createTempFile(code)
|
||||
return compile(tempFile, classpath)
|
||||
}
|
||||
private fun compile(code: String, classpath: List<String>): Boolean = compile(createTempFile(code), classpath)
|
||||
|
||||
private fun compile(fileKt: File? = null, classpath: List<String>): Boolean {
|
||||
|
||||
val scriptKt = fileKt ?: helloKt
|
||||
val kotlinCompilerJar = getKotlinCompilerJar()
|
||||
val libDirLocation = getApplicationLibDir().parentFile
|
||||
@@ -183,7 +136,7 @@ class LocalCompiler {
|
||||
LOG.error(BufferedReader(InputStreamReader(process.errorStream)).lines().collect(Collectors.joining("\n")))
|
||||
Notifier.updateStatus("Compilation error (see idea.log)")
|
||||
GuiRecorderComponent.state = GuiRecorderComponent.States.COMPILATION_ERROR
|
||||
throw CompilationException("Compilation error (see idea.log)")
|
||||
throw CompilationException()
|
||||
}
|
||||
else {
|
||||
Notifier.updateStatus("Compilation is done")
|
||||
@@ -195,10 +148,8 @@ class LocalCompiler {
|
||||
private fun getKotlinCompilerJar(): File {
|
||||
val kotlinCompilerDir = getPluginKotlincDir()
|
||||
if (!isKotlinCompilerDir(kotlinCompilerDir)) downloadKotlinCompilerJar(kotlinCompilerDir.path)
|
||||
val kotlinCompilerJar = kotlinCompilerDir.listFiles().filter { file -> file.name.contains("kotlin-compiler") }.firstOrNull()
|
||||
?: throw FileNotFoundException("Unable to find kotlin-compiler*.jar in ${kotlinCompilerDir.path} directory")
|
||||
|
||||
return kotlinCompilerJar
|
||||
return kotlinCompilerDir.listFiles().firstOrNull { file -> file.name.contains("kotlin-compiler") }
|
||||
?: throw FileNotFoundException("Unable to find kotlin-compiler*.jar in ${kotlinCompilerDir.path} directory")
|
||||
}
|
||||
|
||||
private fun getApplicationLibDir(): File {
|
||||
@@ -206,66 +157,47 @@ class LocalCompiler {
|
||||
}
|
||||
|
||||
private fun getPluginKotlincDir(): File {
|
||||
|
||||
// if (ApplicationManager.getApplication().isUnitTestMode || (this.javaClass.classLoader.javaClass.name == "sun.misc.Launcher\$AppClassLoader")) {
|
||||
val tempPath = PathManager.getTempPath()
|
||||
val tempDirFile = File(tempPath)
|
||||
val tempDirFile = File(PathManager.getTempPath())
|
||||
FileUtil.ensureExists(tempDirFile)
|
||||
return tempDirFile
|
||||
// }
|
||||
//
|
||||
// val pluginId = (this.javaClass.classLoader as PluginClassLoader).pluginId
|
||||
// val pluginPath = PluginManager.getPlugin(pluginId)!!.path
|
||||
// val kotlinCompilerDirPath = pluginPath.path + File.separator + KOTLINC_PLUGIN_DIR
|
||||
// val kotlinCompilerDir = File(kotlinCompilerDirPath)
|
||||
//
|
||||
//// ensure that dir for kotlinc is created
|
||||
// FileUtil.ensureExists(kotlinCompilerDir)
|
||||
// return kotlinCompilerDir
|
||||
}
|
||||
|
||||
private fun isKotlinCompilerDir(dir: File): Boolean {
|
||||
return dir.listFiles().any { file -> file.name.contains("kotlin-compiler") }
|
||||
private fun isKotlinCompilerDir(dir: File): Boolean = dir.listFiles().any { file ->
|
||||
file.name.contains("kotlin-compiler")
|
||||
}
|
||||
|
||||
fun downloadKotlinCompilerJar(destDirPath: String?): File {
|
||||
|
||||
private fun downloadKotlinCompilerJar(destDirPath: String?): File {
|
||||
Notifier.updateStatus("${Notifier.LONG_OPERATION_PREFIX}Downloading kotlin-compiler.jar...")
|
||||
val downloader = DownloadableFileService.getInstance()
|
||||
val description = downloader.createFileDescription(kotlinCompilerJarUrl, kotlinCompilerJarName)
|
||||
ApplicationManager.getApplication().invokeAndWait({
|
||||
downloader.createDownloader(Arrays.asList(description), kotlinCompilerJarName)
|
||||
.downloadFilesWithProgress(destDirPath, null, null)
|
||||
})
|
||||
ApplicationManager.getApplication().invokeAndWait(
|
||||
{
|
||||
downloader.createDownloader(Arrays.asList(description), kotlinCompilerJarName).downloadFilesWithProgress(destDirPath, null, null)
|
||||
})
|
||||
Notifier.updateStatus("kotlin-compiler.jar downloaded successfully")
|
||||
return File(destDirPath + File.separator + kotlinCompilerJarName)
|
||||
}
|
||||
|
||||
class CompilationException(s: String) : Exception()
|
||||
private class CompilationException : Exception()
|
||||
|
||||
|
||||
fun buildClasspath(cp: List<String>): String {
|
||||
private fun buildClasspath(cp: List<String>): String {
|
||||
if (SystemInfo.isWindows) {
|
||||
val IDEA_JAR = "idea.jar"
|
||||
val ideaJarPath = cp.find { pathStr -> pathStr.endsWith("${File.separator}$IDEA_JAR") }
|
||||
val ideaLibPath = ideaJarPath!!.substring(startIndex = 0, endIndex = ideaJarPath.length - IDEA_JAR.length - File.separator.length)
|
||||
val ideaJar = "idea.jar"
|
||||
val ideaJarPath = cp.find { pathStr -> pathStr.endsWith("${File.separator}$ideaJar") }
|
||||
val ideaLibPath = ideaJarPath!!.substring(startIndex = 0, endIndex = ideaJarPath.length - ideaJar.length - File.separator.length)
|
||||
return cp.filterNot { pathStr -> pathStr.startsWith(ideaLibPath) }.plus(ideaLibPath).joinToString(";")
|
||||
}
|
||||
else return cp.joinToString(":")
|
||||
}
|
||||
|
||||
private fun getProcessBuilderForWin(kotlinCompilerJar: File,
|
||||
libDirLocation: File,
|
||||
classpath: List<String>,
|
||||
private fun getProcessBuilderForWin(kotlinCompilerJar: File, libDirLocation: File, classpath: List<String>,
|
||||
scriptKt: File): ProcessBuilder {
|
||||
val moduleXmlFile = createTempFile(
|
||||
content = ModuleXmlBuilder.build(outputDir = tempDir.path, classPath = classpath, sourcePath = scriptKt.path), fileName = "module",
|
||||
extension = ".xml")
|
||||
return ProcessBuilder("java", "-jar",
|
||||
kotlinCompilerJar.path,
|
||||
"-kotlin-home", libDirLocation.path,
|
||||
"-module", moduleXmlFile.path,
|
||||
scriptKt.path)
|
||||
return ProcessBuilder(
|
||||
"java", "-jar", kotlinCompilerJar.path, "-kotlin-home", libDirLocation.path, "-module", moduleXmlFile.path, scriptKt.path)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+9
-5
@@ -20,14 +20,18 @@ package com.intellij.testGuiFramework.recorder.compile
|
||||
*/
|
||||
object ModuleXmlBuilder {
|
||||
|
||||
fun module(function: () -> String): String = "<modules>\n${function.invoke()}\n</modules>"
|
||||
private fun module(function: () -> String): String = """<modules>
|
||||
${function.invoke()}
|
||||
</modules>"""
|
||||
|
||||
fun modules(outputDir: String,
|
||||
function: () -> String): String = "<module name=\"main\" outputDir=\"$outputDir\" type=\"java-production\">\n${function.invoke()}\n</module>"
|
||||
private fun modules(outputDir: String, function: () -> String): String =
|
||||
"""<module name="main" outputDir="$outputDir" type="java-production">
|
||||
${function.invoke()}
|
||||
</module>"""
|
||||
|
||||
fun addSource(path: String) = "<sources path=\"$path\"/>"
|
||||
private fun addSource(path: String) = """<sources path="$path"/>"""
|
||||
|
||||
fun addClasspath(path: String) = "<classpath path=\"$path\"/>"
|
||||
private fun addClasspath(path: String) = """<classpath path="$path"/>"""
|
||||
|
||||
|
||||
fun build(outputDir: String, classPath: List<String>, sourcePath: String) =
|
||||
|
||||
Reference in New Issue
Block a user