diff --git a/src/main/kotlin/com/beust/kobalt/Main.kt b/src/main/kotlin/com/beust/kobalt/Main.kt index 0d79d3c9..8b5ab364 100644 --- a/src/main/kotlin/com/beust/kobalt/Main.kt +++ b/src/main/kotlin/com/beust/kobalt/Main.kt @@ -44,13 +44,13 @@ private class Main @Inject constructor( data class RunInfo(val jc: JCommander, val args: Args) - public fun run(jc: JCommander, args: Args) { - + public fun run(jc: JCommander, args: Args) : Int { + var result = 0 val latestVersionFuture = github.latestKobaltVersion benchmark("Build", { println(Banner.get() + Kobalt.version + "\n") // runTest() - runWithArgs(jc, args) + result = runWithArgs(jc, args) executors.shutdown() debug("All done") }) @@ -67,6 +67,7 @@ private class Main @Inject constructor( log(1, it ) } } + return result } public class Worker(val runNodes: ArrayList, val n: T) : IWorker { @@ -94,7 +95,8 @@ private class Main @Inject constructor( private val SCRIPT_JAR = "buildScript.jar" - private fun runWithArgs(jc: JCommander, args: Args) { + private fun runWithArgs(jc: JCommander, args: Args) : Int { + var result = 0 val p = if (args.buildFile != null) File(args.buildFile) else findBuildFile() args.buildFile = p.absolutePath val buildFile = BuildFile(Paths.get(p.absolutePath), p.name) @@ -154,10 +156,14 @@ private class Main @Inject constructor( // // Launch the build // - taskManager.runTargets(args.targets, allProjects) + val thisResult = taskManager.runTargets(args.targets, allProjects) + if (result == 0) { + result = thisResult + } } } } + return result } private fun findBuildFile(): File { diff --git a/src/main/kotlin/com/beust/kobalt/internal/DynamicGraph.kt b/src/main/kotlin/com/beust/kobalt/internal/DynamicGraph.kt index eaceb07d..b1940076 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/DynamicGraph.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/DynamicGraph.kt @@ -39,7 +39,11 @@ public class DynamicGraphExecutor(val graph: DynamicGraph, val executor = Executors.newFixedThreadPool(5, NamedThreadFactory("DynamicGraphExecutor")) val completion = ExecutorCompletionService>(executor) - public fun run() { + /** + * @return 0 if all went well, > 0 otherwise + */ + public fun run() : Int { + var lastResult : TaskResult? = null while (graph.freeNodes.size() > 0) { log(3, "Current count: ${graph.nodeCount}") synchronized(graph) { @@ -55,6 +59,7 @@ public class DynamicGraphExecutor(val graph: DynamicGraph, try { val future = completion.take() val taskResult = future.get(2, TimeUnit.SECONDS) + lastResult = taskResult log(3, "Received task result $taskResult") n-- graph.setStatus(taskResult.value, @@ -70,6 +75,7 @@ public class DynamicGraphExecutor(val graph: DynamicGraph, } } executor.shutdown() + return if (lastResult?.success!!) 0 else 1 } } diff --git a/src/main/kotlin/com/beust/kobalt/internal/TaskManager.kt b/src/main/kotlin/com/beust/kobalt/internal/TaskManager.kt index e2d3212d..cd9f3782 100644 --- a/src/main/kotlin/com/beust/kobalt/internal/TaskManager.kt +++ b/src/main/kotlin/com/beust/kobalt/internal/TaskManager.kt @@ -43,7 +43,8 @@ public class TaskManager @Inject constructor(val plugins: Plugins, val args: Arg fun matches(projectName: String) = project == null || project == projectName } - public fun runTargets(targets: List, projects: List) { + public fun runTargets(targets: List, projects: List) : Int { + var result = 0 val tasksAlreadyRun = hashSetOf() projects.forEach { project -> val projectName = project.name!! @@ -141,10 +142,14 @@ public class TaskManager @Inject constructor(val plugins: Plugins, val args: Arg } val executor = DynamicGraphExecutor(graph, factory) - executor.run() + val thisResult = executor.run() + if (result == 0) { + result = thisResult + } } } } + return result } /** diff --git a/src/main/kotlin/com/beust/kobalt/maven/Http.kt b/src/main/kotlin/com/beust/kobalt/maven/Http.kt index 5ea69649..9f1ea0bc 100644 --- a/src/main/kotlin/com/beust/kobalt/maven/Http.kt +++ b/src/main/kotlin/com/beust/kobalt/maven/Http.kt @@ -55,6 +55,7 @@ public class Http { .put(RequestBody.create(MEDIA_TYPE_BINARY, file)) .build() + log(2, "Uploading $file to $url") val response = OkHttpClient().newCall(request).execute() if (! response.isSuccessful) { error(response) diff --git a/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt b/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt index 3a6f9a08..bb57bc0c 100644 --- a/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt +++ b/src/main/kotlin/com/beust/kobalt/misc/KobaltLogger.kt @@ -15,9 +15,9 @@ interface KobaltLogger { Logger(false) } - fun log(level: Int, s: String) { + fun log(level: Int, s: String, newLine: Boolean = true) { if (level <= LOG_LEVEL) { - logger.log("Logger", s) + logger.log("Logger", s, newLine) } } @@ -30,28 +30,28 @@ interface KobaltLogger { } } - final fun log(level: Int = 1, message: String) { - if (level <= LOG_LEVEL) { - logger.log("Logger", message) - } - } - - final fun debug(message: String) { - logger.debug(message) - } - - final fun error(message: String, e: Throwable? = null) { - logger.error("Logger", "***** $message", e) - } - - final fun warn(message: String, e: Throwable? = null) { - logger.warn("Logger", message, e) - } +// final fun log(level: Int = 1, message: String) { +// if (level <= LOG_LEVEL) { +// logger.log("Logger", message) +// } +// } +// +// final fun debug(message: String) { +// logger.debug(message) +// } +// +// final fun error(message: String, e: Throwable? = null) { +// logger.error("Logger", "***** $message", e) +// } +// +// final fun warn(message: String, e: Throwable? = null) { +// logger.warn("Logger", message, e) +// } } -fun Any.log(level: Int, text: String) { +fun Any.log(level: Int, text: String, newLine : Boolean = true) { if (level <= KobaltLogger.LOG_LEVEL) { - KobaltLogger.logger.log(javaClass.simpleName, text) + KobaltLogger.logger.log(javaClass.simpleName, text, newLine) } } @@ -88,6 +88,9 @@ class Logger(val dev: Boolean) { final fun warn(tag: String, message: String, e: Throwable? = null) = println(getPattern("W", "***** WARNING ", tag, message)) - final fun log(tag: String, message: String) = - println(getPattern("L", "", tag, message)) + final fun log(tag: String, message: String, newLine: Boolean) = + with(getPattern("L", "", tag, message)) { + if (newLine) println(this) + else print("\r" + this) + } } diff --git a/src/main/kotlin/com/beust/kobalt/plugin/publish/JCenterApi.kt b/src/main/kotlin/com/beust/kobalt/plugin/publish/JCenterApi.kt index 43e2cc9b..9ba7ce26 100644 --- a/src/main/kotlin/com/beust/kobalt/plugin/publish/JCenterApi.kt +++ b/src/main/kotlin/com/beust/kobalt/plugin/publish/JCenterApi.kt @@ -14,6 +14,7 @@ import org.jetbrains.annotations.Nullable import java.io.ByteArrayInputStream import java.io.File import java.nio.charset.Charset +import java.util.concurrent.Callable import javax.inject.Inject data class JCenterPackage(val jo: JsonObject) { @@ -44,7 +45,7 @@ open public class UnauthenticatedJCenterApi @Inject constructor(open val http: H public class JCenterApi @Inject constructor (@Nullable @Assisted("username") val username: String?, @Nullable @Assisted("password") val password: String?, - override val http: Http, val gpg: Gpg) : UnauthenticatedJCenterApi(http) { + override val http: Http, val gpg: Gpg, val executors: KobaltExecutors) : UnauthenticatedJCenterApi(http) { interface IFactory { fun create(@Nullable @Assisted("username") username: String?, @@ -100,8 +101,6 @@ public class JCenterApi @Inject constructor (@Nullable @Assisted("username") val private fun upload(files: List, configuration : JCenterConfiguration?, fileToPath: (File) -> String, generateMd5: Boolean = false, generateAsc: Boolean) : TaskResult { - val successes = arrayListOf() - val failures = hashMapOf() val filesToUpload = arrayListOf() if (generateAsc) { @@ -130,34 +129,36 @@ public class JCenterApi @Inject constructor (@Nullable @Assisted("username") val // // TODO: These files should be uploaded from a thread pool instead of serially // - log(1, "Found ${filesToUpload.size()} artifacts to upload") - filesToUpload.forEach { - var path = fileToPath(it) - if (options.size() > 0) { - path += "?" + options.join("&") - } + val fileCount = filesToUpload.size() + log(1, "Found $fileCount artifacts to upload") + val callables = filesToUpload.map { FileUploadCallable(username, password, fileToPath(it), it) } + var i = 1 + val results = executors.completionService("FileUpload", 5, 60000000, callables, { tr: TaskResult -> + val last = i >= fileCount + val end = if (last) "\n" else "" + log(1, " Uploading " + (i++) + " / $fileCount$end", false) + }) + val errorMessages = results.filter { ! it.success }.map { it.errorMessage!! } + if (errorMessages.isEmpty()) { + return TaskResult() + } else { + error("Errors while uploading:\n" + errorMessages.map { " $it" }.join("\n")) + return com.beust.kobalt.internal.TaskResult(false, errorMessages.join("\n")) + } + } - log(1, " Uploading $it to $path") - http.uploadFile(username, password, path, it, - { r: Response -> successes.add(it) }, + inner class FileUploadCallable(val username: String?, val password: String?, val url: String, val file: File) + : Callable { + override fun call(): TaskResult? { + var result: TaskResult? = null + http.uploadFile(username, password, url, file, + { result = TaskResult() }, { r: Response -> val jo = parseResponse(r.body().string()) - failures.put(it, jo.string("message") ?: "No message found") + result = TaskResult(false, jo.string("message") ?: "No message found") }) + return result } - val result: TaskResult - if (successes.size() == filesToUpload.size()) { - log(1, "All artifacts successfully uploaded") - result = TaskResult(true) - } else { - result = TaskResult(false, failures.values().join(" ")) - error("Failed to upload ${failures.size()} files:") - failures.forEach{ entry -> - error(" - ${entry.key} : ${entry.value}") - } - } - - return result } } diff --git a/src/test/kotlin/com/beust/kobalt/internal/DynamicGraphTest.kt b/src/test/kotlin/com/beust/kobalt/internal/DynamicGraphTest.kt index 19084fec..81965fe6 100644 --- a/src/test/kotlin/com/beust/kobalt/internal/DynamicGraphTest.kt +++ b/src/test/kotlin/com/beust/kobalt/internal/DynamicGraphTest.kt @@ -34,7 +34,7 @@ public class DynamicGraphTest { override val priority = 0 override fun call() : TaskResult2 { - log(2, "Running node $n") + KobaltLogger.log(2, "Running node $n") runNodes.add(n) return TaskResult2(errorFunction(n), n) }