package org.checkerframework.eclipse.util;
import java.io.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jdt.core.IClasspathEntry;
public class Paths {
private Paths() {
throw new AssertionError("Cannot be instantiated");
}
public static String absolutePathOf(IClasspathEntry entry) {
IFile jarFile = ResourceUtils.workspaceRoot().getFile(entry.getPath());
IPath location = jarFile.getLocation();
IPath path = (location != null) ? location : jarFile.getFullPath();
String osString = path.toOSString();
if (PluginUtil.isWindows() && !hasDriveLetter(osString)) {
osString = kludgeFixAddDriveLetterToFilePath(osString);
}
return osString;
}
private static boolean equalsIgnoreCase(char c1, char c2) {
return String.valueOf(c1).toLowerCase().equals(String.valueOf(c2).toLowerCase());
}
private static char driveLetter(final File file) {
return file.getAbsolutePath().charAt(0);
}
/**
* Ordered by preference. Use listRoots to get drive letters for windows and put C (if
* available) up front and (A:) in the back.
*/
private static List<File> determineOrderedDriveRoots() {
final File[] files = File.listRoots();
final List<File> driveRoots = new ArrayList<File>();
final Pattern pattern = Pattern.compile("^([A-Z]):\\\\$");
for (final File file : files) {
final Matcher match = pattern.matcher(file.getAbsolutePath());
if (match.matches()) {
driveRoots.add(file);
}
}
// C up front, a in the back, everything else is equal
Collections.sort(
driveRoots,
new Comparator<File>() {
@Override
public int compare(File o1, File o2) {
if (equalsIgnoreCase(driveLetter(o1), driveLetter(o2))) {
return 0;
}
if (equalsIgnoreCase(driveLetter(o1), 'c')
|| equalsIgnoreCase(driveLetter(o2), 'a')) {
return -1;
}
if (equalsIgnoreCase(driveLetter(o1), 'a')
|| equalsIgnoreCase(driveLetter(o2), 'c')) {
return 1;
}
return 0;
}
});
return driveRoots;
}
private static List<File> orderedDriveRoots =
Collections.unmodifiableList(determineOrderedDriveRoots());
private static boolean hasDriveLetter(String filePath) {
for (File file : orderedDriveRoots) {
if (filePath.startsWith(file.getAbsolutePath())) {
return true;
}
}
return false;
}
private static String toDriveLetter(final char c) {
return c + File.pathSeparator + File.separator;
}
private static String toDrivePath(final char c, String filePath) {
filePath = (filePath.startsWith(File.separator)) ? filePath.substring(1) : filePath;
return toDriveLetter(c) + filePath;
}
/**
* I am having a heck of a time trying to get the drive letter to appear on the filepath for
* jars added via Eclipse classpath entries. For now, use the potentially error prone technique
* of listing all drive letters and testing to see if the path exists on that drive, prefer C:.
* This is error prone because a path can exist on multiple drives. In the case of mirroring it
* could potentially use an archived version rather than the latest version of the jar. This is
* not a huge risk but still a kludge.
*
* @param pathStr A file path that does not start with a drive letter
* @return pathStr
*/
public static String kludgeFixAddDriveLetterToFilePath(final String pathStr) {
for (final File root : orderedDriveRoots) {
final File cPath =
new File(root, (pathStr.startsWith("\\") ? pathStr.substring(1) : pathStr));
if (cPath.exists()) {
return cPath.getAbsolutePath();
}
}
return pathStr;
}
}