Browse Source

Add an attribute accessor to CanonicalTreeParser and use it in Treewalk

When checking out a branch we need to access the attributes stored
in the tree to be checked out. E.g. directly after a clone we checkout
the remote HEAD. In this case index and workingtree are still empty.
So we have to search the tree to be checked out for attributes.

Change-Id: I6d96f5d095ed2e3c259d4b12124e404f5215bd9f
stable-4.3
Christian Halstrick 9 years ago committed by Matthias Sohn
parent
commit
6389948a81
  1. 14
      org.eclipse.jgit/.settings/.api_filters
  2. 3
      org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java
  3. 8
      org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java
  4. 61
      org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java
  5. 53
      org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
  6. 59
      org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java

14
org.eclipse.jgit/.settings/.api_filters

@ -49,6 +49,20 @@
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java" type="org.eclipse.jgit.treewalk.WorkingTreeIterator">
<filter comment="attributes weren't really usable in earlier versions" id="338792546">
<message_arguments>
<message_argument value="org.eclipse.jgit.treewalk.WorkingTreeIterator"/>
<message_argument value="getGlobalAttributesNode()"/>
</message_arguments>
</filter>
<filter comment="attributes weren't really usable in earlier versions" id="338792546">
<message_arguments>
<message_argument value="org.eclipse.jgit.treewalk.WorkingTreeIterator"/>
<message_argument value="getInfoAttributesNode()"/>
</message_arguments>
</filter>
</resource>
<resource path="src/org/eclipse/jgit/util/FileUtils.java" type="org.eclipse.jgit.util.FileUtils">
<filter id="338792546">
<message_arguments>

3
org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheIterator.java vendored

@ -103,9 +103,6 @@ public class DirCacheIterator extends AbstractTreeIterator {
/** The subtree containing {@link #currentEntry} if this is first entry. */
protected DirCacheTree currentSubtree;
/** Holds an {@link AttributesNode} for the current entry */
private AttributesNode attributesNode;
/**
* Create a new iterator for an already loaded DirCache instance.
* <p>

8
org.eclipse.jgit/src/org/eclipse/jgit/treewalk/AbstractTreeIterator.java

@ -49,6 +49,7 @@ import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import org.eclipse.jgit.attributes.AttributesNode;
import org.eclipse.jgit.dircache.DirCacheCheckout;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@ -92,6 +93,13 @@ public abstract class AbstractTreeIterator {
/** The iterator this current entry is path equal to. */
AbstractTreeIterator matches;
/**
* Parsed rules of .gitattributes file if it exists.
*
* @since 4.2
*/
protected AttributesNode attributesNode;
/**
* Number of entries we moved forward to force a D/F conflict match.
*

61
org.eclipse.jgit/src/org/eclipse/jgit/treewalk/CanonicalTreeParser.java

@ -45,8 +45,12 @@
package org.eclipse.jgit.treewalk;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Collections;
import org.eclipse.jgit.attributes.AttributesNode;
import org.eclipse.jgit.attributes.AttributesRule;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.lib.AnyObjectId;
@ -54,10 +58,15 @@ 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 int ATTRIBUTESLENGTH = Constants.DOT_GIT_ATTRIBUTES
.getBytes().length;
private static final byte[] EMPTY = {};
private byte[] raw;
@ -364,5 +373,57 @@ public class CanonicalTreeParser extends AbstractTreeIterator {
}
pathLen = tmp;
nextPtr = ptr + Constants.OBJECT_ID_LENGTH;
// Check if this entry is a .gitattributes file
if (RawParseUtils.match(path, pathOffset,
Constants.DOT_GIT_ATTRIBUTES.getBytes()) == ATTRIBUTESLENGTH)
attributesNode = new LazyLoadingAttributesNode(
ObjectId.fromRaw(idBuffer(), idOffset()));
}
/**
* Retrieve the {@link AttributesNode} for the current entry.
*
* @param reader
* {@link ObjectReader} used to parse the .gitattributes entry.
* @return {@link AttributesNode} for the current entry.
* @throws IOException
* @since 4.2
*/
public AttributesNode getEntryAttributesNode(ObjectReader reader)
throws IOException {
if (attributesNode instanceof LazyLoadingAttributesNode)
attributesNode = ((LazyLoadingAttributesNode) attributesNode)
.load(reader);
return attributesNode;
}
/**
* {@link AttributesNode} implementation that provides lazy loading
*/
private static class LazyLoadingAttributesNode extends AttributesNode {
final ObjectId objectId;
LazyLoadingAttributesNode(ObjectId objectId) {
super(Collections.<AttributesRule> emptyList());
this.objectId = objectId;
}
AttributesNode load(ObjectReader reader) throws IOException {
AttributesNode r = new AttributesNode();
ObjectLoader loader = reader.open(objectId);
if (loader != null) {
InputStream in = loader.openStream();
try {
r.parse(in);
} finally {
in.close();
}
}
return r.getRules().isEmpty() ? null : r;
}
}
}

53
org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java

@ -50,6 +50,7 @@ import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.annotations.Nullable;
import org.eclipse.jgit.api.errors.JGitInternalException;
import org.eclipse.jgit.attributes.Attribute;
import org.eclipse.jgit.attributes.AttributesNode;
@ -1131,8 +1132,10 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
WorkingTreeIterator workingTreeIterator = getTree(WorkingTreeIterator.class);
DirCacheIterator dirCacheIterator = getTree(DirCacheIterator.class);
CanonicalTreeParser other = getTree(CanonicalTreeParser.class);
if (workingTreeIterator == null && dirCacheIterator == null) {
if (workingTreeIterator == null && dirCacheIterator == null
&& other == null) {
// Can not retrieve the attributes without at least one of the above
// iterators.
return Collections.<String, Attribute> emptyMap();
@ -1152,7 +1155,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
// Gets the attributes located on the current entry path
getPerDirectoryEntryAttributes(path, isDir, operationType,
workingTreeIterator, dirCacheIterator,
workingTreeIterator, dirCacheIterator, other,
attributes);
// Gets the attributes located in the global attribute file
@ -1180,6 +1183,8 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
* a {@link WorkingTreeIterator} matching the current entry
* @param dirCacheIterator
* a {@link DirCacheIterator} matching the current entry
* @param other
* a {@link CanonicalTreeParser} matching the current entry
* @param attributes
* Non null map holding the existing attributes. This map will be
* augmented with new entry. None entry will be overrided.
@ -1189,18 +1194,21 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
*/
private void getPerDirectoryEntryAttributes(String path, boolean isDir,
OperationType opType, WorkingTreeIterator workingTreeIterator,
DirCacheIterator dirCacheIterator, Map<String, Attribute> attributes)
DirCacheIterator dirCacheIterator, CanonicalTreeParser other,
Map<String, Attribute> attributes)
throws IOException {
// Prevents infinite recurrence
if (workingTreeIterator != null || dirCacheIterator != null) {
if (workingTreeIterator != null || dirCacheIterator != null
|| other != null) {
AttributesNode currentAttributesNode = getCurrentAttributesNode(
opType, workingTreeIterator, dirCacheIterator);
opType, workingTreeIterator, dirCacheIterator, other);
if (currentAttributesNode != null) {
currentAttributesNode.getAttributes(path, isDir, attributes);
}
getPerDirectoryEntryAttributes(path, isDir, opType,
getParent(workingTreeIterator, WorkingTreeIterator.class),
getParent(dirCacheIterator, DirCacheIterator.class),
getParent(other, CanonicalTreeParser.class),
attributes);
}
}
@ -1236,6 +1244,7 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
* @param opType
* @param workingTreeIterator
* @param dirCacheIterator
* @param other
* @return a {@link AttributesNode} of the current entry,
* {@link NullPointerException} otherwise.
* @throws IOException
@ -1243,8 +1252,10 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
* parsing one on the attributes file.
*/
private AttributesNode getCurrentAttributesNode(OperationType opType,
WorkingTreeIterator workingTreeIterator,
DirCacheIterator dirCacheIterator) throws IOException {
@Nullable WorkingTreeIterator workingTreeIterator,
@Nullable DirCacheIterator dirCacheIterator,
@Nullable CanonicalTreeParser other)
throws IOException {
AttributesNode attributesNode = null;
switch (opType) {
case CHECKIN_OP:
@ -1252,17 +1263,30 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
attributesNode = workingTreeIterator.getEntryAttributesNode();
}
if (attributesNode == null && dirCacheIterator != null) {
attributesNode = dirCacheIterator
.getEntryAttributesNode(getObjectReader());
attributesNode = getAttributesNode(dirCacheIterator
.getEntryAttributesNode(getObjectReader()),
attributesNode);
}
if (attributesNode == null && other != null) {
attributesNode = getAttributesNode(
other.getEntryAttributesNode(getObjectReader()),
attributesNode);
}
break;
case CHECKOUT_OP:
if (dirCacheIterator != null) {
attributesNode = dirCacheIterator
if (other != null) {
attributesNode = other
.getEntryAttributesNode(getObjectReader());
}
if (dirCacheIterator != null) {
attributesNode = getAttributesNode(dirCacheIterator
.getEntryAttributesNode(getObjectReader()),
attributesNode);
}
if (attributesNode == null && workingTreeIterator != null) {
attributesNode = workingTreeIterator.getEntryAttributesNode();
attributesNode = getAttributesNode(
workingTreeIterator.getEntryAttributesNode(),
attributesNode);
}
break;
default:
@ -1274,4 +1298,9 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
return attributesNode;
}
private static AttributesNode getAttributesNode(AttributesNode value,
AttributesNode defaultValue) {
return (value == null) ? defaultValue : value;
}
}

59
org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java

@ -74,8 +74,6 @@ import org.eclipse.jgit.errors.NoWorkTreeException;
import org.eclipse.jgit.ignore.FastIgnoreRule;
import org.eclipse.jgit.ignore.IgnoreNode;
import org.eclipse.jgit.internal.JGitText;
import org.eclipse.jgit.internal.storage.file.GlobalAttributesNode;
import org.eclipse.jgit.internal.storage.file.InfoAttributesNode;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.CoreConfig;
import org.eclipse.jgit.lib.CoreConfig.CheckStat;
@ -136,9 +134,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
/** If there is a .gitignore file present, the parsed rules from it. */
private IgnoreNode ignoreNode;
/** If there is a .gitattributes file present, the parsed rules from it. */
private AttributesNode attributesNode;
/** Repository that is the root level being iterated over */
protected Repository repository;
@ -148,19 +143,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
/** The offset of the content id in {@link #idBuffer()} */
private int contentIdOffset;
/**
* Holds the {@link AttributesNode} that is stored in
* $GIT_DIR/info/attributes file.
*/
private AttributesNode infoAttributesNode;
/**
* Holds the {@link AttributesNode} that is stored in global attribute file.
*
* @see CoreConfig#getAttributesFile()
*/
private AttributesNode globalAttributesNode;
/**
* Create a new iterator with no parent.
*
@ -204,8 +186,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
protected WorkingTreeIterator(final WorkingTreeIterator p) {
super(p);
state = p.state;
infoAttributesNode = p.infoAttributesNode;
globalAttributesNode = p.globalAttributesNode;
}
/**
@ -225,10 +205,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
else
entry = null;
ignoreNode = new RootIgnoreNode(entry, repo);
infoAttributesNode = new InfoAttributesNode(repo);
globalAttributesNode = new GlobalAttributesNode(repo);
}
/**
@ -669,41 +645,6 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
return attributesNode;
}
/**
* Retrieves the {@link AttributesNode} that holds the information located
* in $GIT_DIR/info/attributes file.
*
* @return the {@link AttributesNode} that holds the information located in
* $GIT_DIR/info/attributes file.
* @throws IOException
* if an error is raised while parsing the attributes file
* @since 3.7
*/
public AttributesNode getInfoAttributesNode() throws IOException {
if (infoAttributesNode instanceof InfoAttributesNode)
infoAttributesNode = ((InfoAttributesNode) infoAttributesNode).load();
return infoAttributesNode;
}
/**
* Retrieves the {@link AttributesNode} that holds the information located
* in system-wide file.
*
* @return the {@link AttributesNode} that holds the information located in
* system-wide file.
* @throws IOException
* IOException if an error is raised while parsing the
* attributes file
* @see CoreConfig#getAttributesFile()
* @since 3.7
*/
public AttributesNode getGlobalAttributesNode() throws IOException {
if (globalAttributesNode instanceof GlobalAttributesNode)
globalAttributesNode = ((GlobalAttributesNode) globalAttributesNode)
.load();
return globalAttributesNode;
}
private static final Comparator<Entry> ENTRY_CMP = new Comparator<Entry>() {
public int compare(final Entry o1, final Entry o2) {
final byte[] a = o1.encodedName;

Loading…
Cancel
Save