package org.jboss.loom.utils; import java.io.File; import java.util.regex.Pattern; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang.StringUtils; /** * * @author Ondrej Zizka, ozizka at redhat.com */ public class PathUtils { //private static final Logger log = LoggerFactory.getLogger( PathUtils.class ); /** * Turns ( foo/bar/baz , foo ) into bar/baz . * If file is not under superDir, null is returned. */ public static File cutOffSuperDir( String superDir, String fileStr ) { if( ! fileStr.startsWith( superDir ) ) return null; // Either both are absolute, or both relative. //if( file.isAbsolute() ) String subPath = StringUtils.removeStart( fileStr, superDir ); subPath = StringUtils.removeStart( subPath, "/" ); return new File( subPath ); } public static File cutOffSuperDir( String superDir, File file ) { String fileStr = file.toPath().normalize().toFile().toString(); return cutOffSuperDir( superDir, fileStr ); } public static File cutOffSuperDir( File superDir, String fileStr ) { String superDirStr = superDir.toPath().normalize().toFile().toString(); return cutOffSuperDir( superDirStr, fileStr ); } public static String relativize( File baseDir, File dir ) { return relativize( baseDir.getPath(), dir.getPath(), File.separator ); } /** * Get the relative path from one file to another, specifying the directory separator. * If one of the provided resources does not exist, it is assumed to be a file unless it ends with '/' or '\'. * * @param targetPath targetPath is calculated to this file * @param baseDir basePath is calculated from this file * @param pathSeparator directory separator. * The platform default is not assumed so that we can test Unix behavior when running on Windows (for example) */ public static String relativize( String basePath, String targetPath, String pathSeparator) { // Normalize the paths String normalizedTargetPath = FilenameUtils.normalizeNoEndSeparator(targetPath); String normalizedBasePath = FilenameUtils.normalizeNoEndSeparator(basePath); // Undo the changes to the separators made by normalization if (pathSeparator.equals("/")) { normalizedTargetPath = FilenameUtils.separatorsToUnix(normalizedTargetPath); normalizedBasePath = FilenameUtils.separatorsToUnix(normalizedBasePath); } else if (pathSeparator.equals("\\")) { normalizedTargetPath = FilenameUtils.separatorsToWindows(normalizedTargetPath); normalizedBasePath = FilenameUtils.separatorsToWindows(normalizedBasePath); } else { throw new IllegalArgumentException("Unrecognised dir separator '" + pathSeparator + "'"); } String[] base = normalizedBasePath.split(Pattern.quote(pathSeparator)); String[] target = normalizedTargetPath.split(Pattern.quote(pathSeparator)); // First get all the common elements. Store them as a string, // and also count how many of them there are. StringBuilder common = new StringBuilder(); int commonIndex = 0; while (commonIndex < target.length && commonIndex < base.length && target[commonIndex].equals(base[commonIndex])) { common.append( target[commonIndex] ).append(pathSeparator); commonIndex++; } if (commonIndex == 0) { // No single common path element. This most // likely indicates differing drive letters, like C: and D:. // These paths cannot be relativized. throw new PathResolutionException("No common path element found for '" + normalizedTargetPath + "' and '" + normalizedBasePath + "'"); } // The number of directories we have to backtrack depends on whether the base is a file or a dir // For example, the relative path from // // /foo/bar/baz/gg/ff to /foo/bar/baz // // ".." if ff is a file // "../.." if ff is a directory // // The following is a heuristic to figure out if the base refers to a file or dir. It's not perfect, because // the resource referred to by this path may not actually exist, but it's the best I can do boolean baseIsFile = true; File baseResource = new File(normalizedBasePath); if (baseResource.exists()) { baseIsFile = baseResource.isFile(); } else if (basePath.endsWith(pathSeparator)) { baseIsFile = false; } StringBuilder relative = new StringBuilder(); if (base.length != commonIndex) { int numDirsUp = baseIsFile ? base.length - commonIndex - 1 : base.length - commonIndex; for (int i = 0; i < numDirsUp; i++) { relative.append( ".." ).append(pathSeparator); } } relative.append(normalizedTargetPath.substring(common.length())); return relative.toString(); } static class PathResolutionException extends RuntimeException { PathResolutionException(String msg) { super(msg); } } }// class