diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/InMemoryNoteBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/InMemoryNoteBucket.java index 7d0df73cb..4630f9b0f 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/InMemoryNoteBucket.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/InMemoryNoteBucket.java @@ -54,6 +54,17 @@ abstract class InMemoryNoteBucket extends NoteBucket { */ final int prefixLen; + /** + * Chain of non-note tree entries found at this path in the tree. + * + * During parsing of a note tree into the in-memory representation, + * {@link NoteParser} keeps track of all non-note tree entries and stores + * them here as a sorted linked list. That list can be merged back with the + * note data that is held by the subclass, allowing the tree to be + * recreated. + */ + NonNoteEntry nonNotes; + InMemoryNoteBucket(int prefixLen) { this.prefixLen = prefixLen; } diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NonNoteEntry.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NonNoteEntry.java new file mode 100644 index 000000000..20fd3a88a --- /dev/null +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NonNoteEntry.java @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2010, Google Inc. + * and other copyright owners as documented in the project's IP log. + * + * This program and the accompanying materials are made available + * under the terms of the Eclipse Distribution License v1.0 which + * accompanies this distribution, is reproduced below, and is + * available at http://www.eclipse.org/org/documents/edl-v10.php + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following + * conditions are met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * + * - Neither the name of the Eclipse Foundation, Inc. nor the + * names of its contributors may be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.eclipse.jgit.notes; + +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.TreeFormatter; + +/** A tree entry found in a note branch that isn't a valid note. */ +class NonNoteEntry extends ObjectId { + /** Name of the entry in the tree, in raw format. */ + private final byte[] name; + + /** Mode of the entry as parsed from the tree. */ + private final FileMode mode; + + /** The next non-note entry in the same tree, as defined by tree order. */ + NonNoteEntry next; + + NonNoteEntry(byte[] name, FileMode mode, AnyObjectId id) { + super(id); + this.name = name; + this.mode = mode; + } + + void format(TreeFormatter fmt) { + fmt.append(name, mode, this); + } +} diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java index 04e260ac3..d916e351b 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/NoteParser.java @@ -52,6 +52,7 @@ import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.lib.AbbreviatedObjectId; +import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.MutableObjectId; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.ObjectReader; @@ -87,13 +88,17 @@ final class NoteParser extends CanonicalTreeParser { static InMemoryNoteBucket parse(AbbreviatedObjectId prefix, final ObjectId treeId, final ObjectReader reader) throws IOException { - return new NoteParser(prefix, reader, treeId).parseTree(); + return new NoteParser(prefix, reader, treeId).parse(); } private final AbbreviatedObjectId prefix; private final int pathPadding; + private NonNoteEntry firstNonNote; + + private NonNoteEntry lastNonNote; + private NoteParser(AbbreviatedObjectId p, ObjectReader r, ObjectId t) throws IncorrectObjectTypeException, IOException { super(encodeASCII(p.name()), r, t); @@ -106,6 +111,12 @@ private NoteParser(AbbreviatedObjectId p, ObjectReader r, ObjectId t) System.arraycopy(path, 0, path, pathPadding, prefix.length()); } + private InMemoryNoteBucket parse() { + InMemoryNoteBucket r = parseTree(); + r.nonNotes = firstNonNote; + return r; + } + private InMemoryNoteBucket parseTree() { for (; !eof(); next(1)) { if (pathLen == pathPadding + OBJECT_ID_STRING_LENGTH && isHex()) @@ -113,6 +124,9 @@ private InMemoryNoteBucket parseTree() { else if (getNameLength() == 2 && isHex() && isTree()) return parseFanoutTree(); + + else + storeNonNote(); } // If we cannot determine the style used, assume its a leaf. @@ -126,6 +140,8 @@ private LeafBucket parseLeafTree() { for (; !eof(); next(1)) { if (parseObjectId(idBuf)) leaf.parseOneEntry(idBuf, getEntryObjectId()); + else + storeNonNote(); } return leaf; @@ -150,6 +166,8 @@ private FanoutBucket parseFanoutTree() { final int cell = parseFanoutCell(); if (0 <= cell) fanout.parseOneEntry(cell, getEntryObjectId()); + else + storeNonNote(); } return fanout; @@ -168,6 +186,21 @@ private int parseFanoutCell() { } } + private void storeNonNote() { + ObjectId id = getEntryObjectId(); + FileMode fileMode = getEntryFileMode(); + + byte[] name = new byte[getNameLength()]; + getName(name, 0); + + NonNoteEntry ent = new NonNoteEntry(name, fileMode, id); + if (firstNonNote == null) + firstNonNote = ent; + if (lastNonNote != null) + lastNonNote.next = ent; + lastNonNote = ent; + } + private boolean isTree() { return TREE.equals(mode); }