Skip to content

Implementation of the Java FileVisitor that matches glob patterns and can respect Git ignore files.

License

Notifications You must be signed in to change notification settings

cthing/filevisitor

Repository files navigation

C Thing Software filevisitor

CI Maven Central javadoc

A Java library providing glob pattern matching traversal of the file system. In addition to pattern matching, Git ignore files can be honored.

Usage

The library is available from Maven Central using the following Maven dependency:

<dependency>
  <groupId>org.cthing</groupId>
  <artifactId>filevisitor</artifactId>
  <version>1.0.0</version>
</dependency>

or the following Gradle dependency:

implementation("org.cthing:filevisitor:1.0.0")

File Tree Traversal

In a similar manner to Files.walkFileTree, the MatchingTreeWalker will traverse the file system starting at the specified directory. The walker will attempt to match files and directories against the patterns specified (see Pattern Matching Syntax). Specify an implementation of the MatchHandler interface to process the matched files and directories. The following example looks for all Java files:

final MatchHandler handler = new MyMatchHandler();
final MatchingTreeWalker walker = new MatchingTreeWalker(start, handler, "**/*.java");
walker.walk();

To use Files.walkFileTree directly, specify an instance of the MatchingFileVisitor. The equivalent to the above example is:

final MatchHandler handler = new MyMatchHandler();
final MatchingFileVisitor visitor = new MatchingFileVisitor(handler, "**/*.java");
Files.walkFileTree(start, visitor);

To obtain a list of all matched files and directories, use the CollectingMatchHandler.

final CollectingMatchHandler handler = new CollectingMatchHandler();
new MatchingTreeWalker(start, handler, "**/*.java").walk();
final List<Path> matchedPaths = handler.getPaths();

To obtain a list of only matched files:

final CollectingMatchHandler handler = new CollectingMatchHandler(false);
new MatchingTreeWalker(start, handler, "**/*.java").walk();
final List<Path> matchedPaths = handler.getPaths();

Pattern Matching Syntax

Patterns to match files and directories use the Git ignore glob syntax. Note that unlike Git ignore globs, which indicate the files and directories to exclude, in this library, they indicate the files and directories to include. For example, specifying **/*.java includes all Java files in any directory. To exclude files and directories, use the "!" negation prefix. Below is summary of the glob syntax. See the Git ignore documentation for a detailed explanation.

  • Blank lines are ignored
  • Lines starting with "#" are comments
  • A "!" prefix negates the pattern
  • A "" escapes special characters (e.g. to use a "#" character, specify "\#")
  • A "/" is used as the directory separator regardless of the platform
  • A "/" at the end of the pattern only matches directories
  • Relative paths are resolved against the starting directory of the traversal
  • A "*" matches anything except a slash
  • A "?" matches any one character except a slash
  • Range notation (e.g. "[a-zA-Z]") can be used to match one character in that range
  • A leading "*/" (e.g. "*/foo") matches in all directories
  • A trailing "/**" (e.g. "foo/**") matches everything inside
  • A slash followed by two consecutive asterisks followed by a slash (e.g. "a/**/b") matches zero or more directories

Git Ignore Files

By default, file tree traversal respects Git ignore files. If the start directory is anywhere within a Git work tree, any Git ignore files will be used to exclude files from matching. Global Git ignore files are also considered. Git ignore files have the same precedence as they do in Git. User specified match patterns have higher precedence than Git ignore patterns.

To disable the use of Git ignore files, call the MatchingTreeWalker.respectGitignore or MatchingFileVisitor.respectGitignore method with false.

Hidden Files

By default, file tree traversal ignores hidden files and directories. To include hidden files and directories, call the MatchingTreeWalker.excludeHidden or MatchingFileVisitor.excludeHidden method with false.

Symbolic Links

By default, the MatchingTreeWalker does not follow symbolic links. To follow symbolic links, call the MatchingTreeWalker.followLinks method with true.

Walk Depth

By default, the MatchingTreeWalker performs a depth first traversal of the entire file tree under the starting directory. To restrict the traversal to a specific depth, call the MatchingTreeWalker.maxDepth method. Specify, Integer.MAX_VALUE for unlimited depth.

Acknowledgements

The glob and Git ignore pattern parsing and matching in this library is based on the Rust code in the ripgrep project's globset and ignore crates covered by the Unlicense (i.e. public domain).

The Git config file parser is a heavily modified copy of the Config class from the Eclipse JGitTM project and is covered by the EDL license.

Building

The library is compiled for Java 17. If a Java 17 toolchain is not available, one will be downloaded.

Gradle is used to build the library:

./gradlew build

The Javadoc for the library can be generated by running:

./gradlew javadoc

Releasing

This project is released on the Maven Central repository. Perform the following steps to create a release.

  • Commit all changes for the release
  • In the build.gradle.kts file, edit the ProjectVersion object
    • Set the version for the release. The project follows semantic versioning.
    • Set the build type to BuildType.release
  • Commit the changes
  • Wait until CI builds the release candidate
  • Run the command mkrelease filevisitor <version>
  • In a browser go to the Maven Central Repository Manager
  • Log in
  • Use the Staging Upload to upload the generated artifact bundle filevisitor-bundle-<version>.jar
  • Click on Staging Repositories
  • Once it is enabled, press Release to release the artifacts to Maven Central
  • Log out
  • Wait for the new release to be available on Maven Central
  • In a browser, go to the project on GitHub
  • Generate a release with the tag <version>
  • In the build.gradle.kts file, edit the ProjectVersion object
    • Increment the version patch number
    • Set the build type to BuildType.snapshot
  • Update the CHANGELOG.md with the changes in the release and prepare for next release changes
  • Update the Usage section in the README.md with the latest artifact release version
  • Commit these changes