import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.aspectj.ajdt.internal.compiler.InterimCompilationResult;
+import org.aspectj.asm.IHierarchy;
+import org.aspectj.asm.IRelationshipMap;
import org.aspectj.bridge.IMessage;
import org.aspectj.bridge.Message;
import org.aspectj.bridge.SourceLocation;
import org.aspectj.org.eclipse.jdt.internal.core.builder.ReferenceCollection;
import org.aspectj.org.eclipse.jdt.internal.core.builder.StringSet;
import org.aspectj.util.FileUtil;
+import org.aspectj.weaver.bcel.BcelWeaver;
+import org.aspectj.weaver.bcel.BcelWorld;
import org.aspectj.weaver.bcel.UnwovenClassFile;
public class AjState {
AjBuildManager buildManager;
- // static so beware of multi-threading bugs...
+ // SECRETAPI static so beware of multi-threading bugs...
public static IStateListener stateListener = null;
+
+ private IHierarchy structureModel;
+ private IRelationshipMap relmap;
+
+ private long lastSuccessfulFullBuildTime = -1;
+ private Hashtable /* File, long */ structuralChangesSinceLastFullBuild = new Hashtable();
+
+ private long lastSuccessfulBuildTime = -1;
+ private long currentBuildTime = -1;
- long lastSuccessfulBuildTime = -1;
- long currentBuildTime = -1;
AjBuildConfig buildConfig;
AjBuildConfig newBuildConfig;
Set /*BinarySourceFile*/addedBinaryFiles;
Set /*BinarySourceFile*/deletedBinaryFiles;
+ private BcelWeaver weaver;
+ private BcelWorld world;
+
List addedClassFiles;
public AjState(AjBuildManager buildManager) {
this.buildManager = buildManager;
}
- void successfulCompile(AjBuildConfig config) {
+ void successfulCompile(AjBuildConfig config,boolean wasFullBuild) {
buildConfig = config;
lastSuccessfulBuildTime = currentBuildTime;
+ if (stateListener!=null) stateListener.buildSuccessful(wasFullBuild);
+ if (wasFullBuild) lastSuccessfulFullBuildTime = currentBuildTime;
}
/**
addedClassFiles = new ArrayList();
if (lastSuccessfulBuildTime == -1 || buildConfig == null) {
+ structuralChangesSinceLastFullBuild.clear();
return false;
}
// we don't support incremental with an outjar yet
- if (newBuildConfig.getOutputJar() != null) return false;
+ if (newBuildConfig.getOutputJar() != null) {
+ structuralChangesSinceLastFullBuild.clear();
+ return false;
+ }
// we can't do an incremental build if one of our paths
// has changed, or a jar on a path has been modified
// since the last build will not be deleted from the output directory.
removeAllResultsOfLastBuild();
if (stateListener!=null) stateListener.pathChangeDetected();
+ structuralChangesSinceLastFullBuild.clear();
return false;
}
}
private boolean classFileChangedInDirSinceLastBuild(File dir) {
- File[] classFiles = FileUtil.listFiles(dir, new FileFilter(){
-
+ // Is another process building into that directory?
+ AjState state = IncrementalStateManager.findStateManagingOutputLocation(dir);
+
+ File[] classFiles = FileUtil.listFiles(dir, new FileFilter() {
public boolean accept(File pathname) {
return pathname.getName().endsWith(".class");
}
-
});
+
for (int i = 0; i < classFiles.length; i++) {
long modTime = classFiles[i].lastModified();
- if (modTime + 1000 >= lastSuccessfulBuildTime) {
- return true;
+ if ((modTime+1000)>=lastSuccessfulBuildTime) {
+ // so the class on disk has changed since our last successful build
+
+ // To work out if it is a real change we should ask any state
+ // object managing this output location whether the file has
+ // structurally changed or not
+ if (state!=null) {
+ boolean realChange = state.hasStructuralChangedSince(classFiles[i],lastSuccessfulBuildTime);
+ if (realChange) return true;
+ } else {
+ // FIXME asc you should ask Eclipse project state here...
+ return true; // no state object to ask so it must have changed
+ }
}
}
return false;
}
+ /**
+ * Determine if a file has changed since a given time, using the local information
+ * recorded in the structural changes data structure.
+ *
+ * file is the file we are wondering about
+ * lastSBT is the last build time for the state asking the question
+ */
+ private boolean hasStructuralChangedSince(File file,long lastSuccessfulBuildTime) {
+ long lastModTime = file.lastModified();
+ Long l = (Long)structuralChangesSinceLastFullBuild.get(file.getAbsolutePath());
+ long strucModTime = -1;
+ if (l!=null) strucModTime = l.longValue();
+ else strucModTime = this.lastSuccessfulFullBuildTime;
+ // we now have:
+ // 'strucModTime'-> the last time the class was structurally changed
+ return (strucModTime>lastSuccessfulBuildTime);
+ }
+
private boolean pathChange(AjBuildConfig oldConfig, AjBuildConfig newConfig) {
boolean changed = false;
List oldClasspath = oldConfig.getClasspath();
private void deleteClassFile(UnwovenClassFile classFile) {
classesFromName.remove(classFile.getClassName());
- buildManager.bcelWeaver.deleteClassFile(classFile.getClassName());
+ weaver.deleteClassFile(classFile.getClassName());
try {
classFile.deleteRealFile();
} catch (IOException e) {
private UnwovenClassFile createUnwovenClassFile(AjBuildConfig.BinarySourceFile bsf) {
UnwovenClassFile ucf = null;
try {
- ucf = buildManager.bcelWeaver.addClassFile(bsf.binSrc, bsf.fromInPathDirectory, buildConfig.getOutputDir());
+ ucf = weaver.addClassFile(bsf.binSrc, bsf.fromInPathDirectory, buildConfig.getOutputDir());
} catch(IOException ex) {
IMessage msg = new Message("can't read class file " + bsf.binSrc.getPath(),
new SourceLocation(bsf.binSrc,0),false);
try {
ClassFileReader reader = new ClassFileReader(oldBytes, lastTime.getFilename().toCharArray());
// ignore local types since they're only visible inside a single method
- if (!(reader.isLocal() || reader.isAnonymous()) && reader.hasStructuralChanges(newBytes)) {
+ if (!(reader.isLocal() || reader.isAnonymous()) &&
+ reader.hasStructuralChanges(newBytes)) {
+ structuralChangesSinceLastFullBuild.put(thisTime.getFilename(),new Long(currentBuildTime));
addDependentsOf(lastTime.getClassName());
}
} catch (ClassFormatException e) {
}
}
+ public void setStructureModel(IHierarchy model) {
+ structureModel = model;
+ }
+
+ public IHierarchy getStructureModel() {
+ return structureModel;
+ }
+
+ public void setWeaver(BcelWeaver bw) { weaver=bw;}
+ public BcelWeaver getWeaver() {return weaver;}
+
+ public void setWorld(BcelWorld bw) {world=bw;}
+ public BcelWorld getBcelWorld() {return world; }
+
+ public void setRelationshipMap(IRelationshipMap irm) { relmap = irm;}
+ public IRelationshipMap getRelationshipMap() { return relmap;}
+
+ public int getNumberOfStructuralChangesSinceLastFullBuild() {
+ return structuralChangesSinceLastFullBuild.size();
+ }
+
+ /** Returns last time we did a full or incremental build. */
+ public long getLastBuildTime() {
+ return lastSuccessfulBuildTime;
+ }
+
+ /** Returns last time we did a full build */
+ public long getLastFullBuildTime() {
+ return lastSuccessfulFullBuildTime;
+ }
+
}