aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java')
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java339
1 files changed, 262 insertions, 77 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 8d2cb1d8cd..0cac374844 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/FileTreeIterator.java
@@ -2,56 +2,27 @@
* Copyright (C) 2008, Google Inc.
* Copyright (C) 2007-2010, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
- * Copyright (C) 2009, Tor Arne Vestbø <torarnv@gmail.com>
- * and other copyright owners as documented in the project's IP log.
+ * Copyright (C) 2009, Tor Arne Vestbø <torarnv@gmail.com> and others
*
- * 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
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://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.
+ * SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.treewalk;
+import static java.nio.charset.StandardCharsets.UTF_8;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.time.Instant;
+import org.eclipse.jgit.dircache.DirCacheIterator;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
@@ -63,12 +34,14 @@ import org.eclipse.jgit.util.FS;
* Working directory iterator for standard Java IO.
* <p>
* This iterator uses the standard <code>java.io</code> package to read the
- * specified working directory as part of a {@link TreeWalk}.
+ * specified working directory as part of a
+ * {@link org.eclipse.jgit.treewalk.TreeWalk}.
*/
public class FileTreeIterator extends WorkingTreeIterator {
+
/**
- * the starting directory. This directory should correspond to the root of
- * the repository.
+ * the starting directory of this Iterator. All entries are located directly
+ * in this directory.
*/
protected final File directory;
@@ -79,14 +52,41 @@ public class FileTreeIterator extends WorkingTreeIterator {
protected final FS fs;
/**
+ * the strategy used to compute the FileMode for a FileEntry. Can be used to
+ * control things such as whether to recurse into a directory or create a
+ * gitlink.
+ *
+ * @since 4.3
+ */
+ protected final FileModeStrategy fileModeStrategy;
+
+ /**
* Create a new iterator to traverse the work tree and its children.
*
* @param repo
* the repository whose working tree will be scanned.
*/
public FileTreeIterator(Repository repo) {
+ this(repo,
+ repo.getConfig().get(WorkingTreeOptions.KEY).isDirNoGitLinks() ?
+ NoGitlinksStrategy.INSTANCE :
+ DefaultFileModeStrategy.INSTANCE);
+ }
+
+ /**
+ * Create a new iterator to traverse the work tree and its children.
+ *
+ * @param repo
+ * the repository whose working tree will be scanned.
+ * @param fileModeStrategy
+ * the strategy to use to determine the FileMode for a FileEntry;
+ * controls gitlinks etc.
+ * @since 4.3
+ */
+ public FileTreeIterator(Repository repo, FileModeStrategy fileModeStrategy) {
this(repo.getWorkTree(), repo.getFS(),
- repo.getConfig().get(WorkingTreeOptions.KEY));
+ repo.getConfig().get(WorkingTreeOptions.KEY),
+ fileModeStrategy);
initRootIterator(repo);
}
@@ -102,10 +102,32 @@ public class FileTreeIterator extends WorkingTreeIterator {
* @param options
* working tree options to be used
*/
- public FileTreeIterator(final File root, FS fs, WorkingTreeOptions options) {
+ public FileTreeIterator(File root, FS fs, WorkingTreeOptions options) {
+ this(root, fs, options, DefaultFileModeStrategy.INSTANCE);
+ }
+
+ /**
+ * Create a new iterator to traverse the given directory and its children.
+ *
+ * @param root
+ * the starting directory. This directory should correspond to
+ * the root of the repository.
+ * @param fs
+ * the file system abstraction which will be necessary to perform
+ * certain file system operations.
+ * @param options
+ * working tree options to be used
+ * @param fileModeStrategy
+ * the strategy to use to determine the FileMode for a FileEntry;
+ * controls gitlinks etc.
+ * @since 4.3
+ */
+ public FileTreeIterator(final File root, FS fs, WorkingTreeOptions options,
+ FileModeStrategy fileModeStrategy) {
super(options);
directory = root;
this.fs = fs;
+ this.fileModeStrategy = fileModeStrategy;
init(entries());
}
@@ -114,41 +136,165 @@ public class FileTreeIterator extends WorkingTreeIterator {
*
* @param p
* the parent iterator we were created from.
+ * @param root
+ * the subdirectory. This should be a directory contained within
+ * the parent directory.
* @param fs
* the file system abstraction which will be necessary to perform
* certain file system operations.
+ * @since 4.3
+ */
+ protected FileTreeIterator(final FileTreeIterator p, final File root,
+ FS fs) {
+ this(p, root, fs, p.fileModeStrategy);
+ }
+
+ /**
+ * Create a new iterator to traverse a subdirectory, given the specified
+ * FileModeStrategy.
+ *
+ * @param p
+ * the parent iterator we were created from.
* @param root
* the subdirectory. This should be a directory contained within
- * the parent directory.
+ * the parent directory
+ * @param fs
+ * the file system abstraction which will be necessary to perform
+ * certain file system operations.
+ * @param fileModeStrategy
+ * the strategy to use to determine the FileMode for a given
+ * FileEntry.
+ * @since 4.3
*/
protected FileTreeIterator(final WorkingTreeIterator p, final File root,
- FS fs) {
+ FS fs, FileModeStrategy fileModeStrategy) {
super(p);
directory = root;
this.fs = fs;
+ this.fileModeStrategy = fileModeStrategy;
init(entries());
}
@Override
- public AbstractTreeIterator createSubtreeIterator(final ObjectReader reader)
+ public AbstractTreeIterator createSubtreeIterator(ObjectReader reader)
throws IncorrectObjectTypeException, IOException {
- return new FileTreeIterator(this, ((FileEntry) current()).getFile(), fs);
+ 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() {
- final File[] all = directory.listFiles();
- if (all == null)
- return EOF;
- final Entry[] r = new Entry[all.length];
- for (int i = 0; i < r.length; i++)
- r[i] = new FileEntry(all[i], fs);
- return r;
+ return fs.list(directory, fileModeStrategy);
+ }
+
+ /**
+ * An interface representing the methods used to determine the FileMode for
+ * a FileEntry.
+ *
+ * @since 4.3
+ */
+ public interface FileModeStrategy {
+ /**
+ * Compute the FileMode for a given File, based on its attributes.
+ *
+ * @param f
+ * the file to return a FileMode for
+ * @param attributes
+ * the attributes of a file
+ * @return a FileMode indicating whether the file is a regular file, a
+ * directory, a gitlink, etc.
+ */
+ FileMode getMode(File f, FS.Attributes attributes);
}
/**
+ * A default implementation of a FileModeStrategy; defaults to treating
+ * nested .git directories as gitlinks, etc.
+ *
+ * @since 4.3
+ */
+ public static class DefaultFileModeStrategy implements FileModeStrategy {
+ /**
+ * a singleton instance of the default FileModeStrategy
+ */
+ public static final DefaultFileModeStrategy INSTANCE =
+ new DefaultFileModeStrategy();
+
+ @Override
+ public FileMode getMode(File f, FS.Attributes attributes) {
+ if (attributes.isSymbolicLink()) {
+ return FileMode.SYMLINK;
+ } else if (attributes.isDirectory()) {
+ if (new File(f, Constants.DOT_GIT).exists()) {
+ return FileMode.GITLINK;
+ }
+ return FileMode.TREE;
+ } else if (attributes.isExecutable()) {
+ return FileMode.EXECUTABLE_FILE;
+ } else {
+ return FileMode.REGULAR_FILE;
+ }
+ }
+ }
+
+ /**
+ * A FileModeStrategy that implements native git's DIR_NO_GITLINKS
+ * behavior. This is the same as the default FileModeStrategy, except
+ * all directories will be treated as directories regardless of whether
+ * or not they contain a .git directory or file.
+ *
+ * @since 4.3
+ */
+ public static class NoGitlinksStrategy implements FileModeStrategy {
+
+ /**
+ * a singleton instance of the default FileModeStrategy
+ */
+ public static final NoGitlinksStrategy INSTANCE = new NoGitlinksStrategy();
+
+ @Override
+ public FileMode getMode(File f, FS.Attributes attributes) {
+ if (attributes.isSymbolicLink()) {
+ return FileMode.SYMLINK;
+ } else if (attributes.isDirectory()) {
+ return FileMode.TREE;
+ } else if (attributes.isExecutable()) {
+ return FileMode.EXECUTABLE_FILE;
+ } else {
+ return FileMode.REGULAR_FILE;
+ }
+ }
+ }
+
+
+ /**
* Wrapper for a standard Java IO file
*/
- static public class FileEntry extends Entry {
+ public static class FileEntry extends Entry {
private final FileMode mode;
private FS.Attributes attributes;
@@ -164,20 +310,50 @@ public class FileTreeIterator extends WorkingTreeIterator {
* file system
*/
public FileEntry(File f, FS fs) {
+ this(f, fs, DefaultFileModeStrategy.INSTANCE);
+ }
+
+ /**
+ * Create a new file entry given the specified FileModeStrategy
+ *
+ * @param f
+ * file
+ * @param fs
+ * file system
+ * @param fileModeStrategy
+ * the strategy to use when determining the FileMode of a
+ * file; controls gitlinks etc.
+ *
+ * @since 4.3
+ */
+ public FileEntry(File f, FS fs, FileModeStrategy fileModeStrategy) {
this.fs = fs;
f = fs.normalize(f);
attributes = fs.getAttributes(f);
- if (attributes.isSymbolicLink())
- mode = FileMode.SYMLINK;
- else if (attributes.isDirectory()) {
- if (new File(f, Constants.DOT_GIT).exists())
- mode = FileMode.GITLINK;
- else
- mode = FileMode.TREE;
- } else if (attributes.isExecutable())
- mode = FileMode.EXECUTABLE_FILE;
- else
- mode = FileMode.REGULAR_FILE;
+ mode = fileModeStrategy.getMode(f, attributes);
+ }
+
+ /**
+ * Create a new file entry given the specified FileModeStrategy
+ *
+ * @param f
+ * file
+ * @param fs
+ * file system
+ * @param attributes
+ * of the file
+ * @param fileModeStrategy
+ * the strategy to use when determining the FileMode of a
+ * file; controls gitlinks etc.
+ *
+ * @since 5.0
+ */
+ public FileEntry(File f, FS fs, FS.Attributes attributes,
+ FileModeStrategy fileModeStrategy) {
+ this.fs = fs;
+ this.attributes = attributes;
+ f = fs.normalize(f);
+ mode = fileModeStrategy.getMode(f, attributes);
}
@Override
@@ -195,19 +371,21 @@ public class FileTreeIterator extends WorkingTreeIterator {
return attributes.getLength();
}
+ /**
+ * @since 5.1.9
+ */
@Override
- public long getLastModified() {
- return attributes.getLastModifiedTime();
+ public Instant getLastModifiedInstant() {
+ return attributes.getLastModifiedInstant();
}
@Override
public InputStream openInputStream() throws IOException {
- if (fs.isSymLink(getFile()))
+ if (attributes.isSymbolicLink()) {
return new ByteArrayInputStream(fs.readSymLink(getFile())
- .getBytes(
- Constants.CHARACTER_ENCODING));
- else
- return new FileInputStream(getFile());
+ .getBytes(UTF_8));
+ }
+ return new FileInputStream(getFile());
}
/**
@@ -221,6 +399,8 @@ public class FileTreeIterator extends WorkingTreeIterator {
}
/**
+ * <p>Getter for the field <code>directory</code>.</p>
+ *
* @return The root directory of this iterator
*/
public File getDirectory() {
@@ -228,6 +408,8 @@ public class FileTreeIterator extends WorkingTreeIterator {
}
/**
+ * Get the location of the working file.
+ *
* @return The location of the working file. This is the same as {@code new
* File(getDirectory(), getEntryPath())} but may be faster by
* reusing an internal File instance.
@@ -237,9 +419,12 @@ public class FileTreeIterator extends WorkingTreeIterator {
}
@Override
- protected byte[] idSubmodule(final Entry e) {
- if (repository == null)
- return idSubmodule(getDirectory(), e);
- return super.idSubmodule(e);
+ protected byte[] idSubmodule(Entry e) {
+ return idSubmodule(getDirectory(), e);
+ }
+
+ @Override
+ protected String readSymlinkTarget(Entry entry) throws IOException {
+ return fs.readSymLink(getEntryFile());
}
}