/*
 * 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.
 *
 * 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
 *
 * 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.
 */

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;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.util.FS;

Working directory iterator for standard Java IO.

This iterator uses the standard java.io package to read the specified working directory as part of a TreeWalk.

/** * 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 org.eclipse.jgit.treewalk.TreeWalk}. */
public class FileTreeIterator extends WorkingTreeIterator {
the starting directory of this Iterator. All entries are located directly in this directory.
/** * the starting directory of this Iterator. All entries are located directly * in this directory. */
protected final File directory;
the file system abstraction which will be necessary to perform certain file system operations.
/** * the file system abstraction which will be necessary to perform certain * file system operations. */
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
/** * 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.
Params:
  • repo – the repository whose working tree will be scanned.
/** * 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.
Params:
  • repo – the repository whose working tree will be scanned.
  • fileModeStrategy – the strategy to use to determine the FileMode for a FileEntry; controls gitlinks etc.
Since:4.3
/** * 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), fileModeStrategy); initRootIterator(repo); }
Create a new iterator to traverse the given directory and its children.
Params:
  • root – the starting directory. This directory should correspond to the root of the repository.
  • fs – the file system abstraction which will be necessary to perform certain file system operations.
  • options – working tree options to be used
/** * 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 */
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.
Params:
  • root – the starting directory. This directory should correspond to the root of the repository.
  • fs – the file system abstraction which will be necessary to perform certain file system operations.
  • options – working tree options to be used
  • fileModeStrategy – the strategy to use to determine the FileMode for a FileEntry; controls gitlinks etc.
Since:4.3
/** * 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()); }
Create a new iterator to traverse a subdirectory.
Params:
  • p – the parent iterator we were created from.
  • root – the subdirectory. This should be a directory contained within the parent directory.
  • fs – the file system abstraction which will be necessary to perform certain file system operations.
Since:4.3
/** * Create a new iterator to traverse a subdirectory. * * @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.
Params:
  • p – the parent iterator we were created from.
  • root – the subdirectory. This should be a directory contained within the parent directory
  • fs – the file system abstraction which will be necessary to perform certain file system operations.
  • fileModeStrategy – the strategy to use to determine the FileMode for a given FileEntry.
Since:4.3
/** * 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 * @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, FileModeStrategy fileModeStrategy) { super(p); directory = root; this.fs = fs; this.fileModeStrategy = fileModeStrategy; init(entries()); }
{@inheritDoc}
/** {@inheritDoc} */
@Override public AbstractTreeIterator createSubtreeIterator(ObjectReader reader) throws IncorrectObjectTypeException, IOException { 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.

The parent reference of the iterator must be this, otherwise the caller would not be able to exit out of the subtree iterator correctly and return to continue walking this.

Returns:a new iterator that walks over the current subtree.
Since:5.0
/** * 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() { return fs.list(directory, fileModeStrategy); }
An interface representing the methods used to determine the FileMode for a FileEntry.
Since:4.3
/** * 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.
Params:
  • f – the file to return a FileMode for
  • attributes – the attributes of a file
Returns:a FileMode indicating whether the file is a regular file, a directory, a gitlink, etc.
/** * 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
/** * 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
/** * a singleton instance of the default FileModeStrategy */
public final static 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; } else { 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
/** * 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
/** * a singleton instance of the default FileModeStrategy */
public final static 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
/** * Wrapper for a standard Java IO file */
public static class FileEntry extends Entry { private final FileMode mode; private FS.Attributes attributes; private FS fs;
Create a new file entry.
Params:
  • f – file
  • fs – file system
/** * Create a new file entry. * * @param f * file * @param fs * file system */
public FileEntry(File f, FS fs) { this(f, fs, DefaultFileModeStrategy.INSTANCE); }
Create a new file entry given the specified FileModeStrategy
Params:
  • f – file
  • fs – file system
  • fileModeStrategy – the strategy to use when determining the FileMode of a file; controls gitlinks etc.
Since:4.3
/** * 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); mode = fileModeStrategy.getMode(f, attributes); }
Create a new file entry given the specified FileModeStrategy
Params:
  • f – file
  • fs – file system
  • attributes – of the file
  • fileModeStrategy – the strategy to use when determining the FileMode of a file; controls gitlinks etc.
Since:5.0
/** * 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 public FileMode getMode() { return mode; } @Override public String getName() { return attributes.getName(); } @Override public long getLength() { return attributes.getLength(); } @Override @Deprecated public long getLastModified() { return attributes.getLastModifiedInstant().toEpochMilli(); }
Since:5.1.9
/** * @since 5.1.9 */
@Override public Instant getLastModifiedInstant() { return attributes.getLastModifiedInstant(); } @Override public InputStream openInputStream() throws IOException { if (attributes.isSymbolicLink()) { return new ByteArrayInputStream(fs.readSymLink(getFile()) .getBytes(UTF_8)); } else { return new FileInputStream(getFile()); } }
Get the underlying file of this entry.
Returns:the underlying file of this entry
/** * Get the underlying file of this entry. * * @return the underlying file of this entry */
public File getFile() { return attributes.getFile(); } }

Getter for the field directory.

Returns:The root directory of this iterator
/** * <p>Getter for the field <code>directory</code>.</p> * * @return The root directory of this iterator */
public File getDirectory() { return directory; }
Get the location of the working file.
Returns:The location of the working file. This is the same as new File(getDirectory(), getEntryPath()) but may be faster by reusing an internal File instance.
/** * 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. */
public File getEntryFile() { return ((FileEntry) current()).getFile(); }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected byte[] idSubmodule(Entry e) { return idSubmodule(getDirectory(), e); }
{@inheritDoc}
/** {@inheritDoc} */
@Override protected String readSymlinkTarget(Entry entry) throws IOException { return fs.readSymLink(getEntryFile()); } }