From 64d4c652f9db83b0a5ae62f319cc442a2cb79400 Mon Sep 17 00:00:00 2001 From: juliexxia Date: Fri, 23 Mar 2018 14:51:43 -0700 Subject: Create a new output formatter for cquery which output transition information in either a FULL or LITE version. Trigger new output with the new --transitions cquery flag in the new CqueryOptions class. PiperOrigin-RevId: 190278664 --- .../build/lib/analysis/config/BuildOptions.java | 75 ++++++++++++++++------ 1 file changed, 57 insertions(+), 18 deletions(-) (limited to 'src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java') diff --git a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java index c4ce4e5ea3..d84db4ce32 100644 --- a/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java +++ b/src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java @@ -21,12 +21,14 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.collect.ImmutableSortedMap; +import com.google.common.collect.Iterables; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; import com.google.devtools.build.lib.cmdline.Label; import com.google.devtools.build.lib.runtime.proto.InvocationPolicyOuterClass.InvocationPolicy; import com.google.devtools.build.lib.skyframe.serialization.autocodec.AutoCodec; import com.google.devtools.build.lib.util.Fingerprint; +import com.google.devtools.build.lib.util.OrderedSetMultimap; import com.google.devtools.common.options.InvocationPolicyEnforcer; import com.google.devtools.common.options.OptionDefinition; import com.google.devtools.common.options.OptionsBase; @@ -34,11 +36,13 @@ import com.google.devtools.common.options.OptionsClassProvider; import com.google.devtools.common.options.OptionsParser; import com.google.devtools.common.options.OptionsParsingException; import java.io.Serializable; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Objects; @@ -344,16 +348,32 @@ public final class BuildOptions implements Cloneable, Serializable { } } - /** Returns the difference between two BuildOptions in a {@link BuildOptions.OptionsDiff}. */ - public static OptionsDiff diff(BuildOptions first, BuildOptions second) { + /** Returns the difference between two BuildOptions in a new {@link BuildOptions.OptionsDiff}. */ + public static OptionsDiff diff(@Nullable BuildOptions first, @Nullable BuildOptions second) { + return diff(new OptionsDiff(), first, second); + } + + /** + * Returns the difference between two BuildOptions in a pre-existing {@link + * BuildOptions.OptionsDiff}. + * + *

In a single pass through this method, the method can only compare a single "first" {@link + * BuildOptions} and single "second" BuildOptions; but an OptionsDiff instance can store the diff + * between a single "first" BuildOptions and multiple "second" BuildOptions. Being able to + * maintain a single OptionsDiff over multiple calls to diff is useful for, for example, + * aggregating the difference between a single BuildOptions and the results of applying a {@link + * com.google.devtools.build.lib.analysis.config.transitions.SplitTransition}) to it. + */ + public static OptionsDiff diff( + OptionsDiff diff, @Nullable BuildOptions first, @Nullable BuildOptions second) { if (first == null || second == null) { throw new IllegalArgumentException("Cannot diff null BuildOptions"); } - OptionsDiff diff = new OptionsDiff(); if (first.equals(second)) { return diff; } - // Check if either class has been trimmed of an options class that exists in the other. + // Check and report if either class has been trimmed of an options class that exists in the + // other. ImmutableSet> firstOptionClasses = first.getOptions() .stream() @@ -405,7 +425,17 @@ public final class BuildOptions implements Cloneable, Serializable { Collection fields = diff.differingOptions.get(clazz); HashMap valueMap = new HashMap<>(fields.size()); for (OptionDefinition optionDefinition : fields) { - Object secondValue = diff.second.get(optionDefinition); + Object secondValue; + try { + secondValue = Iterables.getOnlyElement(diff.second.get(optionDefinition)); + } catch (IllegalArgumentException e) { + // TODO(janakr): Currently this exception should never be thrown since diff is never + // constructed using the diff method that takes in a preexisting OptionsDiff. If this + // changes, add a test verifying this error catching works properly. + throw new IllegalStateException( + "OptionsDiffForReconstruction can only handle a single first BuildOptions and a " + + "single second BuildOptions and has encountered multiple second BuildOptions"); + } valueMap.put(optionDefinition.getField().getName(), secondValue); } differingOptions.put(clazz, valueMap); @@ -419,14 +449,20 @@ public final class BuildOptions implements Cloneable, Serializable { } /** - * A diff class for BuildOptions. Fields are meant to be populated and returned by - * {@link BuildOptions#diff} + * A diff class for BuildOptions. Fields are meant to be populated and returned by {@link + * BuildOptions#diff} */ public static class OptionsDiff{ private final Multimap, OptionDefinition> differingOptions = ArrayListMultimap.create(); - private final Map first = new HashMap<>(); - private final Map second = new HashMap<>(); + // The keyset for the {@link first} and {@link second} maps are identical and indicate which + // specific options differ between the first and second built options. + private final Map first = new LinkedHashMap<>(); + // Since this class can be used to track the result of transitions, {@link second} is a multimap + // to be able to handle [@link SplitTransition}s. + private final Multimap second = OrderedSetMultimap.create(); + // List of "extra" fragments for each BuildOption aka fragments that were trimmed off one + // BuildOption but not the other. private final Set> extraFirstFragments = new HashSet<>(); private final Set extraSecondFragments = new HashSet<>(); @@ -452,7 +488,7 @@ public final class BuildOptions implements Cloneable, Serializable { return first; } - public Map getSecond() { + public Multimap getSecond() { return second; } @@ -480,17 +516,20 @@ public final class BuildOptions implements Cloneable, Serializable { public String prettyPrint() { StringBuilder toReturn = new StringBuilder(); - for (Map.Entry firstOption : first.entrySet()) { - toReturn - .append(firstOption.getKey().getOptionName()) - .append(":") - .append(firstOption.getValue()) - .append(" -> ") - .append(second.get(firstOption.getKey())) - .append(System.lineSeparator()); + for (String diff : getPrettyPrintList()) { + toReturn.append(diff).append(System.lineSeparator()); } return toReturn.toString(); } + + public List getPrettyPrintList() { + List toReturn = new ArrayList<>(); + first.forEach( + (option, value) -> + toReturn.add( + option.getOptionName() + ":" + value + " -> " + second.get(option))); + return toReturn; + } } /** -- cgit v1.2.3