diff --git a/src/main/kotlin/com/beust/kobalt/Main.kt b/src/main/kotlin/com/beust/kobalt/Main.kt index 911f9818..6195c6a8 100644 --- a/src/main/kotlin/com/beust/kobalt/Main.kt +++ b/src/main/kotlin/com/beust/kobalt/Main.kt @@ -5,6 +5,8 @@ import com.beust.kobalt.api.Kobalt import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.Project import com.beust.kobalt.internal.* +import com.beust.kobalt.internal.remote.KobaltClient +import com.beust.kobalt.internal.remote.KobaltServer import com.beust.kobalt.kotlin.BuildFile import com.beust.kobalt.maven.* import com.beust.kobalt.misc.* diff --git a/src/main/kotlin/com/beust/kobalt/internal/KobaltServer.kt b/src/main/kotlin/com/beust/kobalt/internal/KobaltServer.kt deleted file mode 100644 index 4781419c..00000000 --- a/src/main/kotlin/com/beust/kobalt/internal/KobaltServer.kt +++ /dev/null @@ -1,155 +0,0 @@ -package com.beust.kobalt.internal - -import com.beust.kobalt.Args -import com.beust.kobalt.kotlin.BuildFile -import com.beust.kobalt.kotlin.BuildFileCompiler -import com.beust.kobalt.maven.IClasspathDependency -import com.beust.kobalt.maven.MavenDependency -import com.beust.kobalt.misc.KobaltExecutors -import com.beust.kobalt.misc.log -import com.google.gson.Gson -import com.google.gson.JsonObject -import com.google.gson.JsonParser -import com.google.inject.Inject -import java.io.BufferedReader -import java.io.InputStreamReader -import java.io.PrintWriter -import java.net.ServerSocket -import java.net.SocketException -import java.nio.file.Paths - -public class KobaltServer @Inject constructor(val args: Args, val executors: KobaltExecutors, - val buildFileCompilerFactory: BuildFileCompiler.IFactory) : Runnable { - var outgoing: PrintWriter? = null - val pending = arrayListOf() - - override fun run() { - val portNumber = args.port - - log1("Listening to port $portNumber") - var quit = false - val serverSocket = ServerSocket(portNumber) - while (! quit) { - val clientSocket = serverSocket.accept() - outgoing = PrintWriter(clientSocket.outputStream, true) - if (pending.size() > 0) { - log1("Emptying the queue, size $pending.size()") - synchronized(pending) { - pending.forEach { sendData(it) } - pending.clear() - } - } - val ins = BufferedReader(InputStreamReader(clientSocket.inputStream)) - try { - var line = ins.readLine() - while (!quit && line != null) { - log1("Received from client $line") - val jo = JsonParser().parse(line) as JsonObject - if ("Quit" == jo.get("name").asString) { - log1("Quitting") - quit = true - } else { - runCommand(jo) - line = ins.readLine() - } - } - } catch(ex: SocketException) { - log1("Client disconnected, resetting") - } - } - } - - interface Command { - fun run(jo: JsonObject) - } - - class CommandData(val commandName: String, val data: String) - - inner class PingCommand() : Command { - override fun run(jo: JsonObject) = sendData("{ \"response\" : \"${jo.toString()}\" }") - } - - inner class GetDependenciesCommand() : Command { - override fun run(jo: JsonObject) { - val buildFile = BuildFile(Paths.get(jo.get("buildFile").asString), "GetDependenciesCommand") - val scriptCompiler = buildFileCompilerFactory.create(listOf(buildFile)) - scriptCompiler.observable.subscribe { - buildScriptInfo -> if (buildScriptInfo.projects.size() > 0) { - sendData(toJson(buildScriptInfo)) - } - } - scriptCompiler.compileBuildFiles(args) - sendData("{ \"name\": \"Quit\" }") - } - } - - class DependencyData(val id: String, val scope: String, val path: String) - - class ProjectData( val name: String, val dependencies: List) - - class GetDependenciesData(val projects: List) { - fun toData() : CommandData { - val data = Gson().toJson(this) - return CommandData("GetDependencies", data) - } - } - - private fun toJson(info: BuildFileCompiler.BuildScriptInfo) : String { - val executor = executors.miscExecutor - val projects = arrayListOf() - - fun toDependencyData(d: IClasspathDependency, scope: String) : DependencyData { - val dep = MavenDependency.create(d.id, executor) - return DependencyData(d.id, scope, dep.jarFile.get().absolutePath) - } - - info.projects.forEach { project -> - val allDependencies = - project.compileDependencies.map { toDependencyData(it, "compile") } + - project.compileProvidedDependencies.map { toDependencyData(it, "provided") } + - project.compileRuntimeDependencies.map { toDependencyData(it, "runtime") } + - project.testDependencies.map { toDependencyData(it, "testCompile") } + - project.testProvidedDependencies.map { toDependencyData(it, "testProvided") } - - projects.add(ProjectData(project.name!!, allDependencies)) - } - log1("Returning BuildScriptInfo") - val result = Gson().toJson(GetDependenciesData(projects).toData()) - log2(" $result") - return result - } - - private val COMMANDS = hashMapOf( - Pair("GetDependencies", GetDependenciesCommand()) - ) - - private fun runCommand(jo: JsonObject) { - val command = jo.get("name").asString - if (command != null) { - COMMANDS.getOrElse(command, { PingCommand() }).run(jo) - } else { - error("Did not find a name in command: $jo") - } - } - - fun sendData(info: String) { - if (outgoing != null) { - outgoing!!.println(info) - } else { - log1("Queuing $info") - synchronized(pending) { - pending.add(info) - } - } - } - - private fun log1(s: String) { - log(1, "[KobaltServer] $s") - } - - private fun log2(s: String) { - log(2, "[KobaltServer] $s") - } -} - - diff --git a/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt new file mode 100644 index 00000000..3b6c7342 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/GetDependenciesCommand.kt @@ -0,0 +1,66 @@ +package com.beust.kobalt.internal.remote + +import com.beust.kobalt.Args +import com.beust.kobalt.kotlin.BuildFile +import com.beust.kobalt.kotlin.BuildFileCompiler +import com.beust.kobalt.maven.IClasspathDependency +import com.beust.kobalt.maven.MavenDependency +import com.beust.kobalt.misc.KobaltExecutors +import com.beust.kobalt.misc.log +import com.google.gson.Gson +import com.google.gson.JsonObject +import com.google.inject.Inject +import java.nio.file.Paths + +class GetDependenciesCommand @Inject constructor(val executors: KobaltExecutors, + val buildFileCompilerFactory: BuildFileCompiler.IFactory, val args: Args) : ICommand { + override val name = "getDependencies" + override fun run(sender: ICommandSender, received: JsonObject) { + val buildFile = BuildFile(Paths.get(received.get("buildFile").asString), "GetDependenciesCommand") + val scriptCompiler = buildFileCompilerFactory.create(listOf(buildFile)) + scriptCompiler.observable.subscribe { + buildScriptInfo -> if (buildScriptInfo.projects.size() > 0) { + sender.sendData(toJson(buildScriptInfo)) + } + } + scriptCompiler.compileBuildFiles(args) + } + + private fun toJson(info: BuildFileCompiler.BuildScriptInfo) : String { + val executor = executors.miscExecutor + val projects = arrayListOf() + + fun toDependencyData(d: IClasspathDependency, scope: String) : DependencyData { + val dep = MavenDependency.create(d.id, executor) + return DependencyData(d.id, scope, dep.jarFile.get().absolutePath) + } + + info.projects.forEach { project -> + val allDependencies = + project.compileDependencies.map { toDependencyData(it, "compile") } + + project.compileProvidedDependencies.map { toDependencyData(it, "provided") } + + project.compileRuntimeDependencies.map { toDependencyData(it, "runtime") } + + project.testDependencies.map { toDependencyData(it, "testCompile") } + + project.testProvidedDependencies.map { toDependencyData(it, "testProvided") } + + projects.add(ProjectData(project.name!!, allDependencies)) + } + log(1, "Returning BuildScriptInfo") + val result = Gson().toJson(GetDependenciesData(projects).toData()) + log(2, " $result") + return result + } +} + +class DependencyData(val id: String, val scope: String, val path: String) + +class ProjectData( val name: String, val dependencies: List) + +class GetDependenciesData(val projects: List) { + fun toData() : CommandData { + val data = Gson().toJson(this) + return CommandData("getDependencies", data) + } +} + + diff --git a/src/main/kotlin/com/beust/kobalt/internal/KobaltClient.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltClient.kt similarity index 94% rename from src/main/kotlin/com/beust/kobalt/internal/KobaltClient.kt rename to src/main/kotlin/com/beust/kobalt/internal/remote/KobaltClient.kt index 2c938dc4..cf9935e9 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/KobaltClient.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltClient.kt @@ -1,4 +1,4 @@ -package com.beust.kobalt.internal +package com.beust.kobalt.internal.remote import com.beust.kobalt.Args import com.beust.kobalt.SystemProperties @@ -47,7 +47,7 @@ public class KobaltClient @Inject constructor() : Runnable { done = true } else { val data = jo.get("data").asString - val dd = Gson().fromJson(data, KobaltServer.GetDependenciesData::class.java) + val dd = Gson().fromJson(data, GetDependenciesData::class.java) println("Read GetDependencyData, project count: ${dd.projects.size()}") line = ins.readLine() } diff --git a/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltServer.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltServer.kt new file mode 100644 index 00000000..f1ac4f55 --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/KobaltServer.kt @@ -0,0 +1,112 @@ +package com.beust.kobalt.internal.remote + +import com.beust.kobalt.Args +import com.beust.kobalt.api.Kobalt +import com.beust.kobalt.misc.log +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import com.google.inject.Inject +import com.google.inject.Singleton +import java.io.BufferedReader +import java.io.InputStreamReader +import java.io.PrintWriter +import java.net.ServerSocket +import java.net.SocketException + +interface ICommandSender { + fun sendData(content: String) +} + +interface ICommand { + val name: String + fun run(sender: ICommandSender, received: JsonObject) +} + +class CommandData(val commandName: String, val data: String) + +@Singleton +public class KobaltServer @Inject constructor(val args: Args) : Runnable, ICommandSender { + var outgoing: PrintWriter? = null + val pending = arrayListOf() + + private val COMMAND_CLASSES = listOf(GetDependenciesCommand::class.java, PingCommand::class.java) + + private val COMMANDS = hashMapOf() + + init { + COMMAND_CLASSES.forEach { + val c = Kobalt.INJECTOR.getInstance(it) + COMMANDS.put(c.name, c) + } + } + + override fun run() { + val portNumber = args.port + + log1("Listening to port $portNumber") + var quit = false + val serverSocket = ServerSocket(portNumber) + while (! quit) { + val clientSocket = serverSocket.accept() + outgoing = PrintWriter(clientSocket.outputStream, true) + if (pending.size() > 0) { + log1("Emptying the queue, size $pending.size()") + synchronized(pending) { + pending.forEach { sendData(it) } + pending.clear() + } + } + val ins = BufferedReader(InputStreamReader(clientSocket.inputStream)) + try { + var line = ins.readLine() + while (!quit && line != null) { + log1("Received from client $line") + val jo = JsonParser().parse(line) as JsonObject + if ("Quit" == jo.get("name").asString) { + log1("Quitting") + quit = true + } else { + runCommand(jo) + + // Done, send a quit to the client + sendData("{ \"name\": \"Quit\" }") + + line = ins.readLine() + } + } + } catch(ex: SocketException) { + log1("Client disconnected, resetting") + } + } + } + + private fun runCommand(jo: JsonObject) { + val command = jo.get("name").asString + if (command != null) { + COMMANDS.getOrElse(command, { PingCommand() }).run(this, jo) + } else { + error("Did not find a name in command: $jo") + } + } + + override fun sendData(info: String) { + if (outgoing != null) { + outgoing!!.println(info) + } else { + log1("Queuing $info") + synchronized(pending) { + pending.add(info) + } + } + } + + private fun log1(s: String) { + log(1, "[KobaltServer] $s") + } + + private fun log2(s: String) { + log(2, "[KobaltServer] $s") + } +} + + diff --git a/src/main/kotlin/com/beust/kobalt/internal/remote/PingCommand.kt b/src/main/kotlin/com/beust/kobalt/internal/remote/PingCommand.kt new file mode 100644 index 00000000..432caf3d --- /dev/null +++ b/src/main/kotlin/com/beust/kobalt/internal/remote/PingCommand.kt @@ -0,0 +1,10 @@ +package com.beust.kobalt.internal.remote + +import com.google.gson.JsonObject + +class PingCommand() : ICommand { + override val name = "ping" + override fun run(sender: ICommandSender, received: JsonObject) = + sender.sendData("{ \"response\" : \"${received.toString()}\"" + " }") +} + diff --git a/src/main/kotlin/com/beust/kobalt/kotlin/BuildFileCompiler.kt b/src/main/kotlin/com/beust/kobalt/kotlin/BuildFileCompiler.kt index 386dd4c5..7b9ac9d0 100644 --- a/src/main/kotlin/com/beust/kobalt/kotlin/BuildFileCompiler.kt +++ b/src/main/kotlin/com/beust/kobalt/kotlin/BuildFileCompiler.kt @@ -7,7 +7,7 @@ import com.beust.kobalt.api.KobaltContext import com.beust.kobalt.api.Plugin import com.beust.kobalt.api.Project import com.beust.kobalt.api.annotation.Task -import com.beust.kobalt.internal.KobaltServer +import com.beust.kobalt.internal.remote.KobaltServer import com.beust.kobalt.maven.KobaltException import com.beust.kobalt.misc.* import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate