aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
diff options
context:
space:
mode:
authorGravatar Erik Abair <abaire@google.com>2016-02-29 18:57:22 +0000
committerGravatar Kristina Chodorow <kchodorow@google.com>2016-03-01 19:13:06 +0000
commit927f459ae2f630deed237677102d7cd56bcf0abf (patch)
treefbffb22d48693072b54c3082fcdae4de806d282a /src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
parent9f7a2a6ae7b5e1a1e1bc11daab019599b67c9c3b (diff)
Add JSON conversion for Skylark structs.
This change adds a to_json method on Skylark structs, paralleling the existing to_proto built-in. RELNOTES[NEW]: Adds a to_json method to Skylark structs, providing conversion to JSON format. -- MOS_MIGRATED_REVID=115873229
Diffstat (limited to 'src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java')
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java84
1 files changed, 78 insertions, 6 deletions
diff --git a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
index 9b764cc6be..19af953380 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java
@@ -683,7 +683,7 @@ public class SkylarkRuleClassFunctions {
printTextMessage((ClassObject) value, sb, indent + 1, loc);
print(sb, "}", indent);
} else if (value instanceof String) {
- print(sb, key + ": \"" + escape((String) value) + "\"", indent);
+ print(sb, key + ": \"" + escapeString((String) value) + "\"", indent);
} else if (value instanceof Integer) {
print(sb, key + ": " + value, indent);
} else if (value instanceof Boolean) {
@@ -710,11 +710,6 @@ public class SkylarkRuleClassFunctions {
}
}
- private String escape(String string) {
- // TODO(bazel-team): use guava's SourceCodeEscapers when it's released.
- return string.replace("\"", "\\\"").replace("\n", "\\n");
- }
-
private void print(StringBuilder sb, String text, int indent) {
for (int i = 0; i < indent; i++) {
sb.append(" ");
@@ -724,6 +719,83 @@ public class SkylarkRuleClassFunctions {
}
};
+ // Escapes the given string for use in Proto messages or JSON strings.
+ private static String escapeString(String string) {
+ // TODO(bazel-team): use guava's SourceCodeEscapers when it's released.
+ return string.replace("\"", "\\\"").replace("\n", "\\n");
+ }
+
+ @SkylarkSignature(name = "to_json",
+ doc = "Creates a JSON string from the struct parameter. This method only works if all "
+ + "struct elements (recursively) are strings, ints, booleans, other structs or a "
+ + "list of these types. Quotes and new lines in strings are escaped. "
+ + "Examples:<br><pre class=language-python>"
+ + "struct(key=123).to_json()\n# {\"key\":123}\n\n"
+ + "struct(key=True).to_json()\n# {\"key\":true}\n\n"
+ + "struct(key=[1, 2, 3]).to_json()\n# {\"key\":[1,2,3]}\n\n"
+ + "struct(key='text').to_json()\n# {\"key\":\"text\"}\n\n"
+ + "struct(key=struct(inner_key='text')).to_json()\n"
+ + "# {\"key\":{\"inner_key\":\"text\"}}\n\n"
+ + "struct(key=[struct(inner_key=1), struct(inner_key=2)]).to_json()\n"
+ + "# {\"key\":[{\"inner_key\":1},{\"inner_key\":2}]}\n\n"
+ + "struct(key=struct(inner_key=struct(inner_inner_key='text'))).to_json()\n"
+ + "# {\"key\":{\"inner_key\":{\"inner_inner_key\":\"text\"}}}\n</pre>",
+ objectType = SkylarkClassObject.class, returnType = String.class,
+ mandatoryPositionals = {
+ // TODO(bazel-team): shouldn't we accept any ClassObject?
+ @Param(name = "self", type = SkylarkClassObject.class,
+ doc = "this struct")},
+ useLocation = true)
+ private static final BuiltinFunction toJson = new BuiltinFunction("to_json") {
+ public String invoke(SkylarkClassObject self, Location loc) throws EvalException {
+ StringBuilder sb = new StringBuilder();
+ printJson(self, sb, loc, "struct field", null);
+ return sb.toString();
+ }
+
+ private void printJson(Object value, StringBuilder sb, Location loc, String container,
+ String key) throws EvalException {
+ if (value == Runtime.NONE) {
+ sb.append("null");
+ } else if (value instanceof ClassObject) {
+ sb.append("{");
+
+ String join = "";
+ for (String subKey : ((ClassObject) value).getKeys()) {
+ sb.append(join);
+ join = ",";
+ sb.append("\"");
+ sb.append(subKey);
+ sb.append("\":");
+ printJson(((ClassObject) value).getValue(subKey), sb, loc, "struct field", subKey);
+ }
+ sb.append("}");
+ } else if (value instanceof List) {
+ sb.append("[");
+ String join = "";
+ for (Object item : ((List) value)) {
+ sb.append(join);
+ join = ",";
+ printJson(item, sb, loc, "list element in struct field", key);
+ }
+ sb.append("]");
+ } else if (value instanceof String) {
+ sb.append("\"");
+ sb.append(escapeString((String) value));
+ sb.append("\"");
+ } else if (value instanceof Integer || value instanceof Boolean) {
+ sb.append(value);
+ } else {
+ String errorMessage = "Invalid text format, expected a struct, a string, a bool, or an int "
+ + "but got a " + EvalUtils.getDataTypeName(value) + " for " + container;
+ if (key != null) {
+ errorMessage += " '" + key + "'";
+ }
+ throw new EvalException(loc, errorMessage);
+ }
+ }
+ };
+
@SkylarkSignature(name = "output_group",
documented = false, // TODO(dslomov): document.
objectType = TransitiveInfoCollection.class,