| /* |
| * 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 |
| |
| import com.google.inject.ImplementedBy |
| import com.google.inject.Inject |
| import com.google.inject.Singleton |
| import com.google.protobuf.util.JsonFormat |
| import io.bazel.kotlin.builder.utils.ArgMap |
| import io.bazel.kotlin.builder.utils.DefaultKotlinCompilerPluginArgsEncoder |
| import io.bazel.kotlin.model.KotlinModel |
| import io.bazel.kotlin.model.KotlinModel.BuilderCommand |
| |
| |
| @ImplementedBy(DefaultBuildCommandBuilder::class) |
| interface BuildCommandBuilder { |
| fun fromInput(argMap: ArgMap): BuilderCommand |
| fun withSources(command: BuilderCommand, sources: Iterator<String>): BuilderCommand |
| fun withGeneratedSources(command: BuilderCommand, sources: Iterator<String>): BuilderCommand |
| } |
| |
| @Singleton |
| private class DefaultBuildCommandBuilder @Inject constructor( |
| private val pluginEncoder: DefaultKotlinCompilerPluginArgsEncoder |
| ) : BuildCommandBuilder { |
| companion object { |
| @JvmStatic |
| private val jsonTypeRegistry = JsonFormat.TypeRegistry.newBuilder() |
| .add(KotlinModel.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(val flag: String) { |
| 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") |
| } |
| |
| override fun fromInput(argMap: ArgMap): BuilderCommand = |
| BuilderCommand.newBuilder().let { root -> |
| with(root.outputsBuilder) { |
| classDirectory = argMap.mandatorySingle(JavaBuilderFlags.CLASSDIR.flag) |
| tempDirectory = argMap.mandatorySingle(JavaBuilderFlags.TEMPDIR.flag) |
| sourceGenDir = argMap.mandatorySingle(JavaBuilderFlags.SOURCEGEN_DIR.flag) |
| output = argMap.mandatorySingle(JavaBuilderFlags.OUTPUT.flag) |
| outputJdeps = argMap.mandatorySingle("--output_jdeps") |
| } |
| |
| with(root.inputsBuilder) { |
| addAllClasspath(argMap.mandatory(JavaBuilderFlags.CLASSPATH.flag)) |
| putAllIndirectDependencies(argMap.labelDepMap(JavaBuilderFlags.DIRECT_DEPENDENCY.flag)) |
| putAllIndirectDependencies(argMap.labelDepMap(JavaBuilderFlags.INDIRECT_DEPENDENCY.flag)) |
| |
| argMap.optional(JavaBuilderFlags.SOURCES.flag)?.iterator()?.partitionSources( |
| { addKotlinSources(it) }, |
| { addJavaSources(it) } |
| ) |
| argMap.optional(JavaBuilderFlags.SOURCE_JARS.flag)?.also { |
| addAllSourceJars(it) |
| } |
| |
| |
| joinedClasspath = classpathList.joinToString(":") |
| } |
| |
| with(root.infoBuilder) { |
| label = argMap.mandatorySingle(JavaBuilderFlags.TARGET_LABEL.flag) |
| ruleKind = argMap.mandatorySingle(JavaBuilderFlags.RULE_KIND.flag) |
| kotlinModuleName = argMap.mandatorySingle("--kotlin_module_name").also { |
| check(it.isNotBlank()) { "--kotlin_module_name should not be blank" } |
| } |
| passthroughFlags = argMap.optionalSingle("--kotlin_passthrough_flags") |
| addAllFriendPaths(argMap.mandatory("--kotlin_friend_paths")) |
| toolchainInfoBuilder.commonBuilder.apiVersion = argMap.mandatorySingle("--kotlin_api_version") |
| toolchainInfoBuilder.commonBuilder.languageVersion = argMap.mandatorySingle("--kotlin_language_version") |
| toolchainInfoBuilder.jvmBuilder.jvmTarget = argMap.mandatorySingle("--kotlin_jvm_target") |
| |
| argMap.optionalSingle("--kt-plugins")?.let { input -> |
| plugins = KotlinModel.CompilerPlugins.newBuilder().let { |
| jsonFormat.merge(input, it) |
| it.build() |
| } |
| } |
| |
| if (plugins.annotationProcessorsList.isNotEmpty()) { |
| addAllEncodedPluginDescriptors(pluginEncoder.encode(root)) |
| } |
| |
| label.split(":").also { |
| check(it.size == 2) { "the label ${root.info.label} is invalid" } |
| `package` = it[0] |
| target = it[1] |
| } |
| } |
| root.build() |
| } |
| |
| override fun withSources(command: BuilderCommand, sources: Iterator<String>): BuilderCommand = |
| command.updateBuilder { builder -> |
| sources.partitionSources( |
| { builder.inputsBuilder.addKotlinSources(it) }, |
| { builder.inputsBuilder.addJavaSources(it) }) |
| } |
| |
| |
| override fun withGeneratedSources(command: BuilderCommand, sources: Iterator<String>): BuilderCommand = |
| command.updateBuilder { builder -> |
| sources.partitionSources( |
| { builder.inputsBuilder.addGeneratedKotlinSources(it) }, |
| { builder.inputsBuilder.addGeneratedJavaSources(it) }) |
| } |
| |
| private fun BuilderCommand.updateBuilder(init: (BuilderCommand.Builder) -> Unit): BuilderCommand = |
| toBuilder().let { |
| init(it) |
| it.build() |
| } |
| |
| |
| private fun Iterator<String>.partitionSources(kt: (String) -> Unit, java: (String) -> Unit) { |
| forEach { |
| when { |
| it.endsWith(".kt") -> kt(it) |
| it.endsWith(".java") -> java(it) |
| else -> throw IllegalStateException("invalid source file type $it") |
| } |
| } |
| } |
| } |
| |