Rename OutputGroupProvider -> OutputGroupInfo.
RELNOTES: None
PiperOrigin-RevId: 179046403
diff --git a/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupInfo.java b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupInfo.java
new file mode 100644
index 0000000..8c313d0
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/analysis/OutputGroupInfo.java
@@ -0,0 +1,288 @@
+// Copyright 2014 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.analysis;
+
+import static com.google.devtools.build.lib.syntax.EvalUtils.SKYLARK_COMPARATOR;
+
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSortedSet;
+import com.google.common.collect.Sets;
+import com.google.devtools.build.lib.actions.Artifact;
+import com.google.devtools.build.lib.analysis.configuredtargets.MergedConfiguredTarget.DuplicateException;
+import com.google.devtools.build.lib.analysis.skylark.SkylarkRuleConfiguredTargetUtil;
+import com.google.devtools.build.lib.collect.nestedset.NestedSet;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetBuilder;
+import com.google.devtools.build.lib.collect.nestedset.Order;
+import com.google.devtools.build.lib.concurrent.ThreadSafety.Immutable;
+import com.google.devtools.build.lib.events.Location;
+import com.google.devtools.build.lib.packages.NativeInfo;
+import com.google.devtools.build.lib.packages.NativeProvider;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.SkylarkIndexable;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import javax.annotation.Nullable;
+
+/**
+ * {@code ConfiguredTarget}s implementing this interface can provide artifacts that <b>can</b> be
+ * built when the target is mentioned on the command line (as opposed to being always built, like
+ * {@link com.google.devtools.build.lib.analysis.FileProvider})
+ *
+ * <p>The artifacts are grouped into "output groups". Which output groups are built is controlled by
+ * the {@code --output_groups} undocumented command line option, which in turn is added to the
+ * command line at the discretion of the build command being run.
+ *
+ * <p>Output groups starting with an underscore are "not important". This means that artifacts built
+ * because such an output group is mentioned in a {@code --output_groups} command line option are
+ * not mentioned on the output.
+ */
+@Immutable
+public final class OutputGroupInfo extends NativeInfo
+ implements SkylarkIndexable, Iterable<String> {
+ public static final String SKYLARK_NAME = "output_groups";
+
+ public static NativeProvider<OutputGroupInfo> SKYLARK_CONSTRUCTOR = new Constructor();
+
+ /**
+ * Prefix for output groups that are not reported to the user on the terminal output of Blaze when
+ * they are built.
+ */
+ public static final String HIDDEN_OUTPUT_GROUP_PREFIX = "_";
+
+ /**
+ * Suffix for output groups that are internal to bazel and may not be referenced from a filegroup.
+ */
+ public static final String INTERNAL_SUFFIX = "_INTERNAL_";
+
+ /**
+ * Building these artifacts only results in the compilation (and not e.g. linking) of the
+ * associated target. Mostly useful for C++, less so for e.g. Java.
+ */
+ public static final String FILES_TO_COMPILE = "files_to_compile" + INTERNAL_SUFFIX;
+
+ /**
+ * These artifacts are the direct requirements for compilation, but building these does not
+ * actually compile the target. Mostly useful when IDEs want Blaze to emit generated code so that
+ * they can do the compilation in their own way.
+ */
+ public static final String COMPILATION_PREREQUISITES =
+ "compilation_prerequisites" + INTERNAL_SUFFIX;
+
+ /**
+ * These files are built when a target is mentioned on the command line, but are not reported to
+ * the user. This is mostly runfiles, which is necessary because we don't want a target to
+ * successfully build if a file in its runfiles is broken.
+ */
+ public static final String HIDDEN_TOP_LEVEL =
+ HIDDEN_OUTPUT_GROUP_PREFIX + "hidden_top_level" + INTERNAL_SUFFIX;
+
+ /**
+ * Temporary files created during building a rule, for example, .i, .d and .s files for C++
+ * compilation.
+ *
+ * <p>This output group is somewhat special: it is always built, but it only contains files when
+ * the {@code --save_temps} command line option present. I'm not sure if this is to save RAM by
+ * not creating the associated actions and artifacts if we don't need them or just historical
+ * baggage.
+ */
+ public static final String TEMP_FILES = "temp_files" + INTERNAL_SUFFIX;
+
+ /**
+ * The default group of files built by a target when it is mentioned on the command line.
+ */
+ public static final String DEFAULT = "default";
+
+ /**
+ * The default set of OutputGroups we typically want to build.
+ */
+ public static final ImmutableSet<String> DEFAULT_GROUPS =
+ ImmutableSet.of(DEFAULT, TEMP_FILES, HIDDEN_TOP_LEVEL);
+
+ private final ImmutableMap<String, NestedSet<Artifact>> outputGroups;
+
+ public OutputGroupInfo(ImmutableMap<String, NestedSet<Artifact>> outputGroups) {
+ super(SKYLARK_CONSTRUCTOR, ImmutableMap.<String, Object>of());
+ this.outputGroups = outputGroups;
+ }
+
+ @Nullable
+ public static OutputGroupInfo get(TransitiveInfoCollection collection) {
+ return collection.get(OutputGroupInfo.SKYLARK_CONSTRUCTOR);
+ }
+
+ @Nullable
+ public static OutputGroupInfo get(ConfiguredAspect aspect) {
+ return (OutputGroupInfo) aspect.get(SKYLARK_CONSTRUCTOR.getKey());
+ }
+
+
+ /** Return the artifacts in a particular output group.
+ *
+ * @return the artifacts in the output group with the given name. The return value is never null.
+ * If the specified output group is not present, the empty set is returned.
+ */
+ public NestedSet<Artifact> getOutputGroup(String outputGroupName) {
+ return outputGroups.containsKey(outputGroupName)
+ ? outputGroups.get(outputGroupName)
+ : NestedSetBuilder.<Artifact>emptySet(Order.STABLE_ORDER);
+ }
+
+ /**
+ * Merges output groups from two output providers. The set of output groups must be disjoint.
+ *
+ * @param providers providers to merge {@code this} with.
+ */
+ @Nullable
+ public static OutputGroupInfo merge(List<OutputGroupInfo> providers)
+ throws DuplicateException {
+ if (providers.size() == 0) {
+ return null;
+ }
+ if (providers.size() == 1) {
+ return providers.get(0);
+ }
+
+ ImmutableMap.Builder<String, NestedSet<Artifact>> resultBuilder = new ImmutableMap.Builder<>();
+ Set<String> seenGroups = new HashSet<>();
+ for (OutputGroupInfo provider : providers) {
+ for (String outputGroup : provider.outputGroups.keySet()) {
+ if (!seenGroups.add(outputGroup)) {
+ throw new DuplicateException(
+ "Output group " + outputGroup + " provided twice");
+ }
+
+ resultBuilder.put(outputGroup, provider.getOutputGroup(outputGroup));
+ }
+ }
+ return new OutputGroupInfo(resultBuilder.build());
+ }
+
+ public static ImmutableSortedSet<String> determineOutputGroups(List<String> outputGroups) {
+ return determineOutputGroups(DEFAULT_GROUPS, outputGroups);
+ }
+
+ public static ImmutableSortedSet<String> determineOutputGroups(
+ Set<String> defaultOutputGroups, List<String> outputGroups) {
+
+ Set<String> current = Sets.newHashSet();
+
+ // If all of the requested output groups start with "+" or "-", then these are added or
+ // subtracted to the set of default output groups.
+ // If any of them don't start with "+" or "-", then the list of requested output groups
+ // overrides the default set of output groups.
+ boolean addDefaultOutputGroups = true;
+ for (String outputGroup : outputGroups) {
+ if (!(outputGroup.startsWith("+") || outputGroup.startsWith("-"))) {
+ addDefaultOutputGroups = false;
+ break;
+ }
+ }
+ if (addDefaultOutputGroups) {
+ current.addAll(defaultOutputGroups);
+ }
+
+ for (String outputGroup : outputGroups) {
+ if (outputGroup.startsWith("+")) {
+ current.add(outputGroup.substring(1));
+ } else if (outputGroup.startsWith("-")) {
+ current.remove(outputGroup.substring(1));
+ } else {
+ current.add(outputGroup);
+ }
+ }
+
+ return ImmutableSortedSet.copyOf(current);
+ }
+
+ @Override
+ public Object getIndex(Object key, Location loc) throws EvalException {
+ if (!(key instanceof String)) {
+ throw new EvalException(loc, String.format(
+ "Output grout names must be strings, got %s instead",
+ EvalUtils.getDataTypeName(key)));
+ }
+
+ NestedSet<Artifact> result = outputGroups.get(key);
+ if (result != null) {
+ return SkylarkNestedSet.of(Artifact.class, result);
+ } else {
+ throw new EvalException(loc, String.format(
+ "Output group %s not present", key
+ ));
+ }
+ }
+
+ @Override
+ public boolean containsKey(Object key, Location loc) throws EvalException {
+ return outputGroups.containsKey(key);
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ return SKYLARK_COMPARATOR.sortedCopy(outputGroups.keySet()).iterator();
+ }
+
+ @Override
+ public Object getValue(String name) {
+ NestedSet<Artifact> result = outputGroups.get(name);
+ if (result == null) {
+ return null;
+ }
+ return SkylarkNestedSet.of(Artifact.class, result);
+ }
+
+ @Override
+ public ImmutableCollection<String> getKeys() {
+ return outputGroups.keySet();
+ }
+
+ /** A constructor callable from Skylark for OutputGroupInfo. */
+ private static class Constructor extends NativeProvider<OutputGroupInfo> {
+
+ private Constructor() {
+ super(OutputGroupInfo.class, "OutputGroupInfo");
+ }
+
+ @Override
+ protected OutputGroupInfo createInstanceFromSkylark(Object[] args, Location loc)
+ throws EvalException {
+
+ @SuppressWarnings("unchecked")
+ Map<String, Object> kwargs = (Map<String, Object>) args[0];
+
+ ImmutableMap.Builder<String, NestedSet<Artifact>> builder = ImmutableMap.builder();
+ for (Entry<String, Object> entry : kwargs.entrySet()) {
+ builder.put(
+ entry.getKey(),
+ SkylarkRuleConfiguredTargetUtil.convertToOutputGroupValue(
+ loc, entry.getKey(), entry.getValue()));
+ }
+ return new OutputGroupInfo(builder.build());
+ }
+
+ @Override
+ public String getErrorMessageFormatForInstances() {
+ return "Output group %s not present";
+ }
+ }
+}