package org.eclipse.jgit.revwalk;
+import org.eclipse.jgit.lib.FileTreeEntry;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.Tree;
+
public class ObjectWalkTest extends RevWalkTestCase {
protected ObjectWalk objw;
assertSame(f2, objw.nextObject());
assertNull(objw.nextObject());
}
+
+ public void testEmptyTreeCorruption() throws Exception {
+ ObjectId bId = ObjectId
+ .fromString("abbbfafe3129f85747aba7bfac992af77134c607");
+ final RevTree tree_root, tree_A, tree_AB;
+ final RevCommit b;
+ {
+ Tree root = new Tree(db);
+ Tree A = root.addTree("A");
+ FileTreeEntry B = root.addFile("B");
+ B.setId(bId);
+
+ Tree A_A = A.addTree("A");
+ Tree A_B = A.addTree("B");
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ A_A.setId(ow.writeTree(A_A));
+ A_B.setId(ow.writeTree(A_B));
+ A.setId(ow.writeTree(A));
+ root.setId(ow.writeTree(root));
+
+ tree_root = rw.parseTree(root.getId());
+ tree_A = rw.parseTree(A.getId());
+ tree_AB = rw.parseTree(A_A.getId());
+ assertSame(tree_AB, rw.parseTree(A_B.getId()));
+ b = commit(rw.parseTree(root.getId()));
+ }
+
+ markStart(b);
+
+ assertCommit(b, objw.next());
+ assertNull(objw.next());
+
+ assertSame(tree_root, objw.nextObject());
+ assertSame(tree_A, objw.nextObject());
+ assertSame(tree_AB, objw.nextObject());
+ assertSame(rw.lookupBlob(bId), objw.nextObject());
+ assertNull(objw.nextObject());
+ }
}
private RevTree currentTree;
- private boolean fromTreeWalk;
-
- private RevTree nextSubtree;
+ private RevObject last;
/**
* Create a new revision and object walker for a given repository.
*/
public RevObject nextObject() throws MissingObjectException,
IncorrectObjectTypeException, IOException {
- fromTreeWalk = false;
-
- if (nextSubtree != null) {
- treeWalk = treeWalk.createSubtreeIterator0(db, nextSubtree, curs);
- nextSubtree = null;
- }
+ if (last != null)
+ treeWalk = last instanceof RevTree ? enter(last) : treeWalk.next();
while (!treeWalk.eof()) {
final FileMode mode = treeWalk.getEntryFileMode();
- final int sType = mode.getObjectType();
-
- switch (sType) {
+ switch (mode.getObjectType()) {
case Constants.OBJ_BLOB: {
treeWalk.getEntryObjectId(idBuffer);
final RevBlob o = lookupBlob(idBuffer);
o.flags |= SEEN;
if (shouldSkipObject(o))
break;
- fromTreeWalk = true;
+ last = o;
return o;
}
case Constants.OBJ_TREE: {
o.flags |= SEEN;
if (shouldSkipObject(o))
break;
- nextSubtree = o;
- fromTreeWalk = true;
+ last = o;
return o;
}
default:
treeWalk = treeWalk.next();
}
+ last = null;
for (;;) {
final RevObject o = pendingObjects.next();
if (o == null)
}
}
+ private CanonicalTreeParser enter(RevObject tree) throws IOException {
+ CanonicalTreeParser p = treeWalk.createSubtreeIterator0(db, tree, curs);
+ if (p.eof()) {
+ // We can't tolerate the subtree being an empty tree, as
+ // that will break us out early before we visit all names.
+ // If it is, advance to the parent's next record.
+ //
+ return treeWalk.next();
+ }
+ return p;
+ }
+
private final boolean shouldSkipObject(final RevObject o) {
return (o.flags & UNINTERESTING) != 0 && !hasRevSort(RevSort.BOUNDARY);
}
* has no path, such as for annotated tags or root level trees.
*/
public String getPathString() {
- return fromTreeWalk ? treeWalk.getEntryPathString() : null;
+ return last != null ? treeWalk.getEntryPathString() : null;
}
@Override
super.dispose();
pendingObjects = new BlockObjQueue();
treeWalk = new CanonicalTreeParser();
- nextSubtree = null;
currentTree = null;
+ last = null;
}
@Override
super.reset(retainFlags);
pendingObjects = new BlockObjQueue();
treeWalk = new CanonicalTreeParser();
- nextSubtree = null;
+ currentTree = null;
+ last = null;
}
private void addObject(final RevObject o) {