diff --git a/build.gradle b/build.gradle
index d2a5a212..928554da 100644
--- a/build.gradle
+++ b/build.gradle
@@ -48,7 +48,8 @@ dependencies {
'com.google.inject.extensions:guice-assistedinject:4.0',
'com.google.guava:guava:18.0',
'org.apache.maven:maven-model:3.3.3',
- 'com.github.spullara.mustache.java:compiler:0.8.18'
+ 'com.github.spullara.mustache.java:compiler:0.8.18',
+ "io.reactivex:rxjava:1.0.14"
// compile files("/Users/beust/.kobalt/repository/com/beust/kobalt-example-plugin/build/libs/kobalt-example-plugin.jar")
testCompile 'org.testng:testng:6.9.6'
diff --git a/kobalt.iml b/kobalt.iml
index 99f9efd0..bf0ac307 100644
--- a/kobalt.iml
+++ b/kobalt.iml
@@ -40,5 +40,6 @@
+
\ No newline at end of file
diff --git a/kobalt/src/Build.kt b/kobalt/src/Build.kt
index 84bfe947..71dd7370 100644
--- a/kobalt/src/Build.kt
+++ b/kobalt/src/Build.kt
@@ -66,7 +66,8 @@ val kobalt = kotlinProject(wrapper) {
"com.google.inject.extensions:guice-assistedinject:4.0",
"com.google.guava:guava:19.0-rc2",
"org.apache.maven:maven-model:3.3.3",
- "com.github.spullara.mustache.java:compiler:0.9.1"
+ "com.github.spullara.mustache.java:compiler:0.9.1",
+ "io.reactivex:rxjava:1.0.14"
)
}
}
diff --git a/src/main/kotlin/com/beust/kobalt/Args.kt b/src/main/kotlin/com/beust/kobalt/Args.kt
index 697aa83a..7bb16a29 100644
--- a/src/main/kotlin/com/beust/kobalt/Args.kt
+++ b/src/main/kotlin/com/beust/kobalt/Args.kt
@@ -13,6 +13,9 @@ class Args {
"dependencies")
var checkVersions = false
+ @Parameter(names = arrayOf("--client"))
+ var client: Boolean = false
+
@Parameter(names = arrayOf("--dev"), description = "Turn of dev mode, resulting in a more verbose log output")
var dev: Boolean = false
@@ -29,6 +32,16 @@ class Args {
@Parameter(names = arrayOf("--log"), description = "Define the log level (1-3)")
var log: Int = 1
+ companion object {
+ const val DEFAULT_SERVER_PORT = 3867
+ }
+
+ @Parameter(names = arrayOf("--port"), description = "Port, if --server was specified")
+ var port: Int = DEFAULT_SERVER_PORT
+
+ @Parameter(names = arrayOf("--server"), description = "Run in server mode")
+ var serverMode: Boolean = false
+
@Parameter(names = arrayOf("--tasks"), description = "Display the tasks available for this build")
var tasks: Boolean = false
diff --git a/src/main/kotlin/com/beust/kobalt/Main.kt b/src/main/kotlin/com/beust/kobalt/Main.kt
index 93dae213..8117e284 100644
--- a/src/main/kotlin/com/beust/kobalt/Main.kt
+++ b/src/main/kotlin/com/beust/kobalt/Main.kt
@@ -47,11 +47,19 @@ private class Main @Inject constructor(
val depFactory: DepFactory,
val checkVersions: CheckVersions,
val github: GithubApi,
- val updateKobalt: UpdateKobalt) {
+ val updateKobalt: UpdateKobalt,
+ val client: KobaltClient,
+ val server: KobaltServer) {
data class RunInfo(val jc: JCommander, val args: Args)
public fun run(jc: JCommander, args: Args) : Int {
+
+ if (args.client) {
+ client.run()
+ return 0
+ }
+
var result = 0
val latestVersionFuture = github.latestKobaltVersion
benchmark("Build", {
@@ -120,7 +128,15 @@ private class Main @Inject constructor(
} else {
val context = KobaltContext(args)
Kobalt.context = context
- val allProjects = script2.create(arrayListOf(buildFile)).findProjects()
+ val scriptCompiler = script2.create(arrayListOf(buildFile))
+
+ if (args.serverMode) {
+ scriptCompiler.observable.subscribe {
+ info -> server.sendInfo(info)
+ }
+ executors.miscExecutor.submit(server)
+ }
+ val allProjects = scriptCompiler.findProjects()
//
// Force each project.directory to be an absolute path, if it's not already
diff --git a/src/main/kotlin/com/beust/kobalt/internal/KobaltClient.kt b/src/main/kotlin/com/beust/kobalt/internal/KobaltClient.kt
new file mode 100644
index 00000000..58d9286e
--- /dev/null
+++ b/src/main/kotlin/com/beust/kobalt/internal/KobaltClient.kt
@@ -0,0 +1,52 @@
+package com.beust.kobalt.internal
+
+import com.beust.kobalt.Args
+import com.beust.kobalt.kotlin.ScriptCompiler2
+import com.beust.kobalt.mainNoExit
+import com.beust.kobalt.misc.log
+import com.google.inject.Inject
+import java.io.BufferedReader
+import java.io.InputStreamReader
+import java.io.PrintWriter
+import java.net.ConnectException
+import java.net.Socket
+import java.util.concurrent.Executors
+
+public class KobaltClient @Inject constructor() : Runnable {
+ var outgoing: PrintWriter? = null
+
+ override fun run() {
+ val portNumber = Args.DEFAULT_SERVER_PORT
+
+ Executors.newFixedThreadPool(1).submit {
+ log(1, "Lauching Kobalt main")
+ mainNoExit(arrayOf("--dev", "--server", "assemble"))
+ }
+
+ var done = false
+ var attempts = 1
+ while (attempts < 3 && ! done) {
+ try {
+ val socket = Socket("localhost", portNumber)
+ val ins = BufferedReader(InputStreamReader(socket.inputStream))
+ done = true
+ log(1, "Launching listening server")
+ var fromServer = ins.readLine()
+ while (fromServer != null) {
+ log(1, "From server: " + fromServer);
+ if (fromServer.equals("Bye."))
+ break;
+ fromServer = ins.readLine()
+ }
+ } catch(ex: ConnectException) {
+ log(1, "Server not up, sleeping a bit")
+ Thread.sleep(2000)
+ attempts++
+ }
+ }
+ }
+
+ fun sendInfo(info: ScriptCompiler2.BuildScriptInfo) {
+ outgoing!!.println("Sending info with project count: " + info.projects.size())
+ }
+}
diff --git a/src/main/kotlin/com/beust/kobalt/internal/KobaltServer.kt b/src/main/kotlin/com/beust/kobalt/internal/KobaltServer.kt
new file mode 100644
index 00000000..2305e7ff
--- /dev/null
+++ b/src/main/kotlin/com/beust/kobalt/internal/KobaltServer.kt
@@ -0,0 +1,50 @@
+package com.beust.kobalt.internal
+
+import com.beust.kobalt.Args
+import com.beust.kobalt.kotlin.ScriptCompiler2
+import com.beust.kobalt.misc.log
+import com.google.inject.Inject
+import java.io.BufferedReader
+import java.io.InputStreamReader
+import java.io.PrintWriter
+import java.net.ServerSocket
+
+public class KobaltServer @Inject constructor() : Runnable {
+ var outgoing: PrintWriter? = null
+ val pending = arrayListOf()
+
+ override fun run() {
+ val portNumber = Args.DEFAULT_SERVER_PORT
+
+ log(1, "Starting on port $portNumber")
+ val serverSocket = ServerSocket(portNumber)
+ val clientSocket = serverSocket.accept()
+ outgoing = PrintWriter(clientSocket.outputStream, true)
+ if (pending.size() > 0) {
+ log(1, "Emptying the queue, size $pending.size()")
+ synchronized(pending) {
+ pending.forEach { sendInfo(it) }
+ pending.clear()
+ }
+ }
+ val ins = BufferedReader(InputStreamReader(clientSocket.inputStream))
+ var inputLine = ins.readLine()
+ while (inputLine != null) {
+ log(1, "Received $inputLine")
+ if (inputLine.equals("Bye."))
+ break;
+ inputLine = ins.readLine()
+ }
+ }
+
+ fun sendInfo(info: ScriptCompiler2.BuildScriptInfo) {
+ if (outgoing != null) {
+ outgoing!!.println("Sending info with project count: " + info.projects.size())
+ } else {
+ log(1, "Queuing $info")
+ synchronized(pending) {
+ pending.add(info)
+ }
+ }
+ }
+}
diff --git a/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler2.kt b/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler2.kt
index c8cec56c..52308195 100644
--- a/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler2.kt
+++ b/src/main/kotlin/com/beust/kobalt/kotlin/ScriptCompiler2.kt
@@ -11,6 +11,7 @@ import com.beust.kobalt.misc.countChar
import com.beust.kobalt.misc.log
import com.beust.kobalt.plugin.kotlin.kotlinCompilePrivate
import com.google.inject.assistedinject.Assisted
+import rx.subjects.PublishSubject
import java.io.File
import java.io.FileInputStream
import java.io.InputStream
@@ -29,6 +30,8 @@ public class ScriptCompiler2 @Inject constructor(@Assisted("buildFiles") val bui
fun create(@Assisted("buildFiles") buildFiles: List) : ScriptCompiler2
}
+ val observable = PublishSubject.create()
+
private val SCRIPT_JAR = "buildScript.jar"
fun findProjects(): List {
@@ -38,8 +41,8 @@ public class ScriptCompiler2 @Inject constructor(@Assisted("buildFiles") val bui
val buildScriptJarFile = File(KFiles.findBuildScriptLocation(buildFile, SCRIPT_JAR))
maybeCompileBuildFile(buildFile, buildScriptJarFile, pluginUrls)
- val output = parseBuildScriptJarFile(buildScriptJarFile, pluginUrls)
- result.addAll(output.projects)
+ val buildScriptInfo = parseBuildScriptJarFile(buildScriptJarFile, pluginUrls)
+ result.addAll(buildScriptInfo.projects)
}
return result
}
@@ -130,7 +133,7 @@ public class ScriptCompiler2 @Inject constructor(@Assisted("buildFiles") val bui
class BuildScriptInfo(val projects: List, val classLoader: ClassLoader)
private fun parseBuildScriptJarFile(buildScriptJarFile: File, urls: List) : BuildScriptInfo {
- val result = arrayListOf()
+ val projects = arrayListOf()
var stream : InputStream? = null
val allUrls = arrayListOf().plus(urls).plus(arrayOf(
buildScriptJarFile.toURI().toURL(),
@@ -172,7 +175,7 @@ public class ScriptCompiler2 @Inject constructor(@Assisted("buildFiles") val bui
val r = method.invoke(null)
if (r is Project) {
log(2, "Found project ${r} in class ${cls}")
- result.add(r)
+ projects.add(r)
}
} else {
val taskAnnotation = method.getAnnotation(Task::class.java)
@@ -188,6 +191,8 @@ public class ScriptCompiler2 @Inject constructor(@Assisted("buildFiles") val bui
}
// Now that we all the projects, sort them topologically
- return BuildScriptInfo(Kobalt.sortProjects(result), classLoader)
+ val result = BuildScriptInfo(Kobalt.sortProjects(projects), classLoader)
+ observable.onNext(result)
+ return result
}
}