Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(350)

Unified Diff: third_party/jmake/src/org/pantsbuild/jmake/ClassPath.java

Issue 1373723003: Fix javac --incremental by using jmake for dependency analysis (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@aidl
Patch Set: fix license check Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/jmake/src/org/pantsbuild/jmake/ClassPath.java
diff --git a/third_party/jmake/src/org/pantsbuild/jmake/ClassPath.java b/third_party/jmake/src/org/pantsbuild/jmake/ClassPath.java
new file mode 100644
index 0000000000000000000000000000000000000000..e6e1aebd86a31054fc802960991986414288ef01
--- /dev/null
+++ b/third_party/jmake/src/org/pantsbuild/jmake/ClassPath.java
@@ -0,0 +1,448 @@
+/* Copyright (c) 2002-2008 Sun Microsystems, Inc. All rights reserved
+ *
+ * This program is distributed under the terms of
+ * the GNU General Public License Version 2. See the LICENSE file
+ * at the top of the source tree.
+ */
+package org.pantsbuild.jmake;
+
+import java.io.File;
+import java.io.FilenameFilter;
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+/**
+ * An instance of this class represents a class path, on which binary classes can be looked up.
+ * It also provides several static methods to create and utilize several specific class paths used
+ * throughout jmake.
+ *
+ * @author Misha Dmitriev
+ * 12 October 2004
+ */
+public class ClassPath {
+
+ private PathEntry[] paths;
+ private static ClassPath projectClassPath; // Class path (currently it can contain only JARs) containing sourceless project classes.
+ // See also the comment to standardClassPath.
+ private static ClassPath standardClassPath; // Class path that the user specifies via the -classpath option. A sum of the
+ // standardClassPath, the projectClassPath, and the virtualPath is passed to the compiler. Each of these
+ // class paths are also used to look up non-project superclasses/superinterfaces of
+ // project classes.
+ private static ClassPath bootClassPath, extClassPath; // Class paths that by default are sun.boot.class.path and all JARs on
+ // java.ext.class.path, respectively. They are used to look up non-project
+ // superclasses/superinterfaces of project classes. Their values can be changed using
+ // setBootClassPath() and setExtDirs().
+ private static ClassPath virtualPath; // Class path that the user specifies via the -vpath option.
+ private static String compilerUserClassPath; // Class path to be passed to the compiler; equals to the sum of values of parameters of
+ // setClassPath() and setProjectClassPath() methods.
+ private static String standardClassPathStr, projectClassPathStr, bootClassPathStr, extDirsStr,
+ virtualPathStr;
+ private static Map<String,ClassInfo> classCache;
+
+
+ static {
+ resetOnFinish();
+ }
+
+ /**
+ * Needed since some environments, e.g. NetBeans, can keep jmake classes in memory
+ * permanently. Thus unchanged class paths from previous, possibly unrelated invocations
+ * of jmake, may interfere with the current settings.
+ */
+ public static void resetOnFinish() {
+ projectClassPath = standardClassPath = bootClassPath = extClassPath = virtualPath =
+ null;
+ compilerUserClassPath = null;
+ standardClassPathStr = projectClassPathStr = bootClassPathStr =
+ extDirsStr = virtualPathStr = null;
+ classCache = new LinkedHashMap<String,ClassInfo>();
+ }
+
+ public static void setClassPath(String value) throws PublicExceptions.InvalidCmdOptionException {
+ standardClassPathStr = value;
+ standardClassPath = new ClassPath(value, false);
+ }
+
+ public static void setProjectClassPath(String value) throws PublicExceptions.InvalidCmdOptionException {
+ projectClassPathStr = value;
+ projectClassPath = new ClassPath(value, true);
+ }
+
+ public static void setBootClassPath(String value) throws PublicExceptions.InvalidCmdOptionException {
+ bootClassPathStr = value;
+ bootClassPath = new ClassPath(value, false);
+ }
+
+ public static void setExtDirs(String value) throws PublicExceptions.InvalidCmdOptionException {
+ extDirsStr = value;
+ // Extension class path needs special handling, since it consists of directories, which contain .jars
+ // So we need to find all these .jars in all these dirs and add them to extClassPathElementList
+ List<String> extClassPathElements = new ArrayList<String>();
+ for (StringTokenizer tok =
+ new StringTokenizer(value, File.pathSeparator); tok.hasMoreTokens();) {
+ File extDir = new File(tok.nextToken());
+ String[] extJars = extDir.list(new FilenameFilter() {
+
+ public boolean accept(File dir, String name) {
+ name = name.toLowerCase(Locale.ENGLISH);
+ return name.endsWith(".zip") || name.endsWith(".jar");
+ }
+ });
+ if (extJars == null) {
+ continue;
+ }
+ for (int i = 0; i < extJars.length; i++) {
+ extClassPathElements.add(extDir + File.separator + extJars[i]);
+ }
+ }
+ extClassPath = new ClassPath(extClassPathElements, false);
+ }
+
+ public static void setVirtualPath(String value) throws PublicExceptions.InvalidCmdOptionException {
+ if (value == null) {
+ throw new PublicExceptions.InvalidCmdOptionException("null argument");
+ }
+ StringTokenizer st = new StringTokenizer(value, File.pathSeparator);
+ while (st.hasMoreElements()) {
+ String dir = st.nextToken();
+ if ( ! (new File(dir)).isDirectory()) {
+ throw new PublicExceptions.InvalidCmdOptionException("Virtual path must contain only directories." +
+ " Entry " + dir + " is not a directory.");
+ }
+ }
+ virtualPathStr = value;
+ virtualPath = new ClassPath(value, false);
+ }
+
+ public static void initializeAllClassPaths() {
+ // First set the compiler class path value
+ if (standardClassPathStr == null && projectClassPathStr == null) {
+ compilerUserClassPath = ".";
+ } else if (standardClassPathStr == null) {
+ compilerUserClassPath = projectClassPathStr;
+ } else if (projectClassPathStr == null) {
+ compilerUserClassPath = standardClassPathStr;
+ } else {
+ compilerUserClassPath =
+ standardClassPathStr + File.pathSeparator + projectClassPathStr;
+ }
+
+ if (virtualPathStr != null) {
+ compilerUserClassPath += File.pathSeparator + virtualPathStr;
+ }
+
+ if (standardClassPathStr == null) {
+ try {
+ String tmp = ".";
+ if (virtualPathStr != null) {
+ tmp += File.pathSeparator + virtualPathStr;
+ }
+ standardClassPath = new ClassPath(tmp, false);
+ } catch (PublicExceptions.InvalidCmdOptionException ex) { /* Should not happen */ }
+ }
+ if (projectClassPathStr == null) {
+ projectClassPath = new ClassPath();
+ }
+
+ // Create the core class path as a combination of sun.boot.class.path and java.ext.dirs contents
+ if (bootClassPathStr == null) {
+ try {
+ bootClassPath =
+ new ClassPath(System.getProperty("sun.boot.class.path"), false);
+ } catch (PublicExceptions.InvalidCmdOptionException ex) { /* Shouldn't happen */ }
+ // bootClassPathStr should remain null, so that nothing that the user didn't specify is passed to the compiler
+ }
+
+ if (extDirsStr == null) {
+ try {
+ setExtDirs(System.getProperty("java.ext.dirs"));
+ } catch (PublicExceptions.InvalidCmdOptionException ex) { /* Shouldn't happen */ }
+ // extDirsStr should remain null, so that nothing that the user didn't specify is passed to the compiler
+ extDirsStr = null;
+ }
+ }
+
+ /** Never returns null - if classpath wasn't set explicitly, returns "." */
+ public static String getCompilerUserClassPath() {
+ return compilerUserClassPath;
+ }
+
+ /** Will return null if boot class path wasn't explicitly specified */
+ public static String getCompilerBootClassPath() {
+ return bootClassPathStr;
+ }
+
+ /** Will return null if extdirs weren't explicitly specified */
+ public static String getCompilerExtDirs() {
+ return extDirsStr;
+ }
+
+ /** Will return null if virtualPath wasn't explicitly specified */
+ public static String getVirtualPath() {
+ return virtualPathStr;
+ }
+
+ /**
+ * For the given class return the list of all of its superclasses (excluding Object), that can be loaded from
+ * projectClassPath or standardClassPath, plus the first superclass that can be loaded from coreClassPath.
+ * The latter is an optimization based on the assumption that core classes never change, or rather the programmer
+ * will recompile everything when they switch to a new JDK version. The optimization prevents us from wasting time
+ * repeatedly loading the same sets of core classes.
+ */
+ public static void getSuperclasses(String className,
+ Collection<String> res, PCDManager pcdm) {
+ int iterNo = 0;
+ while (!"java/lang/Object".equals(className)) {
+ ClassInfo ci = getClassInfoForName(className, pcdm);
+ if (ci == null) {
+ return;
+ }
+ if (iterNo++ > 0) {
+ res.add(ci.name);
+ }
+ className = ci.superName;
+ }
+ }
+
+ /**
+ * Add to the given set the names of all interfaces implemented by the given class, that can be loaded from
+ * projectClassPath or standardClassPath, plus the first interface on each branch that can be loaded from
+ * coreClassPath. It's the same optimization as in getSuperclasses().
+ */
+ public static void addAllImplementedInterfaceNames(String className,
+ Set<String> intfSet, PCDManager pcdm) {
+ if ("java/lang/Object".equals(className)) {
+ return;
+ }
+ ClassInfo ci = getClassInfoForName(className, pcdm);
+ if (ci == null) {
+ return;
+ }
+ String[] interfaces = ci.interfaces;
+ if (interfaces != null) {
+ for (int i = 0; i < interfaces.length; i++) {
+ intfSet.add(interfaces[i]);
+ addAllImplementedInterfaceNames(interfaces[i], intfSet, pcdm);
+ }
+ }
+
+ String superName = ci.superName;
+ if (superName != null) {
+ addAllImplementedInterfaceNames(superName, intfSet, pcdm);
+ }
+ }
+
+ public static String[] getProjectJars() {
+ if (projectClassPath == null || projectClassPath.isEmpty()) {
+ return null;
+ }
+ PathEntry paths[] = projectClassPath.paths;
+ String[] ret = new String[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ ret[i] = paths[i].toString();
+ }
+ return ret;
+ }
+
+ public static ClassInfo getClassInfoForName(String className, PCDManager pcdm) {
+ ClassInfo info = classCache.get(className);
+ if (info != null) {
+ return info;
+ }
+
+ byte buf[] = bootClassPath.getBytesForClass(className);
+ if (buf == null) {
+ buf = extClassPath.getBytesForClass(className);
+ }
+ if (buf == null) {
+ buf = standardClassPath.getBytesForClass(className);
+ }
+ if (buf == null) {
+ buf = projectClassPath.getBytesForClass(className);
+ }
+ if (buf == null) {
+ return null;
+ }
+
+ info = new ClassInfo(buf, pcdm, className);
+ classCache.put(className, info);
+ return info;
+ }
+
+ /** Returns the class loader that would load classes from the given class path. */
+ public static ClassLoader getClassLoaderForPath(String classPath) throws Exception {
+ boolean isWindows = System.getProperty("os.name").startsWith("Win");
+ ClassPath cp = new ClassPath(classPath, false);
+ PathEntry[] paths = cp.paths;
+ URL[] urls = new URL[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ String dirOrJar = paths[i].toString();
+ if (!(dirOrJar.startsWith("file://") || dirOrJar.startsWith("http://"))) {
+ // On Windows, if I have path specified as "file://c:\...", (i.e. with the drive name) URLClassLoader works
+ // unbelievably slow. However, if an additional slash is added, like : "file:///c:\...", the speed becomes
+ // normal. To me it looks like a bug, but, anyway, I am taking measure here.
+ if (isWindows && dirOrJar.charAt(1) == ':') {
+ dirOrJar = "/" + dirOrJar;
+ }
+ dirOrJar = new File(dirOrJar).toURI().toString();
+ }
+ if (!(dirOrJar.endsWith(".jar") || dirOrJar.endsWith(".zip") || dirOrJar.endsWith(File.separator))) {
+ dirOrJar += File.separator; // So that URLClassLoader correctly handles it as a directory
+ }
+ urls[i] = new URL(dirOrJar);
+ }
+
+ return new URLClassLoader(urls);
+ //} catch (java.net.MalformedURLException e) {
+
+ //}
+ }
+
+
+ // ------------------------------------ Private implementation --------------------------------------------
+ private ClassPath() {
+ paths = new PathEntry[0];
+ }
+
+ private ClassPath(String classPath, boolean isJarOnly) throws PublicExceptions.InvalidCmdOptionException {
+ if (classPath == null) {
+ throw new PublicExceptions.InvalidCmdOptionException("null argument");
+ }
+ List<String> vec = new ArrayList<String>();
+
+ for (StringTokenizer tok =
+ new StringTokenizer(classPath, File.pathSeparator); tok.hasMoreTokens();) {
+ String path = tok.nextToken();
+ vec.add(path);
+ }
+ init(vec, isJarOnly);
+ }
+
+ private ClassPath(List<String> pathEntries, boolean isJarOnly) throws PublicExceptions.InvalidCmdOptionException {
+ init(pathEntries, isJarOnly);
+ }
+
+ private void init(List<String> pathEntries, boolean isJarOnly) throws PublicExceptions.InvalidCmdOptionException {
+ if (pathEntries == null) {
+ throw new PublicExceptions.InvalidCmdOptionException("null argument");
+ }
+ List<PathEntry> vec = new ArrayList<PathEntry>(pathEntries.size());
+ for (int i = 0; i < pathEntries.size(); i++) {
+ String path = pathEntries.get(i);
+ if (!path.equals("")) {
+ File file = new File(path);
+ try {
+ if (file.exists() && file.canRead()) {
+ if (file.isDirectory()) {
+ if (isJarOnly) {
+ throw new PublicExceptions.InvalidCmdOptionException("directories are not allowed on this class path: " + path);
+ }
+ vec.add(new Dir(file));
+ } else {
+ vec.add(new Zip(new ZipFile(file)));
+ }
+ } else if (isJarOnly) {
+ throw new IOException("file does not exist");
+ }
+ } catch (IOException e) {
+ if (isJarOnly) {
+ throw new PublicExceptions.InvalidCmdOptionException("error initializing class path component " + path + ": " + e.getMessage());
+ }
+ }
+ }
+ }
+
+ paths = new PathEntry[vec.size()];
+ vec.toArray(paths);
+ }
+
+ private boolean isEmpty() {
+ return paths.length == 0;
+ }
+
+ private byte[] getBytesForClass(String className) {
+ String fileName = className + ".class";
+ for (int i = 0; i < paths.length; i++) {
+ byte buf[] = paths[i].getBytesForClassFile(fileName);
+ if (buf != null) {
+ return buf;
+ }
+ }
+ return null;
+ }
+
+ public String toString() {
+ if (paths == null) {
+ return "NULL";
+ }
+ StringBuilder res = new StringBuilder();
+ for (int i = 0; i < paths.length; i++) {
+ res.append(paths[i].toString());
+ }
+ return res.toString();
+ }
+
+
+ // ------------------------------------ Private helper classes --------------------------------------------
+ private static abstract class PathEntry {
+
+ abstract byte[] getBytesForClassFile(String fileName);
+
+ public abstract String toString();
+ }
+
+ private static class Dir extends PathEntry {
+
+ private String dir;
+
+ Dir(File f) throws IOException {
+ dir = f.getCanonicalPath();
+ }
+
+ byte[] getBytesForClassFile(String fileName) {
+ File file = new File(dir + File.separatorChar + fileName);
+ if (file.exists()) {
+ return Utils.readFileIntoBuffer(file);
+ } else {
+ return null;
+ }
+ }
+
+ public String toString() {
+ return dir;
+ }
+ }
+
+ private static class Zip extends PathEntry {
+
+ private ZipFile zip;
+
+ Zip(ZipFile z) {
+ zip = z;
+ }
+
+ byte[] getBytesForClassFile(String fileName) {
+ ZipEntry entry = zip.getEntry(fileName);
+ if (entry != null) {
+ return Utils.readZipEntryIntoBuffer(zip, entry);
+ } else {
+ return null;
+ }
+ }
+
+ public String toString() {
+ return zip.getName();
+ }
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698