| // Copyright 2019 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.bazel.rules.ninja.parser; |
| |
| import com.google.common.base.Preconditions; |
| import com.google.common.collect.ImmutableSortedMap; |
| import com.google.devtools.build.lib.collect.ImmutableSortedKeyListMultimap; |
| import com.google.devtools.build.lib.vfs.PathFragment; |
| import com.google.errorprone.annotations.Immutable; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.Objects; |
| import java.util.stream.Collectors; |
| |
| /** Ninja target (build statement) representation. */ |
| public final class NinjaTarget { |
| /** Builder for {@link NinjaTarget}. */ |
| public static class Builder { |
| private String ruleName; |
| private final ImmutableSortedKeyListMultimap.Builder<InputKind, PathFragment> inputsBuilder; |
| private final ImmutableSortedKeyListMultimap.Builder<OutputKind, PathFragment> outputsBuilder; |
| private final NinjaScope scope; |
| private final int offset; |
| |
| private final ImmutableSortedMap.Builder<String, String> variablesBuilder; |
| |
| private Builder(NinjaScope scope, int offset) { |
| this.scope = scope; |
| this.offset = offset; |
| inputsBuilder = ImmutableSortedKeyListMultimap.builder(); |
| outputsBuilder = ImmutableSortedKeyListMultimap.builder(); |
| variablesBuilder = ImmutableSortedMap.naturalOrder(); |
| } |
| |
| public Builder setRuleName(String ruleName) { |
| this.ruleName = ruleName; |
| return this; |
| } |
| |
| public Builder addInputs(InputKind kind, Collection<PathFragment> inputs) { |
| inputsBuilder.putAll(kind, inputs); |
| return this; |
| } |
| |
| public Builder addOutputs(OutputKind kind, Collection<PathFragment> outputs) { |
| outputsBuilder.putAll(kind, outputs); |
| return this; |
| } |
| |
| public Builder addVariable(String key, String value) { |
| variablesBuilder.put(key, value); |
| return this; |
| } |
| |
| public NinjaTarget build() { |
| Preconditions.checkNotNull(ruleName); |
| return new NinjaTarget( |
| ruleName, |
| inputsBuilder.build(), |
| outputsBuilder.build(), |
| variablesBuilder.build(), |
| scope, |
| offset); |
| } |
| } |
| |
| /** Enum with possible kinds of inputs. */ |
| @Immutable |
| public enum InputKind implements InputOutputKind { |
| USUAL, |
| IMPLICIT, |
| ORDER_ONLY |
| } |
| |
| /** Enum with possible kinds of outputs. */ |
| @Immutable |
| public enum OutputKind implements InputOutputKind { |
| USUAL, |
| IMPLICIT |
| } |
| |
| /** |
| * Marker interface, so that it is possible to address {@link InputKind} and {@link OutputKind} |
| * together in one map. |
| */ |
| @Immutable |
| public interface InputOutputKind {} |
| |
| private final String ruleName; |
| private final ImmutableSortedKeyListMultimap<InputKind, PathFragment> inputs; |
| private final ImmutableSortedKeyListMultimap<OutputKind, PathFragment> outputs; |
| private final ImmutableSortedMap<String, String> variables; |
| private final NinjaScope scope; |
| private final int offset; |
| |
| public NinjaTarget( |
| String ruleName, |
| ImmutableSortedKeyListMultimap<InputKind, PathFragment> inputs, |
| ImmutableSortedKeyListMultimap<OutputKind, PathFragment> outputs, |
| ImmutableSortedMap<String, String> variables, |
| NinjaScope scope, |
| int offset) { |
| this.ruleName = ruleName; |
| this.inputs = inputs; |
| this.outputs = outputs; |
| this.variables = variables; |
| this.scope = scope; |
| this.offset = offset; |
| } |
| |
| public String getRuleName() { |
| return ruleName; |
| } |
| |
| public ImmutableSortedMap<String, String> getVariables() { |
| return variables; |
| } |
| |
| public boolean hasInputs() { |
| return !inputs.isEmpty(); |
| } |
| |
| public List<PathFragment> getOutputs() { |
| return outputs.get(OutputKind.USUAL); |
| } |
| |
| public List<PathFragment> getImplicitOutputs() { |
| return outputs.get(OutputKind.IMPLICIT); |
| } |
| |
| public Collection<PathFragment> getAllOutputs() { |
| return outputs.values(); |
| } |
| |
| public Collection<PathFragment> getAllInputs() { |
| return inputs.values(); |
| } |
| |
| public Collection<PathFragment> getUsualInputs() { |
| return inputs.get(InputKind.USUAL); |
| } |
| |
| public Collection<PathFragment> getImplicitInputs() { |
| return inputs.get(InputKind.IMPLICIT); |
| } |
| |
| public Collection<PathFragment> getOrderOnlyInputs() { |
| return inputs.get(InputKind.ORDER_ONLY); |
| } |
| |
| public NinjaScope getScope() { |
| return scope; |
| } |
| |
| public int getOffset() { |
| return offset; |
| } |
| |
| public static Builder builder(NinjaScope scope, int offset) { |
| return new Builder(scope, offset); |
| } |
| |
| public String prettyPrint() { |
| return "build " |
| + prettyPrintPaths("\n", getOutputs()) |
| + prettyPrintPaths("\n| ", getImplicitOutputs()) |
| + "\n: " |
| + this.ruleName |
| + prettyPrintPaths("\n", getUsualInputs()) |
| + prettyPrintPaths("\n| ", getImplicitInputs()) |
| + prettyPrintPaths("\n|| ", getOrderOnlyInputs()); |
| } |
| |
| @Override |
| public boolean equals(Object o) { |
| if (this == o) { |
| return true; |
| } |
| if (o == null || getClass() != o.getClass()) { |
| return false; |
| } |
| NinjaTarget that = (NinjaTarget) o; |
| // Note: NinjaScope is compared with default Object#equals; it is enough |
| // because we do not do any copies of NinjaScope. |
| return offset == that.offset && scope.equals(that.scope); |
| } |
| |
| @Override |
| public int hashCode() { |
| return Objects.hash(scope, offset); |
| } |
| |
| private static String prettyPrintPaths(String startDelimiter, Collection<PathFragment> paths) { |
| if (paths.isEmpty()) { |
| return ""; |
| } |
| return startDelimiter |
| + paths.stream().map(PathFragment::getPathString).collect(Collectors.joining("$\n")); |
| } |
| } |