aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar Googler <noreply@google.com>2018-05-18 06:59:57 -0700
committerGravatar Copybara-Service <copybara-piper@google.com>2018-05-18 07:01:46 -0700
commit72d62bcaf58056db343f357c4591fbfd3baf999f (patch)
tree4aa14fbf696eb431648ee78951466e814831ee3c /src
parent7a71ce816bc8a67a63c2d147ac953ac451ebd23b (diff)
Skylark debug server: add serialization code
Small self-contained part of the debug server (see unknown commit for the larger picture). PiperOrigin-RevId: 197140094
Diffstat (limited to 'src')
-rw-r--r--src/BUILD1
-rw-r--r--src/main/java/com/google/devtools/build/lib/BUILD1
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkdebug/server/BUILD20
-rw-r--r--src/main/java/com/google/devtools/build/lib/skylarkdebug/server/DebuggerSerialization.java140
-rw-r--r--src/test/java/com/google/devtools/build/lib/BUILD1
-rw-r--r--src/test/java/com/google/devtools/build/lib/skylarkdebug/server/BUILD26
-rw-r--r--src/test/java/com/google/devtools/build/lib/skylarkdebug/server/DebuggerSerializationTest.java205
7 files changed, 394 insertions, 0 deletions
diff --git a/src/BUILD b/src/BUILD
index 6525feb2c6..d1ef9366fd 100644
--- a/src/BUILD
+++ b/src/BUILD
@@ -351,6 +351,7 @@ genrule(
srcs = [
"//src/main/protobuf:dist_jars",
"//src/main/java/com/google/devtools/build/lib/buildeventstream/proto:dist_jars",
+ "//src/main/java/com/google/devtools/build/lib/skylarkdebug/proto:dist_jars",
"@googleapis//:dist_jars",
],
outs = ["derived_java_srcs.zip"],
diff --git a/src/main/java/com/google/devtools/build/lib/BUILD b/src/main/java/com/google/devtools/build/lib/BUILD
index 432a4d2ac4..b7d86d6f6d 100644
--- a/src/main/java/com/google/devtools/build/lib/BUILD
+++ b/src/main/java/com/google/devtools/build/lib/BUILD
@@ -60,6 +60,7 @@ filegroup(
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/cpp:srcs",
"//src/main/java/com/google/devtools/build/lib/skylarkbuildapi/java:srcs",
"//src/main/java/com/google/devtools/build/lib/skylarkdebug/proto:srcs",
+ "//src/main/java/com/google/devtools/build/lib/skylarkdebug/server:srcs",
"//src/main/java/com/google/devtools/build/lib/skylarkinterface/processor:srcs",
"//src/main/java/com/google/devtools/build/lib/ssd:srcs",
"//src/main/java/com/google/devtools/build/lib/standalone:srcs",
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/BUILD b/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/BUILD
new file mode 100644
index 0000000000..42768bb69d
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/BUILD
@@ -0,0 +1,20 @@
+package(default_visibility = ["//src:__subpackages__"])
+
+filegroup(
+ name = "srcs",
+ srcs = glob(["**"]),
+ visibility = ["//src/main/java/com/google/devtools/build/lib:__pkg__"],
+)
+
+java_library(
+ name = "server",
+ srcs = glob(["*.java"]),
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:skylarkinterface",
+ "//src/main/java/com/google/devtools/build/lib:syntax",
+ "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
+ "//src/main/java/com/google/devtools/build/lib/skylarkdebug/proto:skylark_debugging_java_proto",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ ],
+)
diff --git a/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/DebuggerSerialization.java b/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/DebuggerSerialization.java
new file mode 100644
index 0000000000..70d716332a
--- /dev/null
+++ b/src/main/java/com/google/devtools/build/lib/skylarkdebug/server/DebuggerSerialization.java
@@ -0,0 +1,140 @@
+// Copyright 2018 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.skylarkdebug.server;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Ordering;
+import com.google.devtools.build.lib.collect.nestedset.NestedSetView;
+import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos;
+import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.Value;
+import com.google.devtools.build.lib.syntax.ClassObject;
+import com.google.devtools.build.lib.syntax.EvalException;
+import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.Printer;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import java.lang.reflect.Array;
+import java.util.Map;
+
+/** Helper class for creating {@link SkylarkDebuggingProtos.Value} from skylark objects. */
+final class DebuggerSerialization {
+
+ static Value getValueProto(String label, Object value) {
+ // TODO(bazel-team): prune cycles, and provide a way to limit breadth/depth of children reported
+ return Value.newBuilder()
+ .setLabel(label)
+ // TODO(bazel-team): omit type details for non-Skylark values
+ .setType(EvalUtils.getDataTypeName(value))
+ .setDescription(Printer.repr(value))
+ .addAllChild(getChildren(value))
+ .build();
+ }
+
+ private static Value errorValue(String errorMessage) {
+ return Value.newBuilder().setLabel("Error").setDescription(errorMessage).build();
+ }
+
+ private static ImmutableList<Value> getChildren(Object value) {
+ // TODO(bazel-team): move child-listing logic to SkylarkValue where practical
+ if (value instanceof ClassObject) {
+ return getChildren((ClassObject) value);
+ }
+ if (value instanceof SkylarkNestedSet) {
+ return getChildren((SkylarkNestedSet) value);
+ }
+ if (value instanceof NestedSetView) {
+ return getChildren((NestedSetView) value);
+ }
+ if (value instanceof Map) {
+ return getChildren(((Map) value).entrySet());
+ }
+ if (value instanceof Map.Entry) {
+ return getChildren((Map.Entry) value);
+ }
+ if (value instanceof Iterable) {
+ return getChildren((Iterable) value);
+ }
+ if (value.getClass().isArray()) {
+ return getArrayChildren(value);
+ }
+ // fallback to assuming there are no children
+ return ImmutableList.of();
+ }
+
+ private static ImmutableList<Value> getChildren(ClassObject classObject) {
+ ImmutableList.Builder<Value> builder = ImmutableList.builder();
+ ImmutableList<String> keys;
+ try {
+ keys = Ordering.natural().immutableSortedCopy(classObject.getFieldNames());
+ } catch (EvalException e) {
+ return ImmutableList.of(errorValue("Error retrieving field names: " + e.getMessage()));
+ }
+ for (String key : keys) {
+ Object value;
+ try {
+ value = classObject.getValue(key);
+ } catch (EvalException e) {
+ return ImmutableList.of(
+ errorValue(
+ String.format("Error retrieving value for field '%s': %s", key, e.getMessage())));
+ }
+ if (value != null) {
+ builder.add(getValueProto(key, value));
+ }
+ }
+ return builder.build();
+ }
+
+ private static ImmutableList<Value> getChildren(SkylarkNestedSet nestedSet) {
+ Class<?> type = nestedSet.getContentType().getType();
+ return ImmutableList.<Value>builder()
+ .add(
+ Value.newBuilder()
+ .setLabel("order")
+ .setType("Traversal order")
+ .setDescription(nestedSet.getOrder().getSkylarkName())
+ .build())
+ .addAll(getChildren(new NestedSetView<>(nestedSet.getSet(type))))
+ .build();
+ }
+
+ private static ImmutableList<Value> getChildren(NestedSetView<?> nestedSet) {
+ return ImmutableList.of(
+ getValueProto("directs", nestedSet.directs()),
+ getValueProto("transitives", nestedSet.transitives()));
+ }
+
+ private static ImmutableList<Value> getChildren(Map.Entry<?, ?> entry) {
+ return ImmutableList.of(
+ getValueProto("key", entry.getKey()), getValueProto("value", entry.getValue()));
+ }
+
+ private static ImmutableList<Value> getChildren(Iterable<?> iterable) {
+ ImmutableList.Builder<Value> builder = ImmutableList.builder();
+ int index = 0;
+ for (Object value : iterable) {
+ builder.add(getValueProto(String.format("[%d]", index++), value));
+ }
+ return builder.build();
+ }
+
+ private static ImmutableList<Value> getArrayChildren(Object array) {
+ ImmutableList.Builder<Value> builder = ImmutableList.builder();
+ int index = 0;
+ for (int i = 0; i < Array.getLength(array); i++) {
+ builder.add(getValueProto(String.format("[%d]", index++), Array.get(array, i)));
+ }
+ return builder.build();
+ }
+}
diff --git a/src/test/java/com/google/devtools/build/lib/BUILD b/src/test/java/com/google/devtools/build/lib/BUILD
index 52c95b19cc..887620485a 100644
--- a/src/test/java/com/google/devtools/build/lib/BUILD
+++ b/src/test/java/com/google/devtools/build/lib/BUILD
@@ -58,6 +58,7 @@ filegroup(
"//src/test/java/com/google/devtools/build/lib/skyframe/serialization:srcs",
"//src/test/java/com/google/devtools/build/lib/skyframe:srcs",
"//src/test/java/com/google/devtools/build/lib/skylark:srcs",
+ "//src/test/java/com/google/devtools/build/lib/skylarkdebug/server:srcs",
"//src/test/java/com/google/devtools/build/lib/skylarkinterface/processor:srcs",
],
visibility = ["//src:__pkg__"],
diff --git a/src/test/java/com/google/devtools/build/lib/skylarkdebug/server/BUILD b/src/test/java/com/google/devtools/build/lib/skylarkdebug/server/BUILD
new file mode 100644
index 0000000000..5d9f881575
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skylarkdebug/server/BUILD
@@ -0,0 +1,26 @@
+package(
+ default_testonly = 1,
+ default_visibility = ["//src:__subpackages__"],
+)
+
+filegroup(
+ name = "srcs",
+ testonly = 0,
+ srcs = glob(["**"]),
+ visibility = ["//src/test/java/com/google/devtools/build/lib:__pkg__"],
+)
+
+java_test(
+ name = "DebuggerSerializationTest",
+ srcs = glob(["DebuggerSerializationTest.java"]),
+ deps = [
+ "//src/main/java/com/google/devtools/build/lib:syntax",
+ "//src/main/java/com/google/devtools/build/lib/collect/nestedset",
+ "//src/main/java/com/google/devtools/build/lib/skylarkdebug/proto:skylark_debugging_java_proto",
+ "//src/main/java/com/google/devtools/build/lib/skylarkdebug/server",
+ "//third_party:guava",
+ "//third_party:jsr305",
+ "//third_party:junit4",
+ "//third_party:truth",
+ ],
+)
diff --git a/src/test/java/com/google/devtools/build/lib/skylarkdebug/server/DebuggerSerializationTest.java b/src/test/java/com/google/devtools/build/lib/skylarkdebug/server/DebuggerSerializationTest.java
new file mode 100644
index 0000000000..525f1ce005
--- /dev/null
+++ b/src/test/java/com/google/devtools/build/lib/skylarkdebug/server/DebuggerSerializationTest.java
@@ -0,0 +1,205 @@
+// Copyright 2018 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.skylarkdebug.server;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+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.NestedSetView;
+import com.google.devtools.build.lib.skylarkdebugging.SkylarkDebuggingProtos.Value;
+import com.google.devtools.build.lib.syntax.EvalUtils;
+import com.google.devtools.build.lib.syntax.Printer;
+import com.google.devtools.build.lib.syntax.SkylarkNestedSet;
+import java.util.Map;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/** Unit tests for {@link DebuggerSerialization}. */
+@RunWith(JUnit4.class)
+public final class DebuggerSerializationTest {
+
+ @Test
+ public void testSimpleNestedSet() {
+ Set<String> children = ImmutableSet.of("a", "b");
+ SkylarkNestedSet set =
+ SkylarkNestedSet.of(Object.class, NestedSetBuilder.stableOrder().addAll(children).build());
+
+ Value value = DebuggerSerialization.getValueProto("name", set);
+
+ assertTypeAndDescription(set, value);
+ assertThat(value.getChildList()).hasSize(3);
+ assertThat(value.getChild(0))
+ .isEqualTo(
+ Value.newBuilder()
+ .setLabel("order")
+ .setType("Traversal order")
+ .setDescription("default")
+ .build());
+ assertEqualIgnoringTypeAndDescription(
+ value.getChild(1), DebuggerSerialization.getValueProto("directs", children));
+ assertEqualIgnoringTypeAndDescription(
+ value.getChild(2), DebuggerSerialization.getValueProto("transitives", ImmutableList.of()));
+ }
+
+ @Test
+ public void testNestedSetWithNestedChildren() {
+ NestedSet<String> innerNestedSet =
+ NestedSetBuilder.<String>stableOrder().add("inner1").add("inner2").build();
+ ImmutableSet<String> directChildren = ImmutableSet.of("a", "b");
+ SkylarkNestedSet outerSet =
+ SkylarkNestedSet.of(
+ String.class,
+ NestedSetBuilder.<String>linkOrder()
+ .addAll(directChildren)
+ .addTransitive(innerNestedSet)
+ .build());
+
+ Value value = DebuggerSerialization.getValueProto("name", outerSet);
+
+ assertTypeAndDescription(outerSet, value);
+ assertThat(value.getChildList()).hasSize(3);
+ assertThat(value.getChild(0))
+ .isEqualTo(
+ Value.newBuilder()
+ .setLabel("order")
+ .setType("Traversal order")
+ .setDescription("topological")
+ .build());
+ assertEqualIgnoringTypeAndDescription(
+ value.getChild(1), DebuggerSerialization.getValueProto("directs", directChildren));
+ assertEqualIgnoringTypeAndDescription(
+ value.getChild(2),
+ DebuggerSerialization.getValueProto(
+ "transitives", ImmutableList.of(new NestedSetView<>(innerNestedSet))));
+ }
+
+ @Test
+ public void testSimpleMap() {
+ Map<String, Integer> map = ImmutableMap.of("a", 1, "b", 2);
+
+ Value value = DebuggerSerialization.getValueProto("name", map);
+
+ assertTypeAndDescription(map, value);
+ assertThat(value.getChildList()).hasSize(2);
+ assertThat(value.getChild(0).getLabel()).isEqualTo("[0]");
+ assertThat(value.getChild(0).getChildList())
+ .isEqualTo(
+ ImmutableList.of(
+ DebuggerSerialization.getValueProto("key", "a"),
+ DebuggerSerialization.getValueProto("value", 1)));
+ assertThat(value.getChild(1).getLabel()).isEqualTo("[1]");
+ assertThat(value.getChild(1).getChildList())
+ .isEqualTo(
+ ImmutableList.of(
+ DebuggerSerialization.getValueProto("key", "b"),
+ DebuggerSerialization.getValueProto("value", 2)));
+ }
+
+ @Test
+ public void testNestedMap() {
+ Set<String> set = ImmutableSet.of("a", "b");
+ Map<String, Object> map = ImmutableMap.of("a", set);
+
+ Value value = DebuggerSerialization.getValueProto("name", map);
+
+ assertTypeAndDescription(map, value);
+ assertThat(value.getChildList()).hasSize(1);
+ assertThat(value.getChild(0).getLabel()).isEqualTo("[0]");
+ assertThat(value.getChild(0).getChildList())
+ .isEqualTo(
+ ImmutableList.of(
+ DebuggerSerialization.getValueProto("key", "a"),
+ DebuggerSerialization.getValueProto("value", set)));
+ }
+
+ @Test
+ public void testSimpleIterable() {
+ Iterable<Integer> iter = ImmutableList.of(1, 2);
+
+ Value value = DebuggerSerialization.getValueProto("name", iter);
+
+ assertTypeAndDescription(iter, value);
+ assertThat(value.getChildList()).hasSize(2);
+ assertThat(value.getChild(0)).isEqualTo(DebuggerSerialization.getValueProto("[0]", 1));
+ assertThat(value.getChild(1)).isEqualTo(DebuggerSerialization.getValueProto("[1]", 2));
+ }
+
+ @Test
+ public void testNestedIterable() {
+ Iterable<Object> iter = ImmutableList.of(ImmutableList.of(1, 2));
+
+ Value value = DebuggerSerialization.getValueProto("name", iter);
+
+ assertTypeAndDescription(iter, value);
+ assertThat(value.getChildList()).hasSize(1);
+ assertThat(value.getChild(0))
+ .isEqualTo(DebuggerSerialization.getValueProto("[0]", ImmutableList.of(1, 2)));
+ }
+
+ @Test
+ public void testSimpleArray() {
+ int[] array = new int[] {1, 2};
+
+ Value value = DebuggerSerialization.getValueProto("name", array);
+
+ assertTypeAndDescription(array, value);
+ assertThat(value.getChildList()).hasSize(2);
+ assertThat(value.getChild(0)).isEqualTo(DebuggerSerialization.getValueProto("[0]", 1));
+ assertThat(value.getChild(1)).isEqualTo(DebuggerSerialization.getValueProto("[1]", 2));
+ }
+
+ @Test
+ public void testNestedArray() {
+ Object[] array = new Object[] {1, ImmutableList.of(2, 3)};
+
+ Value value = DebuggerSerialization.getValueProto("name", array);
+
+ assertTypeAndDescription(array, value);
+ assertThat(value.getChildList()).hasSize(2);
+ assertThat(value.getChild(0)).isEqualTo(DebuggerSerialization.getValueProto("[0]", 1));
+ assertThat(value.getChild(1))
+ .isEqualTo(DebuggerSerialization.getValueProto("[1]", ImmutableList.of(2, 3)));
+ }
+
+ @Test
+ public void testUnrecognizedObjectOrSkylarkPrimitiveHasNoChildren() {
+ assertThat(DebuggerSerialization.getValueProto("name", 1).getChildList()).isEmpty();
+ assertThat(DebuggerSerialization.getValueProto("name", "string").getChildList()).isEmpty();
+ assertThat(DebuggerSerialization.getValueProto("name", new Object()).getChildList()).isEmpty();
+ }
+
+ private static void assertTypeAndDescription(Object object, Value value) {
+ assertThat(value.getType()).isEqualTo(EvalUtils.getDataTypeName(object));
+ assertThat(value.getDescription()).isEqualTo(Printer.repr(object));
+ }
+
+ /**
+ * Type and description are implementation dependent (e.g. NestedSetView#directs returns a list
+ * instead of a set if there are no duplicates, which changes both 'type' and 'description').
+ */
+ private static void assertEqualIgnoringTypeAndDescription(Value value1, Value value2) {
+ assertThat(value1.getLabel()).isEqualTo(value2.getLabel());
+ assertThat(value1.getChildCount()).isEqualTo(value2.getChildCount());
+ for (int i = 0; i < value1.getChildCount(); i++) {
+ assertEqualIgnoringTypeAndDescription(value1.getChild(i), value2.getChild(i));
+ }
+ }
+}