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