diff options
Diffstat (limited to 'framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java')
-rw-r--r-- | framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java | 917 |
1 files changed, 917 insertions, 0 deletions
diff --git a/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java new file mode 100644 index 00000000..cc65129f --- /dev/null +++ b/framework/src/ant/apache-ant-1.9.6/src/main/org/apache/tools/ant/taskdefs/optional/depend/Depend.java @@ -0,0 +1,917 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.apache.tools.ant.taskdefs.optional.depend; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.net.URL; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Vector; + +import org.apache.tools.ant.AntClassLoader; +import org.apache.tools.ant.BuildException; +import org.apache.tools.ant.DirectoryScanner; +import org.apache.tools.ant.Project; +import org.apache.tools.ant.taskdefs.MatchingTask; +import org.apache.tools.ant.taskdefs.rmic.DefaultRmicAdapter; +import org.apache.tools.ant.taskdefs.rmic.WLRmic; +import org.apache.tools.ant.types.Path; +import org.apache.tools.ant.types.Reference; +import org.apache.tools.ant.util.FileUtils; +import org.apache.tools.ant.util.depend.DependencyAnalyzer; + +/** + * Generates a dependency file for a given set of classes. + * + */ +public class Depend extends MatchingTask { + private static final int ONE_SECOND = 1000; + + /** + * A class (struct) user to manage information about a class + * + */ + private static class ClassFileInfo { + /** The file where the class file is stored in the file system */ + private File absoluteFile; + + /** The Java class name of this class */ + private String className; + + /** The source File containing this class */ + private File sourceFile; + + /** if user has been warned about this file not having a source file */ + private boolean isUserWarned = false; + } + + /** The path where source files exist */ + private Path srcPath; + + /** The path where compiled class files exist. */ + private Path destPath; + + /** The directory which contains the dependency cache. */ + private File cache; + + /** The list of source paths derived from the srcPath field. */ + private String[] srcPathList; + + /** + * A map which gives for every class a list of the class which it + * affects. + */ + private Hashtable affectedClassMap; + + /** A map which gives information about a class */ + private Hashtable classFileInfoMap; + + /** + * A map which gives the list of jars and classes from the classpath + * that a class depends upon + */ + private Hashtable classpathDependencies; + + /** The list of classes which are out of date. */ + private Hashtable outOfDateClasses; + + /** + * indicates that the dependency relationships should be extended beyond + * direct dependencies to include all classes. So if A directly affects + * B and B directly affects C, then A indirectly affects C. + */ + private boolean closure = false; + + /** + * flag to enable warning if we encounter RMI stubs + */ + private boolean warnOnRmiStubs = true; + + /** + * Flag which controls whether the reversed dependencies should be + * dumped to the log + */ + private boolean dump = false; + + /** The classpath to look for additional dependencies */ + private Path dependClasspath; + + /** constants used with the cache file */ + private static final String CACHE_FILE_NAME = "dependencies.txt"; + /** String Used to separate classnames in the dependency file */ + private static final String CLASSNAME_PREPEND = "||:"; + + /** + * Set the classpath to be used for this dependency check. + * + * @param classpath the classpath to be used when checking for + * dependencies on elements in the classpath + */ + public void setClasspath(Path classpath) { + if (dependClasspath == null) { + dependClasspath = classpath; + } else { + dependClasspath.append(classpath); + } + } + + /** + * Gets the classpath to be used for this dependency check. + * + * @return the current dependency classpath + */ + public Path getClasspath() { + return dependClasspath; + } + + /** + * Adds a classpath to be used for this dependency check. + * + * @return A path object to be configured by Ant + */ + public Path createClasspath() { + if (dependClasspath == null) { + dependClasspath = new Path(getProject()); + } + return dependClasspath.createPath(); + } + + /** + * Adds a reference to a classpath defined elsewhere. + * + * @param r a reference to a path object to be used as the depend + * classpath + */ + public void setClasspathRef(Reference r) { + createClasspath().setRefid(r); + } + + /** + * Flag to set to true if you want dependency issues with RMI + * stubs to appear at warning level. + * @param warnOnRmiStubs if true set dependency issues to appear at warning level. + * @since Ant1.7 + */ + public void setWarnOnRmiStubs(boolean warnOnRmiStubs) { + this.warnOnRmiStubs = warnOnRmiStubs; + } + + /** + * Read the dependencies from cache file + * + * @return a collection of class dependencies + * @exception IOException if the dependency file cannot be read + */ + private Hashtable readCachedDependencies(File depFile) throws IOException { + Hashtable dependencyMap = new Hashtable(); + + BufferedReader in = null; + try { + in = new BufferedReader(new FileReader(depFile)); + String line = null; + Vector dependencyList = null; + String className = null; + int prependLength = CLASSNAME_PREPEND.length(); + while ((line = in.readLine()) != null) { + if (line.startsWith(CLASSNAME_PREPEND)) { + dependencyList = new Vector(); + className = line.substring(prependLength); + dependencyMap.put(className, dependencyList); + } else { + dependencyList.addElement(line); + } + } + } finally { + FileUtils.close(in); + } + + return dependencyMap; + } + + /** + * Write the dependencies to cache file + * + * @param dependencyMap the map of dependencies to be written out. + * @exception IOException if the dependency file cannot be written out. + */ + private void writeCachedDependencies(Hashtable dependencyMap) + throws IOException { + if (cache != null) { + BufferedWriter pw = null; + try { + cache.mkdirs(); + File depFile = new File(cache, CACHE_FILE_NAME); + + pw = new BufferedWriter(new FileWriter(depFile)); + Enumeration e = dependencyMap.keys(); + while (e.hasMoreElements()) { + String className = (String) e.nextElement(); + + pw.write(CLASSNAME_PREPEND + className); + pw.newLine(); + + Vector dependencyList + = (Vector) dependencyMap.get(className); + int size = dependencyList.size(); + for (int x = 0; x < size; x++) { + pw.write(String.valueOf(dependencyList.elementAt(x))); + pw.newLine(); + } + } + } finally { + FileUtils.close(pw); + } + } + } + + /** + * Get the classpath for dependency checking. + * + * This method removes the dest dirs if it is given from the dependency classpath + */ + private Path getCheckClassPath() { + if (dependClasspath == null) { + return null; + } + + String[] destPathElements = destPath.list(); + String[] classpathElements = dependClasspath.list(); + String checkPath = ""; + for (int i = 0; i < classpathElements.length; ++i) { + String element = classpathElements[i]; + boolean inDestPath = false; + for (int j = 0; j < destPathElements.length && !inDestPath; ++j) { + inDestPath = destPathElements[j].equals(element); + } + if (!inDestPath) { + if (checkPath.length() == 0) { + checkPath = element; + } else { + checkPath += ":" + element; + } + } + } + + Path p = null; + if (checkPath.length() > 0) { + p = new Path(getProject(), checkPath); + } + + log("Classpath without dest dir is " + p, Project.MSG_DEBUG); + return p; + } + + /** + * Determine the dependencies between classes. Class dependencies are + * determined by examining the class references in a class file to other + * classes. + * + * This method sets up the following fields + * <ul> + * <li>affectedClassMap - the list of classes each class affects</li> + * <li>classFileInfoMap - information about each class</li> + * <li>classpathDependencies - the list of jars and classes from the + * classpath that each class depends upon.</li> + * </ul> + * + * If required, the dependencies are written to the cache. + * + * @exception IOException if either the dependencies cache or the class + * files cannot be read or written + */ + private void determineDependencies() throws IOException { + affectedClassMap = new Hashtable(); + classFileInfoMap = new Hashtable(); + boolean cacheDirty = false; + + Hashtable dependencyMap = new Hashtable(); + File cacheFile = null; + boolean cacheFileExists = true; + long cacheLastModified = Long.MAX_VALUE; + + // read the dependency cache from the disk + if (cache != null) { + cacheFile = new File(cache, CACHE_FILE_NAME); + cacheFileExists = cacheFile.exists(); + cacheLastModified = cacheFile.lastModified(); + if (cacheFileExists) { + dependencyMap = readCachedDependencies(cacheFile); + } + } + Enumeration classfileEnum = getClassFiles(destPath).elements(); + while (classfileEnum.hasMoreElements()) { + ClassFileInfo info = (ClassFileInfo) classfileEnum.nextElement(); + log("Adding class info for " + info.className, Project.MSG_DEBUG); + classFileInfoMap.put(info.className, info); + + Vector dependencyList = null; + + if (cache != null) { + // try to read the dependency info from the map if it is + // not out of date + if (cacheFileExists + && cacheLastModified > info.absoluteFile.lastModified()) { + // depFile exists and is newer than the class file + // need to get dependency list from the map. + dependencyList = (Vector) dependencyMap.get(info.className); + } + } + + if (dependencyList == null) { + // not cached - so need to read directly from the class file + DependencyAnalyzer analyzer = new AntAnalyzer(); + analyzer.addRootClass(info.className); + analyzer.addClassPath(destPath); + analyzer.setClosure(false); + dependencyList = new Vector(); + Enumeration depEnum = analyzer.getClassDependencies(); + while (depEnum.hasMoreElements()) { + Object o = depEnum.nextElement(); + dependencyList.addElement(o); + log("Class " + info.className + " depends on " + o, + Project.MSG_DEBUG); + } + cacheDirty = true; + 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 + Enumeration depEnum = dependencyList.elements(); + while (depEnum.hasMoreElements()) { + String dependentClass = (String) depEnum.nextElement(); + + Hashtable affectedClasses + = (Hashtable) affectedClassMap.get(dependentClass); + if (affectedClasses == null) { + affectedClasses = new Hashtable(); + affectedClassMap.put(dependentClass, affectedClasses); + } + + affectedClasses.put(info.className, info); + log(dependentClass + " affects " + info.className, + Project.MSG_DEBUG); + } + } + + classpathDependencies = null; + Path checkPath = getCheckClassPath(); + if (checkPath != null) { + // now determine which jars each class depends upon + classpathDependencies = new Hashtable(); + AntClassLoader loader = null; + try { + loader = getProject().createClassLoader(checkPath); + + Hashtable classpathFileCache = new Hashtable(); + Object nullFileMarker = new Object(); + for (Enumeration e = dependencyMap.keys(); e.hasMoreElements();) { + String className = (String) e.nextElement(); + log("Determining classpath dependencies for " + className, + Project.MSG_DEBUG); + Vector dependencyList = (Vector) dependencyMap.get(className); + Hashtable dependencies = new Hashtable(); + classpathDependencies.put(className, dependencies); + Enumeration e2 = dependencyList.elements(); + while (e2.hasMoreElements()) { + String dependency = (String) e2.nextElement(); + log("Looking for " + dependency, Project.MSG_DEBUG); + Object classpathFileObject + = classpathFileCache.get(dependency); + if (classpathFileObject == null) { + classpathFileObject = nullFileMarker; + + if (!dependency.startsWith("java.") + && !dependency.startsWith("javax.")) { + URL classURL + = loader.getResource(dependency.replace('.', '/') + ".class"); + log("URL is " + classURL, Project.MSG_DEBUG); + if (classURL != null) { + if (classURL.getProtocol().equals("jar")) { + String jarFilePath = classURL.getFile(); + int classMarker = jarFilePath.indexOf('!'); + jarFilePath = jarFilePath.substring(0, classMarker); + if (jarFilePath.startsWith("file:")) { + classpathFileObject = new File( + FileUtils.getFileUtils().fromURI(jarFilePath)); + } else { + throw new IOException( + "Bizarre nested path in jar: protocol: " + + jarFilePath); + } + } else if (classURL.getProtocol().equals("file")) { + classpathFileObject = new File( + FileUtils.getFileUtils() + .fromURI(classURL.toExternalForm())); + } + log("Class " + className + + " depends on " + classpathFileObject + + " due to " + dependency, Project.MSG_DEBUG); + } + } else { + log("Ignoring base classlib dependency " + + dependency, Project.MSG_DEBUG); + } + classpathFileCache.put(dependency, classpathFileObject); + } + if (classpathFileObject != nullFileMarker) { + // we need to add this jar to the list for this class. + File jarFile = (File) classpathFileObject; + log("Adding a classpath dependency on " + jarFile, + Project.MSG_DEBUG); + dependencies.put(jarFile, jarFile); + } + } + } + } finally { + if (loader != null) { + loader.cleanup(); + } + } + } else { + log("No classpath to check", Project.MSG_DEBUG); + } + + // write the dependency cache to the disk + if (cache != null && cacheDirty) { + writeCachedDependencies(dependencyMap); + } + } + + /** + * Delete all the class files which are out of date, by way of their + * dependency on a class which is out of date + * + * @return the number of files deleted. + */ + private int deleteAllAffectedFiles() { + int count = 0; + for (Enumeration e = outOfDateClasses.elements(); e.hasMoreElements();) { + String className = (String) e.nextElement(); + count += deleteAffectedFiles(className); + ClassFileInfo classInfo + = (ClassFileInfo) classFileInfoMap.get(className); + if (classInfo != null && classInfo.absoluteFile.exists()) { + if (classInfo.sourceFile == null) { + warnOutOfDateButNotDeleted(classInfo, className, className); + } else { + classInfo.absoluteFile.delete(); + count++; + } + } + } + return count; + } + + /** + * Delete all the class files of classes which depend on the given class + * + * @param className the name of the class whose dependent classes will be + * deleted + * @return the number of class files removed + */ + private int deleteAffectedFiles(String className) { + int count = 0; + + Hashtable affectedClasses = (Hashtable) affectedClassMap.get(className); + if (affectedClasses == null) { + return count; + } + for (Enumeration e = affectedClasses.keys(); e.hasMoreElements();) { + String affectedClass = (String) e.nextElement(); + ClassFileInfo affectedClassInfo + = (ClassFileInfo) affectedClasses.get(affectedClass); + + if (!affectedClassInfo.absoluteFile.exists()) { + continue; + } + + if (affectedClassInfo.sourceFile == null) { + warnOutOfDateButNotDeleted(affectedClassInfo, affectedClass, className); + continue; + } + + log("Deleting file " + affectedClassInfo.absoluteFile.getPath() + + " since " + className + " out of date", Project.MSG_VERBOSE); + + affectedClassInfo.absoluteFile.delete(); + count++; + if (closure) { + count += deleteAffectedFiles(affectedClass); + } else { + // without closure we may delete an inner class but not the + // top level class which would not trigger a recompile. + + if (affectedClass.indexOf("$") == -1) { + continue; + } + // need to delete the main class + String topLevelClassName + = affectedClass.substring(0, affectedClass.indexOf("$")); + log("Top level class = " + topLevelClassName, + Project.MSG_VERBOSE); + ClassFileInfo topLevelClassInfo + = (ClassFileInfo) classFileInfoMap.get(topLevelClassName); + if (topLevelClassInfo != null + && topLevelClassInfo.absoluteFile.exists()) { + log("Deleting file " + + topLevelClassInfo.absoluteFile.getPath() + + " since one of its inner classes was removed", + Project.MSG_VERBOSE); + topLevelClassInfo.absoluteFile.delete(); + count++; + if (closure) { + count += deleteAffectedFiles(topLevelClassName); + } + } + } + } + return count; + } + + /** + * warn when a class is out of date, but not deleted as its source is unknown. + * MSG_WARN is the normal level, but we downgrade to MSG_VERBOSE for RMI files + * if {@link #warnOnRmiStubs is false} + * @param affectedClassInfo info about the affectd class + * @param affectedClass the name of the affected .class file + * @param className the file that is triggering the out of dateness + */ + private void warnOutOfDateButNotDeleted( + ClassFileInfo affectedClassInfo, String affectedClass, + String className) { + if (affectedClassInfo.isUserWarned) { + return; + } + int level = Project.MSG_WARN; + if (!warnOnRmiStubs) { + //downgrade warnings on RMI stublike classes, as they are generated + //by rmic, so there is no need to tell the user that their source is + //missing. + if (isRmiStub(affectedClass, className)) { + level = Project.MSG_VERBOSE; + } + } + log("The class " + affectedClass + " in file " + + affectedClassInfo.absoluteFile.getPath() + + " is out of date due to " + className + + " but has not been deleted because its source file" + + " could not be determined", level); + affectedClassInfo.isUserWarned = true; + } + + /** + * test for being an RMI stub + * @param affectedClass class being tested + * @param className possible origin of the RMI stub + * @return whether the class affectedClass is a RMI stub + */ + private boolean isRmiStub(String affectedClass, String className) { + return isStub(affectedClass, className, DefaultRmicAdapter.RMI_STUB_SUFFIX) + || isStub(affectedClass, className, DefaultRmicAdapter.RMI_SKEL_SUFFIX) + || isStub(affectedClass, className, WLRmic.RMI_STUB_SUFFIX) + || isStub(affectedClass, className, WLRmic.RMI_SKEL_SUFFIX); + } + + private boolean isStub(String affectedClass, String baseClass, String suffix) { + return (baseClass + suffix).equals(affectedClass); + } + + /** + * Dump the dependency information loaded from the classes to the Ant log + */ + private void dumpDependencies() { + log("Reverse Dependency Dump for " + affectedClassMap.size() + + " classes:", Project.MSG_DEBUG); + + Enumeration classEnum = affectedClassMap.keys(); + while (classEnum.hasMoreElements()) { + String className = (String) classEnum.nextElement(); + log(" Class " + className + " affects:", Project.MSG_DEBUG); + Hashtable affectedClasses + = (Hashtable) affectedClassMap.get(className); + Enumeration affectedClassEnum = affectedClasses.keys(); + while (affectedClassEnum.hasMoreElements()) { + String affectedClass = (String) affectedClassEnum.nextElement(); + ClassFileInfo info + = (ClassFileInfo) affectedClasses.get(affectedClass); + log(" " + affectedClass + " in " + + info.absoluteFile.getPath(), Project.MSG_DEBUG); + } + } + + if (classpathDependencies != null) { + log("Classpath file dependencies (Forward):", Project.MSG_DEBUG); + + Enumeration classpathEnum = classpathDependencies.keys(); + while (classpathEnum.hasMoreElements()) { + String className = (String) classpathEnum.nextElement(); + log(" Class " + className + " depends on:", Project.MSG_DEBUG); + Hashtable dependencies + = (Hashtable) classpathDependencies.get(className); + + Enumeration classpathFileEnum = dependencies.elements(); + while (classpathFileEnum.hasMoreElements()) { + File classpathFile = (File) classpathFileEnum.nextElement(); + log(" " + classpathFile.getPath(), Project.MSG_DEBUG); + } + } + } + } + + private void determineOutOfDateClasses() { + outOfDateClasses = new Hashtable(); + for (int i = 0; i < srcPathList.length; i++) { + File srcDir = getProject().resolveFile(srcPathList[i]); + if (srcDir.exists()) { + DirectoryScanner ds = this.getDirectoryScanner(srcDir); + String[] files = ds.getIncludedFiles(); + scanDir(srcDir, files); + } + } + + // now check classpath file dependencies + if (classpathDependencies == null) { + return; + } + + Enumeration classpathDepsEnum = classpathDependencies.keys(); + while (classpathDepsEnum.hasMoreElements()) { + String className = (String) classpathDepsEnum.nextElement(); + if (outOfDateClasses.containsKey(className)) { + continue; + } + ClassFileInfo info + = (ClassFileInfo) classFileInfoMap.get(className); + + // if we have no info about the class - it may have been deleted already and we + // are using cached info. + if (info != null) { + Hashtable dependencies + = (Hashtable) classpathDependencies.get(className); + for (Enumeration e2 = dependencies.elements(); e2.hasMoreElements();) { + File classpathFile = (File) e2.nextElement(); + if (classpathFile.lastModified() + > info.absoluteFile.lastModified()) { + log("Class " + className + + " is out of date with respect to " + + classpathFile, Project.MSG_DEBUG); + outOfDateClasses.put(className, className); + break; + } + } + } + } + } + + /** + * Does the work. + * + * @exception BuildException Thrown in case of an unrecoverable error. + */ + public void execute() throws BuildException { + try { + long start = System.currentTimeMillis(); + if (srcPath == null) { + throw new BuildException("srcdir attribute must be set", + getLocation()); + } + + srcPathList = srcPath.list(); + if (srcPathList.length == 0) { + throw new BuildException("srcdir attribute must be non-empty", + getLocation()); + } + + if (destPath == null) { + destPath = srcPath; + } + + 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(); + if (dump) { + dumpDependencies(); + } + determineOutOfDateClasses(); + int count = deleteAllAffectedFiles(); + + long duration = (System.currentTimeMillis() - start) / ONE_SECOND; + + final int summaryLogLevel; + if (count > 0) { + summaryLogLevel = Project.MSG_INFO; + } else { + summaryLogLevel = Project.MSG_DEBUG; + } + + log("Deleted " + count + " out of date files in " + + duration + " seconds", summaryLogLevel); + } catch (Exception e) { + throw new BuildException(e); + } + } + + /** + * Scans the directory looking for source files that are newer than + * their class files. The results are returned in the class variable + * compileList + * + * @param srcDir the source directory + * @param files the names of the files in the source dir which are to be + * checked. + */ + protected void scanDir(File srcDir, String[] files) { + + for (int i = 0; i < files.length; i++) { + File srcFile = new File(srcDir, files[i]); + if (files[i].endsWith(".java")) { + String filePath = srcFile.getPath(); + String className + = filePath.substring(srcDir.getPath().length() + 1, + filePath.length() - ".java".length()); + className = ClassFileUtils.convertSlashName(className); + ClassFileInfo info + = (ClassFileInfo) classFileInfoMap.get(className); + if (info == null) { + // there was no class file. add this class to the list + outOfDateClasses.put(className, className); + } else { + if (srcFile.lastModified() + > info.absoluteFile.lastModified()) { + outOfDateClasses.put(className, className); + } + } + } + } + } + + + /** + * Get the list of class files we are going to analyse. + * + * @param classLocations a path structure containing all the directories + * where classes can be found. + * @return a vector containing the classes to analyse. + */ + private Vector getClassFiles(Path classLocations) { + // break the classLocations into its components. + String[] classLocationsList = classLocations.list(); + + Vector classFileList = new Vector(); + + for (int i = 0; i < classLocationsList.length; ++i) { + File dir = new File(classLocationsList[i]); + if (dir.isDirectory()) { + addClassFiles(classFileList, dir, dir); + } + } + + return classFileList; + } + + /** + * Find the source file for a given class + * + * @param classname the classname in slash format. + * @param sourceFileKnownToExist if not null, a file already known to exist + * (saves call to .exists()) + */ + private File findSourceFile(String classname, File sourceFileKnownToExist) { + String sourceFilename; + int innerIndex = classname.indexOf("$"); + if (innerIndex != -1) { + sourceFilename = classname.substring(0, innerIndex) + ".java"; + } else { + sourceFilename = classname + ".java"; + } + + // search the various source path entries + for (int i = 0; i < srcPathList.length; ++i) { + File sourceFile = new File(srcPathList[i], sourceFilename); + if (sourceFile.equals(sourceFileKnownToExist) || sourceFile.exists()) { + return sourceFile; + } + } + return null; + } + + /** + * Add the list of class files from the given directory to the class + * file vector, including any subdirectories. + * + * @param classFileList a list of ClassFileInfo objects for all the + * files in the directory tree + * @param dir the directory tree to be searched, recursively, for class + * files + * @param root the root of the source tree. This is used to determine + * the absolute class name from the relative position in the + * source tree + */ + private void addClassFiles(Vector classFileList, File dir, File root) { + String[] filesInDir = dir.list(); + + if (filesInDir == null) { + return; + } + int length = filesInDir.length; + + int rootLength = root.getPath().length(); + File sourceFileKnownToExist = null; // speed optimization + for (int i = 0; i < length; ++i) { + File file = new File(dir, filesInDir[i]); + if (filesInDir[i].endsWith(".class")) { + ClassFileInfo info = new ClassFileInfo(); + info.absoluteFile = file; + String relativeName = file.getPath().substring( + rootLength + 1, + file.getPath().length() - ".class".length()); + info.className + = ClassFileUtils.convertSlashName(relativeName); + info.sourceFile = sourceFileKnownToExist = findSourceFile( + relativeName, sourceFileKnownToExist); + classFileList.addElement(info); + } else { + addClassFiles(classFileList, file, root); + } + } + } + + + /** + * Set the directories path to find the Java source files. + * + * @param srcPath the source path + */ + public void setSrcdir(Path srcPath) { + this.srcPath = srcPath; + } + + /** + * Set the destination directory where the compiled Java files exist. + * + * @param destPath the destination areas where build files are written + */ + public void setDestDir(Path destPath) { + this.destPath = destPath; + } + + /** + * Sets the dependency cache file. + * + * @param cache the dependency cache file + */ + public void setCache(File cache) { + this.cache = cache; + } + + /** + * If true, transitive dependencies are followed until the + * closure of the dependency set if reached. + * When not set, the depend task will only follow + * direct dependencies between classes. + * + * @param closure indicate if dependency closure is required. + */ + public void setClosure(boolean closure) { + this.closure = closure; + } + + /** + * If true, the dependency information will be written + * to the debug level log. + * + * @param dump set to true to dump dependency information to the log + */ + public void setDump(boolean dump) { + this.dump = dump; + } +} + |