diff options
author | Thomas Wolf <thomas.wolf@paranor.ch> | 2018-03-27 22:22:09 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2018-05-22 03:03:35 +0200 |
commit | d7deda98d0a18ca1e3a1fbb70acf8e7cbcf25833 (patch) | |
tree | f9d7fc4ad0ac7ce7d0dc0dc5eb931239b8b1f59f /org.eclipse.jgit | |
parent | 1da2ff7242dfc6df4d470e8519bfd8267940791a (diff) | |
download | jgit-d7deda98d0a18ca1e3a1fbb70acf8e7cbcf25833.tar.gz jgit-d7deda98d0a18ca1e3a1fbb70acf8e7cbcf25833.zip |
Skip ignored directories in FileTreeIterator
Make FileTreeIterator not enter ignored directories by default. We
only need to enter ignored directories if we do some operation against
git, and there is at least one tracked file underneath an ignored
directory.
Walking ignored directories should be avoided as much as possible as
it is a potential performance bottleneck. Some projects have a lot of
files or very deep hierarchies in ignored directories; walking those
may be costly (especially so on Windows). See for instance also bug
500106.
Provide a FileTreeIterator.setWalkIgnoredDirectories() operation to
force the iterator to iterate also through otherwise ignored
directories. Useful for tests (IgnoreNodeTest, CGitIgnoreTest), or
to implement things like "git ls-files --ignored".
Add tests in DirCacheCheckoutTest, and amend IndexDiffTest to test a
little bit more.
Bug: 388582
Change-Id: I6ff584a42c55a07120a4369fd308409431bdb94a
Signed-off-by: Thomas Wolf <thomas.wolf@paranor.ch>
Diffstat (limited to 'org.eclipse.jgit')
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java | 30 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java | 44 |
2 files changed, 72 insertions, 2 deletions
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java index ccd5e70912..24b9ac086e 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java @@ -52,6 +52,7 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import org.eclipse.jgit.dircache.DirCacheIterator; import org.eclipse.jgit.errors.IncorrectObjectTypeException; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.FileMode; @@ -67,6 +68,7 @@ import org.eclipse.jgit.util.FS; * {@link org.eclipse.jgit.treewalk.TreeWalk}. */ public class FileTreeIterator extends WorkingTreeIterator { + /** * the starting directory of this Iterator. All entries are located directly * in this directory. @@ -207,7 +209,33 @@ public class FileTreeIterator extends WorkingTreeIterator { @Override public AbstractTreeIterator createSubtreeIterator(ObjectReader reader) throws IncorrectObjectTypeException, IOException { - return new FileTreeIterator(this, ((FileEntry) current()).getFile(), fs, fileModeStrategy); + if (!walksIgnoredDirectories() && isEntryIgnored()) { + DirCacheIterator iterator = getDirCacheIterator(); + if (iterator == null) { + return new EmptyTreeIterator(this); + } + // Only enter if we have an associated DirCacheIterator that is + // at the same entry (which indicates there is some already + // tracked file underneath this directory). Otherwise the + // directory is indeed ignored and can be skipped entirely. + } + return enterSubtree(); + } + + + /** + * Create a new iterator for the current entry's subtree. + * <p> + * The parent reference of the iterator must be <code>this</code>, otherwise + * the caller would not be able to exit out of the subtree iterator + * correctly and return to continue walking <code>this</code>. + * + * @return a new iterator that walks over the current subtree. + * @since 5.0 + */ + protected AbstractTreeIterator enterSubtree() { + return new FileTreeIterator(this, ((FileEntry) current()).getFile(), fs, + fileModeStrategy); } private Entry[] entries() { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java index 10e9196411..179fd46791 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java @@ -256,6 +256,45 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { state.dirCacheTree = treeId; } + /** + * Retrieves the {@link DirCacheIterator} at the current entry if + * {@link #setDirCacheIterator(TreeWalk, int)} was called. + * + * @return the DirCacheIterator, or {@code null} if not set or not at the + * current entry + * @since 5.0 + */ + protected DirCacheIterator getDirCacheIterator() { + if (state.dirCacheTree >= 0 && state.walk != null) { + return state.walk.getTree(state.dirCacheTree, + DirCacheIterator.class); + } + return null; + } + + /** + * Defines whether this {@link WorkingTreeIterator} walks ignored + * directories. + * + * @param includeIgnored + * {@code false} to skip ignored directories, if possible; + * {@code true} to always include them in the walk + * @since 5.0 + */ + public void setWalkIgnoredDirectories(boolean includeIgnored) { + state.walkIgnored = includeIgnored; + } + + /** + * Tells whether this {@link WorkingTreeIterator} walks ignored directories. + * + * @return {@code true} if it does, {@code false} otherwise + * @since 5.0 + */ + public boolean walksIgnoredDirectories() { + return state.walkIgnored; + } + /** {@inheritDoc} */ @Override public boolean hasId() { @@ -1365,7 +1404,10 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator { TreeWalk walk; /** Position of the matching {@link DirCacheIterator}. */ - int dirCacheTree; + int dirCacheTree = -1; + + /** Whether the iterator shall walk ignored directories. */ + boolean walkIgnored = false; final Map<String, Boolean> directoryToIgnored = new HashMap<>(); |