A native Swift implementation of glob patterns, those patterns used to match and filter files.
- Fast matching against patterns, even as the complexity of a pattern and the length of the path increase.
- Concurrent searching of directory hierarchies and thread safety.
- Configurable pattern matching behavior. There are lots of different implementations of glob pattern matching with different features and behavior. Switching to a Swift based library may mean matching existing behavior from other tools.
- Ergonomic API that is accessible to users of varying skill levels and fits in to all types of Swift projects.
In other words, the project seeks to be the glob library for Swift that can be used both in low level tools and in high level apps.
By creating a glob matching implementation in native Swift with strict compatibility with existing things like POSIX, it allows tools to be migrated to Swift, behavior to be customized and extended, and implimentations to be made more performant and concurrent.
search performs a recursive enumeration of all files in the given directory, filtering them by the include and exclude patterns.
let output = try await Glob.search(
directory: searchURL,
include: [
Glob.Pattern("**/*.swift"),
],
exclude: [
Glob.Pattern("**/*.generated.swift"),
],
skipHiddenFiles: true
)
// output is an async sequence
// you can iterate it as files are found:
for try await url in output {
// do something with the file
}
// or convert the results to an array and wait for the search to finish:
output.reduce(into: [URL]()) { $0.append($1) }There is also a version of search that takes a matching closure instead of include and exclude patterns if you need more control over how files are matched.
You can use a pattern directly to match against a string.
let pattern = try Glob.Pattern("Hello *!")
pattern.match("Hello World!") // returns trueGlob.Pattern takes an Options argument that can be used to customize how the pattern is parsed and how matches are evaluated. Several configurations are provided such as Glob.Pattern.Options.posix() that attempt to match the behavior of other glob algorithms.
let pattern = try Glob.Pattern("**/*.swift", options: .posix())
pattern.match("a/b/c/d/file.swift") // returns false because posix glob patters don't support ** (path level wildcard) matching.The default configuration tries to use sensible defaults that most developers would expect with as many features enabled as possible. You can customize either the default or any configuration by creating a mutable copy:
var options = Glob.Pattern.Options.default
options.pathSeparator = #"\"# // use windows path separatorThe .fnmatch() preset provides compatibility with the POSIX fnmatch function. However, there is one notable difference related to locale-dependent character ranges.
For a comprehensive guide to all supported glob pattern features, options, and implementation compatibility, see Glob Features.
Contributions are highly encouraged. Here are some ways you can contribute:
Writing code: if you see a missing piece of functionality or bug, I welcome pull requests. It's best to open an issue first to make sure you don't waste any effort in case what you are building is already being worked on or going in a different direction. Even if you aren't up to writing an implimentation, creating a PR with a failing test goes a long way towards getting something off the ground.
Improving documentation: if you find something that isn't clear it's likely that other people would find it unclear as well.
Submitting issues: if you find a bug or an inconsistentcy in how patterns are matched, pleas file an issue.
If you have any questions, either open an issue on Github or reach out on Mastodon.
By participating in this project you agree to abide by the Contributor Code of Conduct.