Skip to content

A native Swift implementation of glob match patterns.

License

Notifications You must be signed in to change notification settings

davbeck/swift-glob

Repository files navigation

swift-glob

A native Swift implementation of glob patterns, those patterns used to match and filter files.

Project goals

  • 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 implimentations 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 implimentation in native Swift with strict compatibility with existing things like POSIX, it allows tools to be migrated to Swift, behavior to be customized and exteded, and implimentations to be made more performant and concurrent.

Status

Basic pattern matching and director search is working and in my tests searching a large hiearchy of files and folders with about 10 exclude patterns runs very quickly. However there are still some features missing like grouping. The tests to match fnmatch behavior has 588 failing tests as of this writing.

A 1.0.0 release is dependent on compatibility tests with fnmatch passing.

Usage

Searching files

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.

Matching file names (and other strings)

You can use a pattern directly to match against a string.

let pattern = try Glob.Pattern("Hello *!")
pattern.match("Hello World!") // returns true

Configuration

Glob.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 separator

Contributing

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.

There are already a good number of failing tests (wrapped in XCTExpectFailure). These would be a good place to start.

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.

About

A native Swift implementation of glob match patterns.

Resources

License

Code of conduct

Stars

Watchers

Forks

Packages

No packages published

Languages