diff options
Diffstat (limited to 'src/net/sf/antcontrib/cpptasks/DependencyTable.java')
-rw-r--r-- | src/net/sf/antcontrib/cpptasks/DependencyTable.java | 612 |
1 files changed, 0 insertions, 612 deletions
diff --git a/src/net/sf/antcontrib/cpptasks/DependencyTable.java b/src/net/sf/antcontrib/cpptasks/DependencyTable.java deleted file mode 100644 index 9e57eb1..0000000 --- a/src/net/sf/antcontrib/cpptasks/DependencyTable.java +++ /dev/null @@ -1,612 +0,0 @@ -/* - * - * Copyright 2002-2004 The Ant-Contrib project - * - * Licensed 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 net.sf.antcontrib.cpptasks; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.UnsupportedEncodingException; -import java.util.Enumeration; -import java.util.Hashtable; -import java.util.Vector; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; -import net.sf.antcontrib.cpptasks.compiler.CompilerConfiguration; -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.Project; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; -/** - * @author Curt Arnold - */ -public final class DependencyTable { - /** - * This class handles populates the TargetHistory hashtable in response to - * SAX parse events - */ - private class DependencyTableHandler extends DefaultHandler { - private File baseDir; - private final DependencyTable dependencyTable; - private String includePath; - private Vector includes; - private String source; - private long sourceLastModified; - private Vector sysIncludes; - /** - * Constructor - * - * @param history - * hashtable of TargetHistory keyed by output name - * @param outputFiles - * existing files in output directory - */ - private DependencyTableHandler(DependencyTable dependencyTable, - File baseDir) { - this.dependencyTable = dependencyTable; - this.baseDir = baseDir; - includes = new Vector(); - sysIncludes = new Vector(); - source = null; - } - public void endElement(String namespaceURI, String localName, - String qName) throws SAXException { - // - // if </source> then - // create Dependency object and add to hashtable - // if corresponding source file exists and - // has the same timestamp - // - if (qName.equals("source")) { - if (source != null && includePath != null) { - File existingFile = new File(baseDir, source); - // - // if the file exists and the time stamp is right - // preserve the dependency info - if (existingFile.exists()) { - // - // would have expected exact matches - // but was seeing some unexpected difference by - // a few tens of milliseconds, as long - // as the times are within a second - long existingLastModified = existingFile.lastModified(); - if (!CUtil.isSignificantlyAfter(existingLastModified, sourceLastModified) && - !CUtil.isSignificantlyBefore(existingLastModified, sourceLastModified)) { - DependencyInfo dependInfo = new DependencyInfo( - includePath, source, sourceLastModified, - includes, sysIncludes); - dependencyTable.putDependencyInfo(source, - dependInfo); - } - } - source = null; - includes.setSize(0); - } - } else { - // - // this causes any <source> elements outside the - // scope of an <includePath> to be discarded - // - if (qName.equals("includePath")) { - includePath = null; - } - } - } - /** - * startElement handler - */ - public void startElement(String namespaceURI, String localName, - String qName, Attributes atts) throws SAXException { - // - // if includes, then add relative file name to vector - // - if (qName.equals("include")) { - includes.addElement(atts.getValue("file")); - } else { - if (qName.equals("sysinclude")) { - sysIncludes.addElement(atts.getValue("file")); - } else { - // - // if source then - // capture source file name, - // modification time and reset includes vector - // - if (qName.equals("source")) { - source = atts.getValue("file"); - sourceLastModified = Long.parseLong(atts - .getValue("lastModified"), 16); - includes.setSize(0); - sysIncludes.setSize(0); - } else { - if (qName.equals("includePath")) { - includePath = atts.getValue("signature"); - } - } - } - } - } - } - public abstract class DependencyVisitor { - /** - * Previews all the children of this source file. - * - * May be called multiple times as DependencyInfo's for children are - * filled in. - * - * @return true to continue towards recursion into included files - */ - public abstract boolean preview(DependencyInfo parent, - DependencyInfo[] children); - /** - * Called if the dependency depth exhausted the stack. - */ - public abstract void stackExhausted(); - /** - * Visits the dependency info. - * - * @returns true to continue towards recursion into included files - */ - public abstract boolean visit(DependencyInfo dependInfo); - } - public class TimestampChecker extends DependencyVisitor { - private boolean noNeedToRebuild; - private long outputLastModified; - private boolean rebuildOnStackExhaustion; - public TimestampChecker(final long outputLastModified, - boolean rebuildOnStackExhaustion) { - this.outputLastModified = outputLastModified; - noNeedToRebuild = true; - this.rebuildOnStackExhaustion = rebuildOnStackExhaustion; - } - public boolean getMustRebuild() { - return !noNeedToRebuild; - } - public boolean preview(DependencyInfo parent, DependencyInfo[] children) { - int withCompositeTimes = 0; - long parentCompositeLastModified = parent.getSourceLastModified(); - for (int i = 0; i < children.length; i++) { - if (children[i] != null) { - // - // expedient way to determine if a child forces us to - // rebuild - // - visit(children[i]); - long childCompositeLastModified = children[i] - .getCompositeLastModified(); - if (childCompositeLastModified != Long.MIN_VALUE) { - withCompositeTimes++; - if (childCompositeLastModified > parentCompositeLastModified) { - parentCompositeLastModified = childCompositeLastModified; - } - } - } - } - if (withCompositeTimes == children.length) { - parent.setCompositeLastModified(parentCompositeLastModified); - } - // - // may have been changed by an earlier call to visit() - // - return noNeedToRebuild; - } - public void stackExhausted() { - if (rebuildOnStackExhaustion) { - noNeedToRebuild = false; - } - } - public boolean visit(DependencyInfo dependInfo) { - if (noNeedToRebuild) { - if (CUtil.isSignificantlyAfter(dependInfo.getSourceLastModified(), outputLastModified) - || CUtil.isSignificantlyAfter(dependInfo.getCompositeLastModified(), outputLastModified)) { - noNeedToRebuild = false; - } - } - // - // only need to process the children if - // it has not yet been determined whether - // we need to rebuild and the composite modified time - // has not been determined for this file - return noNeedToRebuild - && dependInfo.getCompositeLastModified() == Long.MIN_VALUE; - } - } - private/* final */File baseDir; - private String baseDirPath; - /** - * a hashtable of DependencyInfo[] keyed by output file name - */ - private final Hashtable dependencies = new Hashtable(); - /** The file the cache was loaded from. */ - private/* final */File dependenciesFile; - /** Flag indicating whether the cache should be written back to file. */ - private boolean dirty; - /** - * Creates a target history table from dependencies.xml in the prject - * directory, if it exists. Otherwise, initializes the dependencies empty. - * - * @param task - * task used for logging history load errors - * @param baseDir - * output directory for task - */ - public DependencyTable(File baseDir) { - if (baseDir == null) { - throw new NullPointerException("baseDir"); - } - this.baseDir = baseDir; - try { - baseDirPath = baseDir.getCanonicalPath(); - } catch (IOException ex) { - baseDirPath = baseDir.toString(); - } - dirty = false; - // - // load any existing dependencies from file - dependenciesFile = new File(baseDir, "dependencies.xml"); - } - public void commit(CCTask task) { - // - // if not dirty, no need to update file - // - if (dirty) { - // - // walk through dependencies to get vector of include paths - // identifiers - // - Vector includePaths = getIncludePaths(); - // - // - // write dependency file - // - try { - FileOutputStream outStream = new FileOutputStream( - dependenciesFile); - OutputStreamWriter streamWriter; - // - // Early VM's may not have UTF-8 support - // fallback to default code page which - // "should" be okay unless there are - // non ASCII file names - String encodingName = "UTF-8"; - try { - streamWriter = new OutputStreamWriter(outStream, "UTF-8"); - } catch (UnsupportedEncodingException ex) { - streamWriter = new OutputStreamWriter(outStream); - encodingName = streamWriter.getEncoding(); - } - BufferedWriter writer = new BufferedWriter(streamWriter); - writer.write("<?xml version='1.0' encoding='"); - writer.write(encodingName); - writer.write("'?>\n"); - writer.write("<dependencies>\n"); - StringBuffer buf = new StringBuffer(); - Enumeration includePathEnum = includePaths.elements(); - while (includePathEnum.hasMoreElements()) { - writeIncludePathDependencies((String) includePathEnum - .nextElement(), writer, buf); - } - writer.write("</dependencies>\n"); - writer.close(); - dirty = false; - } catch (IOException ex) { - task.log("Error writing " + dependenciesFile.toString() + ":" - + ex.toString()); - } - } - } - /** - * Returns an enumerator of DependencyInfo's - */ - public Enumeration elements() { - return dependencies.elements(); - } - /** - * This method returns a DependencyInfo for the specific source file and - * include path identifier - * - */ - public DependencyInfo getDependencyInfo(String sourceRelativeName, - String includePathIdentifier) { - DependencyInfo dependInfo = null; - DependencyInfo[] dependInfos = (DependencyInfo[]) dependencies - .get(sourceRelativeName); - if (dependInfos != null) { - for (int i = 0; i < dependInfos.length; i++) { - dependInfo = dependInfos[i]; - if (dependInfo.getIncludePathIdentifier().equals( - includePathIdentifier)) { - return dependInfo; - } - } - } - return null; - } - private Vector getIncludePaths() { - Vector includePaths = new Vector(); - DependencyInfo[] dependInfos; - Enumeration dependenciesEnum = dependencies.elements(); - while (dependenciesEnum.hasMoreElements()) { - dependInfos = (DependencyInfo[]) dependenciesEnum.nextElement(); - for (int i = 0; i < dependInfos.length; i++) { - DependencyInfo dependInfo = dependInfos[i]; - boolean matchesExisting = false; - final String dependIncludePath = dependInfo - .getIncludePathIdentifier(); - Enumeration includePathEnum = includePaths.elements(); - while (includePathEnum.hasMoreElements()) { - if (dependIncludePath.equals(includePathEnum.nextElement())) { - matchesExisting = true; - break; - } - } - if (!matchesExisting) { - includePaths.addElement(dependIncludePath); - } - } - } - return includePaths; - } - public void load() throws IOException, ParserConfigurationException, - SAXException { - dependencies.clear(); - if (dependenciesFile.exists()) { - SAXParserFactory factory = SAXParserFactory.newInstance(); - factory.setValidating(false); - SAXParser parser = factory.newSAXParser(); - parser.parse(dependenciesFile, new DependencyTableHandler(this, - baseDir)); - dirty = false; - } - } - /** - * Determines if the specified target needs to be rebuilt. - * - * This task may result in substantial IO as files are parsed to determine - * their dependencies - */ - public boolean needsRebuild(CCTask task, TargetInfo target, - int dependencyDepth) { - // look at any files where the compositeLastModified - // is not known, but the includes are known - // - boolean mustRebuild = false; - CompilerConfiguration compiler = (CompilerConfiguration) target - .getConfiguration(); - String includePathIdentifier = compiler.getIncludePathIdentifier(); - File[] sources = target.getSources(); - DependencyInfo[] dependInfos = new DependencyInfo[sources.length]; - long outputLastModified = target.getOutput().lastModified(); - // - // try to solve problem using existing dependency info - // (not parsing any new files) - // - DependencyInfo[] stack = new DependencyInfo[50]; - boolean rebuildOnStackExhaustion = true; - if (dependencyDepth >= 0) { - if (dependencyDepth < 50) { - stack = new DependencyInfo[dependencyDepth]; - } - rebuildOnStackExhaustion = false; - } - TimestampChecker checker = new TimestampChecker(outputLastModified, - rebuildOnStackExhaustion); - for (int i = 0; i < sources.length && !mustRebuild; i++) { - File source = sources[i]; - String relative = CUtil.getRelativePath(baseDirPath, source); - DependencyInfo dependInfo = getDependencyInfo(relative, - includePathIdentifier); - if (dependInfo == null) { - task.log("Parsing " + relative, Project.MSG_VERBOSE); - dependInfo = parseIncludes(task, compiler, source); - } - walkDependencies(task, dependInfo, compiler, stack, checker); - mustRebuild = checker.getMustRebuild(); - } - return mustRebuild; - } - public DependencyInfo parseIncludes(CCTask task, - CompilerConfiguration compiler, File source) { - DependencyInfo dependInfo = compiler.parseIncludes(task, baseDir, - source); - String relativeSource = CUtil.getRelativePath(baseDirPath, source); - putDependencyInfo(relativeSource, dependInfo); - return dependInfo; - } - private void putDependencyInfo(String key, DependencyInfo dependInfo) { - // - // optimistic, add new value - // - DependencyInfo[] old = (DependencyInfo[]) dependencies.put(key, - new DependencyInfo[]{dependInfo}); - dirty = true; - // - // something was already there - // - if (old != null) { - // - // see if the include path matches a previous entry - // if so replace it - String includePathIdentifier = dependInfo - .getIncludePathIdentifier(); - for (int i = 0; i < old.length; i++) { - DependencyInfo oldDepend = old[i]; - if (oldDepend.getIncludePathIdentifier().equals( - includePathIdentifier)) { - old[i] = dependInfo; - dependencies.put(key, old); - return; - } - } - // - // no match prepend the new entry to the array - // of dependencies for the file - DependencyInfo[] combined = new DependencyInfo[old.length + 1]; - combined[0] = dependInfo; - for (int i = 0; i < old.length; i++) { - combined[i + 1] = old[i]; - } - dependencies.put(key, combined); - } - return; - } - public void walkDependencies(CCTask task, DependencyInfo dependInfo, - CompilerConfiguration compiler, DependencyInfo[] stack, - DependencyVisitor visitor) throws BuildException { - // - // visit this node - // if visit returns true then - // visit the referenced include and sysInclude dependencies - // - if (visitor.visit(dependInfo)) { - // - // find first null entry on stack - // - int stackPosition = -1; - for (int i = 0; i < stack.length; i++) { - if (stack[i] == null) { - stackPosition = i; - stack[i] = dependInfo; - break; - } else { - // - // if we have appeared early in the calling history - // then we didn't exceed the criteria - if (stack[i] == dependInfo) { - return; - } - } - } - if (stackPosition == -1) { - visitor.stackExhausted(); - return; - } - // - // locate dependency infos - // - String[] includes = dependInfo.getIncludes(); - String includePathIdentifier = compiler.getIncludePathIdentifier(); - DependencyInfo[] includeInfos = new DependencyInfo[includes.length]; - for (int i = 0; i < includes.length; i++) { - DependencyInfo includeInfo = getDependencyInfo(includes[i], - includePathIdentifier); - includeInfos[i] = includeInfo; - } - // - // preview with only the already available dependency infos - // - if (visitor.preview(dependInfo, includeInfos)) { - // - // now need to fill in the missing DependencyInfos - // - int missingCount = 0; - for (int i = 0; i < includes.length; i++) { - if (includeInfos[i] == null) { - missingCount++; - task.log("Parsing " + includes[i], Project.MSG_VERBOSE); - // - // If the include filepath is relative - // then anchor it the base directory - File src = new File(includes[i]); - if (!src.isAbsolute()) { - src = new File(baseDir, includes[i]); - } - DependencyInfo includeInfo = parseIncludes(task, - compiler, src); - includeInfos[i] = includeInfo; - } - } - // - // if it passes a review the second time - // then recurse into all the children - if (missingCount == 0 - || visitor.preview(dependInfo, includeInfos)) { - // - // recurse into - // - for (int i = 0; i < includeInfos.length; i++) { - DependencyInfo includeInfo = includeInfos[i]; - walkDependencies(task, includeInfo, compiler, stack, - visitor); - } - } - } - stack[stackPosition] = null; - } - } - private void writeDependencyInfo(BufferedWriter writer, StringBuffer buf, - DependencyInfo dependInfo) throws IOException { - String[] includes = dependInfo.getIncludes(); - String[] sysIncludes = dependInfo.getSysIncludes(); - // - // if the includes have not been evaluted then - // it is not worth our time saving it - // and trying to distiguish between files with - // no dependencies and those with undetermined dependencies - buf.setLength(0); - buf.append(" <source file=\""); - buf.append(CUtil.xmlAttribEncode(dependInfo.getSource())); - buf.append("\" lastModified=\""); - buf.append(Long.toHexString(dependInfo.getSourceLastModified())); - buf.append("\">\n"); - writer.write(buf.toString()); - for (int i = 0; i < includes.length; i++) { - buf.setLength(0); - buf.append(" <include file=\""); - buf.append(CUtil.xmlAttribEncode(includes[i])); - buf.append("\"/>\n"); - writer.write(buf.toString()); - } - for (int i = 0; i < sysIncludes.length; i++) { - buf.setLength(0); - buf.append(" <sysinclude file=\""); - buf.append(CUtil.xmlAttribEncode(sysIncludes[i])); - buf.append("\"/>\n"); - writer.write(buf.toString()); - } - writer.write(" </source>\n"); - return; - } - private void writeIncludePathDependencies(String includePathIdentifier, - BufferedWriter writer, StringBuffer buf) throws IOException { - // - // include path element - // - buf.setLength(0); - buf.append(" <includePath signature=\""); - buf.append(CUtil.xmlAttribEncode(includePathIdentifier)); - buf.append("\">\n"); - writer.write(buf.toString()); - Enumeration dependenciesEnum = dependencies.elements(); - while (dependenciesEnum.hasMoreElements()) { - DependencyInfo[] dependInfos = (DependencyInfo[]) dependenciesEnum - .nextElement(); - for (int i = 0; i < dependInfos.length; i++) { - DependencyInfo dependInfo = dependInfos[i]; - // - // if this is for the same include path - // then output the info - if (dependInfo.getIncludePathIdentifier().equals( - includePathIdentifier)) { - writeDependencyInfo(writer, buf, dependInfo); - } - } - } - writer.write(" </includePath>\n"); - } -} |