aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/analysis/config
diff options
context:
space:
mode:
authorGravatar juliexxia <juliexxia@google.com>2018-02-23 08:11:48 -0800
committerGravatar Copybara-Service <copybara-piper@google.com>2018-02-23 08:13:21 -0800
commitc4b49f276fc4a410f8f249e32f30ac4602724a95 (patch)
treee7c264b0bb8c768e5cd5a860d29848eed4002b85 /src/main/java/com/google/devtools/build/lib/analysis/config
parent09077a35da3def2474d90f1cc1bb14848dd6fd4f (diff)
Add a new BuildOptions diff method that holds and pretty prints the different option values between two BuildOptions
PiperOrigin-RevId: 186769975
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/analysis/config')
-rw-r--r--src/main/java/com/google/devtools/build/lib/analysis/config/BuildOptions.java111
1 files changed, 111 insertions, 0 deletions
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 cd1db7c261..df99dc6aa0 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
@@ -20,6 +20,7 @@ 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.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.DeserializationContext;
@@ -28,6 +29,7 @@ import com.google.devtools.build.lib.skyframe.serialization.SerializationContext
import com.google.devtools.build.lib.skyframe.serialization.SerializationException;
import com.google.devtools.build.lib.util.Fingerprint;
import com.google.devtools.common.options.InvocationPolicyEnforcer;
+import com.google.devtools.common.options.OptionDefinition;
import com.google.devtools.common.options.OptionsBase;
import com.google.devtools.common.options.OptionsClassProvider;
import com.google.devtools.common.options.OptionsParser;
@@ -36,12 +38,14 @@ import com.google.protobuf.CodedInputStream;
import com.google.protobuf.CodedOutputStream;
import java.io.IOException;
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.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
@@ -332,6 +336,113 @@ 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) {
+ 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.
+ ImmutableSet<Class<? extends FragmentOptions>> firstOptionClasses =
+ first.getOptions()
+ .stream()
+ .map(FragmentOptions::getClass)
+ .collect(ImmutableSet.toImmutableSet());
+ ImmutableSet<Class<? extends FragmentOptions>> secondOptionClasses =
+ second.getOptions()
+ .stream()
+ .map(FragmentOptions::getClass)
+ .collect(ImmutableSet.toImmutableSet());
+ Sets.difference(firstOptionClasses, secondOptionClasses).forEach(diff::addExtraFirstFragments);
+ Sets.difference(secondOptionClasses, firstOptionClasses).forEach(diff::addExtraSecondFragments);
+ // For fragments in common, report differences.
+ for (Class<? extends FragmentOptions> clazz :
+ Sets.intersection(firstOptionClasses, secondOptionClasses)) {
+ if (!first.get(clazz).equals(second.get(clazz))) {
+ ImmutableList<OptionDefinition> definitions = OptionsParser.getOptionDefinitions(clazz);
+ Map<String, Object> firstClazzOptions = first.get(clazz).asMap();
+ Map<String, Object> secondClazzOptions = second.get(clazz).asMap();
+ for (OptionDefinition definition : definitions) {
+ String name = definition.getOptionName();
+ Object firstValue = firstClazzOptions.get(name);
+ Object secondValue = secondClazzOptions.get(name);
+ if (!Objects.equals(firstValue, secondValue)) {
+ diff.addDiff(definition, firstValue, secondValue);
+ }
+ }
+ }
+ }
+ return diff;
+ }
+
+ /**
+ * A diff class for BuildOptions. Fields are meant to be populated and returned by
+ * {@link BuildOptions#diff}
+ */
+ public static class OptionsDiff{
+ private final Map<OptionDefinition, Object> first = new HashMap<>();
+ private final Map<OptionDefinition, Object> second = new HashMap<>();
+ private final List<Class<? extends FragmentOptions>> extraFirstFragments = new ArrayList<>();
+ private final List<Class<? extends FragmentOptions>> extraSecondFragments = new ArrayList<>();
+
+ private void addExtraFirstFragments(Class<? extends FragmentOptions> clazz) {
+ extraFirstFragments.add(clazz);
+ }
+
+ private void addExtraSecondFragments(Class<? extends FragmentOptions> clazz) {
+ extraSecondFragments.add(clazz);
+ }
+
+ /** Return the extra fragments from the first configuration. */
+ public List<Class<? extends FragmentOptions>> getExtraFirstFragments() {
+ return extraFirstFragments;
+ }
+
+ /** Return the extra fragments from the second configuration. */
+ public List<Class<? extends FragmentOptions>> getExtraSecondFragments() {
+ return extraSecondFragments;
+ }
+
+ public Map<OptionDefinition, Object> getFirst() {
+ return first;
+ }
+
+ public Map<OptionDefinition, Object> getSecond() {
+ return second;
+ }
+
+
+ private void addDiff(OptionDefinition option, Object firstValue, Object secondValue) {
+ first.put(option, firstValue);
+ second.put(option, secondValue);
+ }
+
+ /**
+ * Note: it's not enough for first and second to be empty, with trimming, they must also contain
+ * the same options classes.
+ */
+ boolean areSame() {
+ return first.isEmpty()
+ && second.isEmpty()
+ && extraSecondFragments.isEmpty()
+ && extraFirstFragments.isEmpty();
+ }
+
+ public String prettyPrint() {
+ StringBuilder toReturn = new StringBuilder();
+ for (Map.Entry<OptionDefinition, Object> firstOption : first.entrySet()) {
+ toReturn
+ .append(firstOption.getKey().getOptionName())
+ .append(":")
+ .append(firstOption.getValue())
+ .append(" -> ")
+ .append(second.get(firstOption.getKey()))
+ .append(System.lineSeparator());
+ }
+ return toReturn.toString();
+ }
+ }
+
private static class BuildOptionsCodec implements ObjectCodec<BuildOptions> {
@Override
public Class<BuildOptions> getEncodedClass() {