merge task builder into kotlin builder and move task specific logic to
executor class
diff --git a/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar b/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar
index 2e614f0..6b75802 100755
--- a/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar
+++ b/kotlin/builder/proto/jars/libkotlin_model_proto-speed.jar
Binary files differ
diff --git a/kotlin/builder/proto/kotlin_model.proto b/kotlin/builder/proto/kotlin_model.proto
index 2af674f..ead4726 100644
--- a/kotlin/builder/proto/kotlin_model.proto
+++ b/kotlin/builder/proto/kotlin_model.proto
@@ -94,6 +94,8 @@
CompilerPlugins plugins = 7;
// Paths to Jars that the kotlin compiler will allow package private access to.
repeated string friend_paths = 8;
+ // The path of the primary output for the task, this is derived from the flagfile.
+ string primary_output_path = 9;
}
// Mested messages not marked with stable could be refactored.
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 901bfb5..70ce4ae 100644
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt
+++ b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/KotlinBuilder.kt
@@ -15,15 +15,12 @@
*/
package io.bazel.kotlin.builder.tasks
+import com.google.protobuf.util.JsonFormat
import io.bazel.kotlin.builder.tasks.jvm.KotlinJvmTaskExecutor
import io.bazel.kotlin.builder.toolchain.CompilationStatusException
-import io.bazel.kotlin.builder.utils.ArgMaps
-import io.bazel.kotlin.builder.utils.IS_JVM_SOURCE_FILE
-import io.bazel.kotlin.builder.utils.ensureDirectories
-import io.bazel.kotlin.builder.utils.expandWithSources
-import io.bazel.kotlin.builder.utils.jars.SourceJarExtractor
-import io.bazel.kotlin.model.JvmCompilationTask
-import java.nio.charset.StandardCharsets.UTF_8
+import io.bazel.kotlin.builder.utils.*
+import io.bazel.kotlin.model.*
+import java.nio.charset.StandardCharsets
import java.nio.file.Files
import java.nio.file.Paths
import java.util.regex.Pattern
@@ -33,70 +30,160 @@
@Singleton
@Suppress("MemberVisibilityCanBePrivate")
class KotlinBuilder @Inject internal constructor(
- private val taskBuilder: TaskBuilder,
private val jvmTaskExecutor: KotlinJvmTaskExecutor
) : CommandLineProgram {
companion object {
- // regex that matches the regular bazel param file naming convention.
- private val STANDARD_FLAGFILE_RE = Pattern.compile(""".*.jar-\d+.params$""").toRegex()
+ @JvmStatic
+ private val jsonTypeRegistry = JsonFormat.TypeRegistry.newBuilder()
+ .add(KotlinModel.getDescriptor().messageTypes).build()
+
+ @JvmStatic
+ private val jsonFormat: JsonFormat.Parser = JsonFormat.parser().usingTypeRegistry(jsonTypeRegistry)
+
+ @JvmStatic
+ private val FLAGFILE_RE = Pattern.compile("""^--flagfile=((.*)-(\d+).params)$""").toRegex()
}
- fun execute(args: List<String>): Int {
- check(args.isNotEmpty() && args[0].startsWith("--flagfile=")) { "no flag file supplied" }
- val flagFile = args[0].replace("--flagfile=", "")
- val flagFilePath = Paths.get(flagFile)
- check(flagFilePath.toFile().exists()) { "flagfile $flagFile does not exist" }
- val task = when {
- STANDARD_FLAGFILE_RE.matches(flagFile) -> {
- Files.readAllLines(flagFilePath, UTF_8).let { loadedFlags ->
- ArgMaps.from(loadedFlags).let {
- val taskInfo = taskBuilder.buildTaskInfo(it)
- taskBuilder.buildJvm(taskInfo, it)
+ 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()
+
+ 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")
+ }
+ } catch (ex: CompilationStatusException) {
+ return ex.status
+ }
+ return 0
+ }
+
+
+ /**
+ * Declares the flags used by the java builder.
+ */
+ private enum class JavaBuilderFlags(override val flag: String) : Flag {
+ TARGET_LABEL("--target_label"),
+ CLASSPATH("--classpath"),
+ JAVAC_OPTS("--javacopts"),
+ DEPENDENCIES("--dependencies"),
+ DIRECT_DEPENDENCIES("--direct_dependencies"),
+ DIRECT_DEPENDENCY("--direct_dependency"),
+ INDIRECT_DEPENDENCY("--indirect_dependency"),
+ STRICT_JAVA_DEPS("--strict_java_deps"),
+ OUTPUT_DEPS_PROTO("--output_deps_proto"),
+ DEPS_ARTIFACTS("--deps_artifacts"),
+ REDUCE_CLASSPATH("--reduce_classpath"),
+ SOURCEGEN_DIR("--sourcegendir"),
+ GENERATED_SOURCES_OUTPUT("--generated_sources_output"),
+ OUTPUT_MANIFEST_PROTO("--output_manifest_proto"),
+ SOURCES("--sources"),
+ SOURCE_ROOTS("--source_roots"),
+ SOURCE_JARS("--source_jars"),
+ SOURCE_PATH("--sourcepath"),
+ BOOT_CLASSPATH("--bootclasspath"),
+ PROCESS_PATH("--processorpath"),
+ PROCESSORS("--processors"),
+ EXT_CLASSPATH("--extclasspath"),
+ EXT_DIR("--extdir"),
+ OUTPUT("--output"),
+ NATIVE_HEADER_OUTPUT("--native_header_output"),
+ CLASSDIR("--classdir"),
+ TEMPDIR("--tempdir"),
+ GENDIR("--gendir"),
+ POST_PROCESSOR("--post_processor"),
+ COMPRESS_JAR("--compress_jar"),
+ RULE_KIND("--rule_kind"),
+ TEST_ONLY("--testonly");
+ }
+
+ private enum class KotlinBuilderFlags(override val flag: String) : Flag {
+ MODULE_NAME("--kotlin_module_name"),
+ PASSTHROUGH_FLAGS("--kotlin_passthrough_flags"),
+ API_VERSION("--kotlin_api_version"),
+ LANGUAGE_VERSION("--kotlin_language_version"),
+ JVM_TARGET("--kotlin_jvm_target"),
+ OUTPUT_SRCJAR("--kotlin_output_srcjar"),
+ GENERATED_CLASSDIR("--kotlin_generated_classdir"),
+ PLUGINS("--kotlin_plugins"),
+ FRIEND_PATHS("--kotlin_friend_paths"),
+ OUTPUT_JDEPS("--kotlin_output_jdeps"),
+ TASK_ID("--kotlin_task_id");
+ }
+
+ private fun buildTaskInfo(argMap: ArgMap): CompilationTaskInfo.Builder =
+ with(CompilationTaskInfo.newBuilder()) {
+ label = argMap.mandatorySingle(JavaBuilderFlags.TARGET_LABEL)
+ argMap.mandatorySingle(JavaBuilderFlags.RULE_KIND).split("_").also {
+ check(it.size == 3 && it[0] == "kt") { "invalid rule kind $it" }
+ platform = checkNotNull(Platform.valueOf(it[1].toUpperCase())) {
+ "unrecognized platform ${it[1]}"
+ }
+ ruleKind = checkNotNull(RuleKind.valueOf(it[2].toUpperCase())) {
+ "unrecognized rule kind ${it[2]}"
+ }
+ }
+ moduleName = argMap.mandatorySingle(KotlinBuilderFlags.MODULE_NAME).also {
+ check(it.isNotBlank()) { "--kotlin_module_name should not be blank" }
+ }
+ passthroughFlags = argMap.optionalSingle(KotlinBuilderFlags.PASSTHROUGH_FLAGS)
+ argMap.optional(KotlinBuilderFlags.FRIEND_PATHS)?.let(::addAllFriendPaths)
+ toolchainInfoBuilder.commonBuilder.apiVersion = argMap.mandatorySingle(KotlinBuilderFlags.API_VERSION)
+ toolchainInfoBuilder.commonBuilder.languageVersion = argMap.mandatorySingle(KotlinBuilderFlags.LANGUAGE_VERSION)
+ this
+ }
+
+ private fun executeJvmTask(info: CompilationTaskInfo, argMap: ArgMap) =
+ jvmTaskExecutor.execute(buildJvmTask(info,argMap))
+
+ private fun buildJvmTask(info: CompilationTaskInfo, argMap: ArgMap): JvmCompilationTask =
+ JvmCompilationTask.newBuilder().let { root ->
+ root.info = info
+
+ with(root.outputsBuilder) {
+ jar = argMap.mandatorySingle(JavaBuilderFlags.OUTPUT)
+ jdeps = argMap.mandatorySingle(KotlinBuilderFlags.OUTPUT_JDEPS)
+ srcjar = argMap.mandatorySingle(KotlinBuilderFlags.OUTPUT_SRCJAR)
+ }
+
+ with(root.directoriesBuilder) {
+ classes = argMap.mandatorySingle(JavaBuilderFlags.CLASSDIR)
+ generatedClasses = argMap.mandatorySingle(KotlinBuilderFlags.GENERATED_CLASSDIR)
+ temp = argMap.mandatorySingle(JavaBuilderFlags.TEMPDIR)
+ generatedSources = argMap.mandatorySingle(JavaBuilderFlags.SOURCEGEN_DIR)
+ }
+
+ with(root.inputsBuilder) {
+ addAllClasspath(argMap.mandatory(JavaBuilderFlags.CLASSPATH))
+ putAllIndirectDependencies(argMap.labelDepMap(JavaBuilderFlags.DIRECT_DEPENDENCY))
+ putAllIndirectDependencies(argMap.labelDepMap(JavaBuilderFlags.INDIRECT_DEPENDENCY))
+
+ argMap.optional(JavaBuilderFlags.SOURCES)?.iterator()?.partitionSources(
+ { addKotlinSources(it) },
+ { addJavaSources(it) }
+ )
+ argMap.optional(JavaBuilderFlags.SOURCE_JARS)?.also {
+ addAllSourceJars(it)
+ }
+ }
+
+ with(root.infoBuilder) {
+ toolchainInfoBuilder.jvmBuilder.jvmTarget = argMap.mandatorySingle(KotlinBuilderFlags.JVM_TARGET)
+
+ argMap.optionalSingle(KotlinBuilderFlags.PLUGINS)?.let { input ->
+ plugins = CompilerPlugins.newBuilder().let {
+ jsonFormat.merge(input, it)
+ it.build()
}
}
}
- else -> throw IllegalStateException("unknown flag file format for $flagFile")
+ root.build()
}
-
- return execute(task)
- }
-
- fun execute(command: JvmCompilationTask): Int {
- ensureDirectories(
- command.directories.classes,
- command.directories.temp,
- command.directories.generatedSources,
- command.directories.generatedClasses
- )
- val updatedCommand = expandWithSourceJarSources(command)
- return try {
- jvmTaskExecutor.execute(updatedCommand)
- 0
- } catch (ex: CompilationStatusException) {
- ex.status
- }
- }
-
- /**
- * If any srcjars were provided expand the jars sources and create a new [JvmCompilationTask] with the
- * Java and Kotlin sources merged in.
- */
- private fun expandWithSourceJarSources(command: JvmCompilationTask): JvmCompilationTask =
- if (command.inputs.sourceJarsList.isEmpty()) {
- command
- } else {
- SourceJarExtractor(
- destDir = Paths.get(command.directories.temp).resolve("_srcjars"),
- fileMatcher = IS_JVM_SOURCE_FILE
- ).also {
- it.jarFiles.addAll(command.inputs.sourceJarsList.map { p -> Paths.get(p) })
- it.execute()
- }.let {
- command.expandWithSources(it.sourcesList.iterator())
- }
- }
-
- override fun apply(args: List<String>): Int {
- return execute(args)
- }
}
diff --git a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/TaskBuilder.kt b/kotlin/builder/src/io/bazel/kotlin/builder/tasks/TaskBuilder.kt
deleted file mode 100644
index 63e984c..0000000
--- a/kotlin/builder/src/io/bazel/kotlin/builder/tasks/TaskBuilder.kt
+++ /dev/null
@@ -1,158 +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
-
-import com.google.protobuf.util.JsonFormat
-import io.bazel.kotlin.builder.tasks.TaskBuilder.JavaBuilderFlags.*
-import io.bazel.kotlin.builder.tasks.TaskBuilder.KotlinBuilderFlags.*
-import io.bazel.kotlin.builder.utils.*
-import io.bazel.kotlin.model.*
-import io.bazel.kotlin.model.KotlinModel.getDescriptor
-import javax.inject.Inject
-import javax.inject.Singleton
-
-@Singleton
-class TaskBuilder @Inject internal constructor() {
- companion object {
- @JvmStatic
- private val jsonTypeRegistry = JsonFormat.TypeRegistry.newBuilder()
- .add(getDescriptor().messageTypes).build()
-
- @JvmStatic
- private val jsonFormat: JsonFormat.Parser = JsonFormat.parser().usingTypeRegistry(jsonTypeRegistry)
- }
-
- /**
- * Declares the flags used by the java builder.
- */
- private enum class JavaBuilderFlags(override val flag: String) : Flag {
- TARGET_LABEL("--target_label"),
- CLASSPATH("--classpath"),
- JAVAC_OPTS("--javacopts"),
- DEPENDENCIES("--dependencies"),
- DIRECT_DEPENDENCIES("--direct_dependencies"),
- DIRECT_DEPENDENCY("--direct_dependency"),
- INDIRECT_DEPENDENCY("--indirect_dependency"),
- STRICT_JAVA_DEPS("--strict_java_deps"),
- OUTPUT_DEPS_PROTO("--output_deps_proto"),
- DEPS_ARTIFACTS("--deps_artifacts"),
- REDUCE_CLASSPATH("--reduce_classpath"),
- SOURCEGEN_DIR("--sourcegendir"),
- GENERATED_SOURCES_OUTPUT("--generated_sources_output"),
- OUTPUT_MANIFEST_PROTO("--output_manifest_proto"),
- SOURCES("--sources"),
- SOURCE_ROOTS("--source_roots"),
- SOURCE_JARS("--source_jars"),
- SOURCE_PATH("--sourcepath"),
- BOOT_CLASSPATH("--bootclasspath"),
- PROCESS_PATH("--processorpath"),
- PROCESSORS("--processors"),
- EXT_CLASSPATH("--extclasspath"),
- EXT_DIR("--extdir"),
- OUTPUT("--output"),
- NATIVE_HEADER_OUTPUT("--native_header_output"),
- CLASSDIR("--classdir"),
- TEMPDIR("--tempdir"),
- GENDIR("--gendir"),
- POST_PROCESSOR("--post_processor"),
- COMPRESS_JAR("--compress_jar"),
- RULE_KIND("--rule_kind"),
- TEST_ONLY("--testonly");
- }
-
- enum class KotlinBuilderFlags(override val flag: String) : Flag {
- MODULE_NAME("--kotlin_module_name"),
- PASSTHROUGH_FLAGS("--kotlin_passthrough_flags"),
- API_VERSION("--kotlin_api_version"),
- LANGUAGE_VERSION("--kotlin_language_version"),
- JVM_TARGET("--kotlin_jvm_target"),
- OUTPUT_SRCJAR("--kotlin_output_srcjar"),
- GENERATED_CLASSDIR("--kotlin_generated_classdir"),
- PLUGINS("--kotlin_plugins"),
- FRIEND_PATHS("--kotlin_friend_paths"),
- OUTPUT_JDEPS("--kotlin_output_jdeps"),
- TASK_ID("--kotlin_task_id");
- }
-
- fun buildTaskInfo(argMap: ArgMap): CompilationTaskInfo =
- with(CompilationTaskInfo.newBuilder()) {
- label = argMap.mandatorySingle(TARGET_LABEL)
- argMap.mandatorySingle(RULE_KIND).split("_").also {
- check(it.size == 3 && it[0] == "kt") { "invalid rule kind $it" }
- platform = checkNotNull(Platform.valueOf(it[1].toUpperCase())) {
- "unrecognized platform ${it[1]}"
- }
- ruleKind = checkNotNull(RuleKind.valueOf(it[2].toUpperCase())) {
- "unrecognized rule kind ${it[2]}"
- }
- }
- moduleName = argMap.mandatorySingle(MODULE_NAME).also {
- check(it.isNotBlank()) { "--kotlin_module_name should not be blank" }
- }
- passthroughFlags = argMap.optionalSingle(PASSTHROUGH_FLAGS)
- argMap.optional(FRIEND_PATHS)?.let(::addAllFriendPaths)
- toolchainInfoBuilder.commonBuilder.apiVersion = argMap.mandatorySingle(API_VERSION)
- toolchainInfoBuilder.commonBuilder.languageVersion = argMap.mandatorySingle(LANGUAGE_VERSION)
- build()
- }
-
-
- fun buildJvm(info: CompilationTaskInfo, argMap: ArgMap): JvmCompilationTask =
- JvmCompilationTask.newBuilder().let { root ->
- root.info = info
-
- with(root.outputsBuilder) {
- jar = argMap.mandatorySingle(OUTPUT)
- jdeps = argMap.mandatorySingle(OUTPUT_JDEPS)
- srcjar = argMap.mandatorySingle(OUTPUT_SRCJAR)
- }
-
- with(root.directoriesBuilder) {
- classes = argMap.mandatorySingle(CLASSDIR)
- generatedClasses = argMap.mandatorySingle(GENERATED_CLASSDIR)
- temp = argMap.mandatorySingle(TEMPDIR)
- generatedSources = argMap.mandatorySingle(SOURCEGEN_DIR)
- }
-
- with(root.inputsBuilder) {
- addAllClasspath(argMap.mandatory(CLASSPATH))
- putAllIndirectDependencies(argMap.labelDepMap(DIRECT_DEPENDENCY))
- putAllIndirectDependencies(argMap.labelDepMap(INDIRECT_DEPENDENCY))
-
- argMap.optional(SOURCES)?.iterator()?.partitionSources(
- { addKotlinSources(it) },
- { addJavaSources(it) }
- )
- argMap.optional(SOURCE_JARS)?.also {
- addAllSourceJars(it)
- }
- }
-
- with(root.infoBuilder) {
- toolchainInfoBuilder.jvmBuilder.jvmTarget = argMap.mandatorySingle(JVM_TARGET)
-
- argMap.optionalSingle(PLUGINS)?.let { input ->
- plugins = CompilerPlugins.newBuilder().let {
- jsonFormat.merge(input, it)
- it.build()
- }
- }
- }
-
- root.build()
- }
-}
-
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 738fd88..7727861 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
@@ -18,8 +18,11 @@
import io.bazel.kotlin.builder.toolchain.CompilationStatusException
import io.bazel.kotlin.builder.toolchain.CompilationTaskExecutor
+import io.bazel.kotlin.builder.utils.IS_JVM_SOURCE_FILE
+import io.bazel.kotlin.builder.utils.ensureDirectories
import io.bazel.kotlin.builder.utils.expandWithSources
import io.bazel.kotlin.builder.utils.jars.SourceJarCreator
+import io.bazel.kotlin.builder.utils.jars.SourceJarExtractor
import io.bazel.kotlin.model.JvmCompilationTask
import java.io.File
import java.nio.file.Files
@@ -36,11 +39,12 @@
private val outputJarCreator: OutputJarCreator
) : CompilationTaskExecutor<JvmCompilationTask>() {
override fun execute(task: JvmCompilationTask): Result {
+ val preprocessedTask = preprocessingSteps(task)
// fix error handling
try {
val context = Context()
val commandWithApSources = context.execute("kapt") {
- runAnnotationProcessors(task)
+ runAnnotationProcessors(preprocessedTask)
}
compileClasses(context, commandWithApSources)
context.execute("create jar") {
@@ -58,6 +62,35 @@
}
+ private fun preprocessingSteps(command: JvmCompilationTask): JvmCompilationTask {
+ ensureDirectories(
+ command.directories.classes,
+ command.directories.temp,
+ command.directories.generatedSources,
+ command.directories.generatedClasses
+ )
+ return expandWithSourceJarSources(command)
+ }
+
+ /**
+ * If any srcjars were provided expand the jars sources and create a new [JvmCompilationTask] with the
+ * Java and Kotlin sources merged in.
+ */
+ private fun expandWithSourceJarSources(command: JvmCompilationTask): JvmCompilationTask =
+ if (command.inputs.sourceJarsList.isEmpty()) {
+ command
+ } else {
+ SourceJarExtractor(
+ destDir = Paths.get(command.directories.temp).resolve("_srcjars"),
+ fileMatcher = IS_JVM_SOURCE_FILE
+ ).also {
+ it.jarFiles.addAll(command.inputs.sourceJarsList.map { p -> Paths.get(p) })
+ it.execute()
+ }.let {
+ command.expandWithSources(it.sourcesList.iterator())
+ }
+ }
+
private fun produceSourceJar(command: JvmCompilationTask) {
Paths.get(command.outputs.srcjar).also { sourceJarPath ->
Files.createFile(sourceJarPath)