|
|
|
@ -44,6 +44,13 @@
|
|
|
|
|
|
|
|
|
|
package org.eclipse.jgit.treewalk; |
|
|
|
|
|
|
|
|
|
import static org.eclipse.jgit.lib.Constants.DOT_GIT_ATTRIBUTES; |
|
|
|
|
import static org.eclipse.jgit.lib.Constants.OBJECT_ID_LENGTH; |
|
|
|
|
import static org.eclipse.jgit.lib.Constants.OBJ_BLOB; |
|
|
|
|
import static org.eclipse.jgit.lib.Constants.OBJ_TREE; |
|
|
|
|
import static org.eclipse.jgit.lib.Constants.TYPE_TREE; |
|
|
|
|
import static org.eclipse.jgit.lib.Constants.encode; |
|
|
|
|
|
|
|
|
|
import java.io.IOException; |
|
|
|
|
import java.io.InputStream; |
|
|
|
|
import java.util.Arrays; |
|
|
|
@ -54,20 +61,15 @@ import org.eclipse.jgit.attributes.AttributesRule;
|
|
|
|
|
import org.eclipse.jgit.errors.IncorrectObjectTypeException; |
|
|
|
|
import org.eclipse.jgit.errors.MissingObjectException; |
|
|
|
|
import org.eclipse.jgit.lib.AnyObjectId; |
|
|
|
|
import org.eclipse.jgit.lib.Constants; |
|
|
|
|
import org.eclipse.jgit.lib.FileMode; |
|
|
|
|
import org.eclipse.jgit.lib.MutableObjectId; |
|
|
|
|
import org.eclipse.jgit.lib.ObjectId; |
|
|
|
|
import org.eclipse.jgit.lib.ObjectLoader; |
|
|
|
|
import org.eclipse.jgit.lib.ObjectReader; |
|
|
|
|
import org.eclipse.jgit.util.RawParseUtils; |
|
|
|
|
|
|
|
|
|
/** Parses raw Git trees from the canonical semi-text/semi-binary format. */ |
|
|
|
|
public class CanonicalTreeParser extends AbstractTreeIterator { |
|
|
|
|
private static final byte[] EMPTY = {}; |
|
|
|
|
|
|
|
|
|
private static final byte[] ATTRS = Constants |
|
|
|
|
.encode(Constants.DOT_GIT_ATTRIBUTES); |
|
|
|
|
private static final byte[] ATTRS = encode(DOT_GIT_ATTRIBUTES); |
|
|
|
|
|
|
|
|
|
private byte[] raw; |
|
|
|
|
|
|
|
|
@ -133,6 +135,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
|
|
|
|
|
* the raw tree content. |
|
|
|
|
*/ |
|
|
|
|
public void reset(final byte[] treeData) { |
|
|
|
|
attributesNode = null; |
|
|
|
|
raw = treeData; |
|
|
|
|
prevPtr = -1; |
|
|
|
|
currPtr = 0; |
|
|
|
@ -208,7 +211,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
|
|
|
|
|
*/ |
|
|
|
|
public void reset(final ObjectReader reader, final AnyObjectId id) |
|
|
|
|
throws IncorrectObjectTypeException, IOException { |
|
|
|
|
reset(reader.open(id, Constants.OBJ_TREE).getCachedBytes()); |
|
|
|
|
reset(reader.open(id, OBJ_TREE).getCachedBytes()); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@ -218,7 +221,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
|
|
|
|
|
idBuffer.fromRaw(idBuffer(), idOffset()); |
|
|
|
|
if (!FileMode.TREE.equals(mode)) { |
|
|
|
|
final ObjectId me = idBuffer.toObjectId(); |
|
|
|
|
throw new IncorrectObjectTypeException(me, Constants.TYPE_TREE); |
|
|
|
|
throw new IncorrectObjectTypeException(me, TYPE_TREE); |
|
|
|
|
} |
|
|
|
|
return createSubtreeIterator0(reader, idBuffer); |
|
|
|
|
} |
|
|
|
@ -263,7 +266,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public int idOffset() { |
|
|
|
|
return nextPtr - Constants.OBJECT_ID_LENGTH; |
|
|
|
|
return nextPtr - OBJECT_ID_LENGTH; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@ -301,7 +304,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
|
|
|
|
|
prevPtr = ptr; |
|
|
|
|
while (raw[ptr] != 0) |
|
|
|
|
ptr++; |
|
|
|
|
ptr += Constants.OBJECT_ID_LENGTH + 1; |
|
|
|
|
ptr += OBJECT_ID_LENGTH + 1; |
|
|
|
|
} |
|
|
|
|
if (delta != 0) |
|
|
|
|
throw new ArrayIndexOutOfBoundsException(delta); |
|
|
|
@ -337,7 +340,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
|
|
|
|
|
trace[delta] = ptr; |
|
|
|
|
while (raw[ptr] != 0) |
|
|
|
|
ptr++; |
|
|
|
|
ptr += Constants.OBJECT_ID_LENGTH + 1; |
|
|
|
|
ptr += OBJECT_ID_LENGTH + 1; |
|
|
|
|
} |
|
|
|
|
if (trace[1] == -1) |
|
|
|
|
throw new ArrayIndexOutOfBoundsException(delta); |
|
|
|
@ -372,12 +375,7 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
pathLen = tmp; |
|
|
|
|
nextPtr = ptr + Constants.OBJECT_ID_LENGTH; |
|
|
|
|
|
|
|
|
|
// Check if this entry is a .gitattributes file
|
|
|
|
|
if (path[pathOffset] == '.' |
|
|
|
|
&& RawParseUtils.match(path, pathOffset, ATTRS) > 0) |
|
|
|
|
attributesNode = new LazyLoadingAttributesNode(idOffset()); |
|
|
|
|
nextPtr = ptr + OBJECT_ID_LENGTH; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
@ -391,36 +389,32 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
|
|
|
|
|
*/ |
|
|
|
|
public AttributesNode getEntryAttributesNode(ObjectReader reader) |
|
|
|
|
throws IOException { |
|
|
|
|
if (attributesNode instanceof LazyLoadingAttributesNode) |
|
|
|
|
attributesNode = ((LazyLoadingAttributesNode) attributesNode) |
|
|
|
|
.load(reader); |
|
|
|
|
return attributesNode; |
|
|
|
|
if (attributesNode == null) { |
|
|
|
|
attributesNode = findAttributes(reader); |
|
|
|
|
} |
|
|
|
|
return attributesNode.getRules().isEmpty() ? null : attributesNode; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* {@link AttributesNode} implementation that provides lazy loading |
|
|
|
|
*/ |
|
|
|
|
private class LazyLoadingAttributesNode extends AttributesNode { |
|
|
|
|
private final int idOffset; |
|
|
|
|
|
|
|
|
|
LazyLoadingAttributesNode(int idOffset) { |
|
|
|
|
super(Collections.<AttributesRule> emptyList()); |
|
|
|
|
this.idOffset = idOffset; |
|
|
|
|
private AttributesNode findAttributes(ObjectReader reader) |
|
|
|
|
throws IOException { |
|
|
|
|
CanonicalTreeParser itr = new CanonicalTreeParser(); |
|
|
|
|
itr.reset(raw); |
|
|
|
|
if (itr.findFile(ATTRS)) { |
|
|
|
|
return loadAttributes(reader, itr.getEntryObjectId()); |
|
|
|
|
} |
|
|
|
|
return noAttributes(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
AttributesNode load(ObjectReader reader) throws IOException { |
|
|
|
|
AttributesNode r = new AttributesNode(); |
|
|
|
|
ObjectId id = ObjectId.fromRaw(raw, idOffset); |
|
|
|
|
ObjectLoader loader = reader.open(id); |
|
|
|
|
if (loader != null) { |
|
|
|
|
InputStream in = loader.openStream(); |
|
|
|
|
try { |
|
|
|
|
r.parse(in); |
|
|
|
|
} finally { |
|
|
|
|
in.close(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
return r.getRules().isEmpty() ? null : r; |
|
|
|
|
private static AttributesNode loadAttributes(ObjectReader reader, |
|
|
|
|
AnyObjectId id) throws IOException { |
|
|
|
|
AttributesNode r = new AttributesNode(); |
|
|
|
|
try (InputStream in = reader.open(id, OBJ_BLOB).openStream()) { |
|
|
|
|
r.parse(in); |
|
|
|
|
} |
|
|
|
|
return r.getRules().isEmpty() ? noAttributes() : r; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static AttributesNode noAttributes() { |
|
|
|
|
return new AttributesNode(Collections.<AttributesRule> emptyList()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|