aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileAction.java
diff options
context:
space:
mode:
authorGravatar Carmi Grushko <carmi@google.com>2015-12-11 18:44:57 +0000
committerGravatar David Chen <dzc@google.com>2015-12-13 18:27:17 +0000
commit08a99317b5b70c6671017dd9b7442f83ad0e5f8f (patch)
tree8103e3f565f844dd25f304b55978d223aa69f97a /src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileAction.java
parent91f3e5ad3b4ca53136a66f8d26111e8a04623f4d (diff)
Open-source code that creates proto-buffer compile actions.
-- MOS_MIGRATED_REVID=110008191
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileAction.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileAction.java270
1 files changed, 270 insertions, 0 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileAction.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileAction.java
new file mode 100644
index 0000000000..cb7243bbb4
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileAction.java
@@ -0,0 +1,270 @@
+// Copyright 2015 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 com.google.devtools.build.lib.rules.proto;
+
+import static com.google.common.base.Optional.absent;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.collect.Iterables.isEmpty;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
+import com.google.common.base.Suppliers;
+import com.google.common.collect.ImmutableList;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.actions.ResourceSet;
+import com.google.devtools.build.lib.analysis.FilesToRunProvider;
+import com.google.devtools.build.lib.analysis.RuleConfiguredTarget.Mode;
+import com.google.devtools.build.lib.analysis.RuleContext;
+import com.google.devtools.build.lib.analysis.actions.CommandLine;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine;
+import com.google.devtools.build.lib.analysis.actions.CustomCommandLine.CustomMultiArgv;
+import com.google.devtools.build.lib.analysis.actions.SpawnAction;
+import com.google.devtools.build.lib.util.LazyString;
+
+import java.util.List;
+
+/**
+ * An action to run the protocol compiler to generate sources from .proto files.
+ */
+public final class ProtoCompileAction {
+
+ private static final String MNEMONIC = "GenProto";
+ private static final ResourceSet GENPROTO_RESOURCE_SET =
+ ResourceSet.createWithRamCpuIo(100, .1, .0);
+
+ private final RuleContext ruleContext;
+ private final SupportData supportData;
+ private final String language;
+ private final Iterable<Artifact> outputs;
+ private final List<? extends CharSequence> prefixArguments;
+ private final FilesToRunProvider langPluginTarget;
+ private final FilesToRunProvider compilerTarget;
+ private final List<String> suffixArguments;
+
+ public static class Builder {
+ private RuleContext ruleContext;
+ private SupportData supportData;
+ private String language;
+ private String langPrefix;
+ private Iterable<Artifact> outputs;
+ private String langParameter;
+ private String langPluginName;
+ private String langPluginParameter;
+ private Supplier<String> langPluginParameterSupplier;
+ private boolean hasServices;
+
+ public Builder setRuleContext(RuleContext ruleContext) {
+ this.ruleContext = ruleContext;
+ return this;
+ }
+
+ public Builder setSupportData(SupportData supportData) {
+ this.supportData = supportData;
+ return this;
+ }
+
+ public Builder setLanguage(String language) {
+ this.language = language;
+ return this;
+ }
+
+ public Builder setLangPrefix(String langPrefix) {
+ this.langPrefix = langPrefix;
+ return this;
+ }
+
+ public Builder setHasServices(boolean hasServices) {
+ this.hasServices = hasServices;
+ return this;
+ }
+
+ public Builder setOutputs(Iterable<Artifact> outputs) {
+ this.outputs = outputs;
+ return this;
+ }
+
+ public Builder setLangParameter(String langParameter) {
+ this.langParameter = langParameter;
+ return this;
+ }
+
+ public Builder setLangPluginName(String langPluginName) {
+ this.langPluginName = langPluginName;
+ return this;
+ }
+
+ public Builder setLangPluginParameter(String langPluginParameter) {
+ this.langPluginParameter = langPluginParameter;
+ return this;
+ }
+
+ public Builder setLangPluginParameterSupplier(Supplier<String> langPluginParameterSupplier) {
+ this.langPluginParameterSupplier = langPluginParameterSupplier;
+ return this;
+ }
+
+ public Builder(RuleContext ruleContext, SupportData supportData, String language,
+ String langPrefix, Iterable<Artifact> outputs) {
+ this.ruleContext = ruleContext;
+ this.supportData = supportData;
+ this.language = language;
+ this.langPrefix = langPrefix;
+ this.outputs = outputs;
+ }
+
+ public Optional<ProtoCompileAction> build() {
+ checkState(langPluginParameter == null || langPluginParameterSupplier == null,
+ "Only one of {langPluginParameter, langPluginParameterSupplier} should be set.");
+
+ final Supplier<String> langPluginParameter1 =
+ langPluginParameter == null
+ ? langPluginParameterSupplier
+ : Suppliers.ofInstance(langPluginParameter);
+ if (isEmpty(outputs)) {
+ return absent();
+ }
+
+ FilesToRunProvider langPluginTarget = null;
+ List<? extends CharSequence> prefixArguments;
+ if (langPluginName != null) {
+ Preconditions.checkArgument(langParameter == null);
+ Preconditions.checkArgument(langPluginParameter1 != null);
+ // We pass a separate langPluginName as there are plugins that cannot be overridden
+ // and thus we have to deal with "$xx_plugin" and "xx_plugin".
+ langPluginTarget = ruleContext.getExecutablePrerequisite(langPluginName, Mode.HOST);
+ if (ruleContext.hasErrors()) {
+ return absent();
+ }
+ LazyString lazyLangPlugingFlag =
+ new LazyString() {
+ @Override
+ public String toString() {
+ return String.format("--%s_out=%s", langPrefix, langPluginParameter1.get());
+ }
+ };
+ prefixArguments =
+ ImmutableList.of(
+ String.format(
+ "--plugin=protoc-gen-%s=%s",
+ langPrefix,
+ langPluginTarget.getExecutable().getExecPathString()),
+ lazyLangPlugingFlag);
+ } else {
+ prefixArguments =
+ (langParameter != null) ? ImmutableList.of(langParameter) : ImmutableList.<String>of();
+ }
+
+ List<String> suffixArguments =
+ hasServices ? ImmutableList.<String>of() : ImmutableList.of("--disallow_services");
+
+ FilesToRunProvider compilerTarget =
+ ruleContext.getExecutablePrerequisite("$compiler", Mode.HOST);
+
+ if (ruleContext.hasErrors()) {
+ return absent();
+ }
+
+ return Optional.of(
+ new ProtoCompileAction(
+ ruleContext,
+ supportData,
+ language,
+ suffixArguments,
+ outputs,
+ prefixArguments,
+ langPluginTarget,
+ compilerTarget));
+ }
+ }
+
+ public ProtoCompileAction(
+ RuleContext ruleContext,
+ SupportData supportData,
+ String language,
+ List<String> suffixArguments,
+ Iterable<Artifact> outputs,
+ List<? extends CharSequence> prefixArguments,
+ FilesToRunProvider langPluginTarget,
+ FilesToRunProvider compilerTarget) {
+ this.ruleContext = ruleContext;
+ this.supportData = supportData;
+ this.language = language;
+ this.suffixArguments = suffixArguments;
+ this.outputs = outputs;
+ this.prefixArguments = prefixArguments;
+ this.langPluginTarget = langPluginTarget;
+ this.compilerTarget = compilerTarget;
+ }
+
+ public SpawnAction.Builder createAction(CommandLine commandLine) {
+ SpawnAction.Builder builder =
+ new SpawnAction.Builder().addTransitiveInputs(supportData.getTransitiveImports());
+
+ // We also depend on the strict protodeps result to ensure this is run.
+ if (supportData.getUsedDirectDeps() != null) {
+ builder.addInput(supportData.getUsedDirectDeps());
+ }
+
+ if (langPluginTarget != null) {
+ builder.addTool(langPluginTarget);
+ }
+
+ builder
+ .addOutputs(outputs)
+ .setResources(GENPROTO_RESOURCE_SET)
+ .useDefaultShellEnvironment()
+ .setExecutable(compilerTarget)
+ .setCommandLine(commandLine)
+ .setProgressMessage("Generating " + language + " proto_library " + ruleContext.getLabel())
+ .setMnemonic(MNEMONIC);
+
+ return builder;
+ }
+
+ /* Commandline generator for protoc invocations. */
+ public CustomCommandLine.Builder protoCompileCommandLine() {
+ CustomCommandLine.Builder arguments = CustomCommandLine.builder();
+ for (CharSequence charSequence : prefixArguments) {
+ arguments.add(charSequence);
+ }
+ arguments.add(ruleContext.getFragment(ProtoConfiguration.class).protocOpts());
+
+ // Add include maps
+ arguments.add(
+ new CustomMultiArgv() {
+ @Override
+ public Iterable<String> argv() {
+ ImmutableList.Builder<String> builder = ImmutableList.builder();
+ for (Artifact artifact : supportData.getTransitiveImports()) {
+ builder.add(
+ "-I"
+ + artifact.getRootRelativePath().getPathString()
+ + "="
+ + artifact.getExecPathString());
+ }
+ return builder.build();
+ }
+ });
+
+ for (Artifact src : supportData.getDirectProtoSources()) {
+ arguments.addPath(src.getRootRelativePath());
+ }
+
+ arguments.add(suffixArguments);
+ return arguments;
+ }
+}
+