1
0
Fork 0
mirror of https://github.com/ethauvin/kobalt.git synced 2025-04-26 08:27:12 -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 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
import com.beust.kobalt.misc.log
import com.google.gson.Gson
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.Project
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.KobaltServer
import com.beust.kobalt.internal.KobaltSettings
@ -65,6 +66,7 @@ private class Main @Inject constructor(
val pluginInfo: PluginInfo,
val projectGenerator: ProjectGenerator,
val depFactory: DepFactory,
val dependencyData: DependencyData,
val resolveDependency: ResolveDependency) {
data class RunInfo(val jc: JCommander, val args: Args)
@ -88,7 +90,7 @@ private class Main @Inject constructor(
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
//
@ -101,6 +103,9 @@ private class Main @Inject constructor(
//
pluginInfo.plugins.forEach { Plugins.addPluginInstance(it) }
// val data = dependencyData.dependenciesDataFor(homeDir("kotlin/klaxon/kobalt/src/Build.kt"), Args())
// println("Data: $data")
// --listTemplates
if (args.listTemplates) {
Templates().list(pluginInfo)
@ -174,8 +179,14 @@ private class Main @Inject constructor(
if (!buildFile.exists()) {
error(buildFile.path.toFile().path + " does not exist")
} else {
val allProjects = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo)
val findProjectResult = buildFileCompilerFactory.create(listOf(buildFile), pluginInfo)
.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

View file

@ -2,8 +2,8 @@ package com.beust.kobalt.app
import com.beust.kobalt.Args
import com.beust.kobalt.Constants
import com.beust.kobalt.KobaltException
import com.beust.kobalt.Plugins
import com.beust.kobalt.TaskResult
import com.beust.kobalt.api.Kobalt
import com.beust.kobalt.api.KobaltContext
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"
fun compileBuildFiles(args: Args): List<Project> {
fun compileBuildFiles(args: Args): FindProjectResult {
//
// 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
//
val allProjects = findProjects(context)
plugins.applyPlugins(context, allProjects)
val projectResult = findProjects(context)
if (projectResult.taskResult.success) {
plugins.applyPlugins(context, projectResult.projects)
}
return allProjects
return projectResult
}
val parsedBuildFiles = arrayListOf<ParsedBuildFile>()
private fun findProjects(context: KobaltContext): List<Project> {
val result = arrayListOf<Project>()
class FindProjectResult(val projects: List<Project>, val taskResult: TaskResult)
private fun findProjects(context: KobaltContext): FindProjectResult {
var errorTaskResult: TaskResult? = null
val projects = arrayListOf<Project>()
buildFiles.forEach { buildFile ->
val parsedBuildFile = parseBuildFile(context, buildFile)
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
val modifiedBuildFile = KFiles.createTempFile(".kt")
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),
buildScriptJarFile, pluginUrls)
val projects = buildScriptUtil.runBuildScriptJarFile(buildScriptJarFile, pluginUrls, context)
result.addAll(projects)
if (taskResult.success) {
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,
pluginUrls: List<URL>) {
pluginUrls: List<URL>) : TaskResult {
log(2, "Running build file ${buildFile.name} jar: $buildScriptJarFile")
if (buildScriptUtil.isUpToDate(buildFile, buildScriptJarFile)) {
log(2, "Build file is up to date")
return TaskResult()
} else {
log(2, "Need to recompile ${buildFile.name}")
buildScriptJarFile.delete()
kotlinCompilePrivate {
val result = kotlinCompilePrivate {
classpath(files.kobaltJar)
classpath(pluginUrls.map { it.file })
sourceFiles(listOf(buildFile.path.toFile().absolutePath))
output = buildScriptJarFile
}.compile(context = context)
if (! buildScriptJarFile.exists()) {
throw KobaltException("Could not compile ${buildFile.name}")
}
return result
}
}

View file

@ -31,11 +31,11 @@ class DependencyData @Inject constructor(val executors: KobaltExecutors, val dep
val buildFile = BuildFile(Paths.get(buildFilePath), "GetDependenciesCommand")
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 pluginDependencies = pluginUrls.map { File(it.toURI()) }.map { FileDependency(it.absolutePath) }
projects.forEach { project ->
projectResult.projects.forEach { project ->
val compileDependencies = pluginDependencies.map { toDependencyData(it, "compile") } +
allDeps(project.compileDependencies).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,
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 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) {
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)
}
}

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.ExitCode
import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.PrintStream
import java.nio.charset.Charset
import java.util.*
import javax.inject.Inject
import javax.inject.Singleton
@ -64,8 +67,7 @@ class KotlinCompiler @Inject constructor(
allArgs.add("-no-stdlib")
}
val success = invokeCompiler(projectName ?: "kobalt-" + Random().nextInt(), cp, allArgs)
return TaskResult(success)
return invokeCompiler(projectName ?: "kobalt-" + Random().nextInt(), cp, allArgs)
}
/**
@ -78,10 +80,10 @@ class KotlinCompiler @Inject constructor(
* There are plenty of ways in which this method can break but this will be immediately
* 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
log(2, "Calling kotlinc " + allArgs.joinToString(" "))
val result : Boolean =
val result : TaskResult =
if (true) {
val classLoader = ParentLastClassLoader(cp.map { it.toURI().toURL() })
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
}[0]
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")
"OK" == nameMethod.invoke(exitCode).toString()
val success = "OK" == nameMethod.invoke(exitCode).toString()
TaskResult(success, errorString)
} else {
val exitCode = CLICompiler.doMainNoExit(K2JVMCompiler(), allArgs.toTypedArray())
exitCode == ExitCode.OK
TaskResult(exitCode == ExitCode.OK)
}
return result
}