You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ant.apache.org by co...@apache.org on 2001/07/24 16:59:04 UTC
cvs commit: jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/depend Depend.java
conor 01/07/24 07:59:04
Modified: src/main/org/apache/tools/ant/taskdefs/optional/depend
Depend.java
Log:
Upgrade <depend> to check dependencies on jars in the classpath. You
need to provide a classpath to <depend> to trigger this behaviour.
Doesn't currently handle classes in the classpath.
PR: 2663
Revision Changes Path
1.7 +194 -32 jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java
Index: Depend.java
===================================================================
RCS file: /home/cvs/jakarta-ant/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Depend.java 2001/02/13 12:31:59 1.6
+++ Depend.java 2001/07/24 14:59:04 1.7
@@ -60,6 +60,7 @@
import java.util.*;
import java.io.*;
+import java.net.URL;
import org.apache.tools.ant.taskdefs.optional.depend.*;
@@ -69,9 +70,18 @@
* @author Conor MacNeill
*/
public class Depend extends MatchingTask {
+ /**
+ * A class (struct) user to manage information about a class
+ */
static private class ClassFileInfo {
+ /** The file where the class file is stored in the file system */
public File absoluteFile;
+
+ /** The location of the file relative to its base directory - the root
+ of the package namespace */
public String relativeName;
+
+ /** The Java class name of this class */
public String className;
};
@@ -99,11 +109,16 @@
* A map which gives information about a class
*/
private Hashtable classFileInfoMap;
+
+ /**
+ * A map which gives the list of jars a class depends upon
+ */
+ private Hashtable classJarDependencies;
/**
* The list of classes which are out of date.
*/
- private Vector outOfDateClasses;
+ private Hashtable outOfDateClasses;
/**
* indicates that the dependency relationships should be extended
@@ -111,7 +126,51 @@
* affects B abd B directly affects C, then A indirectly affects C.
*/
private boolean closure = false;
+
+ /**
+ * Flag which controls whether the reversed dependencies should be dumped
+ * to the log
+ */
+ private boolean dump = false;
+
+ private Path compileClasspath;
+
+ /**
+ * Set the classpath to be used for this compilation.
+ */
+ public void setClasspath(Path classpath) {
+ if (compileClasspath == null) {
+ compileClasspath = classpath;
+ } else {
+ compileClasspath.append(classpath);
+ }
+ }
+
+ /** Gets the classpath to be used for this compilation. */
+ public Path getClasspath() {
+ return compileClasspath;
+ }
+
+ /**
+ * Maybe creates a nested classpath element.
+ */
+ public Path createClasspath() {
+ if (compileClasspath == null) {
+ compileClasspath = new Path(project);
+ }
+ return compileClasspath.createPath();
+ }
+
+ /**
+ * Adds a reference to a CLASSPATH defined elsewhere.
+ */
+ public void setClasspathRef(Reference r) {
+ createClasspath().setRefid(r);
+ }
+
+
+
private void writeDependencyList(File depFile, Vector dependencyList) throws IOException {
// new dependencies so need to write them out to the cache
PrintWriter pw = null;
@@ -154,9 +213,16 @@
}
+ /**
+ * Determine the dependencies between classes.
+ *
+ * Class dependencies are determined by examining the class references in a class file
+ * to other classes
+ */
private void determineDependencies() throws IOException {
affectedClassMap = new Hashtable();
classFileInfoMap = new Hashtable();
+ Hashtable dependencyMap = new Hashtable();
for (Enumeration e = getClassFiles(destPath).elements(); e.hasMoreElements(); ) {
ClassFileInfo info = (ClassFileInfo)e.nextElement();
log("Adding class info for " + info.className, Project.MSG_DEBUG);
@@ -197,9 +263,9 @@
}
}
+ dependencyMap.put(info.className, dependencyList);
// This class depends on each class in the dependency list. For each
// one of those, add this class into their affected classes list
-
for (Enumeration depEnum = dependencyList.elements(); depEnum.hasMoreElements(); ) {
String dependentClass = (String)depEnum.nextElement();
@@ -212,17 +278,68 @@
affectedClasses.put(info.className, info);
}
}
+
+ classJarDependencies = null;
+ if (compileClasspath != null) {
+ // now determine which jars each class depends upon
+ classJarDependencies = new Hashtable();
+ AntClassLoader loader = new AntClassLoader(getProject(), compileClasspath);
+ Hashtable jarFileCache = new Hashtable();
+ Object nullJarFile = new Object();
+ for (Enumeration e = dependencyMap.keys(); e.hasMoreElements();) {
+ String className = (String)e.nextElement();
+ Vector dependencyList = (Vector)dependencyMap.get(className);
+ Hashtable jarDependencies = new Hashtable();
+ classJarDependencies.put(className, jarDependencies);
+ for (Enumeration e2 = dependencyList.elements(); e2.hasMoreElements();) {
+ String dependency =(String)e2.nextElement();
+ Object jarFileObject = jarFileCache.get(dependency);
+ if (jarFileObject == null) {
+ jarFileObject = nullJarFile;
+
+ if (!dependency.startsWith("java.") && !dependency.startsWith("javax.")) {
+ URL classURL = loader.getResource(dependency.replace('.', '/') + ".class");
+ if (classURL != null) {
+ String jarFilePath = classURL.getFile();
+ if (jarFilePath.startsWith("file:")) {
+ int classMarker = jarFilePath.indexOf('!');
+ jarFilePath = jarFilePath.substring(5, classMarker);
+ }
+ jarFileObject = new File(jarFilePath);
+ log("Class " + className +
+ " depends on " + jarFileObject +
+ " due to " + dependency, Project.MSG_DEBUG);
+ }
+ }
+ jarFileCache.put(dependency, jarFileObject);
+ }
+ if (jarFileObject != null && jarFileObject != nullJarFile) {
+ // we need to add this jar to the list for this class.
+ File jarFile = (File)jarFileObject;
+ jarDependencies.put(jarFile, jarFile);
+ }
+ }
+ }
+ }
}
-
- private void deleteAllAffectedFiles() {
+ private int deleteAllAffectedFiles() {
+ int count = 0;
for (Enumeration e = outOfDateClasses.elements(); e.hasMoreElements();) {
String className = (String)e.nextElement();
- deleteAffectedFiles(className);
- }
+ count += deleteAffectedFiles(className);
+ ClassFileInfo classInfo = (ClassFileInfo)classFileInfoMap.get(className);
+ if (classInfo != null && classInfo.absoluteFile.exists()) {
+ classInfo.absoluteFile.delete();
+ count++;
+ }
+ }
+ return count;
}
- private void deleteAffectedFiles(String className) {
+ private int deleteAffectedFiles(String className) {
+ int count = 0;
+
Hashtable affectedClasses = (Hashtable)affectedClassMap.get(className);
if (affectedClasses != null) {
for (Enumeration e = affectedClasses.keys(); e.hasMoreElements(); ) {
@@ -232,8 +349,9 @@
log("Deleting file " + affectedClassInfo.absoluteFile.getPath() + " since " +
className + " out of date", Project.MSG_VERBOSE);
affectedClassInfo.absoluteFile.delete();
+ count++;
if (closure) {
- deleteAffectedFiles(affectedClassName);
+ count += deleteAffectedFiles(affectedClassName);
}
else {
// without closure we may delete an inner class but not the
@@ -251,8 +369,9 @@
log("Deleting file " + topLevelClassInfo.absoluteFile.getPath() + " since " +
"one of its inner classes was removed", Project.MSG_VERBOSE);
topLevelClassInfo.absoluteFile.delete();
+ count++;
if (closure) {
- deleteAffectedFiles(topLevelClassName);
+ count += deleteAffectedFiles(topLevelClassName);
}
}
}
@@ -260,6 +379,7 @@
}
}
}
+ return count;
}
/**
@@ -274,7 +394,7 @@
if (srcPathList.length == 0) {
throw new BuildException("srcdir attribute must be set!", location);
}
-
+
if (destPath == null) {
destPath = srcPath;
}
@@ -282,45 +402,80 @@
if (cache != null && cache.exists() && !cache.isDirectory()) {
throw new BuildException("The cache, if specified, must point to a directory");
}
-
+
if (cache != null && !cache.exists()) {
cache.mkdirs();
}
-
+
determineDependencies();
-
-/*
- for (Enumeration e = affectedClassMap.keys(); e.hasMoreElements(); ) {
- String className = (String)e.nextElement();
- log("Class " + className + " affects:", Project.MSG_DEBUG);
- Hashtable affectedClasses = (Hashtable)affectedClassMap.get(className);
- for (Enumeration e2 = affectedClasses.keys(); e2.hasMoreElements(); ) {
- String affectedClass = (String)e2.nextElement();
- ClassFileInfo info = (ClassFileInfo)affectedClasses.get(affectedClass);
- log(" " + affectedClass + " in " + info.absoluteFile.getPath(), Project.MSG_DEBUG);
+
+ if (dump) {
+ log("Reverse Dependency Dump for " + affectedClassMap.size() +
+ " classes:", Project.MSG_DEBUG);
+ for (Enumeration e = affectedClassMap.keys(); e.hasMoreElements(); ) {
+ String className = (String)e.nextElement();
+ log(" Class " + className + " affects:", Project.MSG_DEBUG);
+ Hashtable affectedClasses = (Hashtable)affectedClassMap.get(className);
+ for (Enumeration e2 = affectedClasses.keys(); e2.hasMoreElements(); ) {
+ String affectedClass = (String)e2.nextElement();
+ ClassFileInfo info = (ClassFileInfo)affectedClasses.get(affectedClass);
+ log(" " + affectedClass + " in " + info.absoluteFile.getPath(), Project.MSG_DEBUG);
+ }
}
+
+ if (classJarDependencies != null) {
+ log("Jar dependencies (Forward):", Project.MSG_DEBUG);
+ for (Enumeration e = classJarDependencies.keys(); e.hasMoreElements();) {
+ String className = (String)e.nextElement();
+ log(" Class " + className + " depends on:", Project.MSG_DEBUG);
+ Hashtable jarDependencies = (Hashtable)classJarDependencies.get(className);
+ for (Enumeration e2 = jarDependencies.elements(); e2.hasMoreElements();) {
+ File jarFile = (File)e2.nextElement();
+ log(" " + jarFile.getPath(), Project.MSG_DEBUG);
+ }
+ }
+ }
+
}
-*/
+
// we now need to scan for out of date files. When we have the list
// we go through and delete all class files which are affected by these files.
- outOfDateClasses = new Vector();
- for (int i=0; i<srcPathList.length; i++) {
+ outOfDateClasses = new Hashtable();
+ for (int i=0; i < srcPathList.length; i++) {
File srcDir = (File)project.resolveFile(srcPathList[i]);
if (srcDir.exists()) {
-
DirectoryScanner ds = this.getDirectoryScanner(srcDir);
-
String[] files = ds.getIncludedFiles();
-
scanDir(srcDir, files);
}
}
+
+ // now check jar dependencies
+ if (classJarDependencies != null) {
+ for (Enumeration e = classJarDependencies.keys(); e.hasMoreElements();) {
+ String className = (String)e.nextElement();
+ if (!outOfDateClasses.containsKey(className)) {
+ ClassFileInfo info = (ClassFileInfo)classFileInfoMap.get(className);
+ Hashtable jarDependencies = (Hashtable)classJarDependencies.get(className);
+ for (Enumeration e2 = jarDependencies.elements(); e2.hasMoreElements();) {
+ File jarFile = (File)e2.nextElement();
+ if (jarFile.lastModified() > info.absoluteFile.lastModified()) {
+ log("Class " + className +
+ " is out of date with respect to " + jarFile, Project.MSG_DEBUG);
+ outOfDateClasses.put(className, className);
+ break;
+ }
+ }
+ }
+ }
+ }
// we now have a complete list of classes which are out of date
// We scan through the affected classes, deleting any affected classes.
- deleteAllAffectedFiles();
+ int count = deleteAllAffectedFiles();
- log("Duration = " + (System.currentTimeMillis() - start));
+ long duration = (System.currentTimeMillis() - start) / 1000;
+ log("Deleted " + count + " out of date files in " + duration + " seconds");
} catch (Exception e) {
throw new BuildException(e);
}
@@ -344,11 +499,11 @@
ClassFileInfo info = (ClassFileInfo)classFileInfoMap.get(className);
if (info == null) {
// there was no class file. add this class to the list
- outOfDateClasses.addElement(className);
+ outOfDateClasses.put(className, className);
}
else {
if (srcFile.lastModified() > info.absoluteFile.lastModified()) {
- outOfDateClasses.addElement(className);
+ outOfDateClasses.put(className, className);
}
}
}
@@ -431,6 +586,13 @@
public void setClosure(boolean closure) {
this.closure = closure;
+ }
+
+ /**
+ * Flag to indicate whether the reverse dependency list should be dumped to debug
+ */
+ public void setDump(boolean dump) {
+ this.dump = dump;
}
}