mirror of
https://github.com/apple/pkl.git
synced 2026-04-20 15:31:28 +02:00
Encode filepaths to be safe on Windows
This changes the file paths to use characters that are safe for Windows. Channges the output of the following: * Package cache directory * Generated pkl-doc files * Kotlin generated code Unsafe characters are encoded as (<hex>). For example, the colon character `:` is encoded as `(3a)`. Additionally, this changes the cache directory prefix (package-1 to package-2). Follows the design of https://github.com/apple/pkl-evolution/pull/3
This commit is contained in:
@@ -413,7 +413,7 @@ final class PackageResolvers {
|
||||
|
||||
private final Path tmpDir;
|
||||
|
||||
private static final String CACHE_DIR_PREFIX = "package-1";
|
||||
private static final String CACHE_DIR_PREFIX = "package-2";
|
||||
|
||||
@GuardedBy("lock")
|
||||
private final EconomicMap<PackageUri, FileSystem> fileSystems = EconomicMaps.create();
|
||||
@@ -438,12 +438,14 @@ final class PackageResolvers {
|
||||
return path;
|
||||
}
|
||||
var checksumIdx = path.lastIndexOf("::");
|
||||
return path.substring(0, checksumIdx);
|
||||
return IoUtils.encodePath(path.substring(0, checksumIdx));
|
||||
}
|
||||
|
||||
private Path getRelativePath(PackageUri uri) {
|
||||
return Path.of(
|
||||
CACHE_DIR_PREFIX, uri.getUri().getAuthority(), getEffectivePackageUriPath(uri));
|
||||
CACHE_DIR_PREFIX,
|
||||
IoUtils.encodePath(uri.getUri().getAuthority()),
|
||||
getEffectivePackageUriPath(uri));
|
||||
}
|
||||
|
||||
private String getLastSegmentName(PackageUri packageUri) {
|
||||
|
||||
@@ -597,6 +597,30 @@ public final class IoUtils {
|
||||
return newUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Windows reserves characters {@code <>:"\|?*} in filenames.
|
||||
*
|
||||
* <p>For any such characters, enclose their decimal character code with parentheses. Verbatim
|
||||
* {@code (} is encoded as {@code ((}.
|
||||
*/
|
||||
public static String encodePath(String path) {
|
||||
if (path.isEmpty()) return path;
|
||||
var sb = new StringBuilder();
|
||||
for (var i = 0; i < path.length(); i++) {
|
||||
var character = path.charAt(i);
|
||||
switch (character) {
|
||||
case '<', '>', ':', '"', '\\', '|', '?', '*' -> {
|
||||
sb.append('(');
|
||||
sb.append(ByteArrayUtils.toHex(new byte[] {(byte) character}));
|
||||
sb.append(")");
|
||||
}
|
||||
case '(' -> sb.append("((");
|
||||
default -> sb.append(path.charAt(i));
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private static int getExclamationMarkIndex(String jarUri) {
|
||||
var index = jarUri.indexOf('!');
|
||||
if (index == -1) {
|
||||
|
||||
@@ -431,4 +431,14 @@ class IoUtilsTest {
|
||||
IoUtils.readString(URI("http://example.com").toURL())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `encodePath encodes characters reserved on windows`() {
|
||||
assertThat(IoUtils.encodePath("foo:bar")).isEqualTo("foo(3a)bar")
|
||||
assertThat(IoUtils.encodePath("<>:\"\\|?*")).isEqualTo("(3c)(3e)(3a)(22)(5c)(7c)(3f)(2a)")
|
||||
assertThat(IoUtils.encodePath("foo(3a)bar")).isEqualTo("foo((3a)bar")
|
||||
assertThat(IoUtils.encodePath("(")).isEqualTo("((")
|
||||
assertThat(IoUtils.encodePath("3a)")).isEqualTo("3a)")
|
||||
assertThat(IoUtils.encodePath("foo/bar/baz")).isEqualTo("foo/bar/baz")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user