diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/KotlinCompileUtil.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/KotlinCompileUtil.kt index 01f52df1628f..1653cf439ece 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/KotlinCompileUtil.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/KotlinCompileUtil.kt @@ -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 { + private fun getAllUrls(): List { 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 { - 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 { + var methodName = "getUrls" + val methodAlternativeName = "getURLs" - fun URL.getParentURL() = File(this.file).parentFile.toURI().toURL() - - fun ClassLoader.forcedUrls(): List { - - 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 { + private fun ClassLoader.forcedBaseUrls(): List { try { - return ((this.javaClass.getMethod("getBaseUrls").invoke( - this) as? List<*>)!!.filter { it is URL && it.protocol == "file" && !it.file.endsWith("jar!") }) as List + return ((this.javaClass.getMethod("getBaseUrls").invoke(this) as? List<*>)!!. + filter { it is URL && it.protocol == "file" && !it.file.endsWith("jar!") }) as List } catch (e: NoSuchMethodException) { return emptyList() } - - } } \ No newline at end of file diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/LocalCompiler.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/LocalCompiler.kt index a133e4cd6023..b2133ff65427 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/LocalCompiler.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/LocalCompiler.kt @@ -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) { \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) { \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) { - 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 @@ -113,52 +109,9 @@ class LocalCompiler { } - private fun run(classpath: List) { - - //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) { - ApplicationManager.getApplication().executeOnPooledThread(Callable { - compile(code, classpath) - }) - } - - fun compile(code: String, classpath: List): Boolean { - val tempFile = createTempFile(code) - return compile(tempFile, classpath) - } + private fun compile(code: String, classpath: List): Boolean = compile(createTempFile(code), classpath) private fun compile(fileKt: File? = null, classpath: List): 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 { + private fun buildClasspath(cp: List): 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, + private fun getProcessBuilderForWin(kotlinCompilerJar: File, libDirLocation: File, classpath: List, 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) } } diff --git a/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/ModuleXmlBuilder.kt b/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/ModuleXmlBuilder.kt index 3e0b074089ca..35aac468ec06 100644 --- a/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/ModuleXmlBuilder.kt +++ b/platform/testGuiFramework/src/com/intellij/testGuiFramework/recorder/compile/ModuleXmlBuilder.kt @@ -20,14 +20,18 @@ package com.intellij.testGuiFramework.recorder.compile */ object ModuleXmlBuilder { - fun module(function: () -> String): String = "\n${function.invoke()}\n" + private fun module(function: () -> String): String = """ +${function.invoke()} +""" - fun modules(outputDir: String, - function: () -> String): String = "\n${function.invoke()}\n" + private fun modules(outputDir: String, function: () -> String): String = + """ +${function.invoke()} +""" - fun addSource(path: String) = "" + private fun addSource(path: String) = """""" - fun addClasspath(path: String) = "" + private fun addClasspath(path: String) = """""" fun build(outputDir: String, classPath: List, sourcePath: String) =