1 package org.unicode.cldr.util; 2 3 import java.io.File; 4 import java.nio.file.Path; 5 import java.nio.file.Paths; 6 7 /** 8 * Recommended utility methods for normalizing paths used throughout the CLDR 9 * libraries. 10 * 11 * <p>The methods in this class are used to normalize file and directory paths 12 * such that resulting paths are: 13 * <ul> 14 * <li>Absolute with respect to the current working directory (if relative). 15 * <li>Normalized with respect to "upward" parent path segments. 16 * </ul> 17 * 18 * <p>For example if the current directory is {@code "/home/user/work/cldr"}: 19 * <pre>{@code 20 * // Append to current directory. 21 * getNormalizedPathString("foo/bar") == "/home/user/work/cldr/foo/bar" 22 * // Resolve parent path segments. 23 * getNormalizedPathString("../bar") == "/home/user/work/bar" 24 * // Retain (but normalize) absolute paths. 25 * getNormalizedPathString("/tmp/foo/../bar") == "/tmp/bar" 26 * }</pre> 27 * 28 * <p>Note that it is very important to realize that this is NOT the same as 29 * obtaining the "canonical" path (e.g. via {@link File#getCanonicalPath()} 30 * since the methods in this class <em>do not follow symbolic links</em>. 31 * 32 * <p>This is important because in some build systems (e.g. Bazel), file 33 * hierarchies are created by mapping files using symbolic links, and there's 34 * no necessary reason that the canonical file path preserves the same relative 35 * relationship between files. 36 * 37 * <p>For example Bazel uses a content addressed file cache, so every file used 38 * at build time has a canonical path of something like: 39 * <pre>{@code 40 * /tmp/build/cache/<hex-formatted-content-fingerprint> 41 * }</pre> 42 * 43 * <p>These files are them mapped (via symbolic links) to a hierarchy such as: 44 * <pre>{@code 45 * /<buid-root>/common/supplemental/plurals.xml 46 * /<buid-root>/common/supplemental/pluralRanges.xml 47 * ... 48 * /<buid-root>/common/dtd/ldmlSupplemental.dtd 49 * }</pre> 50 * 51 * <p>When the XML files are parsed by the CLDR library, the DTD file is found 52 * via the relative path {@code "../../common/dtd/ldmlSupplemental.dtd}. 53 * 54 * <p>If the canonical path for these XML files were given to the XML parser, it 55 * would attempt to resolve the DTD file location as: 56 * <pre>{@code 57 * /tmp/build/cache/<hex-formatted-content-fingerprint>/../../common/dtd/ldmlSupplemental.dtd 58 * }</pre> 59 * which is just: 60 * <pre>{@code 61 * /tmp/build/common/dtd/ldmlSupplemental.dtd 62 * }</pre> 63 * which will obviously not work. 64 * 65 * <p>Over time the CLDR libraries should transition to using {@link Path} 66 * instances (in favour of {@link File} or strings) when handling file paths and 67 * hopefully some of these methods can eventually be deprecated and removed. 68 */ 69 public final class PathUtilities { 70 /** Returns the normalized, absolute path string for the given path. */ getNormalizedPathString(String first, String... rest)71 public static String getNormalizedPathString(String first, String... rest) { 72 return getNormalizedPath(first, rest).toString(); 73 } 74 75 /** Returns the normalized, absolute path string of the given file. */ getNormalizedPathString(File file)76 public static String getNormalizedPathString(File file) { 77 return getNormalizedPath(file).toString(); 78 } 79 80 /** Returns the normalized, absolute path string of the given path. */ getNormalizedPathString(Path path)81 public static String getNormalizedPathString(Path path) { 82 return getNormalizedPath(path).toString(); 83 } 84 85 /** Returns the normalized, absolute path of the given path segments. */ getNormalizedPath(String first, String... rest)86 public static Path getNormalizedPath(String first, String... rest) { 87 return getNormalizedPath(Paths.get(first, rest)); 88 } 89 90 /** Returns the normalized, absolute path of the given file. */ getNormalizedPath(File file)91 public static Path getNormalizedPath(File file) { 92 return getNormalizedPath(Paths.get(file.getPath())); 93 } 94 95 /** Returns the normalized, absolute path of the given path. */ getNormalizedPath(Path path)96 public static Path getNormalizedPath(Path path) { 97 return path.toAbsolutePath().normalize(); 98 } 99 PathUtilities()100 private PathUtilities() {} 101 } 102