diff options
author | Carmi Grushko <carmi@google.com> | 2016-04-06 20:03:56 +0000 |
---|---|---|
committer | Lukacs Berki <lberki@google.com> | 2016-04-07 11:48:11 +0000 |
commit | 802f39ecb2370b497be8ad9e307923e5aa3a7ab7 (patch) | |
tree | f9952fe904fcab201f00866eb436f434faf39201 /src | |
parent | bae12f9e2e0b200da6da9de5e9bdc40365140f39 (diff) |
Clean the API of ProtoCompileAction, in preparation for making the proto-compiler use a params file.
--
MOS_MIGRATED_REVID=119193368
Diffstat (limited to 'src')
3 files changed, 298 insertions, 308 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java index 5eac0d686a..efd137900b 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/RuleContext.java @@ -720,6 +720,7 @@ public final class RuleContext extends TargetContext * * @return the {@link FilesToRunProvider} interface of the prerequisite. */ + @Nullable public FilesToRunProvider getExecutablePrerequisite(String attributeName, Mode mode) { Attribute ruleDefinition = getAttribute(attributeName); 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 deleted file mode 100644 index 94aca1cee0..0000000000 --- a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileAction.java +++ /dev/null @@ -1,308 +0,0 @@ -// 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; - } - - /** Static class to avoid keeping a reference to this builder after build() is called. */ - private static class LazyLangPluginFlag extends LazyString { - private final String langPrefix; - private final Supplier<String> langPluginParameter1; - - LazyLangPluginFlag(String langPrefix, Supplier<String> langPluginParameter1) { - this.langPrefix = langPrefix; - this.langPluginParameter1 = langPluginParameter1; - } - - @Override - public String toString() { - return String.format("--%s_out=%s", langPrefix, langPluginParameter1.get()); - } - } - - 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(); - } - prefixArguments = - ImmutableList.of( - String.format( - "--plugin=protoc-gen-%s=%s", - langPrefix, - langPluginTarget.getExecutable().getExecPathString()), - new LazyLangPluginFlag(langPrefix, langPluginParameter1)); - } 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)); - } - } - - /** - * A convenience method to register an action, if it's present. - * @param protoCompileActionOptional - */ - public static void registerAction(Optional<ProtoCompileAction> protoCompileActionOptional) { - if (protoCompileActionOptional.isPresent()) { - protoCompileActionOptional.get().registerAction(); - } - } - - 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; - } - - /** - * Registers a proto compile action with the RuleContext. - */ - public void registerAction() { - SpawnAction.Builder action = createAction(protoCompileCommandLine().build()); - ruleContext.registerAction(action.build(ruleContext)); - } - - 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; - } - - /** - * Static inner class since these objects live into the execution phase and so they must not - * keep alive references to the surrounding analysis-phase objects. - */ - private static class ProtoCommandLineArgv extends CustomMultiArgv { - private final Iterable<Artifact> transitiveImports; - - ProtoCommandLineArgv(Iterable<Artifact> transitiveImports) { - this.transitiveImports = transitiveImports; - } - - @Override - public Iterable<String> argv() { - ImmutableList.Builder<String> builder = ImmutableList.builder(); - for (Artifact artifact : transitiveImports) { - builder.add( - "-I" - + artifact.getRootRelativePath().getPathString() - + "=" - + artifact.getExecPathString()); - } - return builder.build(); - } - } - - /* 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 ProtoCommandLineArgv(supportData.getTransitiveImports())); - - for (Artifact src : supportData.getDirectProtoSources()) { - arguments.addPath(src.getRootRelativePath()); - } - - arguments.add(suffixArguments); - return arguments; - } -} - diff --git a/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilder.java b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilder.java new file mode 100644 index 0000000000..a743bc4011 --- /dev/null +++ b/src/main/java/com/google/devtools/build/lib/rules/proto/ProtoCompileActionBuilder.java @@ -0,0 +1,297 @@ +// Copyright 2016 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.Preconditions.checkState; +import static com.google.common.collect.Iterables.isEmpty; + +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.Action; +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; +import com.google.devtools.build.lib.analysis.RuleContext; +import com.google.devtools.build.lib.analysis.actions.CustomCommandLine; +import com.google.devtools.build.lib.analysis.actions.SpawnAction; +import com.google.devtools.build.lib.util.LazyString; + +import javax.annotation.Nullable; + +/** + * Constructs actions to run the protocol compiler to generate sources from .proto files. + */ +public class ProtoCompileActionBuilder { + private static final String MNEMONIC = "GenProto"; + private static final ResourceSet GENPROTO_RESOURCE_SET = + ResourceSet.createWithRamCpuIo(100, .1, .0); + private static final Action[] NO_ACTIONS = new Action[0]; + + 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; + private Iterable<String> additionalCommandLineArguments; + private Iterable<FilesToRunProvider> additionalTools; + + public ProtoCompileActionBuilder setRuleContext(RuleContext ruleContext) { + this.ruleContext = ruleContext; + return this; + } + + public ProtoCompileActionBuilder setSupportData(SupportData supportData) { + this.supportData = supportData; + return this; + } + + public ProtoCompileActionBuilder setLanguage(String language) { + this.language = language; + return this; + } + + public ProtoCompileActionBuilder setLangPrefix(String langPrefix) { + this.langPrefix = langPrefix; + return this; + } + + public ProtoCompileActionBuilder setHasServices(boolean hasServices) { + this.hasServices = hasServices; + return this; + } + + public ProtoCompileActionBuilder setOutputs(Iterable<Artifact> outputs) { + this.outputs = outputs; + return this; + } + + public ProtoCompileActionBuilder setLangParameter(String langParameter) { + this.langParameter = langParameter; + return this; + } + + public ProtoCompileActionBuilder setLangPluginName(String langPluginName) { + this.langPluginName = langPluginName; + return this; + } + + public ProtoCompileActionBuilder setLangPluginParameter(String langPluginParameter) { + this.langPluginParameter = langPluginParameter; + return this; + } + + public ProtoCompileActionBuilder setLangPluginParameterSupplier( + Supplier<String> langPluginParameterSupplier) { + this.langPluginParameterSupplier = langPluginParameterSupplier; + return this; + } + + public ProtoCompileActionBuilder setAdditionalCommandLineArguments( + Iterable<String> additionalCmdLine) { + this.additionalCommandLineArguments = additionalCmdLine; + return this; + } + + public ProtoCompileActionBuilder setAdditionalTools( + Iterable<FilesToRunProvider> additionalTools) { + this.additionalTools = additionalTools; + return this; + } + + public ProtoCompileActionBuilder( + 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; + } + + /** + * Static class to avoid keeping a reference to this builder after build() is called. + */ + private static class LazyLangPluginFlag extends LazyString { + private final String langPrefix; + private final Supplier<String> langPluginParameter1; + + LazyLangPluginFlag(String langPrefix, Supplier<String> langPluginParameter1) { + this.langPrefix = langPrefix; + this.langPluginParameter1 = langPluginParameter1; + } + + @Override + public String toString() { + return String.format("--%s_out=%s", langPrefix, langPluginParameter1.get()); + } + } + + public Action[] build() { + checkState( + langPluginParameter == null || langPluginParameterSupplier == null, + "Only one of {langPluginParameter, langPluginParameterSupplier} should be set."); + + if (isEmpty(outputs)) { + return NO_ACTIONS; + } + + try { + return createAction().build(ruleContext); + } catch (MissingPrerequisiteException e) { + return NO_ACTIONS; + } + } + + private SpawnAction.Builder createAction() { + SpawnAction.Builder result = + new SpawnAction.Builder().addTransitiveInputs(supportData.getTransitiveImports()); + + // We also depend on the strict protodeps result to ensure this is run. + if (supportData.getUsedDirectDeps() != null) { + result.addInput(supportData.getUsedDirectDeps()); + } + + FilesToRunProvider langPluginTarget = getLangPluginTarget(); + if (langPluginTarget != null) { + result.addTool(langPluginTarget); + } + + FilesToRunProvider compilerTarget = + ruleContext.getExecutablePrerequisite("$compiler", RuleConfiguredTarget.Mode.HOST); + if (ruleContext.hasErrors()) { + throw new MissingPrerequisiteException(); + } + + if (this.additionalTools != null) { + for (FilesToRunProvider tool : additionalTools) { + result.addTool(tool); + } + } + + result + .addOutputs(outputs) + .setResources(GENPROTO_RESOURCE_SET) + .useDefaultShellEnvironment() + .setExecutable(compilerTarget) + .setCommandLine(createProtoCompilerCommandLine().build()) + .setProgressMessage("Generating " + language + " proto_library " + ruleContext.getLabel()) + .setMnemonic(MNEMONIC); + + return result; + } + + @Nullable + private FilesToRunProvider getLangPluginTarget() { + if (langPluginName == null) { + return null; + } + FilesToRunProvider result = + ruleContext.getExecutablePrerequisite(langPluginName, RuleConfiguredTarget.Mode.HOST); + if (ruleContext.hasErrors()) { + throw new MissingPrerequisiteException(); + } + return result; + } + + /** + * Commandline generator for protoc invocations. + */ + public CustomCommandLine.Builder createProtoCompilerCommandLine() { + CustomCommandLine.Builder result = CustomCommandLine.builder(); + + if (langPluginName == null) { + if (langParameter != null) { + result.add(langParameter); + } + } else { + FilesToRunProvider langPluginTarget = getLangPluginTarget(); + Supplier<String> langPluginParameter1 = + langPluginParameter == null + ? langPluginParameterSupplier + : Suppliers.ofInstance(langPluginParameter); + + 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". + result.add( + String.format( + "--plugin=protoc-gen-%s=%s", + langPrefix, + langPluginTarget.getExecutable().getExecPathString())); + result.add(new LazyLangPluginFlag(langPrefix, langPluginParameter1)); + } + + result.add(ruleContext.getFragment(ProtoConfiguration.class).protocOpts()); + + // Add include maps + result.add(new ProtoCommandLineArgv(supportData.getTransitiveImports())); + + for (Artifact src : supportData.getDirectProtoSources()) { + result.addPath(src.getRootRelativePath()); + } + + if (!hasServices) { + result.add("--disallow_services"); + } + + if (additionalCommandLineArguments != null) { + result.add(additionalCommandLineArguments); + } + + return result; + } + + /** + * Static inner class since these objects live into the execution phase and so they must not + * keep alive references to the surrounding analysis-phase objects. + */ + private static class ProtoCommandLineArgv extends CustomCommandLine.CustomMultiArgv { + private final Iterable<Artifact> transitiveImports; + + ProtoCommandLineArgv(Iterable<Artifact> transitiveImports) { + this.transitiveImports = transitiveImports; + } + + @Override + public Iterable<String> argv() { + ImmutableList.Builder<String> builder = ImmutableList.builder(); + for (Artifact artifact : transitiveImports) { + builder.add( + "-I" + + artifact.getRootRelativePath().getPathString() + + "=" + + artifact.getExecPathString()); + } + return builder.build(); + } + } + + /** + * Signifies that a prerequisite could not be satisfied. + */ + private static class MissingPrerequisiteException extends RuntimeException {} +} |