1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-27 08:38:13 -07:00

Modify commands to report errors to the IDEA plug-in.

This commit is contained in:
Cedric Beust 2016-03-16 01:26:49 +04:00
parent 806ca59f97
commit ce435adf25
7 changed files with 68 additions and 33 deletions

View file

@ -17,7 +17,7 @@ interface ICommand {
*/ */
fun run(sender: ICommandSender, received: JsonObject) fun run(sender: ICommandSender, received: JsonObject)
fun toCommandData(data: String) = CommandData(name, data) fun toCommandData(data: String, error: String? = null) = CommandData(name, data, error)
} }
/** /**

View file

@ -1,6 +1,5 @@
package com.beust.kobalt.internal.remote package com.beust.kobalt.internal.remote
import com.beust.kobalt.misc.log
import com.google.gson.Gson import com.google.gson.Gson
import com.google.gson.JsonObject import com.google.gson.JsonObject

View file

@ -6,6 +6,7 @@ import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.PluginTask import com.beust.kobalt.api.PluginTask
import com.beust.kobalt.api.Project import com.beust.kobalt.api.Project
import com.beust.kobalt.app.* import com.beust.kobalt.app.*
import com.beust.kobalt.app.remote.DependencyData
import com.beust.kobalt.app.remote.KobaltClient import com.beust.kobalt.app.remote.KobaltClient
import com.beust.kobalt.app.remote.KobaltServer import com.beust.kobalt.app.remote.KobaltServer
import com.beust.kobalt.internal.KobaltSettings import com.beust.kobalt.internal.KobaltSettings
@ -65,6 +66,7 @@ private class Main @Inject constructor(
val pluginInfo: PluginInfo, val pluginInfo: PluginInfo,
val projectGenerator: ProjectGenerator, val projectGenerator: ProjectGenerator,
val depFactory: DepFactory, val depFactory: DepFactory,
val dependencyData: DependencyData,
val resolveDependency: ResolveDependency) { val resolveDependency: ResolveDependency) {
data class RunInfo(val jc: JCommander, val args: Args) data class RunInfo(val jc: JCommander, val args: Args)
@ -88,7 +90,7 @@ private class Main @Inject constructor(
return pluginClassLoader return pluginClassLoader
} }
public fun run(jc: JCommander, args: Args, argv: Array<String>): Int { fun run(jc: JCommander, args: Args, argv: Array<String>): Int {
// //
// Install plug-ins requested from the command line // Install plug-ins requested from the command line
// //
@ -101,6 +103,9 @@ private class Main @Inject constructor(
// //
pluginInfo.plugins.forEach { Plugins.addPluginInstance(it) } pluginInfo.plugins.forEach { Plugins.addPluginInstance(it) }
// val data = dependencyData.dependenciesDataFor(homeDir("kotlin/klaxon/kobalt/src/Build.kt"), Args())
// println("Data: $data")
// --listTemplates // --listTemplates
if (args.listTemplates) { if (args.listTemplates) {
Templates().list(pluginInfo) Templates().list(pluginInfo)
@ -174,8 +179,14 @@ private class Main @Inject constructor(
if (!buildFile.exists()) { if (!buildFile.exists()) {
error(buildFile.path.toFile().path + " does not exist") error(buildFile.path.toFile().path + " does not exist")
} else { } else {
val allProjects = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) val findProjectResult = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo)
.compileBuildFiles(args) .compileBuildFiles(args)
if (! findProjectResult.taskResult.success) {
throw KobaltException("Couldn't compile build file: "
+ findProjectResult.taskResult.errorMessage)
}
val allProjects = findProjectResult.projects
// //
// Now that we have projects, add all the repos from repo contributors that need a Project // Now that we have projects, add all the repos from repo contributors that need a Project

View file

@ -2,8 +2,8 @@ package com.beust.kobalt.app
import com.beust.kobalt.Args import com.beust.kobalt.Args
import com.beust.kobalt.Constants import com.beust.kobalt.Constants
import com.beust.kobalt.KobaltException
import com.beust.kobalt.Plugins import com.beust.kobalt.Plugins
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.KobaltContext
import com.beust.kobalt.api.PluginProperties import com.beust.kobalt.api.PluginProperties
@ -39,7 +39,7 @@ public class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val b
private val SCRIPT_JAR = "buildScript.jar" private val SCRIPT_JAR = "buildScript.jar"
fun compileBuildFiles(args: Args): List<Project> { fun compileBuildFiles(args: Args): FindProjectResult {
// //
// Create the KobaltContext // Create the KobaltContext
// //
@ -54,16 +54,21 @@ public class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val b
// //
// Find all the projects in the build file, possibly compiling them // Find all the projects in the build file, possibly compiling them
// //
val allProjects = findProjects(context) val projectResult = findProjects(context)
plugins.applyPlugins(context, allProjects) if (projectResult.taskResult.success) {
plugins.applyPlugins(context, projectResult.projects)
}
return allProjects return projectResult
} }
val parsedBuildFiles = arrayListOf<ParsedBuildFile>() val parsedBuildFiles = arrayListOf<ParsedBuildFile>()
private fun findProjects(context: KobaltContext): List<Project> { class FindProjectResult(val projects: List<Project>, val taskResult: TaskResult)
val result = arrayListOf<Project>()
private fun findProjects(context: KobaltContext): FindProjectResult {
var errorTaskResult: TaskResult? = null
val projects = arrayListOf<Project>()
buildFiles.forEach { buildFile -> buildFiles.forEach { buildFile ->
val parsedBuildFile = parseBuildFile(context, buildFile) val parsedBuildFile = parseBuildFile(context, buildFile)
parsedBuildFiles.add(parsedBuildFile) parsedBuildFiles.add(parsedBuildFile)
@ -83,35 +88,39 @@ public class BuildFileCompiler @Inject constructor(@Assisted("buildFiles") val b
// compile it, jar it in buildScript.jar and run it // compile it, jar it in buildScript.jar and run it
val modifiedBuildFile = KFiles.createTempFile(".kt") val modifiedBuildFile = KFiles.createTempFile(".kt")
KFiles.saveFile(modifiedBuildFile, parsedBuildFile.buildScriptCode) KFiles.saveFile(modifiedBuildFile, parsedBuildFile.buildScriptCode)
maybeCompileBuildFile(context, BuildFile(Paths.get(modifiedBuildFile.path), val taskResult = maybeCompileBuildFile(context, BuildFile(Paths.get(modifiedBuildFile.path),
"Modified ${Constants.BUILD_FILE_NAME}", buildFile.realPath), "Modified ${Constants.BUILD_FILE_NAME}", buildFile.realPath),
buildScriptJarFile, pluginUrls) buildScriptJarFile, pluginUrls)
val projects = buildScriptUtil.runBuildScriptJarFile(buildScriptJarFile, pluginUrls, context) if (taskResult.success) {
result.addAll(projects) projects.addAll(buildScriptUtil.runBuildScriptJarFile(buildScriptJarFile, pluginUrls, context))
} else {
if (errorTaskResult == null) {
errorTaskResult = taskResult
} }
return result }
}
return FindProjectResult(projects, if (errorTaskResult != null) errorTaskResult!! else TaskResult())
} }
private fun maybeCompileBuildFile(context: KobaltContext, buildFile: BuildFile, buildScriptJarFile: File, private fun maybeCompileBuildFile(context: KobaltContext, buildFile: BuildFile, buildScriptJarFile: File,
pluginUrls: List<URL>) { pluginUrls: List<URL>) : TaskResult {
log(2, "Running build file ${buildFile.name} jar: $buildScriptJarFile") log(2, "Running build file ${buildFile.name} jar: $buildScriptJarFile")
if (buildScriptUtil.isUpToDate(buildFile, buildScriptJarFile)) { if (buildScriptUtil.isUpToDate(buildFile, buildScriptJarFile)) {
log(2, "Build file is up to date") log(2, "Build file is up to date")
return TaskResult()
} else { } else {
log(2, "Need to recompile ${buildFile.name}") log(2, "Need to recompile ${buildFile.name}")
buildScriptJarFile.delete() buildScriptJarFile.delete()
kotlinCompilePrivate { val result = kotlinCompilePrivate {
classpath(files.kobaltJar) classpath(files.kobaltJar)
classpath(pluginUrls.map { it.file }) classpath(pluginUrls.map { it.file })
sourceFiles(listOf(buildFile.path.toFile().absolutePath)) sourceFiles(listOf(buildFile.path.toFile().absolutePath))
output = buildScriptJarFile output = buildScriptJarFile
}.compile(context = context) }.compile(context = context)
if (! buildScriptJarFile.exists()) { return result
throw KobaltException("Could not compile ${buildFile.name}")
}
} }
} }

View file

@ -31,11 +31,11 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
val buildFile = BuildFile(Paths.get(buildFilePath), "GetDependenciesCommand") val buildFile = BuildFile(Paths.get(buildFilePath), "GetDependenciesCommand")
val buildFileCompiler = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo) val buildFileCompiler = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo)
val projects = buildFileCompiler.compileBuildFiles(args) val projectResult = buildFileCompiler.compileBuildFiles(args)
val pluginUrls = buildFileCompiler.parsedBuildFiles.flatMap { it.pluginUrls } val pluginUrls = buildFileCompiler.parsedBuildFiles.flatMap { it.pluginUrls }
val pluginDependencies = pluginUrls.map { File(it.toURI()) }.map { FileDependency(it.absolutePath) } val pluginDependencies = pluginUrls.map { File(it.toURI()) }.map { FileDependency(it.absolutePath) }
projects.forEach { project -> projectResult.projects.forEach { project ->
val compileDependencies = pluginDependencies.map { toDependencyData(it, "compile") } + val compileDependencies = pluginDependencies.map { toDependencyData(it, "compile") } +
allDeps(project.compileDependencies).map { toDependencyData(it, "compile") } + allDeps(project.compileDependencies).map { toDependencyData(it, "compile") } +
allDeps(project.compileProvidedDependencies).map { toDependencyData(it, "compile") } allDeps(project.compileProvidedDependencies).map { toDependencyData(it, "compile") }
@ -57,7 +57,7 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
compileDependencies, testDependencies, compileDependencies, testDependencies,
sources.second.toSet(), tests.second.toSet(), sources.first.toSet(), tests.first.toSet())) sources.second.toSet(), tests.second.toSet(), sources.first.toSet(), tests.first.toSet()))
} }
return GetDependenciesData(projectDatas) return GetDependenciesData(projectDatas, projectResult.taskResult.errorMessage)
} }
///// /////
@ -72,5 +72,5 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
val testDependencies: List<DependencyData>, val sourceDirs: Set<String>, val testDirs: Set<String>, val testDependencies: List<DependencyData>, val sourceDirs: Set<String>, val testDirs: Set<String>,
val sourceResourceDirs: Set<String>, val testResourceDirs: Set<String>) val sourceResourceDirs: Set<String>, val testResourceDirs: Set<String>)
class GetDependenciesData(val projects: List<ProjectData>) class GetDependenciesData(val projects: List<ProjectData>, val errorMessage: String?)
} }

View file

@ -19,7 +19,8 @@ class GetDependenciesCommand @Inject constructor(val args: Args, val dependencyD
override fun run(sender: ICommandSender, received: JsonObject) { override fun run(sender: ICommandSender, received: JsonObject) {
val buildFile = received.get("buildFile").asString val buildFile = received.get("buildFile").asString
val data = toCommandData(Gson().toJson(dependencyData.dependenciesDataFor(buildFile, args))) val dd = dependencyData.dependenciesDataFor(buildFile, args)
val data = toCommandData(Gson().toJson(dd), dd.errorMessage)
sender.sendData(data) sender.sendData(data)
} }
} }

View file

@ -14,7 +14,10 @@ import com.beust.kobalt.misc.log
import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.CLICompiler
import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
import java.io.PrintStream
import java.nio.charset.Charset
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -64,8 +67,7 @@ class KotlinCompiler @Inject constructor(
allArgs.add("-no-stdlib") allArgs.add("-no-stdlib")
} }
val success = invokeCompiler(projectName ?: "kobalt-" + Random().nextInt(), cp, allArgs) return invokeCompiler(projectName ?: "kobalt-" + Random().nextInt(), cp, allArgs)
return TaskResult(success)
} }
/** /**
@ -78,10 +80,10 @@ class KotlinCompiler @Inject constructor(
* There are plenty of ways in which this method can break but this will be immediately * There are plenty of ways in which this method can break but this will be immediately
* apparent if it happens. * apparent if it happens.
*/ */
private fun invokeCompiler(projectName: String, cp: List<File>, args: List<String>): Boolean { private fun invokeCompiler(projectName: String, cp: List<File>, args: List<String>): TaskResult {
val allArgs = listOf("-module-name", "project-" + projectName) + args val allArgs = listOf("-module-name", "project-" + projectName) + args
log(2, "Calling kotlinc " + allArgs.joinToString(" ")) log(2, "Calling kotlinc " + allArgs.joinToString(" "))
val result : Boolean = val result : TaskResult =
if (true) { if (true) {
val classLoader = ParentLastClassLoader(cp.map { it.toURI().toURL() }) val classLoader = ParentLastClassLoader(cp.map { it.toURI().toURL() })
val compiler = classLoader.loadClass("org.jetbrains.kotlin.cli.common.CLICompiler") val compiler = classLoader.loadClass("org.jetbrains.kotlin.cli.common.CLICompiler")
@ -89,13 +91,26 @@ class KotlinCompiler @Inject constructor(
it.name == "doMainNoExit" && it.parameterTypes.size == 2 it.name == "doMainNoExit" && it.parameterTypes.size == 2
}[0] }[0]
val kCompiler = classLoader.loadClass("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler") val kCompiler = classLoader.loadClass("org.jetbrains.kotlin.cli.jvm.K2JVMCompiler")
val compilerInstance = kCompiler.newInstance()
val exitCode = compilerMain.invoke(null, compilerInstance, allArgs.toTypedArray()) //
// In order to capture the error stream, I need to invoke CLICompiler.exec(), which
// is the first method that accepts a PrintStream for the errors in parameter
//
val baos = ByteArrayOutputStream()
val ps = PrintStream(baos)
val execMethod = compiler.declaredMethods.filter {
it.name == "exec" && it.parameterTypes.size == 2
}[0]
val exitCode = execMethod.invoke(kCompiler.newInstance(), ps, allArgs.toTypedArray())
val errorString = baos.toString(Charset.defaultCharset().toString())
// The return value is an enum
val nameMethod = exitCode.javaClass.getMethod("name") val nameMethod = exitCode.javaClass.getMethod("name")
"OK" == nameMethod.invoke(exitCode).toString() val success = "OK" == nameMethod.invoke(exitCode).toString()
TaskResult(success, errorString)
} else { } else {
val exitCode = CLICompiler.doMainNoExit(K2JVMCompiler(), allArgs.toTypedArray()) val exitCode = CLICompiler.doMainNoExit(K2JVMCompiler(), allArgs.toTypedArray())
exitCode == ExitCode.OK TaskResult(exitCode == ExitCode.OK)
} }
return result return result
} }