aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/main/java/com/google/devtools/build/lib/rules/SkylarkRuleClassFunctions.java37
-rw-r--r--src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java3
2 files changed, 24 insertions, 16 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 6a8710189f..60483dafe1 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
@@ -91,6 +91,7 @@ import com.google.devtools.build.lib.syntax.Type;
import com.google.devtools.build.lib.syntax.Type.ConversionException;
import com.google.devtools.build.lib.util.Pair;
import com.google.devtools.build.lib.util.Preconditions;
+import com.google.protobuf.TextFormat;
import java.util.List;
import java.util.Map;
@@ -715,25 +716,27 @@ public class SkylarkRuleClassFunctions {
private static final BuiltinFunction toProto = new BuiltinFunction("to_proto") {
public String invoke(SkylarkClassObject self, Location loc) throws EvalException {
StringBuilder sb = new StringBuilder();
- printTextMessage(self, sb, 0, loc);
+ printProtoTextMessage(self, sb, 0, loc);
return sb.toString();
}
- private void printTextMessage(ClassObject object, StringBuilder sb,
+ private void printProtoTextMessage(ClassObject object, StringBuilder sb,
int indent, Location loc) throws EvalException {
for (String key : object.getKeys()) {
- printTextMessage(key, object.getValue(key), sb, indent, loc);
+ printProtoTextMessage(key, object.getValue(key), sb, indent, loc);
}
}
- private void printSimpleTextMessage(String key, Object value, StringBuilder sb,
+ private void printProtoTextMessage(String key, Object value, StringBuilder sb,
int indent, Location loc, String container) throws EvalException {
if (value instanceof ClassObject) {
print(sb, key + " {", indent);
- printTextMessage((ClassObject) value, sb, indent + 1, loc);
+ printProtoTextMessage((ClassObject) value, sb, indent + 1, loc);
print(sb, "}", indent);
} else if (value instanceof String) {
- print(sb, key + ": \"" + escapeString((String) value) + "\"", indent);
+ print(sb,
+ key + ": \"" + escapeDoubleQuotesAndBackslashesAndNewlines((String) value) + "\"",
+ indent);
} else if (value instanceof Integer) {
print(sb, key + ": " + value, indent);
} else if (value instanceof Boolean) {
@@ -747,16 +750,16 @@ public class SkylarkRuleClassFunctions {
}
}
- private void printTextMessage(String key, Object value, StringBuilder sb,
+ private void printProtoTextMessage(String key, Object value, StringBuilder sb,
int indent, Location loc) throws EvalException {
if (value instanceof SkylarkList) {
for (Object item : ((SkylarkList) value)) {
// TODO(bazel-team): There should be some constraint on the fields of the structs
// in the same list but we ignore that for now.
- printSimpleTextMessage(key, item, sb, indent, loc, "list element in struct field");
+ printProtoTextMessage(key, item, sb, indent, loc, "list element in struct field");
}
} else {
- printSimpleTextMessage(key, value, sb, indent, loc, "struct field");
+ printProtoTextMessage(key, value, sb, indent, loc, "struct field");
}
}
@@ -769,10 +772,13 @@ 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");
+ /**
+ * Escapes the given string for use in proto/JSON string.
+ *
+ * <p>This escapes double quotes, backslashes, and newlines.
+ */
+ private static String escapeDoubleQuotesAndBackslashesAndNewlines(String string) {
+ return TextFormat.escapeDoubleQuotesAndBackslashes(string).replace("\n", "\\n");
}
@SkylarkSignature(name = "to_json",
@@ -846,9 +852,8 @@ public class SkylarkRuleClassFunctions {
}
private String jsonEscapeString(String string) {
- return escapeString(string.replace("\\", "\\\\")
- .replace("\r", "\\r")
- .replace("\t", "\\t"));
+ return escapeDoubleQuotesAndBackslashesAndNewlines(string)
+ .replace("\r", "\\r").replace("\t", "\\t");
}
};
diff --git a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
index 7d8a64af50..a0fb6e0636 100644
--- a/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
+++ b/src/test/java/com/google/devtools/build/lib/skylark/SkylarkRuleClassFunctionsTest.java
@@ -599,6 +599,9 @@ public class SkylarkRuleClassFunctionsTest extends SkylarkTestCase {
checkTextMessage("struct(name='a\"b').to_proto()", "name: \"a\\\"b\"");
checkTextMessage("struct(name='a\\'b').to_proto()", "name: \"a'b\"");
checkTextMessage("struct(name='a\\nb').to_proto()", "name: \"a\\nb\"");
+
+ // struct(name="a\\\"b") -> name: "a\\\"b"
+ checkTextMessage("struct(name='a\\\\\\\"b').to_proto()", "name: \"a\\\\\\\"b\"");
}
@Test