aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
diff options
context:
space:
mode:
authorIvan Motsch <ivan.motsch@bsiag.com>2015-11-17 16:04:01 +0100
committerChristian Halstrick <christian.halstrick@sap.com>2016-02-11 17:08:49 +0100
commit975aa8868591ea49e3d8033a0fe224c09e67aec9 (patch)
treedba3cd80359bd820a4dda4e334a7871befd3836a /org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
parent28e2fed761f0ddf01029c999b299ed0bccdf630e (diff)
downloadjgit-975aa8868591ea49e3d8033a0fe224c09e67aec9.tar.gz
jgit-975aa8868591ea49e3d8033a0fe224c09e67aec9.zip
Add Attribute Macro Expansion
Attributes MacroExpander implements macros used in git attributes. This is implemented inside the TreeWalk using a lazy created MacroExpander. In addition, the macro expander caches the global and info attributes node in order to provide fast merge of attributes. Change-Id: I2e69c9fc84e9d7fb8df0a05817d688fc456d8f00 Signed-off-by: Ivan Motsch <ivan.motsch@bsiag.com>
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java322
1 files changed, 101 insertions, 221 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index 5cd713da78..4775e96175 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -49,15 +49,13 @@ import java.util.HashMap;
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.Attribute.State;
import org.eclipse.jgit.attributes.Attributes;
-import org.eclipse.jgit.attributes.AttributesNode;
import org.eclipse.jgit.attributes.AttributesNodeProvider;
import org.eclipse.jgit.attributes.AttributesProvider;
import org.eclipse.jgit.dircache.DirCacheBuildIterator;
+import org.eclipse.jgit.attributes.AttributesHandler;
import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.CorruptObjectException;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
@@ -270,6 +268,9 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
/** Cached attribute for the current entry */
private Attributes attrs = null;
+ /** Cached attributes handler */
+ private AttributesHandler attributesHandler;
+
private Config config;
/**
@@ -310,6 +311,14 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
}
/**
+ * @return the {@link OperationType}
+ * @since 4.3
+ */
+ public OperationType getOperationType() {
+ return operationType;
+ }
+
+ /**
* Release any resources used by this walker's reader.
* <p>
* A walker that has been released can be used again, but may need to be
@@ -435,9 +444,83 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
attributesNodeProvider = provider;
}
+ /**
+ * @return the {@link AttributesNodeProvider} for this {@link TreeWalk}.
+ * @since 4.3
+ */
+ public AttributesNodeProvider getAttributesNodeProvider() {
+ return attributesNodeProvider;
+ }
+
+ /**
+ * Retrieve the git attributes for the current entry.
+ *
+ * <h4>Git attribute computation</h4>
+ *
+ * <ul>
+ * <li>Get the attributes matching the current path entry from the info file
+ * (see {@link AttributesNodeProvider#getInfoAttributesNode()}).</li>
+ * <li>Completes the list of attributes using the .gitattributes files
+ * located on the current path (the further the directory that contains
+ * .gitattributes is from the path in question, the lower its precedence).
+ * For a checkin operation, it will look first on the working tree (if any).
+ * If there is no attributes file, it will fallback on the index. For a
+ * checkout operation, it will first use the index entry and then fallback
+ * on the working tree if none.</li>
+ * <li>In the end, completes the list of matching attributes using the
+ * global attribute file define in the configuration (see
+ * {@link AttributesNodeProvider#getGlobalAttributesNode()})</li>
+ *
+ * </ul>
+ *
+ *
+ * <h4>Iterator constraints</h4>
+ *
+ * <p>
+ * In order to have a correct list of attributes for the current entry, this
+ * {@link TreeWalk} requires to have at least one
+ * {@link AttributesNodeProvider} and a {@link DirCacheIterator} set up. An
+ * {@link AttributesNodeProvider} is used to retrieve the attributes from
+ * the info attributes file and the global attributes file. The
+ * {@link DirCacheIterator} is used to retrieve the .gitattributes files
+ * stored in the index. A {@link WorkingTreeIterator} can also be provided
+ * to access the local version of the .gitattributes files. If none is
+ * provided it will fallback on the {@link DirCacheIterator}.
+ * </p>
+ *
+ * @return a {@link Set} of {@link Attribute}s that match the current entry.
+ * @since 4.2
+ */
+ public Attributes getAttributes() {
+ if (attrs != null)
+ return attrs;
+
+ if (attributesNodeProvider == null) {
+ // The work tree should have a AttributesNodeProvider to be able to
+ // retrieve the info and global attributes node
+ throw new IllegalStateException(
+ "The tree walk should have one AttributesNodeProvider set in order to compute the git attributes."); //$NON-NLS-1$
+ }
+
+ try {
+ // Lazy create the attributesHandler on the first access of
+ // attributes. This requires the info, global and root
+ // attributes nodes
+ if (attributesHandler == null) {
+ attributesHandler = new AttributesHandler(this);
+ }
+ attrs = attributesHandler.getAttributes();
+ return attrs;
+ } catch (IOException e) {
+ throw new JGitInternalException("Error while parsing attributes", //$NON-NLS-1$
+ e);
+ }
+ }
+
/** Reset this walker so new tree iterators can be added to it. */
public void reset() {
attrs = null;
+ attributesHandler = null;
trees = NO_TREES;
advance = false;
depth = 0;
@@ -740,6 +823,16 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
}
/**
+ * Obtain the {@link FileMode} for the current entry on the currentHead tree
+ *
+ * @return mode for the current entry of the currentHead tree.
+ * @since 4.3
+ */
+ public FileMode getFileMode() {
+ return FileMode.fromBits(currentHead.mode);
+ }
+
+ /**
* Obtain the ObjectId for the current entry.
* <p>
* Using this method to compare ObjectId values between trees of this walker
@@ -1109,156 +1202,13 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
}
/**
- * Retrieve the git attributes for the current entry.
- *
- * <h4>Git attribute computation</h4>
- *
- * <ul>
- * <li>Get the attributes matching the current path entry from the info file
- * (see {@link AttributesNodeProvider#getInfoAttributesNode()}).</li>
- * <li>Completes the list of attributes using the .gitattributes files
- * located on the current path (the further the directory that contains
- * .gitattributes is from the path in question, the lower its precedence).
- * For a checkin operation, it will look first on the working tree (if any).
- * If there is no attributes file, it will fallback on the index. For a
- * checkout operation, it will first use the index entry and then fallback
- * on the working tree if none.</li>
- * <li>In the end, completes the list of matching attributes using the
- * global attribute file define in the configuration (see
- * {@link AttributesNodeProvider#getGlobalAttributesNode()})</li>
- *
- * </ul>
- *
- *
- * <h4>Iterator constraints</h4>
- *
- * <p>
- * In order to have a correct list of attributes for the current entry, this
- * {@link TreeWalk} requires to have at least one
- * {@link AttributesNodeProvider} and a {@link DirCacheIterator} set up. An
- * {@link AttributesNodeProvider} is used to retrieve the attributes from
- * the info attributes file and the global attributes file. The
- * {@link DirCacheIterator} is used to retrieve the .gitattributes files
- * stored in the index. A {@link WorkingTreeIterator} can also be provided
- * to access the local version of the .gitattributes files. If none is
- * provided it will fallback on the {@link DirCacheIterator}.
- * </p>
- *
- * @return a {@link Set} of {@link Attribute}s that match the current entry.
- * @since 4.2
- */
- public Attributes getAttributes() {
- if (attrs != null)
- return attrs;
-
- if (attributesNodeProvider == null) {
- // The work tree should have a AttributesNodeProvider to be able to
- // retrieve the info and global attributes node
- throw new IllegalStateException(
- "The tree walk should have one AttributesNodeProvider set in order to compute the git attributes."); //$NON-NLS-1$
- }
-
- WorkingTreeIterator workingTreeIterator = getTree(WorkingTreeIterator.class);
- DirCacheIterator dirCacheIterator = getTree(DirCacheIterator.class);
- CanonicalTreeParser other = getTree(CanonicalTreeParser.class);
-
- if (workingTreeIterator == null && dirCacheIterator == null
- && other == null) {
- // Can not retrieve the attributes without at least one of the above
- // iterators.
- return new Attributes();
- }
-
- String path = currentHead.getEntryPathString();
- final boolean isDir = FileMode.TREE.equals(currentHead.mode);
- Attributes attributes = new Attributes();
- try {
- // Gets the global attributes node
- AttributesNode globalNodeAttr = attributesNodeProvider
- .getGlobalAttributesNode();
- // Gets the info attributes node
- AttributesNode infoNodeAttr = attributesNodeProvider
- .getInfoAttributesNode();
-
- // Gets the info attributes
- if (infoNodeAttr != null) {
- infoNodeAttr.getAttributes(path, isDir, attributes);
- }
-
- // Gets the attributes located on the current entry path
- getPerDirectoryEntryAttributes(path, isDir, operationType,
- workingTreeIterator, dirCacheIterator, other, attributes);
-
- // Gets the attributes located in the global attribute file
- if (globalNodeAttr != null) {
- globalNodeAttr.getAttributes(path, isDir, attributes);
- }
- } catch (IOException e) {
- throw new JGitInternalException("Error while parsing attributes", e); //$NON-NLS-1$
- }
- // now after all attributes are collected - in the correct hierarchy
- // order - remove all unspecified entries (the ! marker)
- for (Attribute a : attributes.getAll()) {
- if (a.getState() == State.UNSPECIFIED)
- attributes.remove(a.getKey());
- }
- return attributes;
- }
-
- /**
- * Get the attributes located on the current entry path.
- *
- * @param path
- * current entry path
- * @param isDir
- * holds true if the current entry is a directory
- * @param opType
- * type of operation
- * @param workingTreeIterator
- * 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.
- * @throws IOException
- * It raises an {@link IOException} if a problem appears while
- * parsing one on the attributes file.
+ * @param type
+ * of the tree to be queried
+ * @return the tree of that type or null if none is present
+ * @since 4.3
*/
- private void getPerDirectoryEntryAttributes(String path, boolean isDir,
- OperationType opType, WorkingTreeIterator workingTreeIterator,
- DirCacheIterator dirCacheIterator, CanonicalTreeParser other,
- Attributes attributes)
- throws IOException {
- // Prevents infinite recurrence
- if (workingTreeIterator != null || dirCacheIterator != null
- || other != null) {
- AttributesNode currentAttributesNode = getCurrentAttributesNode(
- 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);
- }
- }
-
- private static <T extends AbstractTreeIterator> T getParent(T current,
+ public <T extends AbstractTreeIterator> T getTree(
Class<T> type) {
- if (current != null) {
- AbstractTreeIterator parent = current.parent;
- if (type.isInstance(parent)) {
- return type.cast(parent);
- }
- }
- return null;
- }
-
- private <T extends AbstractTreeIterator> T getTree(Class<T> type) {
for (int i = 0; i < trees.length; i++) {
AbstractTreeIterator tree = trees[i];
if (type.isInstance(tree)) {
@@ -1269,76 +1219,6 @@ public class TreeWalk implements AutoCloseable, AttributesProvider {
}
/**
- * Get the {@link AttributesNode} for the current entry.
- * <p>
- * This method implements the fallback mechanism between the index and the
- * working tree depending on the operation type
- * </p>
- *
- * @param opType
- * @param workingTreeIterator
- * @param dirCacheIterator
- * @param other
- * @return a {@link AttributesNode} of the current entry,
- * {@link NullPointerException} otherwise.
- * @throws IOException
- * It raises an {@link IOException} if a problem appears while
- * parsing one on the attributes file.
- */
- private AttributesNode getCurrentAttributesNode(OperationType opType,
- @Nullable WorkingTreeIterator workingTreeIterator,
- @Nullable DirCacheIterator dirCacheIterator,
- @Nullable CanonicalTreeParser other)
- throws IOException {
- AttributesNode attributesNode = null;
- switch (opType) {
- case CHECKIN_OP:
- if (workingTreeIterator != null) {
- attributesNode = workingTreeIterator.getEntryAttributesNode();
- }
- if (attributesNode == null && dirCacheIterator != null) {
- attributesNode = getAttributesNode(dirCacheIterator
- .getEntryAttributesNode(getObjectReader()),
- attributesNode);
- }
- if (attributesNode == null && other != null) {
- attributesNode = getAttributesNode(
- other.getEntryAttributesNode(getObjectReader()),
- attributesNode);
- }
- break;
- case CHECKOUT_OP:
- if (other != null) {
- attributesNode = other
- .getEntryAttributesNode(getObjectReader());
- }
- if (dirCacheIterator != null) {
- attributesNode = getAttributesNode(dirCacheIterator
- .getEntryAttributesNode(getObjectReader()),
- attributesNode);
- }
- if (attributesNode == null && workingTreeIterator != null) {
- attributesNode = getAttributesNode(
- workingTreeIterator.getEntryAttributesNode(),
- attributesNode);
- }
- break;
- default:
- throw new IllegalStateException(
- "The only supported operation types are:" //$NON-NLS-1$
- + OperationType.CHECKIN_OP + "," //$NON-NLS-1$
- + OperationType.CHECKOUT_OP);
- }
-
- return attributesNode;
- }
-
- private static AttributesNode getAttributesNode(AttributesNode value,
- AttributesNode defaultValue) {
- return (value == null) ? defaultValue : value;
- }
-
- /**
* Inspect config and attributes to return a filtercommand applicable for
* the current path
*