centralise output sink class and rework into a task context
diff --git a/WORKSPACE b/WORKSPACE
index e68b3c4..af7d9de 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -39,7 +39,7 @@
github_archive(
name = "bazel_skylib",
repo = "bazelbuild/bazel-skylib",
- commit = "6301f974f02350fe973d8631cf1bb87ab8d2a2bd"
+ commit = "3fea8cb680f4a53a129f7ebace1a5a4d1e035914"
)
github_archive(
diff --git a/kotlin/builder/integrationtests/KotlinBuilderTestCase.java b/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
index 71b69b5..3bfa7db 100644
--- a/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
+++ b/kotlin/builder/integrationtests/KotlinBuilderTestCase.java
@@ -29,7 +29,6 @@
private final JvmCompilationTask.Builder builder = JvmCompilationTask.newBuilder();
private final KotlinBuilderComponent component =
DaggerKotlinBuilderComponent.builder()
- .out(System.err)
.toolchain(KotlinToolchain.createToolchain())
.build();
diff --git a/kotlin/builder/integrationtests/KotlinBuilderTests.java b/kotlin/builder/integrationtests/KotlinBuilderTests.java
index 56534f7..df4ebea 100644
--- a/kotlin/builder/integrationtests/KotlinBuilderTests.java
+++ b/kotlin/builder/integrationtests/KotlinBuilderTests.java
@@ -2,6 +2,7 @@
import com.google.common.truth.Truth;
import com.google.devtools.build.lib.view.proto.Deps;
+import io.bazel.kotlin.builder.utils.CompilationTaskContext;
import io.bazel.kotlin.model.JvmCompilationTask;
import org.junit.Test;
@@ -44,9 +45,13 @@
}
}
int timeoutSeconds = 10;
-// KotlinJvmTaskExecutor executor = instance(KotlinJvmTaskExecutor.class);
try {
- CompletableFuture.runAsync(() -> component().jvmTaskExecutor().execute(command))
+
+ CompletableFuture.runAsync(
+ () ->
+ component()
+ .jvmTaskExecutor()
+ .execute(new CompilationTaskContext(command.getInfo(), System.err), command))
.get(timeoutSeconds, TimeUnit.SECONDS);
} catch (TimeoutException e) {
throw new AssertionError("did not complete in: " + timeoutSeconds);
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/BUILD b/kotlin/builder/src/io/bazel/kotlin/builder/BUILD
index f76b592..f270e45 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/BUILD
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/BUILD
@@ -40,10 +40,10 @@
":builder_kt",
"//kotlin/builder/proto:kotlin_model",
"//third_party:dagger",
- "@com_github_jetbrains_kotlin//:annotations",
+ "@com_github_jetbrains_kotlin//:kotlin-stdlib",
+ "@io_bazel_rules_kotlin_com_google_protobuf_protobuf_java//jar",
],
runtime_deps = [
- "@com_github_jetbrains_kotlin//:kotlin-stdlib",
"@com_github_jetbrains_kotlin//:kotlin-stdlib-jdk7",
"@com_github_jetbrains_kotlin//:kotlin-stdlib-jdk8",
"@io_bazel_rules_kotlin_com_google_code_gson_gson//jar",
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderComponent.java b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderComponent.java
index 73e187a..db95f4d 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderComponent.java
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderComponent.java
@@ -18,32 +18,32 @@
import dagger.BindsInstance;
import dagger.Component;
import dagger.Provides;
+import io.bazel.kotlin.builder.tasks.BazelWorker;
import io.bazel.kotlin.builder.tasks.KotlinBuilder;
import io.bazel.kotlin.builder.tasks.jvm.KotlinJvmCompiler;
import io.bazel.kotlin.builder.tasks.jvm.KotlinJvmTaskExecutor;
import io.bazel.kotlin.builder.toolchain.KotlinToolchain;
-import io.bazel.kotlin.builder.tasks.BazelWorker;
import io.bazel.kotlin.builder.utils.KotlinCompilerPluginArgsEncoder;
import javax.inject.Singleton;
import java.io.PrintStream;
+import java.util.function.Supplier;
@Singleton
@dagger.Component(modules = {KotlinBuilderComponent.Module.class})
public interface KotlinBuilderComponent {
KotlinToolchain toolchain();
+
KotlinJvmTaskExecutor jvmTaskExecutor();
+
KotlinJvmCompiler jvmCompiler();
+
BazelWorker worker();
@Component.Builder
interface Builder {
@BindsInstance
KotlinBuilderComponent.Builder toolchain(KotlinToolchain toolchain);
-
- @BindsInstance
- KotlinBuilderComponent.Builder out(PrintStream out);
-
KotlinBuilderComponent build();
}
@@ -56,6 +56,11 @@
}
@Provides
+ public PrintStream provideDebugPrintStream() {
+ return System.err;
+ }
+
+ @Provides
public BazelWorker provideWorker(KotlinBuilder builder) {
return new BazelWorker(builder, System.err, "KotlinCompile");
}
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderMain.java b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderMain.java
index c7182da..c98ad2d 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderMain.java
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/KotlinBuilderMain.java
@@ -17,6 +17,8 @@
import io.bazel.kotlin.builder.toolchain.KotlinToolchain;
+import javax.inject.Provider;
+import java.io.PrintStream;
import java.util.Arrays;
public class KotlinBuilderMain {
@@ -24,7 +26,6 @@
KotlinBuilderComponent component =
DaggerKotlinBuilderComponent.builder()
.toolchain(KotlinToolchain.createToolchain())
- .out(System.err)
.build();
System.exit(component.worker().apply(Arrays.asList(args)));
}
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt
index 8fd3bc0..8c6c973 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt
@@ -20,16 +20,19 @@
import io.bazel.kotlin.builder.toolchain.CompilationStatusException
import io.bazel.kotlin.builder.utils.*
import io.bazel.kotlin.model.*
+import java.io.PrintStream
import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths
import java.util.regex.Pattern
import javax.inject.Inject
+import javax.inject.Provider
import javax.inject.Singleton
@Singleton
@Suppress("MemberVisibilityCanBePrivate")
class KotlinBuilder @Inject internal constructor(
+ private val outputProvider: Provider<PrintStream>,
private val jvmTaskExecutor: KotlinJvmTaskExecutor
) : CommandLineProgram {
companion object {
@@ -45,19 +48,12 @@
}
override fun apply(args: List<String>): Int {
- check(args.isNotEmpty()) { "expected at least a single arg got: ${args.joinToString(" ")}" }
- val (flagFileName, primaryOutputPath, idx) =
- checkNotNull(FLAGFILE_RE.matchEntire(args[0])) { "invalid flagfile ${args[0]}" }.destructured
- val argMap = Files.readAllLines(Paths.get(flagFileName), StandardCharsets.UTF_8).let(ArgMaps::from)
- val commonInfo = buildTaskInfo(argMap).also {
- it.primaryOutputPath = primaryOutputPath
- }.build()
-
+ val (argMap, context) = buildContext(args)
try {
@Suppress("WHEN_ENUM_CAN_BE_NULL_IN_JAVA")
- when (commonInfo.platform) {
- Platform.JVM -> executeJvmTask(commonInfo, argMap)
- Platform.UNRECOGNIZED, Platform.JS -> throw IllegalStateException("unrecognized platform: $commonInfo")
+ when (context.info.platform) {
+ Platform.JVM -> executeJvmTask(context, argMap)
+ Platform.UNRECOGNIZED, Platform.JS -> throw IllegalStateException("unrecognized platform: ${context.info}")
}
} catch (ex: CompilationStatusException) {
return ex.status
@@ -65,6 +61,18 @@
return 0
}
+ private fun buildContext(args: List<String>): Pair<ArgMap, CompilationTaskContext> {
+ check(args.isNotEmpty()) { "expected at least a single arg got: ${args.joinToString(" ")}" }
+ val (flagFileName, primaryOutputPath, idx) =
+ checkNotNull(FLAGFILE_RE.matchEntire(args[0])) { "invalid flagfile ${args[0]}" }.destructured
+ val argMap = Files.readAllLines(Paths.get(flagFileName), StandardCharsets.UTF_8).let(ArgMaps::from)
+ val info = buildTaskInfo(argMap).also {
+ it.primaryOutputPath = primaryOutputPath
+ }.build()
+ val context = CompilationTaskContext(info, outputProvider.get())
+ return Pair(argMap, context)
+ }
+
/**
* Declares the flags used by the java builder.
@@ -142,8 +150,11 @@
this
}
- private fun executeJvmTask(info: CompilationTaskInfo, argMap: ArgMap) =
- jvmTaskExecutor.execute(buildJvmTask(info,argMap))
+ private fun executeJvmTask(context: CompilationTaskContext, argMap: ArgMap) {
+ val task = buildJvmTask(context.info, argMap)
+ context.debugPrintProto("jvm task message", task)
+ jvmTaskExecutor.execute(context, task)
+ }
private fun buildJvmTask(info: CompilationTaskInfo, argMap: ArgMap): JvmCompilationTask =
JvmCompilationTask.newBuilder().let { root ->
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinCompilerOutputSink.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinCompilerOutputSink.kt
deleted file mode 100644
index 9b7a594..0000000
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinCompilerOutputSink.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 2018 The Bazel Authors. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package io.bazel.kotlin.builder.tasks.jvm
-
-
-import java.io.File
-import java.io.PrintStream
-import java.nio.file.Paths
-import javax.inject.Inject
-import javax.inject.Provider
-import javax.inject.Singleton
-
-@Singleton
-internal class KotlinCompilerOutputSink @Inject constructor(
- private val streamProvider: Provider<PrintStream>
-) {
- private val executionRoot: String = Paths.get("").toAbsolutePath().toString() + File.separator
-
- fun deliver(line: String) {
- streamProvider.get().println(trimExecutionRootPrefix(line))
- }
-
- fun deliver(lines: List<String>) {
- streamProvider.get().also { stream -> lines.map(::trimExecutionRootPrefix).forEach(stream::println) }
- }
-
- private fun trimExecutionRootPrefix(toPrint: String): String {
- // trim off the workspace component
- return if (toPrint.startsWith(executionRoot)) {
- toPrint.replaceFirst(executionRoot, "")
- } else toPrint
- }
-}
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt
index a004df3..b4b5bb5 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmCompiler.kt
@@ -17,6 +17,7 @@
import io.bazel.kotlin.builder.toolchain.CompilationStatusException
import io.bazel.kotlin.builder.toolchain.KotlinToolchain
+import io.bazel.kotlin.builder.utils.CompilationTaskContext
import io.bazel.kotlin.builder.utils.KotlinCompilerPluginArgsEncoder
import io.bazel.kotlin.builder.utils.addAll
import io.bazel.kotlin.builder.utils.joinedClasspath
@@ -40,12 +41,12 @@
private val compiler: KotlinToolchain.KotlincInvoker,
private val pluginArgsEncoder: KotlinCompilerPluginArgsEncoder
) {
- fun runAnnotationProcessor(command: JvmCompilationTask): List<String> {
+ fun runAnnotationProcessor(context: CompilationTaskContext, command: JvmCompilationTask): List<String> {
check(command.info.plugins.annotationProcessorsList.isNotEmpty()) {
"method called without annotation processors"
}
return getCommonArgs(command).also {
- it.addAll(pluginArgsEncoder.encode(command))
+ it.addAll(pluginArgsEncoder.encode(context, command))
it.addAll(command.inputs.kotlinSourcesList)
it.addAll(command.inputs.javaSourcesList)
}.let(::invokeCompilePhase)
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt
index 7727861..caa3372 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/jvm/KotlinJvmTaskExecutor.kt
@@ -17,7 +17,7 @@
import io.bazel.kotlin.builder.toolchain.CompilationStatusException
-import io.bazel.kotlin.builder.toolchain.CompilationTaskExecutor
+import io.bazel.kotlin.builder.utils.CompilationTaskContext
import io.bazel.kotlin.builder.utils.IS_JVM_SOURCE_FILE
import io.bazel.kotlin.builder.utils.ensureDirectories
import io.bazel.kotlin.builder.utils.expandWithSources
@@ -33,18 +33,16 @@
@Singleton
class KotlinJvmTaskExecutor @Inject internal constructor(
private val kotlinCompiler: KotlinJvmCompiler,
- private val outputSink: KotlinCompilerOutputSink,
private val javaCompiler: JavaCompiler,
private val jDepsGenerator: JDepsGenerator,
private val outputJarCreator: OutputJarCreator
-) : CompilationTaskExecutor<JvmCompilationTask>() {
- override fun execute(task: JvmCompilationTask): Result {
+) {
+ fun execute(context: CompilationTaskContext, task: JvmCompilationTask) {
val preprocessedTask = preprocessingSteps(task)
// fix error handling
try {
- val context = Context()
val commandWithApSources = context.execute("kapt") {
- runAnnotationProcessors(preprocessedTask)
+ runAnnotationProcessors(context, preprocessedTask)
}
compileClasses(context, commandWithApSources)
context.execute("create jar") {
@@ -54,8 +52,6 @@
context.execute("generate jdeps") {
jDepsGenerator.generateJDeps(commandWithApSources)
}
- return Result(context.timings, commandWithApSources)
-
} catch (ex: Throwable) {
throw RuntimeException(ex)
}
@@ -114,10 +110,13 @@
}
}
- private fun runAnnotationProcessors(command: JvmCompilationTask): JvmCompilationTask =
+ private fun runAnnotationProcessors(
+ context: CompilationTaskContext,
+ command: JvmCompilationTask
+ ): JvmCompilationTask =
try {
if (command.info.plugins.annotationProcessorsList.isNotEmpty()) {
- kotlinCompiler.runAnnotationProcessor(command)
+ kotlinCompiler.runAnnotationProcessor(context, command)
File(command.directories.generatedSources).walkTopDown()
.filter { it.isFile }
.map { it.path }
@@ -127,11 +126,14 @@
command
}
} catch (ex: CompilationStatusException) {
- ex.lines.also(outputSink::deliver)
+ ex.lines.also(context::printCompilerOutput)
throw ex
}
- private fun compileClasses(context: Context, command: JvmCompilationTask) {
+ private fun compileClasses(
+ context: CompilationTaskContext,
+ command: JvmCompilationTask
+ ) {
var kotlinError: CompilationStatusException? = null
var result: List<String>? = null
context.execute("kotlinc") {
@@ -147,21 +149,8 @@
javaCompiler.compile(command)
}
} finally {
- checkNotNull(result).also(outputSink::deliver)
+ checkNotNull(result).also(context::printCompilerOutput)
kotlinError?.also { throw it }
}
}
-
- internal class Context {
- val timings = mutableListOf<String>()
- inline fun <T> execute(name: String, task: () -> T): T {
- val start = System.currentTimeMillis()
- return try {
- task()
- } finally {
- val stop = System.currentTimeMillis()
- timings += "$name: ${stop - start} ms"
- }
- }
- }
}
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/CompilationTaskExecutor.kt b/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/CompilationTaskExecutor.kt
deleted file mode 100644
index bda3300..0000000
--- a/kotlin/builder/src/io/bazel/kotlin/builder/toolchain/CompilationTaskExecutor.kt
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * Copyright 2018 The Bazel Authors. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package io.bazel.kotlin.builder.toolchain
-
-import com.google.protobuf.MessageOrBuilder
-
-/**
- * Base Compilation Task Executor class
- */
-abstract class CompilationTaskExecutor<T: MessageOrBuilder> {
- @Suppress("unused")
- inner class Result(val timings: List<String>, val command: T)
-
- abstract fun execute(task: T): Result
-}
\ No newline at end of file
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/CompilationTaskContext.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/CompilationTaskContext.kt
new file mode 100644
index 0000000..17946ae
--- /dev/null
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/CompilationTaskContext.kt
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2018 The Bazel Authors. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package io.bazel.kotlin.builder.utils
+
+
+import com.google.protobuf.MessageOrBuilder
+import com.google.protobuf.TextFormat
+import io.bazel.kotlin.model.CompilationTaskInfo
+import java.io.File
+import java.io.PrintStream
+import java.nio.file.Paths
+
+class CompilationTaskContext(val info: CompilationTaskInfo, private val out: PrintStream) {
+ private val executionRoot: String = Paths.get("").toAbsolutePath().toString() + File.separator
+ private val timings = mutableListOf<String>()
+ val isDebug: Boolean = info.debug > 0
+
+ /**
+ * Print debugging messages if it is enabled for the task.
+ */
+ fun debugPrint(msg: String) {
+ if (info.debug > 0) {
+ out.println(msg)
+ }
+ }
+
+ /**
+ * Print a debugging message if it debugging is enabled for the task. The lines are tab seperated.
+ */
+ private inline fun debugPrintHeadedLines(header: String, lines: () -> String) {
+ if (info.debug > 0) {
+ out.println(if (header.endsWith(":")) header else "$header:")
+ out.print("| ${lines().replace("\n", "\n| ")}")
+ }
+ }
+
+ /**
+ * Print a proto message if debugging is enabled for the task.
+ */
+ fun debugPrintProto(header: String, msg: MessageOrBuilder) {
+ debugPrintHeadedLines(header) { TextFormat.printToString(msg) }
+ }
+
+ fun printCompilerOutput(line: String) {
+ out.println(trimExecutionRootPrefix(line))
+ }
+
+ fun printCompilerOutput(lines: List<String>) {
+ lines.map(::trimExecutionRootPrefix).forEach(out::println)
+ }
+
+ private fun trimExecutionRootPrefix(toPrint: String): String {
+ // trim off the workspace component
+ return if (toPrint.startsWith(executionRoot)) {
+ toPrint.replaceFirst(executionRoot, "")
+ } else toPrint
+ }
+
+ fun <T> execute(name: String, task: () -> T): T {
+ val start = System.currentTimeMillis()
+ return try {
+ task()
+ } finally {
+ val stop = System.currentTimeMillis()
+ timings += "$name: ${stop - start} ms"
+ }
+ }
+}
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
index 3f3f98c..6974f0c 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/utils/KotlinCompilerPluginArgsEncoder.kt
@@ -85,9 +85,7 @@
)
}
- fun encode(
- command: JvmCompilationTask
- ): List<String> {
+ fun encode(context: CompilationTaskContext, command: JvmCompilationTask): List<String> {
val javacArgs = mutableMapOf<String, String>(
"-target" to command.info.toolchainInfo.jvm.jvmTarget
)
@@ -101,7 +99,7 @@
arg["javacArguments"] = javacArgs.let(Companion::encodeMap)
arg["aptMode"] = "stubsAndApt"
arg["correctErrorTypes"] = "true"
-// arg["verbose"] = "true"
+ arg["verbose"] = context.isDebug.toString()
arg["processors"] = plugin.annotationProcessorsList
.filter { it.processorClass.isNotEmpty() }