package jetbrains.mps.build.util; /*Generated by MPS */ import org.jetbrains.annotations.Nullable; import org.jetbrains.mps.openapi.module.SModule; import jetbrains.mps.project.AbstractModule; import jetbrains.mps.util.FileUtil; import java.io.File; public class RelativePathHelper { private String myBasePath; public RelativePathHelper(String basePath) { myBasePath = normalizePath(basePath, true); } /** * Transition method to avoid uses of Context.defaultContext().getRelativePathHelper() when we know for sure module is not transient */ @Nullable public static RelativePathHelper forModule(SModule module) { if (module == null || ((AbstractModule) module).getDescriptorFile() == null || module.isPackaged()) { return null; } String basePath = ((AbstractModule) module).getDescriptorFile().getParent().getPath(); return new RelativePathHelper(basePath); } public boolean isRelative(String fullPath) { return normalizePath(fullPath, false).startsWith(myBasePath); } public String makeRelative(String fullPath) throws RelativePathHelper.PathException { if ((fullPath == null || fullPath.length() == 0)) { return ""; } String normalized = normalizePath(fullPath, false); if (normalized.startsWith(myBasePath)) { return normalized.substring(myBasePath.length()); // XXX should I check for myBasePath == fullPath + '/'? } // FIXME I'd like to have this class purely string/Path-based, without need to access FS or care about file existence. // However, present uses need refactoring before this may come true, left legacy code for a while. OTOH, getCanonicalPath is pure File operation // which doesn't check for existence and as such is tolerable here. It's FileUtil.getRelativePath that bugs me, as it checks for file existence try { return normalizePath(FileUtil.getRelativePath(new File(normalized).getCanonicalPath(), new File(myBasePath).getCanonicalPath(), File.separator), false); } catch (Exception ex) { throw new RelativePathHelper.PathException(ex, ex.getMessage()); } } public String makeAbsolute(String shortPath) throws RelativePathHelper.PathException { if ((shortPath == null || shortPath.length() == 0)) { return myBasePath; } shortPath = normalizePath(shortPath, false); if (shortPath.startsWith("./")) { shortPath = shortPath.substring(2); } else if (shortPath.charAt(0) == '/') { shortPath = shortPath.substring(1); } try { File res = new File(myBasePath, shortPath); return normalizePath(res.getCanonicalPath(), false); } catch (Exception ex) { throw new RelativePathHelper.PathException(ex, ex.getMessage()); } } public String getBasePath() { return myBasePath; } /** * Translates backslashes in the path, if any, to regular slashed, and appends a trailing one if requested. * Doesn't require file to exists, operates with strings only. * Accepts null path, treats it as empty path; never returns null */ public static String normalizePath(String path, boolean addSlash) { if (path == null) { path = ""; } path = path.replace('\\', '/'); if (addSlash && (path.length() == 0 || path.charAt(path.length() - 1) != '/')) { path = path + '/'; } return path; } public static class PathException extends Exception { public PathException(Throwable cause, String message) { super(message, cause); } } }