diff --git a/src/main/java/com/google/devtools/build/lib/util/ShellEscaper.java b/src/main/java/com/google/devtools/build/lib/util/ShellEscaper.java index d54bbdaf8e5c0f..121fbb8284006d 100644 --- a/src/main/java/com/google/devtools/build/lib/util/ShellEscaper.java +++ b/src/main/java/com/google/devtools/build/lib/util/ShellEscaper.java @@ -63,6 +63,8 @@ public final class ShellEscaper extends Escaper { .or(CharMatcher.inRange('a', 'z')) // that would also accept non-ASCII digits and .or(CharMatcher.inRange('A', 'Z')) // letters. .precomputed(); + private static final CharMatcher SAFECHAR_MATCHER_WITH_TILDE = + SAFECHAR_MATCHER.or(CharMatcher.is('~')).precomputed(); /** * Escapes a string by adding strong (single) quotes around it if necessary. @@ -98,9 +100,13 @@ public String escape(String unescaped) { // gets treated as a separate argument. return "''"; } else { - return SAFECHAR_MATCHER.matchesAllOf(s) - ? s - : "'" + STRONGQUOTE_ESCAPER.escape(s) + "'"; + if (SAFECHAR_MATCHER.matchesAllOf(s)) { + return s; + } + if (SAFECHAR_MATCHER_WITH_TILDE.matchesAllOf(s) && s.charAt(0) != '~') { + return s; + } + return "'" + STRONGQUOTE_ESCAPER.escape(s) + "'"; } } diff --git a/src/test/java/com/google/devtools/build/lib/util/ShellEscaperTest.java b/src/test/java/com/google/devtools/build/lib/util/ShellEscaperTest.java index cad9ce53f24add..05c5cc676e707a 100644 --- a/src/test/java/com/google/devtools/build/lib/util/ShellEscaperTest.java +++ b/src/test/java/com/google/devtools/build/lib/util/ShellEscaperTest.java @@ -41,6 +41,9 @@ public void shellEscape() throws Exception { assertThat(escapeString("\\'foo\\'")).isEqualTo("'\\'\\''foo\\'\\'''"); assertThat(escapeString("${filename%.c}.o")).isEqualTo("'${filename%.c}.o'"); assertThat(escapeString("")).isEqualTo("''"); + assertThat(escapeString("~not_home")).isEqualTo("'~not_home'"); + assertThat(escapeString("external/protobuf~3.19.6/src/google")).isEqualTo("external/protobuf~3.19.6/src/google"); + assertThat(escapeString("external/~install_dev_dependencies~foo/pkg")).isEqualTo("external/~install_dev_dependencies~foo/pkg"); } @Test