package org.eclipse.jgit.notes;
+import java.io.IOException;
+
import org.eclipse.jgit.junit.TestRepository;
+import org.eclipse.jgit.lib.CommitBuilder;
import org.eclipse.jgit.lib.MutableObjectId;
import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.RepositoryTestCase;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevTree;
+import org.eclipse.jgit.treewalk.TreeWalk;
import org.eclipse.jgit.util.RawParseUtils;
public class NoteMapTest extends RepositoryTestCase {
assertEquals(exp, RawParseUtils.decode(act));
}
+ public void testWriteUnchangedFlat() throws Exception {
+ RevBlob a = tr.blob("a");
+ RevBlob b = tr.blob("b");
+ RevBlob data1 = tr.blob("data1");
+ RevBlob data2 = tr.blob("data2");
+
+ RevCommit r = tr.commit() //
+ .add(a.name(), data1) //
+ .add(b.name(), data2) //
+ .add(".gitignore", "") //
+ .add("zoo-animals.txt", "") //
+ .create();
+ tr.parseBody(r);
+
+ NoteMap map = NoteMap.read(reader, r);
+ assertTrue("has note for a", map.contains(a));
+ assertTrue("has note for b", map.contains(b));
+
+ RevCommit n = commitNoteMap(map);
+ assertNotSame("is new commit", r, n);
+ assertSame("same tree", r.getTree(), n.getTree());
+ }
+
+ public void testWriteUnchangedFanout2_38() throws Exception {
+ RevBlob a = tr.blob("a");
+ RevBlob b = tr.blob("b");
+ RevBlob data1 = tr.blob("data1");
+ RevBlob data2 = tr.blob("data2");
+
+ RevCommit r = tr.commit() //
+ .add(fanout(2, a.name()), data1) //
+ .add(fanout(2, b.name()), data2) //
+ .add(".gitignore", "") //
+ .add("zoo-animals.txt", "") //
+ .create();
+ tr.parseBody(r);
+
+ NoteMap map = NoteMap.read(reader, r);
+ assertTrue("has note for a", map.contains(a));
+ assertTrue("has note for b", map.contains(b));
+
+ // This is a non-lazy map, so we'll be looking at the leaf buckets.
+ RevCommit n = commitNoteMap(map);
+ assertNotSame("is new commit", r, n);
+ assertSame("same tree", r.getTree(), n.getTree());
+
+ // Use a lazy-map for the next round of the same test.
+ map = NoteMap.read(reader, r);
+ n = commitNoteMap(map);
+ assertNotSame("is new commit", r, n);
+ assertSame("same tree", r.getTree(), n.getTree());
+ }
+
public void testCreateFromEmpty() throws Exception {
RevBlob a = tr.blob("a");
RevBlob b = tr.blob("b");
RevCommit r = tr.commit() //
.add(a.name(), data1) //
.add(b.name(), data2) //
+ .add(".gitignore", "") //
+ .add("zoo-animals.txt", b) //
.create();
tr.parseBody(r);
id.setByte(1, p);
assertTrue("contains " + id, map.contains(id));
}
+
+ RevCommit n = commitNoteMap(map);
+ map = NoteMap.read(reader, n);
+ assertEquals(data2, map.get(a));
+ assertEquals(b, map.get(data1));
+ assertFalse("no b", map.contains(b));
+ assertFalse("no data2", map.contains(data2));
+ assertEquals(b, TreeWalk
+ .forPath(reader, "zoo-animals.txt", n.getTree()).getObjectId(0));
}
public void testEditFanout2_38() throws Exception {
RevCommit r = tr.commit() //
.add(fanout(2, a.name()), data1) //
.add(fanout(2, b.name()), data2) //
+ .add(".gitignore", "") //
+ .add("zoo-animals.txt", b) //
.create();
tr.parseBody(r);
assertEquals(b, map.get(data1));
assertFalse("no b", map.contains(b));
assertFalse("no data2", map.contains(data2));
+ RevCommit n = commitNoteMap(map);
map.set(a, null);
map.set(data1, null);
assertFalse("no a", map.contains(a));
assertFalse("no data1", map.contains(data1));
+
+ map = NoteMap.read(reader, n);
+ assertEquals(data2, map.get(a));
+ assertEquals(b, map.get(data1));
+ assertFalse("no b", map.contains(b));
+ assertFalse("no data2", map.contains(data2));
+ assertEquals(b, TreeWalk
+ .forPath(reader, "zoo-animals.txt", n.getTree()).getObjectId(0));
+ }
+
+ public void testRemoveDeletesTreeFanout2_38() throws Exception {
+ RevBlob a = tr.blob("a");
+ RevBlob data1 = tr.blob("data1");
+ RevTree empty = tr.tree();
+
+ RevCommit r = tr.commit() //
+ .add(fanout(2, a.name()), data1) //
+ .create();
+ tr.parseBody(r);
+
+ NoteMap map = NoteMap.read(reader, r);
+ map.set(a, null);
+
+ RevCommit n = commitNoteMap(map);
+ assertEquals("empty tree", empty, n.getTree());
+ }
+
+ private RevCommit commitNoteMap(NoteMap map) throws IOException {
+ tr.tick(600);
+
+ CommitBuilder builder = new CommitBuilder();
+ builder.setTreeId(map.writeTree(inserter));
+ tr.setAuthorAndCommitter(builder);
+ return tr.getRevWalk().parseCommit(inserter.insert(builder));
}
private static String fanout(int prefix, String name) {
package org.eclipse.jgit.notes;
+import static org.eclipse.jgit.lib.FileMode.TREE;
+
import java.io.IOException;
import org.eclipse.jgit.lib.AbbreviatedObjectId;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.TreeFormatter;
/**
* A note tree holding only note subtrees, each named using a 2 digit hex name.
}
}
+ private static final byte[] hexchar = { '0', '1', '2', '3', '4', '5', '6',
+ '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
+
+ @Override
+ ObjectId writeTree(ObjectInserter inserter) throws IOException {
+ byte[] nameBuf = new byte[2];
+ TreeFormatter fmt = new TreeFormatter(treeSize());
+ NonNoteEntry e = nonNotes;
+
+ for (int cell = 0; cell < 256; cell++) {
+ NoteBucket b = table[cell];
+ if (b == null)
+ continue;
+
+ nameBuf[0] = hexchar[cell >>> 4];
+ nameBuf[1] = hexchar[cell & 0x0f];
+
+ while (e != null && e.pathCompare(nameBuf, 0, 2, TREE) < 0) {
+ e.format(fmt);
+ e = e.next;
+ }
+
+ fmt.append(nameBuf, 0, 2, TREE, b.writeTree(inserter));
+ }
+
+ for (; e != null; e = e.next)
+ e.format(fmt);
+ return fmt.insert(inserter);
+ }
+
+ private int treeSize() {
+ int sz = cnt * TreeFormatter.entrySize(TREE, 2);
+ for (NonNoteEntry e = nonNotes; e != null; e = e.next)
+ sz += e.treeEntrySize();
+ return sz;
+ }
+
private int cell(AnyObjectId id) {
return id.getByte(prefixLen >> 1);
}
return load(noteOn, or).set(noteOn, noteData, or);
}
+ @Override
+ ObjectId writeTree(ObjectInserter inserter) {
+ return treeId;
+ }
+
private NoteBucket load(AnyObjectId objId, ObjectReader or)
throws IOException {
AbbreviatedObjectId p = objId.abbreviate(prefixLen + 2);
package org.eclipse.jgit.notes;
+import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
+import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
+
import java.io.IOException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.TreeFormatter;
/**
* A note tree holding only notes, with no subtrees.
}
}
+ @Override
+ ObjectId writeTree(ObjectInserter inserter) throws IOException {
+ byte[] nameBuf = new byte[OBJECT_ID_STRING_LENGTH];
+ int nameLen = OBJECT_ID_STRING_LENGTH - prefixLen;
+ TreeFormatter fmt = new TreeFormatter(treeSize(nameLen));
+ NonNoteEntry e = nonNotes;
+
+ for (int i = 0; i < cnt; i++) {
+ Note n = notes[i];
+
+ n.copyTo(nameBuf, 0);
+
+ while (e != null
+ && e.pathCompare(nameBuf, prefixLen, nameLen, REGULAR_FILE) < 0) {
+ e.format(fmt);
+ e = e.next;
+ }
+
+ fmt.append(nameBuf, prefixLen, nameLen, REGULAR_FILE, n.getData());
+ }
+
+ for (; e != null; e = e.next)
+ e.format(fmt);
+ return fmt.insert(inserter);
+ }
+
+ private int treeSize(final int nameLen) {
+ int sz = cnt * TreeFormatter.entrySize(REGULAR_FILE, nameLen);
+ for (NonNoteEntry e = nonNotes; e != null; e = e.next)
+ sz += e.treeEntrySize();
+ return sz;
+ }
+
void parseOneEntry(AnyObjectId noteOn, AnyObjectId noteData) {
growIfFull();
notes[cnt++] = new Note(noteOn, noteData.copy());