Compare commits

...

678 Commits

Author SHA1 Message Date
Thayne McCombs cdea7f5633 Merge pull request #1943 from tmccombs/archive-script
build: Create archive script
2026-08-27 23:52:23 -06:00
Thayne McCombs fe0e455fee Merge pull request #2102 from tmccombs/changelog-update
chore: Update version in CHANGELOG
2026-08-26 09:54:02 -06:00
Thayne McCombs a89e394a0d chore: Update version in CHANGELOG 2026-08-26 02:12:47 -06:00
Thayne McCombs 4f81778774 Merge pull request #2101 from tmccombs/release-10.5.0
chore: Bump to version 10.5.0
2026-08-26 01:54:19 -06:00
Thayne McCombs 711ba7fe67 chore: Buimp to version 10.5.0 2026-08-26 01:27:33 -06:00
Thayne McCombs c276ac79f4 build: Create archive script
Move the code for creating the archive from the GHA yaml into a
dedicated script file.
2026-08-26 01:00:44 -06:00
Thayne McCombs ee20f426dd Merge pull request #2091 from sharkdp/dependabot/github_actions/actions/attest-4.2.1
build(deps): bump actions/attest from 4.2.0 to 4.2.1
2026-08-09 01:42:46 -06:00
Thayne McCombs 0b10bf2665 Merge pull request #2086 from sharkdp/dependabot/cargo/crossbeam-channel-0.5.16
build(deps): bump crossbeam-channel from 0.5.15 to 0.5.16
2026-08-09 01:37:12 -06:00
Thayne McCombs aaecbc0a58 Merge pull request #2085 from sharkdp/dependabot/cargo/ignore-0.4.31
build(deps): bump ignore from 0.4.26 to 0.4.31
2026-08-09 01:36:38 -06:00
Thayne McCombs cb4069ec55 Merge pull request #2087 from sharkdp/dependabot/cargo/globset-0.4.19
build(deps): bump globset from 0.4.18 to 0.4.19
2026-08-09 01:35:32 -06:00
Thayne McCombs 69a25907ab Merge pull request #2084 from sharkdp/dependabot/cargo/anyhow-1.0.104
build(deps): bump anyhow from 1.0.102 to 1.0.104
2026-08-09 01:35:00 -06:00
Thayne McCombs 868c3a34e2 Merge pull request #2083 from sharkdp/dependabot/cargo/libc-0.2.189
build(deps): bump libc from 0.2.186 to 0.2.189
2026-08-09 01:32:52 -06:00
Thayne McCombs ee195f4dd6 Merge pull request #2082 from nikolauspschuetz/fix-changed-time-overflow-panic
Fix panic on out-of-range '@' Unix timestamp in time filters
2026-08-09 01:32:07 -06:00
Thayne McCombs 0f1f9676dc Merge pull request #2068 from tmccombs/fix-clippy
fix: New clippy warnings
2026-08-06 10:54:59 -06:00
dependabot[bot] 2bb2e2b954 build(deps): bump actions/attest from 4.2.0 to 4.2.1
Bumps [actions/attest](https://github.com/actions/attest) from 4.2.0 to 4.2.1.
- [Release notes](https://github.com/actions/attest/releases)
- [Changelog](https://github.com/actions/attest/blob/main/RELEASE.md)
- [Commits](https://github.com/actions/attest/compare/f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6...508db95dd578ae2727ebd6217d5ba78e4fbda05d)

---
updated-dependencies:
- dependency-name: actions/attest
  dependency-version: 4.2.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-05 17:43:24 +00:00
dependabot[bot] a62a59dafe build(deps): bump globset from 0.4.18 to 0.4.19
Bumps [globset](https://github.com/BurntSushi/ripgrep) from 0.4.18 to 0.4.19.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/globset-0.4.18...globset-0.4.19)

---
updated-dependencies:
- dependency-name: globset
  dependency-version: 0.4.19
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-01 17:42:57 +00:00
dependabot[bot] 7639bced74 build(deps): bump crossbeam-channel from 0.5.15 to 0.5.16
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.15 to 0.5.16.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/main/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.15...crossbeam-channel-0.5.16)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-version: 0.5.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-01 17:42:50 +00:00
dependabot[bot] 51e44c0626 build(deps): bump ignore from 0.4.26 to 0.4.31
Bumps [ignore](https://github.com/BurntSushi/ripgrep) from 0.4.26 to 0.4.31.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/ignore-0.4.26...ignore-0.4.31)

---
updated-dependencies:
- dependency-name: ignore
  dependency-version: 0.4.31
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-01 17:42:41 +00:00
dependabot[bot] 370174528f build(deps): bump anyhow from 1.0.102 to 1.0.104
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.102 to 1.0.104.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.102...1.0.104)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-version: 1.0.104
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-01 17:42:31 +00:00
dependabot[bot] 30fd75b22b build(deps): bump libc from 0.2.186 to 0.2.189
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.186 to 0.2.189.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.189/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.186...0.2.189)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.189
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-08-01 17:42:24 +00:00
Nikolaus Schuetz 5becb9d52c Reject out-of-range '@' Unix timestamp instead of panicking
Use UNIX_EPOCH.checked_add(...) so an out-of-range value returns None
and propagates through the existing ? like every other parse failure in
TimeFilter::from_str, rather than panicking via SystemTime's Add. See #2081.
2026-07-30 08:06:22 -07:00
Nikolaus Schuetz fb0426fed1 Add failing test for out-of-range '@' Unix timestamp
Demonstrates that a '@'-timestamp large enough to overflow SystemTime
panics ('overflow when adding duration to instant') instead of being
rejected like other unparseable time inputs. See #2081.
2026-07-30 08:06:07 -07:00
Thayne McCombs 41532d114e Merge pull request #2075 from cmelaro/fix-readme-example
Update README.md to resolve non-working example.
2026-07-27 09:41:31 -06:00
Chris Melaro 81efb5028c add -u flag to example so it works 2026-07-26 14:24:38 -04:00
Thayne McCombs ca51233d27 Merge pull request #2073 from sharkdp/dependabot/github_actions/actions/checkout-7.0.1
build(deps): bump actions/checkout from 7.0.0 to 7.0.1
2026-07-24 14:22:05 -06:00
Thayne McCombs 3381ab89d7 Merge pull request #2070 from sharkdp/dependabot/github_actions/actions/attest-4.2.0
build(deps): bump actions/attest from 4.1.1 to 4.2.0
2026-07-24 14:21:25 -06:00
dependabot[bot] 5095e95a95 build(deps): bump actions/checkout from 7.0.0 to 7.0.1
Bumps [actions/checkout](https://github.com/actions/checkout) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v7.0.0...v7.0.1)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-24 17:42:24 +00:00
dependabot[bot] 5a093fdfd6 build(deps): bump actions/attest from 4.1.1 to 4.2.0
Bumps [actions/attest](https://github.com/actions/attest) from 4.1.1 to 4.2.0.
- [Release notes](https://github.com/actions/attest/releases)
- [Changelog](https://github.com/actions/attest/blob/main/RELEASE.md)
- [Commits](https://github.com/actions/attest/compare/a1948c3f048ba23858d222213b7c278aabede763...f7c74d28b9d84cb8768d0b8ca14a4bac6ef463e6)

---
updated-dependencies:
- dependency-name: actions/attest
  dependency-version: 4.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-23 17:42:46 +00:00
Thayne McCombs acc64aab12 fix: New clippy warnings 2026-07-23 01:55:04 -06:00
Thayne McCombs eead1886cd Merge pull request #2066 from sharkdp/dependabot/github_actions/softprops/action-gh-release-3.0.2
build(deps): bump softprops/action-gh-release from 3.0.1 to 3.0.2
2026-07-23 01:47:36 -06:00
dependabot[bot] fed92120af build(deps): bump softprops/action-gh-release from 3.0.1 to 3.0.2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 3.0.1 to 3.0.2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/718ea10b132b3b2eba29c1007bb80653f286566b...3d0d9888cb7fd7b750713d6e236d1fcb99157228)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-20 17:42:43 +00:00
Thayne McCombs 1bfeea237a Merge pull request #2063 from kobihikri/docs-msrv
docs: update required Rust version in README to match Cargo.toml MSRV (1.77.2 -> 1.90.0)
2026-07-15 14:22:25 -06:00
Thayne McCombs 369a71a4c5 Merge pull request #2064 from WilliamLeony/fix-readme-bash-fence
Fix inconsistent code fence language in README.md
2026-07-15 14:19:06 -06:00
William Leony cd755e284c Fix inconsistent code fence language in README.md
The checksum example under 'Command execution' was missing the
'bash' language tag on its opening fence, unlike every other shell
example in the file, so it didn't get syntax highlighting.
2026-07-15 16:06:42 -03:00
Kobi Hikri 372584e760 docs: update required Rust version in README (1.77.2 -> 1.90.0, matching Cargo.toml rust-version) 2026-07-15 13:28:38 +03:00
Thayne McCombs 5a5852e15b Merge pull request #2052 from sharkdp/dependabot/github_actions/actions/attest-4.1.1
build(deps): bump actions/attest from 4.1.0 to 4.1.1
2026-07-07 02:00:22 -06:00
Thayne McCombs dda13cccf6 Merge pull request #2047 from sharkdp/dependabot/cargo/nix-0.31.3
build(deps): bump nix from 0.31.2 to 0.31.3
2026-07-06 07:19:29 -06:00
Thayne McCombs aa41f342b5 Merge pull request #2050 from sharkdp/dependabot/cargo/jiff-0.2.29
build(deps): bump jiff from 0.2.27 to 0.2.29
2026-07-04 23:39:02 -06:00
Thayne McCombs cffed27a2e Merge pull request #2049 from sharkdp/dependabot/cargo/regex-1.12.4
build(deps): bump regex from 1.12.3 to 1.12.4
2026-07-04 23:37:52 -06:00
Thayne McCombs 6b5d1ac9d6 Merge pull request #2048 from sharkdp/dependabot/cargo/ignore-0.4.26
build(deps): bump ignore from 0.4.25 to 0.4.26
2026-07-04 23:37:22 -06:00
dependabot[bot] 7d93f3adc7 build(deps): bump actions/attest from 4.1.0 to 4.1.1
Bumps [actions/attest](https://github.com/actions/attest) from 4.1.0 to 4.1.1.
- [Release notes](https://github.com/actions/attest/releases)
- [Changelog](https://github.com/actions/attest/blob/main/RELEASE.md)
- [Commits](https://github.com/actions/attest/compare/59d89421af93a897026c735860bf21b6eb4f7b26...a1948c3f048ba23858d222213b7c278aabede763)

---
updated-dependencies:
- dependency-name: actions/attest
  dependency-version: 4.1.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-03 17:42:31 +00:00
Thayne McCombs fb1486f210 Merge pull request #1905 from tmccombs/release-automation
Add a little more automation for the release
2026-07-01 13:27:06 -06:00
dependabot[bot] 0c9c101e21 build(deps): bump jiff from 0.2.27 to 0.2.29
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.27 to 0.2.29.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/commits/jiff-static-0.2.29)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-01 17:42:52 +00:00
dependabot[bot] 8ff051e801 build(deps): bump regex from 1.12.3 to 1.12.4
Bumps [regex](https://github.com/rust-lang/regex) from 1.12.3 to 1.12.4.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.12.3...1.12.4)

---
updated-dependencies:
- dependency-name: regex
  dependency-version: 1.12.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-01 17:42:44 +00:00
dependabot[bot] daefe07614 build(deps): bump ignore from 0.4.25 to 0.4.26
Bumps [ignore](https://github.com/BurntSushi/ripgrep) from 0.4.25 to 0.4.26.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/ignore-0.4.25...ignore-0.4.26)

---
updated-dependencies:
- dependency-name: ignore
  dependency-version: 0.4.26
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-01 17:42:38 +00:00
dependabot[bot] cade0b5e76 build(deps): bump nix from 0.31.2 to 0.31.3
Bumps [nix](https://github.com/nix-rust/nix) from 0.31.2 to 0.31.3.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.31.2...v0.31.3)

---
updated-dependencies:
- dependency-name: nix
  dependency-version: 0.31.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-07-01 17:42:31 +00:00
Thayne McCombs c73e5e58a4 Merge pull request #2045 from tmccombs/io-error-handling
refactor: Get io error from method
2026-07-01 09:03:44 -06:00
Thayne McCombs f898e95db5 refactor: Get io error from method
use `ignore::Error::io_error()` to inspect the `std::io::Error` insted
of pattern matching on `ignore::Error::Io`.

This avoids relying on the implementation of ignore and how it organizes
the error. In particular, this would allow us to handle if the IO error
was wrapped in a `WithDepth`, as would be the case if
BurntSushi/ripgrep#3458 was merged.

This also allows us to remove some duplicate code.
2026-07-01 00:55:42 -06:00
Thayne McCombs b12606438e Merge pull request #1976 from curious-rabbit/master
fix: sanitize escape sequence injection
2026-07-01 00:36:48 -06:00
Thayne McCombs 95dc6454d5 Merge pull request #2037 from parneetsingh022/tests/search-str-for-entry-edge-cases
Add tests for search_str_for_entry without base dir
2026-06-28 23:44:14 -06:00
Thayne McCombs 61c5399fa4 Merge pull request #2036 from greymoth-jp/fix/and-pattern-path-separator
Check --and patterns for path separators too (match #1975)
2026-06-28 23:42:55 -06:00
Thayne McCombs 126be98699 Merge pull request #2038 from sharkdp/dependabot/github_actions/softprops/action-gh-release-3.0.1
build(deps): bump softprops/action-gh-release from 3.0.0 to 3.0.1
2026-06-28 10:56:02 -06:00
Thayne McCombs 77629639ff Merge pull request #2040 from bonanza127/fix-readme-number-format
docs(README): use consistent thousands separator
2026-06-28 02:03:26 -06:00
bonanza127 3ae9c9567e docs(README): use consistent thousands separator
Change ~750.000 to ~750,000 for consistency with English number formatting.
2026-06-28 04:50:55 +09:00
dependabot[bot] 8965502e8a build(deps): bump softprops/action-gh-release from 3.0.0 to 3.0.1
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/b4309332981a82ec1c5618f44dd2e27cc8bfbfda...718ea10b132b3b2eba29c1007bb80653f286566b)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-26 17:42:37 +00:00
Parneet 86c1e7d30d Add tests for search_str_for_entry without base dir 2026-06-26 16:59:06 +05:30
greymoth-jp 6aac84e4ae fix: flag path separators in --and patterns, not just the primary pattern
The path-separator diagnostic (#1873, made unconditional for the primary
pattern in #1975) only inspected opts.pattern. --and patterns (opts.exprs)
are chained with the primary pattern and matched against the file name in
exactly the same way, so a path separator in any of them is the same silent
"no results" footgun. Factor the per-pattern check into a helper and apply
it to the primary pattern plus every --and pattern, mirroring how
ensure_use_hidden_option_for_leading_dot_pattern already iterates all
patterns. --full-path still suppresses the diagnostic. Adds a regression test.

See #1873.
2026-06-26 17:02:47 +09:00
Thayne McCombs a8a77d2162 Merge pull request #2034 from sharkdp/dependabot/github_actions/actions/checkout-7.0.0
build(deps): bump actions/checkout from 6.0.3 to 7.0.0
2026-06-25 01:13:26 -06:00
dependabot[bot] e8730e6ca3 build(deps): bump actions/checkout from 6.0.3 to 7.0.0
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.3 to 7.0.0.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6.0.3...v7.0.0)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 7.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-24 17:42:30 +00:00
Thayne McCombs 3b3e328b5c Merge pull request #2032 from sharkdp/dependabot/github_actions/actions/checkout-6.0.3
build(deps): bump actions/checkout from 6.0.2 to 6.0.3
2026-06-18 13:36:42 -06:00
dependabot[bot] fccbe9b1ee build(deps): bump actions/checkout from 6.0.2 to 6.0.3
Bumps [actions/checkout](https://github.com/actions/checkout) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6.0.2...v6.0.3)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-18 17:42:30 +00:00
Thayne McCombs b5ae476fb1 Merge pull request #2030 from sharkdp/dependabot/github_actions/actions/checkout-6.0.2
build(deps): bump actions/checkout from 6 to 6.0.2
2026-06-18 00:04:19 -06:00
Thayne McCombs 094446004d Merge pull request #2001 from leno23/docs/extension-help-1693
docs: clarify that -e/--extension matches all entry types
2026-06-18 00:03:42 -06:00
wuyangfan 1161471b7e docs: clarify extension filter scope 2026-06-17 10:56:33 +08:00
Thayne McCombs 25461e5ce1 Merge pull request #2029 from sharkdp/dependabot/cargo/clap_complete-4.6.5
build(deps): bump clap_complete from 4.6.2 to 4.6.5
2026-06-06 00:48:49 -06:00
Thayne McCombs f7d4d717c2 Merge pull request #2026 from sharkdp/dependabot/cargo/filetime-0.2.29
build(deps): bump filetime from 0.2.27 to 0.2.29
2026-06-04 10:30:46 -06:00
dependabot[bot] 21facf8832 build(deps): bump clap_complete from 4.6.2 to 4.6.5
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.6.2 to 4.6.5.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.6.2...clap_complete-v4.6.5)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.6.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 08:10:24 +00:00
Thayne McCombs 8e80bbe721 Merge pull request #2027 from sharkdp/dependabot/cargo/tikv-jemallocator-0.7.0
build(deps): bump tikv-jemallocator from 0.6.1 to 0.7.0
2026-06-04 02:08:22 -06:00
Thayne McCombs b25ca81375 Merge pull request #2028 from sharkdp/dependabot/cargo/normpath-1.5.1
build(deps): bump normpath from 1.5.0 to 1.5.1
2026-06-04 02:07:11 -06:00
dependabot[bot] 5ac75050d1 build(deps): bump normpath from 1.5.0 to 1.5.1
Bumps [normpath](https://github.com/dylni/normpath) from 1.5.0 to 1.5.1.
- [Release notes](https://github.com/dylni/normpath/releases)
- [Commits](https://github.com/dylni/normpath/compare/1.5.0...1.5.1)

---
updated-dependencies:
- dependency-name: normpath
  dependency-version: 1.5.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-04 07:15:00 +00:00
Thayne McCombs f72512ff43 Merge pull request #2025 from sharkdp/dependabot/cargo/jiff-0.2.27
build(deps): bump jiff from 0.2.24 to 0.2.27
2026-06-04 01:13:20 -06:00
dependabot[bot] 75527dd9c6 build(deps): bump actions/checkout from 6 to 6.0.2
Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 6.0.2.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v6...v6.0.2)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: 6.0.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-03 01:50:25 +00:00
dependabot[bot] 86564cd00d build(deps): bump tikv-jemallocator from 0.6.1 to 0.7.0
Bumps [tikv-jemallocator](https://github.com/tikv/jemallocator) from 0.6.1 to 0.7.0.
- [Release notes](https://github.com/tikv/jemallocator/releases)
- [Changelog](https://github.com/tikv/jemallocator/blob/main/CHANGELOG.md)
- [Commits](https://github.com/tikv/jemallocator/compare/0.6.1...0.7.0)

---
updated-dependencies:
- dependency-name: tikv-jemallocator
  dependency-version: 0.7.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-03 01:49:36 +00:00
dependabot[bot] b955593ac6 build(deps): bump filetime from 0.2.27 to 0.2.29
Bumps [filetime](https://github.com/alexcrichton/filetime) from 0.2.27 to 0.2.29.
- [Commits](https://github.com/alexcrichton/filetime/compare/0.2.27...0.2.29)

---
updated-dependencies:
- dependency-name: filetime
  dependency-version: 0.2.29
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-03 01:49:32 +00:00
dependabot[bot] 1d4fa16433 build(deps): bump jiff from 0.2.24 to 0.2.27
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.24 to 0.2.27.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/commits)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-06-03 01:49:25 +00:00
Thayne McCombs 42b2ab8a84 Merge pull request #1983 from DeflateAwning/feat-exact-i1963
feat: Add --exact argument to match exact filename
2026-05-20 01:26:24 -06:00
Thayne McCombs febc1b692f Merge pull request #2011 from stevenwalton/master
docs: Update Help String
2026-05-18 00:22:07 -06:00
Steven Walton 8f1f55b9da Merge resolution 2026-05-17 18:46:39 -07:00
Steven Walton 2fbecc9bd8 Swap regex and glob, fixing space. 2026-05-17 18:45:39 -07:00
Steven Walton 8fdab04b7a Update src/cli.rs
Co-authored-by: Thayne McCombs <astrothayne@gmail.com>
2026-05-17 18:43:27 -07:00
Thayne McCombs a2d6bea5ac Merge pull request #1984 from tmccombs/comment-ai-policy
docs: Add policy for comments
2026-05-17 13:18:30 -06:00
Thayne McCombs e3a065dfe1 docs: Remove unnecessary phrase
"if you are a non-native English speaker" isn't really needed.
2026-05-17 13:13:16 -06:00
curious-rabbit 66be8485bc fix format 2026-05-17 20:49:47 +02:00
curious-rabbit 7d18db23a7 improve patch 2026-05-17 20:35:00 +02:00
Thayne McCombs d491003759 Merge pull request #2006 from Sean-Kenneth-Doherty/codex/single-dash-search-path
Treat single dash as a literal search path
2026-05-17 12:32:09 -06:00
Steven Walton 4d88708d79 That period shouldn't have been included 2026-05-17 10:13:45 -07:00
Steven Walton 96a8dcd58b docs: Update Help String
Updated help string to clarify that fd respects gitignore by default.
Also added verbage to clarify that globbing and regex patterns are
accepted without a flag.
2026-05-17 10:07:02 -07:00
Sean Doherty f1dd935dea Apply changelog wording suggestion 2026-05-17 09:02:21 -05:00
Tavian Barnes 1cfac9ff7b Merge pull request #1974 from sharkdp/dependabot/github_actions/actions/upload-artifact-7.0.1
build(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1
2026-05-16 23:05:41 -04:00
Tavian Barnes 425d7d9e6b Merge pull request #1987 from sharkdp/dependabot/cargo/libc-0.2.186
build(deps): bump libc from 0.2.183 to 0.2.186
2026-05-16 23:00:57 -04:00
Sean Doherty 8dfa67a245 Treat single dash as search path 2026-05-16 17:15:00 -05:00
wuyangfan 9f938bea1e docs: drop accidental --full-path edits from extension PR
Scope this branch to -e/--extension only (#1693). Full-path help
clarifications remain in #1997.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 05:37:07 +08:00
wuyangfan e60582f838 docs: clarify that -e/--extension matches all entry types
Short help stays minimal; long help and man page explain that extension
filtering applies to directories as well unless --type restricts results.

Addresses maintainer feedback on #1922. Fixes #1693

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-17 04:47:24 +08:00
DeflateAwning 9f12a3059c docs: Add --exact to man page 2026-05-14 14:06:02 -06:00
DeflateAwning cb2f37a46a docs: Add --exact to changelog 2026-05-14 14:05:28 -06:00
DeflateAwning d642c446c9 fix: --exact should conflict with --fix-strings 2026-05-14 14:03:44 -06:00
DeflateAwning b77f9b811a test: Should not match substring filenames 2026-05-14 13:59:48 -06:00
curious-rabbit c96398c1bb cleanup 2026-05-05 21:48:32 +02:00
curious-rabbit a00259bf79 optimize 2026-05-05 21:27:25 +02:00
curious-rabbit 9d536e1a40 formatting 2026-05-02 20:56:11 +02:00
curious-rabbit aeecb5d8c0 apply strict filter 2026-05-02 20:52:29 +02:00
Thayne McCombs 7f1b1471d5 Merge pull request #1988 from sharkdp/dependabot/cargo/clap_complete-4.6.2
build(deps): bump clap_complete from 4.6.0 to 4.6.2
2026-05-02 00:49:19 -06:00
Thayne McCombs fe77ab4810 Merge pull request #1989 from sharkdp/dependabot/cargo/clap-4.6.1
build(deps): bump clap from 4.6.0 to 4.6.1
2026-05-02 00:48:55 -06:00
dependabot[bot] a876e69751 build(deps): bump clap_complete from 4.6.0 to 4.6.2
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.6.0 to 4.6.2.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.6.0...clap_complete-v4.6.2)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.6.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-02 06:14:32 +00:00
dependabot[bot] a58e1a2467 build(deps): bump clap from 4.6.0 to 4.6.1
Bumps [clap](https://github.com/clap-rs/clap) from 4.6.0 to 4.6.1.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.6.0...clap_complete-v4.6.1)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.6.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-02 06:14:26 +00:00
Thayne McCombs 5776a05a24 Merge pull request #1986 from sharkdp/dependabot/cargo/jiff-0.2.24
build(deps): bump jiff from 0.2.23 to 0.2.24
2026-05-02 00:13:21 -06:00
dependabot[bot] 8af8db28ed build(deps): bump libc from 0.2.183 to 0.2.186
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.183 to 0.2.186.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.186/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.183...0.2.186)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.186
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-01 21:06:00 +00:00
dependabot[bot] 104d0ce4e5 build(deps): bump jiff from 0.2.23 to 0.2.24
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.23 to 0.2.24.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.23...jiff-static-0.2.24)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.24
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-01 21:05:54 +00:00
curious-rabbit 825f308931 formatting 2026-04-27 12:56:06 +02:00
Thayne McCombs 2250bb0ad1 Merge pull request #1980 from sharkdp/dependabot/github_actions/softprops/action-gh-release-3.0.0
build(deps): bump softprops/action-gh-release from 2.6.1 to 3.0.0
2026-04-24 01:07:53 -06:00
Thayne McCombs a7a67e4998 Merge pull request #1889 from skane-lukas/issue-1888-fix-symlink-bash-completion
Fix symlink for bash completions
2026-04-24 01:00:42 -06:00
DeflateAwning 468c807049 docs: Update suggested non-regex note on regex failure 2026-04-23 15:31:03 -06:00
Thayne McCombs a86e16baa8 docs: Add policy for comments
Specify that comments on PRs should be written by humans
2026-04-23 01:07:42 -06:00
Thayne McCombs 0a3a485bd7 Merge pull request #1967 from tmccombs/pr-expectations
docs: Add PR Expectations
2026-04-23 00:58:15 -06:00
Thayne McCombs 4e2c81277a Merge pull request #1975 from SAY-5/fix/pattern-path-separator-v2
fix: flag any pattern containing a path separator, not just ones naming a directory
2026-04-23 00:36:23 -06:00
DeflateAwning 8f5a1675f5 test: Add --exact test cases, add --fixed-string cases too 2026-04-22 18:57:28 -06:00
DeflateAwning 82485bf18a feat: Add --exact argument to match exact filename 2026-04-22 18:51:04 -06:00
SAY-5 de422afd0b tests: gate forward-slash+full-path test off Windows
Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

On Windows the regex-over-full-path match uses `\`, so the
pattern `one/two/c` cannot match a real entry. The diagnostic-
didn't-fire behaviour this test pins is already covered by the
fact that the invocation does not error. Gate it to non-Windows
per tmccombs's CI feedback on the PR.
2026-04-21 00:58:09 -07:00
Thayne McCombs 4f4900b197 test: Fix included files
Fix test_pattern_with_forward_slash_allowed_with_full_path to include
all expected search results.
2026-04-21 01:08:17 -06:00
Thayne McCombs 0e74d5b75d Merge pull request #1979 from YoshKoz/fix/pwsh-placeholder-docs
docs: document PowerShell placeholder quoting requirement
2026-04-20 20:19:56 -06:00
SAY-5 ed47664191 fix: flag any pattern containing a path separator, not just ones that name a directory
Without --full-path, fd matches patterns against file names, so any pattern
containing a path separator can never match. The previous implementation
in main.rs fired the path-separator diagnostic only when the pattern also
named an existing directory on disk, so the most common Linux/macOS typo
- pasting a full path as the pattern - silently returned zero matches.

Restructure ensure_search_pattern_is_not_a_path so that any '/' in the
pattern triggers the diagnostic unconditionally, and keep the existing
'directory must exist on disk' guard only for the native '\' separator
on Windows, which is also the regex escape character. The Windows check
is short-circuited via '||' so the is_dir syscall never runs when the
pattern already contains '/'. The #[cfg_attr(not(windows), allow(unused_mut))]
attribute keeps the mut binding warning-free on non-Windows targets.

Update the error message to drop the now-ambiguous parenthetical that
showed the platform-specific separator character, and widen the
integration test assertions to cover the full first line so the
assert_failure_with_error helper (which trims lines on both sides) cannot
early-accept on a partial prefix.

Closes #1873

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>
2026-04-20 18:18:21 -07:00
dependabot[bot] 0fc795935d build(deps): bump softprops/action-gh-release from 2.6.1 to 3.0.0
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.6.1 to 3.0.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/153bb8e04406b158c6c84fc1615b65b24149a1fe...b4309332981a82ec1c5618f44dd2e27cc8bfbfda)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-20 20:02:35 +00:00
Yoshi Tacke c7f4f19ffb docs: address review feedback
Drop CHANGELOG entry for docs-only change. Simplify placeholder
note to be shell-agnostic per reviewer request.
2026-04-20 20:11:02 +02:00
curious-rabbit 63a7d85d26 improve patch 2026-04-20 14:28:18 +02:00
Yoshi Tacke d45c99b807 docs: document PowerShell placeholder quoting requirement
Closes #735
2026-04-20 10:24:33 +02:00
curious-rabbit 92c54d37c0 fix: sanitize escape sequence injection 2026-04-19 13:11:47 +02:00
dependabot[bot] 9ceba25bd9 build(deps): bump actions/upload-artifact from 7.0.0 to 7.0.1
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 7.0.0 to 7.0.1.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/bbbca2ddaa5d8feaa63e36b76fdaad77386f024f...043fb46d1a93c77aae656e7c1c64a875d1fc6a0a)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-17 17:43:00 +00:00
Thayne McCombs 90e73d72df Merge pull request #1959 from tmchow/osc/1958-ignore-parent
feat: add --ignore-parent option to override --no-ignore-parent
2026-04-16 13:03:00 -06:00
Thayne McCombs 749ea313f6 docs: Add PR Expectations
Add expectations for making pull requests to CONTRIBUTING.md

My main objective is to try to discourage low-effort AI generated pull
requests. But I realized several of the guidelines were actually more
general, so made the section as a whole more general.
2026-04-14 00:52:15 -06:00
Trevin Chow 72ff3cf694 feat: add --ignore-parent option to override --no-ignore-parent
Add the --ignore-parent flag, mirroring the existing pattern where
--ignore-vcs overrides --no-ignore-vcs. This lets users undo
--no-ignore-parent in aliases or config files.

Closes #1958
2026-04-06 00:53:39 -07:00
Thayne McCombs a665a3bba9 Merge pull request #1953 from Rohan5commit/docs-macos-comment-20260404
docs: fix macOS spelling in BSD ls comment
2026-04-03 23:44:14 -06:00
Codex 078f5d184e docs: fix macOS spelling in BSD ls comment 2026-04-04 10:14:25 +08:00
Thayne McCombs 607ae385f6 Merge pull request #1950 from sharkdp/dependabot/cargo/tempfile-3.27.0
build(deps): bump tempfile from 3.26.0 to 3.27.0
2026-04-03 00:45:52 -06:00
Thayne McCombs 866ba9bfd5 Merge pull request #1951 from sharkdp/dependabot/cargo/clap_complete-4.6.0
build(deps): bump clap_complete from 4.5.66 to 4.6.0
2026-04-02 01:24:27 -06:00
Thayne McCombs 2f6a2a88c5 Merge pull request #1952 from sharkdp/dependabot/cargo/clap-4.6.0
build(deps): bump clap from 4.5.60 to 4.6.0
2026-04-02 01:23:58 -06:00
dependabot[bot] 5c4654acb6 build(deps): bump clap from 4.5.60 to 4.6.0
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.60 to 4.6.0.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.60...clap_complete-v4.6.0)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 22:28:21 +00:00
dependabot[bot] c327231e36 build(deps): bump clap_complete from 4.5.66 to 4.6.0
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.66 to 4.6.0.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.66...clap_complete-v4.6.0)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.6.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 22:28:16 +00:00
dependabot[bot] 246f5b5e66 build(deps): bump tempfile from 3.26.0 to 3.27.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.26.0 to 3.27.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.26.0...v3.27.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.27.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-04-01 22:28:11 +00:00
David Peter 7cf8c85113 Update README 2026-03-31 09:06:11 +02:00
Tavian Barnes fdb5534f66 Merge pull request #1946 from tmccombs/runner-os-update
chore: Update os matrix
2026-03-28 12:30:12 -04:00
Thayne McCombs 1b66ab5d7a chore: Update os matrix
Update the versions of Windows and Mac OSes used in build matrix.

Also add back intel Mac since on the latest version that is still
supported until 2027.

Fixes: #1945
Fixes: #1918
2026-03-28 00:57:39 -06:00
Thayne McCombs 8a7ff7d438 Merge pull request #1941 from tmccombs/fix-attest
Fix attest
2026-03-25 01:08:18 -06:00
Thayne McCombs 45646e2eaf fix(ci): Remove unnecessary compression
Don't compress something that is already compressed.
2026-03-25 00:45:23 -06:00
Thayne McCombs 5008de5052 fix: correct attestation subjects
Use the original files as the source, rather than the file that is
uploaded to the artifact, as that is actually a zip file (what?)

Fixes: #1936
2026-03-25 00:45:23 -06:00
Tavian Barnes d6b44b81b6 Merge pull request #1928 from tmccombs/full-path-fixes
Full path fixes
2026-03-24 06:45:07 -04:00
Thayne McCombs 9d137d358d Merge pull request #1940 from sharkdp/dependabot/github_actions/softprops/action-gh-release-2.6.1
build(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.1
2026-03-23 14:08:37 -07:00
dependabot[bot] 1d386abc84 build(deps): bump softprops/action-gh-release from 2.5.0 to 2.6.1
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.5.0 to 2.6.1.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/a06a81a03ee405af7f2048a818ed3f03bbf83c7b...153bb8e04406b158c6c84fc1615b65b24149a1fe)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-23 18:04:35 +00:00
Thayne McCombs 0336452b96 Merge pull request #1934 from Rohan5commit/docs/fix-contributing-intro-20260319
Fix CONTRIBUTING introduction grammar
2026-03-18 22:21:52 -07:00
rohan436 f8baea833f docs: fix CONTRIBUTING grammar 2026-03-19 09:41:50 +08:00
Thayne McCombs dc9c503c7d refactor: Rename cwd as full_path_base
Because I think it makes it's intention more clear.
2026-03-17 00:53:34 -06:00
Thayne McCombs cd4fd03fa0 refactor: Avoid unnecessary allocation
Use Cow::borrowed, if we can re-use the already absolute path.
2026-03-17 00:53:34 -06:00
Thayne McCombs fcd846651b Merge pull request #1921 from rexkirshner/fix-exclude-value-name-glob
Change --exclude value name from 'pattern' to 'glob'
2026-03-17 00:17:24 -06:00
Thayne McCombs 6d77799759 Merge pull request #1917 from Xavrir/issue-1900
fix: handle invalid working directories gracefully with --full-path
2026-03-16 02:36:16 -06:00
Thayne McCombs db7d448fd4 Merge pull request #1924 from liruiluo/docs/clarify-exec-arg-boundary
docs: clarify how --exec consumes positional arguments
2026-03-13 20:41:09 -06:00
liruiluo 2278836060 docs: clarify --exec positional argument handling 2026-03-14 09:16:22 +08:00
Rex Kirshner 37f3c2e6cb Change --exclude value name from "pattern" to "glob"
The summary line `-E, --exclude <pattern>` is misleading because fd
defaults to regex for its main search pattern, but --exclude takes a
glob. Rename the value placeholder to "glob" in the CLI help, man page,
and README to match the actual behavior.

Fixes #1724

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-12 09:03:56 -07:00
Rizky Mirzaviandy Priambodo 807aa11d03 chore: remove unrelated planning files 2026-03-11 22:11:40 +07:00
Rizky Mirzaviandy Priambodo 647ced8ff0 fix: address review comments - use into_os_string() and move changelog to unreleased section 2026-03-11 22:11:26 +07:00
Rizky Mirzaviandy Priambodo 26756f21fa refactor: cache cwd at startup instead of per-entry resolution
Instead of calling current_dir() for every entry when --full-path is
set, cache it once in Config at startup. This eliminates the need for
FatalError handling and makes path resolution infallible during the
walk. If the cwd can't be retrieved, fd now fails early with a clear
error message.
2026-03-10 20:34:38 +07:00
Rizky Mirzaviandy Priambodo 24f7f2b9ef ci: retrigger workflow for second validation pass 2026-03-10 20:28:12 +07:00
Rizky Mirzaviandy Priambodo d3a500af7a fix: handle invalid working directories gracefully with --full-path (#1900)
- Add FatalError variant to WorkerResult for unrecoverable errors
- Extract search_str_for_entry() helper to propagate IO errors from path_absolute_form
- Propagate fatal errors through job and batch execution paths
- Add regression test for invalid cwd scenario
- Update CHANGELOG for #1900
2026-03-10 20:28:12 +07:00
Thayne McCombs 7027d45303 Merge pull request #1916 from tmccombs/release-v10.4.2
chore: Bump to 10.4.2
2026-03-10 01:32:25 -06:00
Thayne McCombs bf6489a79b chore: Bump to 10.4.2 2026-03-09 01:56:38 -06:00
Thayne McCombs 160d00f8fe Add a little more automation for the release
Add an awk script for automatically updating the help
text in README.md
2026-03-09 01:52:08 -06:00
Thayne McCombs cb3fad48bb Merge pull request #1914 from tmccombs/faster-ignore-contains
perf: Avoid unnecessary syscall for ignore-contain
2026-03-08 19:44:38 -06:00
Thayne McCombs a4d86cc1f5 perf: Avoid unnecessary syscall for ignore-contain
Instead of calling `is_dir` on the path, call it on the file_type of the
DirEntry, since we should already have that information without needing
to do another syscall.

Fixes: #1913
2026-03-08 17:09:39 -06:00
Tavian Barnes b691572928 Merge pull request #1912 from tmccombs/changelog-bump
Add upcoming to changelog
2026-03-08 07:58:54 -04:00
Thayne McCombs ec25d2bc81 Add upcoming to changelog 2026-03-08 03:09:13 -06:00
Thayne McCombs 4ea110d8dd Merge pull request #1911 from tmccombs/release-10.4.1
Prepare 10.4.1 release
2026-03-08 01:38:40 -07:00
Thayne McCombs d766e76351 Prepare 10.4.1 release 2026-03-08 01:02:24 -07:00
Thayne McCombs aa35ef4e45 Merge pull request #1904 from tmccombs/fix-deploy
fix(build): Fix attestation
2026-03-07 12:38:21 -07:00
Thayne McCombs b87d919244 fix(build): Remove extra colons 2026-03-07 11:55:38 -07:00
Thayne McCombs bb3d57c433 fix(build): Fix attestation
Use the right output in the github action.

Also pin the versions of the upload-artifact and attest actions.
2026-03-07 01:34:30 -07:00
Thayne McCombs ff1f66cceb Merge pull request #1901 from sharkdp/dependabot/github_actions/actions/attest-build-provenance-4
build(deps): bump actions/attest-build-provenance from 3 to 4
2026-03-06 20:20:54 -07:00
dependabot[bot] d9fc3272db build(deps): bump actions/attest-build-provenance from 3 to 4
Bumps [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance) from 3 to 4.
- [Release notes](https://github.com/actions/attest-build-provenance/releases)
- [Changelog](https://github.com/actions/attest-build-provenance/blob/main/RELEASE.md)
- [Commits](https://github.com/actions/attest-build-provenance/compare/v3...v4)

---
updated-dependencies:
- dependency-name: actions/attest-build-provenance
  dependency-version: '4'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-03-06 17:43:08 +00:00
skane-lukas 247a5172e5 Fix completions for alias fdfind in deb package for bash, zsh and fish.
Closes #1888
2026-03-03 08:38:53 +01:00
Thayne McCombs c60d0076db Merge pull request #1893 from tmccombs/release-10.4.0
chore(release): Prepare for 10.4.0
2026-03-01 11:45:20 -07:00
Thayne McCombs 801ccd7620 chore(release): Prepare for 10.4.0 2026-02-28 23:31:48 -07:00
Thayne McCombs a07ad51751 Merge pull request #1891 from FidelSch/c-static-link
config: statically link C runtime for Windows MSVC
2026-02-24 10:51:08 -07:00
FidelSch 6067f72742 docs: update changelog to include static linking of CRT for MSVC builds 2026-02-24 10:18:59 -03:00
FidelSch 73e6f95416 config: static linking of C runtime on Windows MSVC 2026-02-24 10:13:42 -03:00
Thayne McCombs 40d8eb30bc Merge pull request #1861 from tmccombs/faster-dev-compile
build: Reduce debug info for dev builds
2026-02-02 19:02:50 -07:00
Thayne McCombs 38986aa42c Merge pull request #1881 from sharkdp/dependabot/cargo/jiff-0.2.18
build(deps): bump jiff from 0.2.17 to 0.2.18
2026-02-01 22:23:48 -07:00
dependabot[bot] 171438be2d build(deps): bump jiff from 0.2.17 to 0.2.18
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.17 to 0.2.18.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.17...jiff-static-0.2.18)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-01 23:34:19 +00:00
Thayne McCombs fe0e173e9e Merge pull request #1880 from sharkdp/dependabot/cargo/filetime-0.2.27
build(deps): bump filetime from 0.2.26 to 0.2.27
2026-02-01 16:31:38 -07:00
Thayne McCombs 9a9c4b921d Merge pull request #1882 from sharkdp/dependabot/cargo/nix-0.31.1
build(deps): bump nix from 0.30.1 to 0.31.1
2026-02-01 16:31:11 -07:00
Thayne McCombs efd9f05fcb Merge pull request #1879 from sharkdp/dependabot/cargo/libc-0.2.180
build(deps): bump libc from 0.2.178 to 0.2.180
2026-02-01 16:29:14 -07:00
Thayne McCombs ccafbbb08a Merge pull request #1878 from sharkdp/dependabot/cargo/clap-4.5.54
build(deps): bump clap from 4.5.53 to 4.5.54
2026-02-01 16:27:17 -07:00
dependabot[bot] 74c389f847 build(deps): bump nix from 0.30.1 to 0.31.1
Bumps [nix](https://github.com/nix-rust/nix) from 0.30.1 to 0.31.1.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.30.1...v0.31.1)

---
updated-dependencies:
- dependency-name: nix
  dependency-version: 0.31.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-01 17:42:47 +00:00
dependabot[bot] 2fc76da442 build(deps): bump filetime from 0.2.26 to 0.2.27
Bumps [filetime](https://github.com/alexcrichton/filetime) from 0.2.26 to 0.2.27.
- [Commits](https://github.com/alexcrichton/filetime/compare/0.2.26...0.2.27)

---
updated-dependencies:
- dependency-name: filetime
  dependency-version: 0.2.27
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-01 17:42:36 +00:00
dependabot[bot] b22a46c103 build(deps): bump libc from 0.2.178 to 0.2.180
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.178 to 0.2.180.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.180/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.178...0.2.180)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.180
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-01 17:42:28 +00:00
dependabot[bot] 1586dabeee build(deps): bump clap from 4.5.53 to 4.5.54
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.53 to 4.5.54.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.53...clap_complete-v4.5.54)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.54
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-02-01 17:42:21 +00:00
Thayne McCombs 0a094a883f Merge pull request #1877 from littleKitchen/docs/update-completions-readme
docs: update shell completions instructions in README
2026-01-30 08:46:50 -07:00
Yuxuan Che 4410dda6e4 docs: add shell completion generation instructions
Add documentation for generating completions using fd --gen-completions,
while keeping and clarifying the existing instructions for pre-built
completions from release archives.

- Clarify that pre-built completions are in release archives (autocomplete dir)
- Add new section for generating completions with fd --gen-completions
- Include examples for bash, zsh, fish, and powershell
2026-01-29 21:33:12 -08:00
Thayne McCombs bf81fb98fa Merge pull request #1852 from fischman/1727-ignore-contain
`--ignore-contain`: ignore directories containing a named entry.
2026-01-20 00:48:43 -07:00
Thayne McCombs 9508153471 Merge pull request #1862 from jylenhof/master
docs(README): add mise alternative method installation
2026-01-20 00:42:34 -07:00
Thayne McCombs 1a37650b2c Merge pull request #1872 from josephadamsdev/fix-1843-windows-hyperlink-slash
Fix Windows hyperlinks for paths with spaces
2026-01-16 09:04:56 -07:00
Joseph Adams dcc5ff84cd Update CHANGELOG.md 2026-01-16 10:44:01 +01:00
Joseph Adams 9c9eeda209 Update CHANGELOG.md 2026-01-16 10:38:42 +01:00
Joseph Adams 4ba10c7837 Add changelog entry for Windows hyperlink fix 2026-01-16 10:37:21 +01:00
Joseph Adams 2efd99bc52 Update hyperlink test for Windows file URLs 2026-01-15 10:12:16 +01:00
Joseph Adams cd8fedc183 Fix Windows hyperlinks for paths with spaces
Fixes #1843

Changed the host() function for Windows to return '/' instead of ''
to generate RFC 3986 compliant file URLs with three slashes.

Before: file://C:/test/hi%20there.txt (broken)
After:  file:///C:/test/hi%20there.txt (works)

This fixes hyperlinks failing on Windows when file paths contain
spaces or other characters that require percent-encoding.
2026-01-14 23:53:43 +01:00
Ami Fischman f3a8bb7ce6 ignore_contain now has higher precedence than root check. 2026-01-14 07:58:30 -08:00
Ami Fischman 1df183e0cd cargo fmt 2026-01-13 16:37:11 -08:00
Ami Fischman 1993c76971 Fixes for tmccombs review comments. 2026-01-13 16:16:11 -08:00
Thayne McCombs 5f95a78121 Merge pull request #1870 from sharkdp/dependabot/cargo/libc-0.2.178
build(deps): bump libc from 0.2.177 to 0.2.178
2026-01-01 12:28:48 -07:00
Thayne McCombs 49ded38b8a Merge pull request #1869 from sharkdp/dependabot/cargo/tempfile-3.24.0
build(deps): bump tempfile from 3.23.0 to 3.24.0
2026-01-01 12:27:39 -07:00
Thayne McCombs 9907632b89 Merge pull request #1868 from sharkdp/dependabot/cargo/jiff-0.2.17
build(deps): bump jiff from 0.2.16 to 0.2.17
2026-01-01 11:07:50 -07:00
dependabot[bot] 8ec9d3115e build(deps): bump libc from 0.2.177 to 0.2.178
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.177 to 0.2.178.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.178/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.177...0.2.178)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.178
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 17:01:32 +00:00
dependabot[bot] 96502d2611 build(deps): bump tempfile from 3.23.0 to 3.24.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.23.0 to 3.24.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.23.0...v3.24.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.24.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 17:01:24 +00:00
dependabot[bot] 6c5267e240 build(deps): bump jiff from 0.2.16 to 0.2.17
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.16 to 0.2.17.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.16...jiff-static-0.2.17)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.17
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-01-01 17:01:19 +00:00
Thayne McCombs 84789bfe57 Merge pull request #1864 from sergii4/update-clap-complete-4.5.62
build(deps): bump clap_complete from 4.5.61 to 4.5.62
2025-12-25 08:04:24 -07:00
Sergii Getman 19dcbff562 build(deps): bump clap_complete from 4.5.61 to 4.5.62
This update fixes fish shell completion formatting issues where
ValueEnum descriptions were not properly separated with tabs,
causing fish to fail parsing the completions.

The fix was introduced in clap-rs/clap#5874 which changed the
fish completion generator to use proper multi-line format with
quotes instead of the brace format.

Fixes fish shell completions for options like --type and --color
that have enum values with descriptions.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-25 14:48:02 +00:00
jylenhof e311e503ba docs(README): add mise alternative method installation
Signed-off-by: jylenhof <jygithub@lenhof.eu.org>
2025-12-15 22:53:01 +01:00
Thayne McCombs bd33bc0eb6 build: Reduce debug info for dev builds
Hopefully this will sped up dev builds. Adds a new debugging profile if
full debug symbols are needed.
2025-12-13 00:04:05 -07:00
Thayne McCombs f5b4171631 Merge pull request #1859 from sharkdp/dependabot/github_actions/softprops/action-gh-release-2.5.0
build(deps): bump softprops/action-gh-release from 2.4.1 to 2.5.0
2025-12-08 10:58:55 -07:00
dependabot[bot] 16e5d9b816 build(deps): bump softprops/action-gh-release from 2.4.1 to 2.5.0
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 2.4.1 to 2.5.0.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/6da8fa9354ddfdc4aeace5fc48d7f679b5214090...a06a81a03ee405af7f2048a818ed3f03bbf83c7b)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-version: 2.5.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-08 17:06:22 +00:00
Thayne McCombs c90994b36a Merge pull request #1853 from sharkdp/dependabot/cargo/clap_complete-4.5.61
build(deps): bump clap_complete from 4.5.60 to 4.5.61
2025-12-02 10:46:34 -07:00
dependabot[bot] 728b380c67 build(deps): bump clap_complete from 4.5.60 to 4.5.61
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.60 to 4.5.61.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.60...clap_complete-v4.5.61)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.5.61
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-02 04:06:28 +00:00
Thayne McCombs 2d9c8dab31 Merge pull request #1855 from sharkdp/dependabot/cargo/clap-4.5.53
build(deps): bump clap from 4.5.51 to 4.5.53
2025-12-01 20:43:19 -07:00
Thayne McCombs 161f3ba7cd Merge pull request #1854 from sharkdp/dependabot/cargo/jiff-0.2.16
build(deps): bump jiff from 0.2.15 to 0.2.16
2025-12-01 20:42:35 -07:00
dependabot[bot] e2ae9e88b2 build(deps): bump clap from 4.5.51 to 4.5.53
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.51 to 4.5.53.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.51...clap_complete-v4.5.53)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.53
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 18:42:58 +00:00
dependabot[bot] a06417d355 build(deps): bump jiff from 0.2.15 to 0.2.16
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.15 to 0.2.16.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.15...jiff-static-0.2.16)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.16
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 18:42:52 +00:00
Ami Fischman d05a718be5 --ignore-contain: ignore directories containing a named entry (e.g. [CACHEDIR.TAG](https://bford.info/cachedir/)).
Fixes #1727.
2025-11-28 11:49:37 -08:00
Thayne McCombs e3a6f8b7e7 Merge pull request #1850 from sharkdp/dependabot/github_actions/actions/checkout-6
build(deps): bump actions/checkout from 5 to 6
2025-11-27 10:22:24 -07:00
dependabot[bot] 76046b23b0 build(deps): bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-27 17:05:20 +00:00
Thayne McCombs 098bb568e1 Merge pull request #1849 from bigmoonbit/master
chore: fix typo in tests/tests.rs
2025-11-27 00:34:21 -07:00
bigmoonbit 1fb1cafc15 chore: fix typo in tests/tests.rs
Signed-off-by: bigmoonbit <bigmoonbit@outlook.com>
2025-11-27 15:00:09 +08:00
Tavian Barnes 8661ac473c Merge pull request #1839 from andstepan/fix/read-bin-from-environment
tests/testenv/mod.rs: Change how fd binary executable is located
2025-11-18 07:18:18 -05:00
Andreas Stergiopoulos b6af107ac6 tests/testenv/mod.rs: Change how fd binary executable is located
This commit changes the way that the binary executable of fd is located
during integration tests. Previously, the find_fd_exe function would just
navigate in the parent directory and try to find the binary here. This
method is not appropriate as it assumes that the test directory will have
the same layout as the build directory, which also leaks the build time
configuration.

With this patch, the location of the binary executable is read using the
CARGO_BIN_EXE_fd environment variable. The code at first tries to read
the variable at run time, and if it is not available it then uses the env!
macro which returns the value of the variable exposed at compile time.

This way of reading the binary location makes the code more flexible and
friendlier to cross compile.

This commit closes #1838 .

Signed-off-by: Andreas Stergiopoulos <andreas.stergiopoulos@smile.fr>
2025-11-18 10:25:35 +01:00
Thayne McCombs 491baaa2d1 Merge pull request #1834 from tmccombs/cross-install
cross install
2025-11-11 00:09:02 -07:00
Thayne McCombs 68fa2dbaed feat(build): Install cross directly
Removes a dependency on an action repo.

This works similarly to how ripgrep currently installs cross.
2025-11-11 00:02:33 -07:00
Tavian Barnes 15b57b9e78 Merge pull request #1833 from tmccombs/build-fixes
fix[build]: Fix syntax of github action
2025-11-09 18:06:33 -05:00
Thayne McCombs 3b32256715 fix[build]: Fix syntax of github action 2025-11-09 15:51:16 -07:00
Tavian Barnes 32f9fd3314 Merge pull request #1832 from sharkdp/dependabot/cargo/globset-0.4.18
build(deps): bump globset from 0.4.17 to 0.4.18
2025-11-09 09:45:31 -05:00
Tavian Barnes cfc4ace4f4 Merge pull request #1831 from sharkdp/dependabot/cargo/lscolors-0.21.0
build(deps): bump lscolors from 0.20.0 to 0.21.0
2025-11-09 09:45:17 -05:00
Tavian Barnes 7fdfd40107 Merge pull request #1830 from sharkdp/dependabot/cargo/ignore-0.4.25
build(deps): bump ignore from 0.4.24 to 0.4.25
2025-11-09 09:45:03 -05:00
dependabot[bot] d7bfcf48b8 build(deps): bump globset from 0.4.17 to 0.4.18
Bumps [globset](https://github.com/BurntSushi/ripgrep) from 0.4.17 to 0.4.18.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/globset-0.4.17...globset-0.4.18)

---
updated-dependencies:
- dependency-name: globset
  dependency-version: 0.4.18
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-09 09:16:26 +00:00
dependabot[bot] 942b68ea3b build(deps): bump lscolors from 0.20.0 to 0.21.0
Bumps [lscolors](https://github.com/sharkdp/lscolors) from 0.20.0 to 0.21.0.
- [Release notes](https://github.com/sharkdp/lscolors/releases)
- [Commits](https://github.com/sharkdp/lscolors/compare/v0.20.0...v0.21.0)

---
updated-dependencies:
- dependency-name: lscolors
  dependency-version: 0.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-09 09:16:21 +00:00
dependabot[bot] e08038c34c build(deps): bump ignore from 0.4.24 to 0.4.25
Bumps [ignore](https://github.com/BurntSushi/ripgrep) from 0.4.24 to 0.4.25.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/ignore-0.4.24...ignore-0.4.25)

---
updated-dependencies:
- dependency-name: ignore
  dependency-version: 0.4.25
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-09 09:16:14 +00:00
Thayne McCombs 2f5ab52897 Merge pull request #1828 from HastD/zizmor
ci: resolve Zizmor-identified workflow issues
2025-11-09 02:15:24 -07:00
Thayne McCombs 19e752d184 Merge pull request #1829 from jaideepkathiresan/docs/security-policy
docs(security): clarify where to send vulnerability reports (#1827)
2025-11-09 00:47:21 -07:00
jaideepkathiresan c3652afc2b docs(security): clarify where to send vulnerability reports (#1827) 2025-11-09 09:22:18 +05:30
Daniel Hast 7014993561 ci: resolve Zizmor-identified workflow issues
* Set dependabot cooldown timer of 7 days, which helps mitigate
  stability and supply-chain security risks. For more info, see
  https://docs.zizmor.sh/audits/#dependabot-cooldown
* Restrict write permissions to the job that actually needs them.
* Set `persist-credentials: false` for `actions/checkout`. See
  https://docs.zizmor.sh/audits/#artipacked
* Use environment variables instead of template expansions in code
  contexts. See https://docs.zizmor.sh/audits/#template-injection
* Pin action dependencies to SHA hashes.
2025-11-06 11:48:12 -05:00
Thayne McCombs 72e54e8e9e Merge pull request #1824 from sharkdp/dependabot/cargo/ctrlc-3.5.1
build(deps): bump ctrlc from 3.5.0 to 3.5.1
2025-11-03 23:29:19 -07:00
Thayne McCombs cd95cfcfe0 Merge pull request #1826 from sharkdp/dependabot/cargo/clap_complete-4.5.60
build(deps): bump clap_complete from 4.5.59 to 4.5.60
2025-11-01 13:23:55 -06:00
Thayne McCombs 78a34dd1e9 Merge pull request #1825 from sharkdp/dependabot/cargo/clap-4.5.51
build(deps): bump clap from 4.5.50 to 4.5.51
2025-11-01 13:23:29 -06:00
Thayne McCombs e7e78d7b6a Merge pull request #1823 from sharkdp/dependabot/cargo/aho-corasick-1.1.4
build(deps): bump aho-corasick from 1.1.3 to 1.1.4
2025-11-01 13:22:58 -06:00
dependabot[bot] a19c874fee build(deps): bump clap_complete from 4.5.59 to 4.5.60
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.59 to 4.5.60.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.59...clap_complete-v4.5.60)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.5.60
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-01 17:01:20 +00:00
dependabot[bot] 90c94a2ea9 build(deps): bump clap from 4.5.50 to 4.5.51
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.50 to 4.5.51.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.50...clap_complete-v4.5.51)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.51
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-01 17:01:14 +00:00
dependabot[bot] 73a470d076 build(deps): bump ctrlc from 3.5.0 to 3.5.1
Bumps [ctrlc](https://github.com/Detegr/rust-ctrlc) from 3.5.0 to 3.5.1.
- [Release notes](https://github.com/Detegr/rust-ctrlc/releases)
- [Commits](https://github.com/Detegr/rust-ctrlc/compare/3.5.0...3.5.1)

---
updated-dependencies:
- dependency-name: ctrlc
  dependency-version: 3.5.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-01 17:01:08 +00:00
dependabot[bot] 7c2584b11d build(deps): bump aho-corasick from 1.1.3 to 1.1.4
Bumps [aho-corasick](https://github.com/BurntSushi/aho-corasick) from 1.1.3 to 1.1.4.
- [Commits](https://github.com/BurntSushi/aho-corasick/compare/1.1.3...1.1.4)

---
updated-dependencies:
- dependency-name: aho-corasick
  dependency-version: 1.1.4
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-01 17:01:03 +00:00
Thayne McCombs 1d85f3be67 Merge pull request #1821 from tmccombs/changelog-updates
docs(CHANGELOG): list bugs fixed by ignore upgrade
2025-11-01 00:40:35 -06:00
Thayne McCombs a836d865f0 Merge pull request #1820 from tmccombs/etc-upgrade
chore(deps): Update etcetera package
2025-11-01 00:40:14 -06:00
Thayne McCombs f360a772b0 docs(CHANGELOG): list bugs fixed by ignore upgrade 2025-10-31 00:52:05 -06:00
Thayne McCombs 202db498c0 chore(deps): Update etcetera package
Which allows removing a dependency on home
2025-10-31 00:08:52 -06:00
Thayne McCombs d23ac06e40 Merge pull request #1813 from tmccombs/rust-version
Rust version
2025-10-27 23:57:53 -06:00
Thayne McCombs dbd3e3c14c build(msrv): Update msrv to 1.90.0
And upgrade to 2024 edition
2025-10-27 02:05:37 -06:00
Thayne McCombs da731c48d9 build(deps): bump ignore to 0.4.24
This should hopefully fix some bugs around gitignore.

Also run `cargo update` to update the lockfile
2025-10-27 02:02:58 -06:00
Thayne McCombs 5558e407be Merge pull request #1805 from tmccombs/exec-nuls
fix: --print0 now works with --exec
2025-10-25 23:49:24 -06:00
Thayne McCombs f77b693db2 Merge pull request #1810 from Sambhram1/master
"Add cargo-binstall support"
2025-10-17 13:09:58 -06:00
Sambhram 9842656b2b "Add cargo-binstall support" 2025-10-17 16:50:14 +00:00
Thayne McCombs 97b3b0404e Merge pull request #1809 from tmccombs/attestation
feat[release]: Add attestation for release artifacts
2025-10-15 16:27:39 -06:00
Thayne McCombs 54fa0112f5 Merge pull request #1808 from sivaramsk/master
Add -C as a short option to change base-directory
2025-10-14 00:38:48 -06:00
Sivaram Kannan c7a05504f4 Remove the trailing white space in -C short option. 2025-10-14 11:42:46 +05:30
Thayne McCombs 80d0fb2b70 feat[release]: Add attestation for release artifacts 2025-10-13 23:59:51 -06:00
Sivaram Kannan 3263141223 Add -C option to the manpage fd.1. 2025-10-14 08:14:46 +05:30
Sivaram Kannan 98a4233e14 Add base-directory entry along with short option -C in the README.md file. 2025-10-14 08:13:55 +05:30
Sivaram Kannan 4e6f46b191 Add short option -C to the option base-directory. 2025-10-14 08:12:04 +05:30
Thayne McCombs 8c9c6bec75 Merge pull request #1802 from sharkdp/dependabot/cargo/anyhow-1.0.100
build(deps): bump anyhow from 1.0.99 to 1.0.100
2025-10-03 01:21:39 -06:00
Thayne McCombs ee5332d0d3 fix: --print0 now works with --exec
If you use --print0 with --exec, it will now print a \0 between each set
of commands run. That is, between the output for the commands run for
each found item.

Fixes: #1797
2025-10-03 01:15:48 -06:00
Thayne McCombs 2ae1154be4 fix: Clippy warning from anyhow update 2025-10-02 23:08:37 -06:00
dependabot[bot] e89650f169 build(deps): bump anyhow from 1.0.99 to 1.0.100
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.99 to 1.0.100.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.99...1.0.100)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-version: 1.0.100
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-02 00:34:09 +00:00
Thayne McCombs ba2dde80f3 Merge pull request #1801 from sharkdp/dependabot/cargo/clap_complete-4.5.58
build(deps): bump clap_complete from 4.5.57 to 4.5.58
2025-10-01 18:29:52 -06:00
Thayne McCombs 7f3dd94092 Merge pull request #1804 from sharkdp/dependabot/cargo/clap-4.5.48
build(deps): bump clap from 4.5.46 to 4.5.48
2025-10-01 18:29:13 -06:00
Thayne McCombs 10d1ecf2a2 Merge pull request #1803 from sharkdp/dependabot/cargo/tempfile-3.23.0
build(deps): bump tempfile from 3.21.0 to 3.23.0
2025-10-01 18:05:41 -06:00
dependabot[bot] 3f77968f1d build(deps): bump clap from 4.5.46 to 4.5.48
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.46 to 4.5.48.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.46...clap_complete-v4.5.48)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.48
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-01 17:01:42 +00:00
dependabot[bot] 92bdd78e56 build(deps): bump tempfile from 3.21.0 to 3.23.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.21.0 to 3.23.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.21.0...v3.23.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.23.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-01 17:01:37 +00:00
dependabot[bot] 27d90dca17 build(deps): bump clap_complete from 4.5.57 to 4.5.58
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.57 to 4.5.58.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.57...clap_complete-v4.5.58)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.5.58
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-01 17:01:27 +00:00
Thayne McCombs 47cedbb44e Merge pull request #1799 from ritoban23/fix-powershell-completion-collision
Fix PowerShell completion filename collision on Windows
2025-09-26 08:39:31 -06:00
ritoban23 a32e6a8d3e Fix PowerShell completion filename collision on Windows 2025-09-26 16:08:10 +05:30
David Peter b3e3977c2b Update Tuple logo 2025-09-23 19:39:33 +02:00
Thayne McCombs 8d254c5337 Merge pull request #1796 from sorairolake/remove-build-rs
build: Remove `build.rs`
2025-09-19 09:29:48 -06:00
Shun Sakai 5c4477c9d3 build: Remove build.rs
The `rust-version` field has been set and the MSRV is validated by
this. So the build script is no longer needed.
2025-09-19 19:31:55 +09:00
Thayne McCombs 4344a26540 Merge pull request #1782 from tmccombs/completion-docs
docs: Add some documentation on how to install completions
2025-09-05 19:22:08 -06:00
David Peter 37b67767a2 Update README 2025-09-04 09:03:17 +02:00
Thayne McCombs 1c316becf3 Merge pull request #1791 from sharkdp/dependabot/cargo/anyhow-1.0.99
build(deps): bump anyhow from 1.0.98 to 1.0.99
2025-09-03 11:46:45 -06:00
dependabot[bot] 1ccb6fd2f2 build(deps): bump anyhow from 1.0.98 to 1.0.99
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.98 to 1.0.99.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.98...1.0.99)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-version: 1.0.99
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-03 17:28:47 +00:00
Thayne McCombs e1cb0f44a3 Merge pull request #1792 from sharkdp/dependabot/cargo/libc-0.2.175
build(deps): bump libc from 0.2.174 to 0.2.175
2025-09-03 11:28:29 -06:00
Thayne McCombs 009d776db5 Merge pull request #1790 from sharkdp/dependabot/cargo/clap_complete-4.5.57
build(deps): bump clap_complete from 4.5.55 to 4.5.57
2025-09-03 11:27:48 -06:00
dependabot[bot] 32558eaf4e build(deps): bump libc from 0.2.174 to 0.2.175
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.174 to 0.2.175.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.175/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.174...0.2.175)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.175
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-03 10:20:00 +00:00
dependabot[bot] 5be8cc0167 build(deps): bump clap_complete from 4.5.55 to 4.5.57
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.55 to 4.5.57.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.55...clap_complete-v4.5.57)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.5.57
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-03 06:34:29 +00:00
Thayne McCombs e6cf1875ed Merge pull request #1785 from sharkdp/dependabot/cargo/clap-4.5.46
build(deps): bump clap from 4.5.42 to 4.5.46
2025-09-02 09:41:11 -06:00
Thayne McCombs 377c442c4e Merge pull request #1786 from sharkdp/dependabot/cargo/regex-syntax-0.8.6
build(deps): bump regex-syntax from 0.8.5 to 0.8.6
2025-09-02 09:40:26 -06:00
Thayne McCombs 13d79ffd41 Merge pull request #1787 from sharkdp/dependabot/cargo/regex-1.11.2
build(deps): bump regex from 1.11.1 to 1.11.2
2025-09-02 09:40:03 -06:00
Thayne McCombs ddf144b596 Merge pull request #1788 from sharkdp/dependabot/cargo/tempfile-3.21.0
build(deps): bump tempfile from 3.20.0 to 3.21.0
2025-09-02 09:39:04 -06:00
dependabot[bot] fb3ffca4c7 build(deps): bump tempfile from 3.20.0 to 3.21.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.20.0 to 3.21.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.20.0...v3.21.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.21.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-02 10:38:14 +00:00
dependabot[bot] 725b296ce4 build(deps): bump regex from 1.11.1 to 1.11.2
Bumps [regex](https://github.com/rust-lang/regex) from 1.11.1 to 1.11.2.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.11.1...1.11.2)

---
updated-dependencies:
- dependency-name: regex
  dependency-version: 1.11.2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-02 09:41:20 +00:00
dependabot[bot] a13e0b9926 build(deps): bump regex-syntax from 0.8.5 to 0.8.6
Bumps [regex-syntax](https://github.com/rust-lang/regex) from 0.8.5 to 0.8.6.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/regex-syntax-0.8.5...regex-syntax-0.8.6)

---
updated-dependencies:
- dependency-name: regex-syntax
  dependency-version: 0.8.6
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-02 09:35:34 +00:00
dependabot[bot] 9ed1ce98a9 build(deps): bump clap from 4.5.42 to 4.5.46
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.42 to 4.5.46.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.42...clap_complete-v4.5.46)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.46
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-02 08:06:54 +00:00
Thayne McCombs e13dd192f1 docs: Add some documentation on how to install completions
Fixes: #1769
2025-08-26 02:48:20 -06:00
Thayne McCombs 498ea1cc77 Merge pull request #1781 from sharkdp/changelog-update
chore: Add next entry to changelog
2025-08-26 02:29:39 -06:00
Thayne McCombs 0d3261daf7 chore: Add next entry to changelog 2025-08-26 02:29:10 -06:00
Thayne McCombs d38148f0aa Merge pull request #1780 from sharkdp/release-10.3
release: 10.3
2025-08-26 01:32:04 -06:00
Thayne McCombs 04832f1ac4 release: 10.3 2025-08-26 00:58:38 -06:00
Tavian Barnes fd06e69ed2 Merge pull request #1776 from tmccombs/os-update
OS update
2025-08-19 16:17:09 -04:00
Thayne McCombs 456afaef88 build: Update OSes for github actions
- Remove macos-13 because GitHub no longer supports it.
 - Update the version of Ubuntu used.
2025-08-19 01:52:07 -06:00
Tavian Barnes 377f8d6ef7 Merge pull request #1771 from sharkdp/dependabot/github_actions/actions/checkout-5
build(deps): bump actions/checkout from 4 to 5
2025-08-12 08:43:34 -04:00
dependabot[bot] d2d1a8580e build(deps): bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-12 06:25:09 +00:00
Thayne McCombs acb7f72254 Merge pull request #1772 from sharkdp/fix-clippy-lifetime-elision
filesystem: Fix a clippy warning about lifetime elision
2025-08-11 23:22:47 -07:00
Tavian Barnes 677823227c filesystem: Fix a clippy warning about lifetime elision 2025-08-11 21:02:01 -04:00
Thayne McCombs d856e78591 Merge pull request #1764 from sharkdp/dependabot/cargo/clap_complete-4.5.55
build(deps): bump clap_complete from 4.5.54 to 4.5.55
2025-08-01 10:37:08 -07:00
Thayne McCombs 0c71954017 Merge pull request #1762 from sharkdp/dependabot/cargo/clap-4.5.42
build(deps): bump clap from 4.5.40 to 4.5.42
2025-08-01 10:35:27 -07:00
dependabot[bot] f58e562809 build(deps): bump clap_complete from 4.5.54 to 4.5.55
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.54 to 4.5.55.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.54...clap_complete-v4.5.55)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.5.55
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 17:21:59 +00:00
dependabot[bot] 221e5dc894 build(deps): bump clap from 4.5.40 to 4.5.42
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.40 to 4.5.42.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.40...clap_complete-v4.5.42)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.42
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-01 17:21:45 +00:00
Thayne McCombs 6dfbbe86fc Merge pull request #1736 from tmccombs/package-updates
chore: Update several packages
2025-07-10 00:08:17 -06:00
Thayne McCombs c8f4a6b546 Merge pull request #1750 from sharkdp/dependabot/cargo/libc-0.2.174
build(deps): bump libc from 0.2.172 to 0.2.174
2025-07-06 09:17:14 -06:00
dependabot[bot] d5894ba4f3 build(deps): bump libc from 0.2.172 to 0.2.174
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.172 to 0.2.174.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.174/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.172...0.2.174)

---
updated-dependencies:
- dependency-name: libc
  dependency-version: 0.2.174
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-06 06:38:00 +00:00
Thayne McCombs be94ec6136 Merge pull request #1755 from tmccombs/master
fix: Remove duplicate nix from lockfile

Fixes #1753
2025-07-06 00:36:15 -06:00
Thayne McCombs 6465ce6d65 chore: Update several packages 2025-07-06 00:21:13 -06:00
Thayne McCombs abb188ef37 fix: Remove duplicate nix from lockfile 2025-07-06 00:01:25 -06:00
Thayne McCombs f91d97e475 Merge pull request #1749 from sharkdp/dependabot/cargo/ctrlc-3.4.7
build(deps): bump ctrlc from 3.4.6 to 3.4.7
2025-07-01 13:25:46 -06:00
Thayne McCombs 377c2c05d8 Merge pull request #1747 from sharkdp/dependabot/cargo/clap_complete-4.5.54
build(deps): bump clap_complete from 4.5.52 to 4.5.54
2025-07-01 13:24:43 -06:00
Thayne McCombs a406b0c5de Merge pull request #1748 from sharkdp/dependabot/cargo/argmax-0.4.0
build(deps): bump argmax from 0.3.1 to 0.4.0
2025-07-01 13:24:02 -06:00
Thayne McCombs edb12d22a2 Merge pull request #1746 from sharkdp/dependabot/cargo/clap-4.5.40
build(deps): bump clap from 4.5.39 to 4.5.40
2025-07-01 13:23:39 -06:00
dependabot[bot] 275b56c168 build(deps): bump ctrlc from 3.4.6 to 3.4.7
Bumps [ctrlc](https://github.com/Detegr/rust-ctrlc) from 3.4.6 to 3.4.7.
- [Release notes](https://github.com/Detegr/rust-ctrlc/releases)
- [Commits](https://github.com/Detegr/rust-ctrlc/compare/3.4.6...3.4.7)

---
updated-dependencies:
- dependency-name: ctrlc
  dependency-version: 3.4.7
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 17:26:02 +00:00
dependabot[bot] b108817d31 build(deps): bump argmax from 0.3.1 to 0.4.0
Bumps [argmax](https://github.com/sharkdp/argmax) from 0.3.1 to 0.4.0.
- [Release notes](https://github.com/sharkdp/argmax/releases)
- [Commits](https://github.com/sharkdp/argmax/compare/v0.3.1...v0.4.0)

---
updated-dependencies:
- dependency-name: argmax
  dependency-version: 0.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 17:25:57 +00:00
dependabot[bot] 1cadc21b42 build(deps): bump clap_complete from 4.5.52 to 4.5.54
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.52 to 4.5.54.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.52...clap_complete-v4.5.54)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.5.54
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 17:25:51 +00:00
dependabot[bot] db6aefa5b8 build(deps): bump clap from 4.5.39 to 4.5.40
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.39 to 4.5.40.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.39...clap_complete-v4.5.40)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.40
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-07-01 17:25:46 +00:00
Thayne McCombs b7fe2ce91b Merge pull request #1742 from nealsid/remove-illumos-jemalloc
Changes to support building/testing fd on Illumos
2025-06-23 15:03:33 -06:00
Neal S e76e7ffbd3 Remove test_invalid_cwd on illumos
rmdir on illumos does not support removing the current working
directory, so this test errors out with EINVAL when calling
std::fs::remove_dir.
2025-06-23 08:52:40 -04:00
Neal S 5c66878fb4 Make test be excluded at compile time rather than at run-time. 2025-06-23 08:52:40 -04:00
Neal S 1857ffff0c Use printf in a test rather than echo -n
echo -n is not POSIX compliant, and this came up while running tests
on Illumos.
2025-06-23 08:52:40 -04:00
Neal S 56ca42aed0 Do not use jemalloc on Illumos
Fix for #1741: jemalloc doesn't build on Illumos, so add it to the list of excluded
platforms.
2025-06-20 19:03:53 -04:00
Thayne McCombs ba35c5ea67 Merge pull request #1738 from tkb-github/patch-3
Update README.md to RHEL 10
2025-06-08 15:08:33 -06:00
tkb-github 3d704fb4b9 Update README.md to RHEL 10 2025-06-08 15:07:32 +08:00
Thayne McCombs fd5ec5fed5 Merge pull request #1732 from sharkdp/dependabot/cargo/tempfile-3.20.0
build(deps): bump tempfile from 3.19.1 to 3.20.0
2025-06-01 15:54:50 -06:00
Thayne McCombs b2c7cd1e3e Merge pull request #1733 from sharkdp/dependabot/cargo/clap-4.5.39
build(deps): bump clap from 4.5.37 to 4.5.39
2025-06-01 15:54:26 -06:00
Thayne McCombs 851fa4e5bb Merge pull request #1731 from sharkdp/dependabot/cargo/clap_complete-4.5.52
build(deps): bump clap_complete from 4.5.48 to 4.5.52
2025-06-01 15:54:05 -06:00
dependabot[bot] 9f2cf9205d build(deps): bump clap from 4.5.37 to 4.5.39
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.37 to 4.5.39.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.37...clap_complete-v4.5.39)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.39
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 21:14:17 +00:00
dependabot[bot] f9eaf7e4b9 build(deps): bump clap_complete from 4.5.48 to 4.5.52
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.48 to 4.5.52.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.48...clap_complete-v4.5.52)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.5.52
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 21:14:12 +00:00
Thayne McCombs 0e73fe9aa5 Merge pull request #1735 from sharkdp/dependabot/cargo/jiff-0.2.14
build(deps): bump jiff from 0.2.10 to 0.2.14
2025-06-01 15:13:16 -06:00
dependabot[bot] 8bd92f0572 build(deps): bump jiff from 0.2.10 to 0.2.14
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.10 to 0.2.14.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.10...jiff-static-0.2.14)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.14
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 17:10:42 +00:00
dependabot[bot] 16fb0cb9d3 build(deps): bump tempfile from 3.19.1 to 3.20.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.19.1 to 3.20.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.19.1...v3.20.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.20.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-06-01 17:10:26 +00:00
Thayne McCombs dbea8a68a8 Merge pull request #1716 from jcotton42/windows-aarch64
Add aarch64 Windows to CI.
2025-05-19 22:17:01 -06:00
Thayne McCombs 8b91260815 Merge pull request #1721 from janderssonse/fix/add-security-policy
docs(security): add initial security policy
2025-05-19 22:16:38 -06:00
Thayne McCombs 9bd1647f86 Merge pull request #1722 from musicinmybrain/tikv
Depend on jemallocator as tikv-jemallocator, and update it to 0.6
2025-05-14 20:09:54 -06:00
Benjamin A. Beasley c4250eca2a Update tikv-jemallocator to 0.6 2025-05-14 17:49:05 -04:00
Benjamin A. Beasley cb150c4fd4 Depend on jemallocator as tikv-jemallocator
Upstream writes: “The project is also published as jemallocator for
historical reasons. The two crates are the same except names. For new
projects, it's recommended to use tikv-xxx versions instead.”
2025-05-14 17:46:08 -04:00
Josef Andersson e389e5d275 docs(security): add initial security policy
Signed-off-by: Josef Andersson <janderssonse@proton.me>
2025-05-11 07:33:45 +02:00
Thayne McCombs efe499ac0d Merge pull request #1717 from tmccombs/doc-better
Doc better
2025-04-30 14:02:22 -06:00
Thayne McCombs 0ada245e37 Fix typo
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-04-30 12:03:32 -06:00
Thayne McCombs 402d4e7c12 docs: Clarify option positions in README 2025-04-30 01:26:43 -06:00
Thayne McCombs 26795f6a55 docs: Mention how to end --exec-batch args
Fixes: #1694
2025-04-30 01:24:56 -06:00
Thayne McCombs bc79395bcf docs: Better specify that if path is given, pattern must be as well.
See: #1376
2025-04-30 00:55:05 -06:00
Josh Cotton ad75d79a52 Add aarch64 Windows to CI. 2025-04-29 14:40:17 -07:00
Thayne McCombs 494eef044c Merge pull request #1715 from sharkdp/update-crossbeam
Update to crossbeam-channel 0.5.15
2025-04-29 09:18:16 -06:00
Tavian Barnes 563c5f3074 Update to crossbeam-channel 0.5.15
To grab a double-free fix.

Link: https://github.com/crossbeam-rs/crossbeam/pull/1187
2025-04-29 09:06:02 -04:00
Tavian Barnes 0d680b48e8 Merge pull request #1711 from musicinmybrain/etcetera-0.10
Update etcetera from 0.9 to 0.10
2025-04-29 09:05:44 -04:00
Benjamin A. Beasley ec81815c4c Update etcetera from 0.9 to 0.10
- Pin home to <0.5.11 to avoid MSRV problems
2025-04-29 08:55:31 -04:00
Thayne McCombs abf4e470ed Merge pull request #1712 from sharkdp/next-back
Use next_back() instead of last()
2025-04-24 09:36:48 -06:00
Tavian Barnes 5c0c86c2d5 ci: Use Ubuntu 22.04 runners
Ubuntu 20.04 is now unsupported.

Link: https://github.com/actions/runner-images/issues/11101
2025-04-24 10:03:57 -04:00
Tavian Barnes 3651f86162 Use next_back() instead of last()
Fixes a new Clippy warning.
2025-04-24 10:01:06 -04:00
Thayne McCombs 16b46710ee Merge pull request #1703 from sharkdp/dependabot/cargo/clap_complete-4.5.47
build(deps): bump clap_complete from 4.5.44 to 4.5.47
2025-04-02 08:01:35 -06:00
Tavian Barnes edafedbbc7 Merge pull request #1704 from vp-elitnet/changed_opt_doc_fix
doc: Disambiguate modification time vs timestamp
2025-04-02 07:53:07 -05:00
Vilius Panevėžys 5b29a4c8b3 Disambiguate modification time vs timestamp 2025-04-02 12:37:09 +03:00
Thayne McCombs 5f606ad6e2 Merge pull request #1701 from sharkdp/dependabot/cargo/jiff-0.2.5
build(deps): bump jiff from 0.2.4 to 0.2.5
2025-04-01 23:03:53 -06:00
dependabot[bot] 202615ccf7 build(deps): bump jiff from 0.2.4 to 0.2.5
Bumps [jiff](https://github.com/BurntSushi/jiff) from 0.2.4 to 0.2.5.
- [Release notes](https://github.com/BurntSushi/jiff/releases)
- [Changelog](https://github.com/BurntSushi/jiff/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/jiff/compare/jiff-static-0.2.4...jiff-static-0.2.5)

---
updated-dependencies:
- dependency-name: jiff
  dependency-version: 0.2.5
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-02 04:34:16 +00:00
Thayne McCombs c644330a52 Merge pull request #1702 from sharkdp/dependabot/cargo/anyhow-1.0.97
build(deps): bump anyhow from 1.0.96 to 1.0.97
2025-04-01 22:33:03 -06:00
Thayne McCombs 34acf31e0f Merge pull request #1700 from sharkdp/dependabot/cargo/clap-4.5.35
build(deps): bump clap from 4.5.31 to 4.5.35
2025-04-01 22:32:12 -06:00
Thayne McCombs 7cfd25cbb6 Merge pull request #1699 from sharkdp/dependabot/cargo/tempfile-3.19.1
build(deps): bump tempfile from 3.16.0 to 3.19.1
2025-04-01 22:31:11 -06:00
dependabot[bot] 39a616d6c4 build(deps): bump clap_complete from 4.5.44 to 4.5.47
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.44 to 4.5.47.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.44...clap_complete-v4.5.47)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-version: 4.5.47
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 17:38:43 +00:00
dependabot[bot] db6eb2959c build(deps): bump anyhow from 1.0.96 to 1.0.97
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.96 to 1.0.97.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.96...1.0.97)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-version: 1.0.97
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 17:38:38 +00:00
dependabot[bot] 5e8ae1d337 build(deps): bump clap from 4.5.31 to 4.5.35
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.31 to 4.5.35.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.5.31...clap_complete-v4.5.35)

---
updated-dependencies:
- dependency-name: clap
  dependency-version: 4.5.35
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 17:38:29 +00:00
dependabot[bot] e3ce16a7b4 build(deps): bump tempfile from 3.16.0 to 3.19.1
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.16.0 to 3.19.1.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.16.0...v3.19.1)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-version: 3.19.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-01 17:38:24 +00:00
Tavian Barnes 045fd2d689 Merge pull request #1695 from Bzero/patch-1
Fix broken Arch Linux link
2025-03-24 12:57:00 -05:00
Bzero 029ce455fd Fix broken Arch Linux link 2025-03-24 18:12:56 +01:00
Thayne McCombs e5b3269d1d Merge pull request #1649 from Its-Just-Nans/add-documentation-key
Add documentation key in Cargo.toml
2025-03-24 01:56:26 -06:00
Thayne McCombs 2b0f609a48 Merge pull request #1692 from tmccombs/jiff-more
Some small improvements to time filter code after switch to jiff
2025-03-22 15:01:46 -06:00
Thayne McCombs f370301a5b Use guard to ensure cleanup of test time 2025-03-22 02:03:15 -06:00
Thayne McCombs f36c7d0be2 refactor: Simplify time filter code 2025-03-19 00:39:46 -06:00
Thayne McCombs e0363fc9f8 refactor: Avoid passing in current time just for tests
Instead use a thread local variable that we can use to set the current
time, and use a separate now function in tests than the actual binary.
2025-03-17 02:22:38 -06:00
Thayne McCombs 9859d5117c docs: More description of jiff change in changelog 2025-03-16 18:50:51 -06:00
Thayne McCombs 803d1fd38b Merge pull request #1690 from sorairolake/replace-humantime-with-jiff
chore(deps): Replace `humantime` and `chrono` with `jiff`
2025-03-13 01:30:39 -06:00
Shun Sakai bbac76747b chore(deps): Replace chrono with jiff 2025-03-13 11:44:36 +09:00
Shun Sakai 7d57f61dfb chore: Change to use jiff::Zoned
Supports when the duration contains calendar units.
2025-03-12 23:50:47 +09:00
Shun Sakai c670a0b366 chore(deps): Replace humantime with jiff 2025-03-12 18:15:37 +09:00
Thayne McCombs a4fdad6ff7 Merge pull request #1683 from sharkdp/dependabot/cargo/clap-4.5.31
build(deps): bump clap from 4.5.27 to 4.5.31
2025-03-03 10:09:04 -07:00
Thayne McCombs da7ccc21d0 Merge pull request #1682 from sharkdp/dependabot/cargo/libc-0.2.170
build(deps): bump libc from 0.2.169 to 0.2.170
2025-03-03 00:31:19 -07:00
Thayne McCombs 595c1af4b6 Merge pull request #1684 from sharkdp/dependabot/cargo/globset-0.4.16
build(deps): bump globset from 0.4.15 to 0.4.16
2025-03-02 17:51:34 -07:00
Thayne McCombs 69e3f1a6e6 Merge pull request #1681 from sharkdp/dependabot/cargo/anyhow-1.0.96
build(deps): bump anyhow from 1.0.95 to 1.0.96
2025-03-02 17:49:26 -07:00
dependabot[bot] df550cce26 build(deps): bump clap from 4.5.27 to 4.5.31
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.27 to 4.5.31.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.27...v4.5.31)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-02 09:09:23 +00:00
dependabot[bot] cc7472d4db build(deps): bump libc from 0.2.169 to 0.2.170
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.169 to 0.2.170.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.170/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.169...0.2.170)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-02 09:09:22 +00:00
dependabot[bot] 0c2b432fd8 build(deps): bump globset from 0.4.15 to 0.4.16
Bumps [globset](https://github.com/BurntSushi/ripgrep) from 0.4.15 to 0.4.16.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/ignore-0.4.15...globset-0.4.16)

---
updated-dependencies:
- dependency-name: globset
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-02 09:09:18 +00:00
dependabot[bot] 5803cdb401 build(deps): bump anyhow from 1.0.95 to 1.0.96
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.95 to 1.0.96.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.95...1.0.96)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-02 09:09:16 +00:00
Thayne McCombs fe51550687 Merge pull request #1680 from sharkdp/dependabot/cargo/etcetera-0.9.0
build(deps): bump etcetera from 0.8.0 to 0.9.0
2025-03-02 02:08:20 -07:00
dependabot[bot] 54fca540e8 build(deps): bump etcetera from 0.8.0 to 0.9.0
Bumps [etcetera](https://github.com/lunacookies/etcetera) from 0.8.0 to 0.9.0.
- [Release notes](https://github.com/lunacookies/etcetera/releases)
- [Commits](https://github.com/lunacookies/etcetera/compare/v0.8.0...v0.9.0)

---
updated-dependencies:
- dependency-name: etcetera
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-01 17:40:12 +00:00
Thayne McCombs 3a56c32a1c Merge pull request #1671 from tmccombs/update-mac-runner
chore: Use macos-13 instead of 12
2025-02-02 10:52:21 -07:00
Thayne McCombs 34d40443a4 Merge pull request #1668 from sharkdp/dependabot/cargo/clap_complete-4.5.44
build(deps): bump clap_complete from 4.5.38 to 4.5.44
2025-02-02 01:33:06 -07:00
Thayne McCombs 3bbe11169a Merge pull request #1669 from sharkdp/dependabot/cargo/clap-4.5.27
build(deps): bump clap from 4.5.23 to 4.5.27
2025-02-02 01:32:39 -07:00
Thayne McCombs d0e2c3d33b Merge pull request #1670 from sharkdp/dependabot/cargo/tempfile-3.16.0
build(deps): bump tempfile from 3.14.0 to 3.16.0
2025-02-02 01:28:24 -07:00
Thayne McCombs 72a58676c6 chore: Use macos-13 instead of 12
Github actions doesn't suport macos-12 anymore
2025-02-02 01:27:51 -07:00
dependabot[bot] 4e6a47fee5 build(deps): bump tempfile from 3.14.0 to 3.16.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.14.0 to 3.16.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.14.0...v3.16.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 17:25:03 +00:00
dependabot[bot] 29bc3345f1 build(deps): bump clap from 4.5.23 to 4.5.27
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.23 to 4.5.27.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.23...clap_complete-v4.5.27)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 17:24:56 +00:00
dependabot[bot] 9c5b66b6b4 build(deps): bump clap_complete from 4.5.38 to 4.5.44
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.38 to 4.5.44.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.38...clap_complete-v4.5.44)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-02-01 17:24:52 +00:00
Thayne McCombs 564a61588d Merge pull request #1663 from tmccombs/more-troubleshooting
docs: Mention --full-path in troubleshooting
2025-01-28 09:09:39 -07:00
Thayne McCombs 8c177567a7 chore: Fix clippy lints
Use is_some_and instead of map_or(false
2025-01-28 01:55:21 -07:00
Thayne McCombs 2a66fbab28 docs: Mention --full-path in troubleshooting
See: #1662
2025-01-28 01:35:00 -07:00
Tavian Barnes 86d6e2d45f Merge pull request #1657 from sharkdp/dependabot/cargo/clap-4.5.23
build(deps): bump clap from 4.5.21 to 4.5.23
2025-01-01 15:49:25 -05:00
Tavian Barnes 62e5b11d8c Merge pull request #1656 from sharkdp/dependabot/cargo/crossbeam-channel-0.5.14
build(deps): bump crossbeam-channel from 0.5.13 to 0.5.14
2025-01-01 15:46:50 -05:00
Tavian Barnes 4327c36280 Merge pull request #1655 from sharkdp/dependabot/cargo/chrono-0.4.39
build(deps): bump chrono from 0.4.38 to 0.4.39
2025-01-01 15:46:09 -05:00
Tavian Barnes 31f8eda117 Merge pull request #1654 from sharkdp/dependabot/cargo/anyhow-1.0.95
build(deps): bump anyhow from 1.0.93 to 1.0.95
2025-01-01 15:45:48 -05:00
Tavian Barnes 727a976d6b Merge pull request #1653 from sharkdp/dependabot/cargo/libc-0.2.169
build(deps): bump libc from 0.2.167 to 0.2.169
2025-01-01 15:45:33 -05:00
dependabot[bot] 0f69a1af62 build(deps): bump clap from 4.5.21 to 4.5.23
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.21 to 4.5.23.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.21...clap_complete-v4.5.23)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 17:34:12 +00:00
dependabot[bot] 5ab7a9b56d build(deps): bump crossbeam-channel from 0.5.13 to 0.5.14
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.13 to 0.5.14.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.13...crossbeam-channel-0.5.14)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 17:34:07 +00:00
dependabot[bot] 1cc4cec3cb build(deps): bump chrono from 0.4.38 to 0.4.39
Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.38 to 0.4.39.
- [Release notes](https://github.com/chronotope/chrono/releases)
- [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
- [Commits](https://github.com/chronotope/chrono/compare/v0.4.38...v0.4.39)

---
updated-dependencies:
- dependency-name: chrono
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 17:34:02 +00:00
dependabot[bot] 64b326da79 build(deps): bump anyhow from 1.0.93 to 1.0.95
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.93 to 1.0.95.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.93...1.0.95)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 17:33:57 +00:00
dependabot[bot] ce39d34483 build(deps): bump libc from 0.2.167 to 0.2.169
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.167 to 0.2.169.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.169/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.167...0.2.169)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-01-01 17:33:53 +00:00
n4n5 f86a460e48 Update Cargo.toml 2024-12-16 17:45:45 +01:00
n4n5 1785baa372 add documentation 2024-12-16 17:44:41 +01:00
Thayne McCombs 331daf10b8 Merge pull request #1644 from sharkdp/dependabot/cargo/clap_complete-4.5.38
build(deps): bump clap_complete from 4.5.28 to 4.5.38
2024-12-09 11:41:18 -07:00
Thayne McCombs 4d957d3a63 Merge pull request #1642 from sharkdp/dependabot/cargo/tempfile-3.14.0
build(deps): bump tempfile from 3.13.0 to 3.14.0
2024-12-02 09:16:35 -07:00
dependabot[bot] 4104411a1b build(deps): bump clap_complete from 4.5.28 to 4.5.38
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.28 to 4.5.38.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.28...clap_complete-v4.5.38)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-02 15:22:24 +00:00
Thayne McCombs 915483bcd0 Merge pull request #1646 from sharkdp/dependabot/cargo/clap-4.5.21
build(deps): bump clap from 4.5.20 to 4.5.21
2024-12-02 08:20:43 -07:00
Thayne McCombs f272180939 Merge pull request #1645 from sharkdp/dependabot/cargo/anyhow-1.0.93
build(deps): bump anyhow from 1.0.89 to 1.0.93
2024-12-02 08:20:18 -07:00
Thayne McCombs 285ff99ce0 Merge pull request #1643 from sharkdp/dependabot/cargo/libc-0.2.167
build(deps): bump libc from 0.2.161 to 0.2.167
2024-12-02 08:19:52 -07:00
dependabot[bot] ff434bb8a0 build(deps): bump clap from 4.5.20 to 4.5.21
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.20 to 4.5.21.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.20...clap_complete-v4.5.21)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 17:47:13 +00:00
dependabot[bot] 54015f3fbe build(deps): bump anyhow from 1.0.89 to 1.0.93
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.89 to 1.0.93.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.89...1.0.93)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 17:47:08 +00:00
dependabot[bot] e11180b323 build(deps): bump libc from 0.2.161 to 0.2.167
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.161 to 0.2.167.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.167/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.161...0.2.167)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 17:46:56 +00:00
dependabot[bot] 9547622726 build(deps): bump tempfile from 3.13.0 to 3.14.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.13.0 to 3.14.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.13.0...v3.14.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-12-01 17:46:50 +00:00
Thayne McCombs 7a908a474c Merge pull request #1633 from sharkdp/dependabot/cargo/clap-4.5.20
build(deps): bump clap from 4.5.16 to 4.5.20
2024-11-01 22:49:11 -06:00
Thayne McCombs 71deea6671 Merge pull request #1632 from sharkdp/dependabot/cargo/lscolors-0.20.0
build(deps): bump lscolors from 0.19.0 to 0.20.0
2024-11-01 11:47:25 -06:00
Thayne McCombs bb676df284 Merge pull request #1634 from sharkdp/dependabot/cargo/regex-1.11.1
build(deps): bump regex from 1.10.6 to 1.11.1
2024-11-01 11:47:02 -06:00
Thayne McCombs b517934b42 Merge pull request #1630 from sharkdp/dependabot/cargo/tempfile-3.13.0
build(deps): bump tempfile from 3.12.0 to 3.13.0
2024-11-01 11:46:26 -06:00
dependabot[bot] 06483d1df5 build(deps): bump regex from 1.10.6 to 1.11.1
Bumps [regex](https://github.com/rust-lang/regex) from 1.10.6 to 1.11.1.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.10.6...1.11.1)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-01 17:23:36 +00:00
dependabot[bot] 8c93b19883 build(deps): bump clap from 4.5.16 to 4.5.20
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.16 to 4.5.20.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.16...clap_complete-v4.5.20)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-01 17:23:31 +00:00
dependabot[bot] 4505da8771 build(deps): bump lscolors from 0.19.0 to 0.20.0
Bumps [lscolors](https://github.com/sharkdp/lscolors) from 0.19.0 to 0.20.0.
- [Release notes](https://github.com/sharkdp/lscolors/releases)
- [Commits](https://github.com/sharkdp/lscolors/compare/v0.19.0...v0.20.0)

---
updated-dependencies:
- dependency-name: lscolors
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-01 17:23:25 +00:00
dependabot[bot] 22b73a0253 build(deps): bump tempfile from 3.12.0 to 3.13.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.12.0 to 3.13.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.12.0...v3.13.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-11-01 17:23:14 +00:00
Thayne McCombs 202e32953c Merge pull request #1627 from hamirmahal/style/simplify-string-formatting-for-readability
style: simplify string formatting for readability
2024-10-06 14:25:02 -06:00
Hamir Mahal 87f230a66e fix: formatting in src/ and tests/ 2024-10-06 09:34:41 -07:00
Hamir Mahal 4bdee80afa style: simplify string formatting for readability 2024-10-06 09:33:58 -07:00
Tavian Barnes 3d0d1865c8 Merge pull request #1617 from cstyles/add-mindepth-alias
Add a hidden `--mindepth` alias for `--min-depth`
2024-10-02 12:30:25 -04:00
Collin Styles 0d99badc1b Add a hidden --mindepth alias for --min-depth 2024-10-02 12:22:01 -04:00
Thayne McCombs 3b7b95d081 Merge pull request #1625 from sharkdp/dependabot/cargo/anyhow-1.0.89
build(deps): bump anyhow from 1.0.86 to 1.0.89
2024-10-01 23:51:08 -06:00
dependabot[bot] bd9882d797 build(deps): bump anyhow from 1.0.86 to 1.0.89
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.86 to 1.0.89.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.86...1.0.89)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-02 04:27:23 +00:00
Thayne McCombs 1fed60d5c1 Merge pull request #1623 from sharkdp/dependabot/cargo/libc-0.2.159
build(deps): bump libc from 0.2.158 to 0.2.159
2024-10-01 22:25:13 -06:00
Thayne McCombs f84c1d67c0 Merge pull request #1624 from sharkdp/dependabot/cargo/ignore-0.4.23
build(deps): bump ignore from 0.4.22 to 0.4.23
2024-10-01 22:24:47 -06:00
Thayne McCombs e50cb817e1 Merge pull request #1621 from sharkdp/dependabot/cargo/clap_complete-4.5.28
build(deps): bump clap_complete from 4.5.24 to 4.5.28
2024-10-01 22:23:58 -06:00
Thayne McCombs 8207b3ebae Merge pull request #1622 from sharkdp/dependabot/cargo/globset-0.4.15
build(deps): bump globset from 0.4.14 to 0.4.15
2024-10-01 22:22:30 -06:00
dependabot[bot] aa81800ffa build(deps): bump ignore from 0.4.22 to 0.4.23
Bumps [ignore](https://github.com/BurntSushi/ripgrep) from 0.4.22 to 0.4.23.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/commits)

---
updated-dependencies:
- dependency-name: ignore
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-01 17:18:00 +00:00
dependabot[bot] 5de01fdd7b build(deps): bump libc from 0.2.158 to 0.2.159
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.158 to 0.2.159.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Changelog](https://github.com/rust-lang/libc/blob/0.2.159/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.158...0.2.159)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-01 17:17:55 +00:00
dependabot[bot] 85764e28ef build(deps): bump globset from 0.4.14 to 0.4.15
Bumps [globset](https://github.com/BurntSushi/ripgrep) from 0.4.14 to 0.4.15.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/globset-0.4.14...ignore-0.4.15)

---
updated-dependencies:
- dependency-name: globset
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-01 17:17:51 +00:00
dependabot[bot] a4b3bd29aa build(deps): bump clap_complete from 4.5.24 to 4.5.28
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.24 to 4.5.28.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.24...clap_complete-v4.5.28)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-10-01 17:17:44 +00:00
Thayne McCombs 27c6b50919 Fix a new clippy warning 2024-09-23 09:42:58 +02:00
Tavian Barnes 8e0bd33af7 Merge pull request #1610 from sharkdp/dependabot/cargo/filetime-0.2.25
build(deps): bump filetime from 0.2.24 to 0.2.25
2024-09-03 10:23:34 -04:00
Thayne McCombs b674b9b820 Merge pull request #1611 from sharkdp/dependabot/cargo/clap_complete-4.5.24
build(deps): bump clap_complete from 4.5.19 to 4.5.24
2024-09-01 12:11:03 -06:00
dependabot[bot] 96ac5fa0a0 build(deps): bump clap_complete from 4.5.19 to 4.5.24
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.19 to 4.5.24.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.19...clap_complete-v4.5.24)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-01 17:23:24 +00:00
dependabot[bot] 9b1017a4d5 build(deps): bump filetime from 0.2.24 to 0.2.25
Bumps [filetime](https://github.com/alexcrichton/filetime) from 0.2.24 to 0.2.25.
- [Commits](https://github.com/alexcrichton/filetime/compare/0.2.24...0.2.25)

---
updated-dependencies:
- dependency-name: filetime
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-01 17:23:19 +00:00
Tavian Barnes b191368713 Merge pull request #1607 from tmccombs/release-10.2
Prepare for 10.2.0 release
2024-08-22 15:27:40 -04:00
Thayne McCombs e3d4f57e75 Bump dependencies
In particular, lscolors
2024-08-19 23:29:02 -06:00
Thayne McCombs 1ce6906808 Prepare for 10.2.0 release 2024-08-18 22:55:28 -06:00
Thayne McCombs 9cf415ccc7 Merge pull request #1593 from sharkdp/deb-improvements
Deb improvements
2024-08-08 21:02:08 -06:00
Thayne McCombs e9fe337921 Merge pull request #1596 from RossSmyth/WinLints
Fix up some lints on Windows
2024-08-07 23:16:56 -06:00
Thayne McCombs 8958a7bd74 Merge pull request #1602 from JCHacking/readme_last_version_regex
docs: documentation link of regular expressions to the latest version
2024-08-05 14:30:05 -06:00
JCHacking c26c45dba3 docs: documentation link of regular expressions to the latest version 2024-08-05 13:32:20 +02:00
Thayne McCombs 7decd53c70 Merge pull request #1601 from sharkdp/dependabot/cargo/clap-4.5.13
build(deps): bump clap from 4.5.8 to 4.5.13
2024-08-01 19:12:08 -06:00
Thayne McCombs d5253c5372 Merge pull request #1600 from sharkdp/dependabot/cargo/clap_complete-4.5.8
build(deps): bump clap_complete from 4.5.7 to 4.5.8
2024-08-01 19:11:30 -06:00
Thayne McCombs 3e7691ee6e Merge pull request #1599 from sharkdp/dependabot/cargo/nu-ansi-term-0.50.1
build(deps): bump nu-ansi-term from 0.50.0 to 0.50.1
2024-08-01 19:10:55 -06:00
Thayne McCombs 385131765d Merge pull request #1598 from sharkdp/dependabot/cargo/version_check-0.9.5
build(deps): bump version_check from 0.9.4 to 0.9.5
2024-08-01 19:06:36 -06:00
dependabot[bot] adbae9cf54 build(deps): bump clap from 4.5.8 to 4.5.13
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.8 to 4.5.13.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.8...v4.5.13)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-01 17:45:49 +00:00
dependabot[bot] b862c11550 build(deps): bump clap_complete from 4.5.7 to 4.5.8
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.7 to 4.5.8.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.7...clap_complete-v4.5.8)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-01 17:45:44 +00:00
dependabot[bot] e7b93e6c96 build(deps): bump nu-ansi-term from 0.50.0 to 0.50.1
Bumps [nu-ansi-term](https://github.com/nushell/nu-ansi-term) from 0.50.0 to 0.50.1.
- [Release notes](https://github.com/nushell/nu-ansi-term/releases)
- [Changelog](https://github.com/nushell/nu-ansi-term/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nushell/nu-ansi-term/compare/v0.50.0...v0.50.1)

---
updated-dependencies:
- dependency-name: nu-ansi-term
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-01 17:45:36 +00:00
dependabot[bot] 2ea5d2a90e build(deps): bump version_check from 0.9.4 to 0.9.5
Bumps [version_check](https://github.com/SergioBenitez/version_check) from 0.9.4 to 0.9.5.
- [Commits](https://github.com/SergioBenitez/version_check/compare/v0.9.4...v0.9.5)

---
updated-dependencies:
- dependency-name: version_check
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-01 17:45:31 +00:00
Ross Smyth 80a73fda49 Fix unused config struct field on Windows 2024-07-22 10:02:08 -04:00
Ross Smyth db9d2fa299 Fix unused OnceLock import lint on Windows 2024-07-22 10:02:05 -04:00
Thayne McCombs 830fed4f82 Fix Conflicts syntax 2024-07-22 01:34:03 -06:00
Thayne McCombs e3b7dcbb7e Create fdfind symlinks in deb package
To be consistent with the offical debian pckage
2024-07-22 00:33:10 -06:00
Thayne McCombs 55d2e78cc1 Refactor creating deb package into separate script
Which I think is cleaner than having it inline in the github actions
yaml
2024-07-22 00:33:10 -06:00
Thayne McCombs 9f0fea6e21 Merge pull request #1594 from sharkdp/deb-readme-update
Note executable name in release debs
2024-07-17 12:54:07 -06:00
Thayne McCombs 3480df88ef Note executable name in release debs
Fixes: #1592
2024-07-17 00:04:36 -06:00
Thayne McCombs cfced9787e Merge pull request #1571 from tmccombs/hyperlink
Add hyperlink support to fd
2024-07-16 15:57:30 -06:00
Thayne McCombs 9cefd79ef4 Merge pull request #1583 from sharkdp/dependabot/cargo/clap_complete-4.5.7
build(deps): bump clap_complete from 4.5.2 to 4.5.7
2024-07-01 16:05:25 -06:00
dependabot[bot] d5525e171b build(deps): bump clap_complete from 4.5.2 to 4.5.7
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.5.2 to 4.5.7.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.2...clap_complete-v4.5.7)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 21:44:07 +00:00
Thayne McCombs 724275f3ef Merge pull request #1582 from sharkdp/dependabot/cargo/clap-4.5.8
build(deps): bump clap from 4.5.4 to 4.5.8
2024-07-01 15:43:27 -06:00
Thayne McCombs 79d1435c68 Merge pull request #1581 from sharkdp/dependabot/cargo/lscolors-0.18.0
build(deps): bump lscolors from 0.17.0 to 0.18.0
2024-07-01 15:42:50 -06:00
Thayne McCombs 5147fd6aec Merge pull request #1580 from sharkdp/dependabot/cargo/regex-1.10.5
build(deps): bump regex from 1.10.4 to 1.10.5
2024-07-01 15:38:59 -06:00
dependabot[bot] f55708e31d build(deps): bump regex from 1.10.4 to 1.10.5
Bumps [regex](https://github.com/rust-lang/regex) from 1.10.4 to 1.10.5.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.10.4...1.10.5)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 21:04:01 +00:00
Thayne McCombs b6b16ce959 Merge pull request #1584 from sharkdp/dependabot/cargo/regex-syntax-0.8.4
build(deps): bump regex-syntax from 0.8.3 to 0.8.4
2024-07-01 15:03:19 -06:00
dependabot[bot] e65104e762 build(deps): bump regex-syntax from 0.8.3 to 0.8.4
Bumps [regex-syntax](https://github.com/rust-lang/regex) from 0.8.3 to 0.8.4.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/regex-syntax-0.8.3...regex-syntax-0.8.4)

---
updated-dependencies:
- dependency-name: regex-syntax
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 17:47:29 +00:00
dependabot[bot] da65108efc build(deps): bump clap from 4.5.4 to 4.5.8
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.4 to 4.5.8.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.5.4...v4.5.8)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 17:47:16 +00:00
dependabot[bot] c74fefabb6 build(deps): bump lscolors from 0.17.0 to 0.18.0
Bumps [lscolors](https://github.com/sharkdp/lscolors) from 0.17.0 to 0.18.0.
- [Release notes](https://github.com/sharkdp/lscolors/releases)
- [Commits](https://github.com/sharkdp/lscolors/compare/v0.17.0...v0.18.0)

---
updated-dependencies:
- dependency-name: lscolors
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-07-01 17:47:08 +00:00
Thayne McCombs 45d6fbb9e2 Fix percent encoding
When the first digit is 0
2024-06-24 00:39:41 -06:00
Bryan Honof 4e9672250b docs: Add flox install 2024-06-23 13:45:22 +02:00
Thayne McCombs f8270a6a44 Merge pull request #1575 from tmccombs/windows-build-updates
Windows build updates
2024-06-14 13:50:14 -06:00
Thayne McCombs 7042dff969 Continue supporting windows 7 with builds
By using an older version of rust to build the artifacts on windows.

Alternatively we could build separate artifacts for windows 7, and
continue using the latest version of rust for later versions of windows
that are more optimized for more recent versions.

Fixes: #1550
2024-06-14 00:06:08 -06:00
Thayne McCombs f477c4f2c9 Update OS versions for github actions 2024-06-14 00:06:03 -06:00
Thayne McCombs b1f7aef00b Change --hyperlink to be an option instead of a flag 2024-06-11 00:38:01 -06:00
Thayne McCombs d8d2c37ec0 Fix test on windows 2024-06-10 00:55:10 -06:00
Thayne McCombs 609f1adf90 Fix unicode encoding of hyperlinks
The problem, is I based the code on the implementation in ripgrep. But
while ripgrep is writing directly to the stream, I am using a Formatter,
which means I have to write characters, not raw bytes.

Thus we need to percent encode all non-ascii bytes (or we could switch
to writing bytes directly, but that would be more complicated, and I
think percent encoding is safer anyway).
2024-06-09 22:57:00 -06:00
Thayne McCombs bd649e2fd7 Add hyperlink support to fd
Fixes: #1295
Fixes: #1563
2024-06-08 23:38:57 -06:00
Thayne McCombs be815c261a Merge pull request #1567 from sharkdp/dependabot/cargo/nix-0.29.0
build(deps): bump nix from 0.28.0 to 0.29.0
2024-06-02 14:29:42 -06:00
Thayne McCombs d8a808c0e3 Merge pull request #1569 from sharkdp/dependabot/cargo/libc-0.2.155
build(deps): bump libc from 0.2.154 to 0.2.155
2024-06-01 23:49:47 -06:00
Thayne McCombs c92290c3d7 Merge pull request #1566 from sharkdp/dependabot/cargo/anyhow-1.0.86
build(deps): bump anyhow from 1.0.82 to 1.0.86
2024-06-01 23:46:33 -06:00
Thayne McCombs 0649c2b379 Merge pull request #1568 from sharkdp/dependabot/cargo/crossbeam-channel-0.5.13
build(deps): bump crossbeam-channel from 0.5.12 to 0.5.13
2024-06-01 23:46:05 -06:00
dependabot[bot] 755970deba build(deps): bump libc from 0.2.154 to 0.2.155
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.154 to 0.2.155.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.154...0.2.155)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-01 17:56:17 +00:00
dependabot[bot] f897b82d76 build(deps): bump crossbeam-channel from 0.5.12 to 0.5.13
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.12 to 0.5.13.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.12...crossbeam-channel-0.5.13)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-01 17:56:11 +00:00
dependabot[bot] dbbabed606 build(deps): bump nix from 0.28.0 to 0.29.0
Bumps [nix](https://github.com/nix-rust/nix) from 0.28.0 to 0.29.0.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.28.0...v0.29.0)

---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-01 17:56:05 +00:00
dependabot[bot] ac178e20af build(deps): bump anyhow from 1.0.82 to 1.0.86
Bumps [anyhow](https://github.com/dtolnay/anyhow) from 1.0.82 to 1.0.86.
- [Release notes](https://github.com/dtolnay/anyhow/releases)
- [Commits](https://github.com/dtolnay/anyhow/compare/1.0.82...1.0.86)

---
updated-dependencies:
- dependency-name: anyhow
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-01 17:55:57 +00:00
David Peter 29936f0fba Update sponsors.md 2024-05-16 16:56:22 +02:00
David Peter bfc16a1dee Remove sponsorship message 2024-05-16 16:55:35 +02:00
Thayne McCombs 289a68bac3 Merge pull request #1555 from tmccombs/fmt-readme
Add --format to help in README
2024-05-08 00:40:02 -06:00
Thayne McCombs fcaff0f385 Add --format to help in README 2024-05-08 00:38:45 -06:00
Thayne McCombs 36163f9c3a Merge pull request #1554 from tmccombs/release-10.1.0
Prepare for 10.1.0 release
2024-05-08 00:36:34 -06:00
Thayne McCombs d90ec1758e Prepare for 10.1.0 release 2024-05-08 00:20:43 -06:00
Thayne McCombs ea22cbd712 Merge pull request #1043 from tmccombs/format-option
Implement option for printing custom formats
2024-05-07 23:10:12 -06:00
Thayne McCombs d44badc190 Implement option for printing custom formats 2024-05-07 22:52:49 -06:00
Thayne McCombs 6becb66185 Merge pull request #1445 from tmccombs/cwd-prefix
feat: Add option to always include cwd prefix
2024-05-07 21:27:45 -06:00
Thayne McCombs 1a1f057e5d Merge pull request #1552 from tmccombs/mac-m1-build
Attempt to add aarch64 osx build to CI
2024-05-07 10:41:09 -06:00
Thayne McCombs 10a269bd3f Merge pull request #1553 from tmccombs/changelog-update
Add upcoming to changelog
2024-05-07 00:24:37 -06:00
Thayne McCombs 90d3381814 docs: Make auto option for --strip-cwd-prefix more clear 2024-05-07 00:24:15 -06:00
Thayne McCombs b1f83a0bb0 feat: Add option to always include cwd prefix
Fixes: #1243
Fixes: #1331
2024-05-07 00:24:06 -06:00
Thayne McCombs 3bc70925a9 Add upcoming to changelog 2024-05-07 00:16:56 -06:00
Thayne McCombs f287f08b9f Attempt to add aarch64 osx build to CI
Fixes: #1088
2024-05-07 00:14:52 -06:00
Tavian Barnes 0e4488e9dc Merge pull request #1549 from tavianator/jemalloc-aarch64
Fix #1085 for real
2024-05-06 12:39:49 -04:00
Tavian Barnes d7d63eddbe Fix #1085 for real
cross doesn't pass all environment variables through into the build
container, so JEMALLOC_SYS_WITH_LG_PAGE=16 wasn't being picked up from
the host.  Instead, set it explicitly in Cross.toml.

Link: https://github.com/cross-rs/cross/wiki/Configuration
2024-05-06 12:29:11 -04:00
Thayne McCombs 8acd7722f0 Merge pull request #1548 from tmccombs/release-9.1.0
Release 10.0.0
2024-05-06 00:01:31 -06:00
Thayne McCombs 92fab6e058 Prepare for 10.0.0 release 2024-05-05 23:52:50 -06:00
Thayne McCombs a0ee0856db Add @timestamp to --help 2024-05-05 23:52:50 -06:00
Thayne McCombs b8df500a70 Add script to automate some of release process. 2024-05-05 23:52:50 -06:00
Thayne McCombs cd96ca071d Merge pull request #1547 from tavianator/jemalloc-aarch64
ci: Support large page sizes on AArch64
2024-05-03 21:46:40 -06:00
Tavian Barnes 216472ff9f ci: Support large page sizes on AArch64
Fixes #1085.
2024-05-03 15:23:41 -04:00
Thayne McCombs 3680d10e5c Merge pull request #1544 from sharkdp/dependabot/cargo/libc-0.2.154
build(deps): bump libc from 0.2.153 to 0.2.154
2024-05-01 12:03:31 -06:00
dependabot[bot] abe3b9cd78 build(deps): bump libc from 0.2.153 to 0.2.154
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.153 to 0.2.154.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.153...0.2.154)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-01 17:47:51 +00:00
Thayne McCombs 7aad6c9edf Merge pull request #1543 from sharkdp/dependabot/cargo/chrono-0.4.38
build(deps): bump chrono from 0.4.37 to 0.4.38
2024-05-01 11:47:39 -06:00
Thayne McCombs ddd3aae249 Merge pull request #1542 from sharkdp/dependabot/cargo/nix-0.28.0
build(deps): bump nix from 0.27.1 to 0.28.0
2024-05-01 11:46:53 -06:00
dependabot[bot] 6d3bb68faf build(deps): bump chrono from 0.4.37 to 0.4.38
Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.37 to 0.4.38.
- [Release notes](https://github.com/chronotope/chrono/releases)
- [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
- [Commits](https://github.com/chronotope/chrono/compare/v0.4.37...v0.4.38)

---
updated-dependencies:
- dependency-name: chrono
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-01 17:31:34 +00:00
dependabot[bot] 21d50dae8c build(deps): bump nix from 0.27.1 to 0.28.0
Bumps [nix](https://github.com/nix-rust/nix) from 0.27.1 to 0.28.0.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.27.1...v0.28.0)

---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-05-01 17:31:29 +00:00
David Peter 9279b1f0af Fix typo in CHANGELOG 2024-04-30 15:56:12 +02:00
Thayne McCombs 6647085015 Add test for gitignore workaround
And make sure it works for user-supplied path of "."

Also add changelog entry
2024-04-30 15:56:12 +02:00
Thayne McCombs 6af8f092ee Workaround for bug with gitinored files
This is a workaround for
https://github.com/BurntSushi/ripgrep/issues/2711

Fixes: #1461
2024-04-30 15:56:12 +02:00
Thayne McCombs c4094c7a05 Merge pull request #1492 from AlbydST/master
Add installation instructions for more Linux distributions in README
2024-04-29 13:13:38 -06:00
AlbydS 6d58df5f0c Remove unnecessary sudo in front of commands
Removed unnecessary "sudo" in front of all commands, also removed the "replace sudo with doas..." instruction at the end.
2024-04-29 18:04:39 +00:00
AlbydS ffecccf209 Merge branch 'sharkdp:master' into master 2024-04-29 17:58:24 +00:00
Thayne McCombs 31f2839751 Merge pull request #1540 from tmccombs/revert-git-ignore
Stop ignore .git folders by default
2024-04-28 20:33:03 -06:00
Thayne McCombs e10a4eab2b Stop ignore .git folders by default
Fixes: #1457
See: #1396, #1403
2024-04-28 20:23:25 -06:00
Thayne McCombs 8eb047945e Merge pull request #1541 from tavianator/clippy-is-empty
filesystem: Remove a redundant as_str()
2024-04-28 20:22:10 -06:00
Tavian Barnes 1031325cca filesystem: Remove a redundant as_str() 2024-04-28 17:30:44 -04:00
Tavian Barnes 9fc2167cf9 Merge pull request #1505 from leuven65/master
set default path separator to '/' in UCRT64 of MSYS
2024-04-28 17:23:43 -04:00
Tavian Barnes ae1de4de24 Merge pull request #1539 from tmccombs/fix-clippy
Fix deprecation warning.
2024-04-28 17:21:41 -04:00
Thayne McCombs 7e5d14b733 Fix deprecation warning. 2024-04-27 21:58:54 -06:00
Thayne McCombs 85cbea8dcb Merge pull request #1494 from nabellows/master
Add support for @%s time format
2024-04-26 22:37:54 -06:00
Thayne McCombs bc6782624e Merge pull request #1520 from tmccombs/clippy
Add clippy using latest rust version to CI
2024-04-15 00:17:20 -06:00
Thayne McCombs cf6ff87c7d Add clippy using latest rust version to CI
Fixes: #1511
2024-04-14 23:33:40 -06:00
Thayne McCombs 3cd73d7927 Merge pull request #1536 from bin-ly/master
Use 'MAIN_SEPARATOR_STR' instead of '&MAIN_SEPARATOR.to_string()'
2024-04-14 20:58:12 -06:00
binlingyu 7794c4aae5 Use 'MAIN_SEPARATOR_STR' instead of '&MAIN_SEPARATOR.to_string()' 2024-04-15 10:36:10 +08:00
Thayne McCombs 8c7a84ea30 Merge pull request #1534 from tmccombs/msrv-update
Update MSRV to 1.77.2
2024-04-11 23:06:41 -06:00
Thayne McCombs e262ade74e Update MSRV to 1.77.2
Prior to this version, `Command` didn't properly escape command line
arguments on windows.

Although, the risk of attacker controlled arguments passed through fd is
relatively small, I think it is best to upgrade to a version that fixes
this.

The biggest risk for users is probably running fd with `--exec` or
`--exec-batch` on directories that contain files with names controlled
by another party (for example a git repo that you cloned).

See: https://blog.rust-lang.org/2024/04/09/cve-2024-24576.html
Security: CVE-2024-24576
2024-04-11 21:14:11 -06:00
Thayne McCombs 11069e284a Merge pull request #1530 from sharkdp/dependabot/cargo/lscolors-0.17.0
build(deps): bump lscolors from 0.16.0 to 0.17.0
2024-04-01 15:22:35 -06:00
Thayne McCombs 6e2e86decb Merge pull request #1529 from sharkdp/dependabot/cargo/aho-corasick-1.1.3
build(deps): bump aho-corasick from 1.1.2 to 1.1.3
2024-04-01 15:22:15 -06:00
Thayne McCombs 15d3b63ccc Merge pull request #1531 from sharkdp/dependabot/cargo/crossbeam-channel-0.5.12
build(deps): bump crossbeam-channel from 0.5.11 to 0.5.12
2024-04-01 15:21:48 -06:00
dependabot[bot] 453577651e build(deps): bump crossbeam-channel from 0.5.11 to 0.5.12
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.11 to 0.5.12.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.11...crossbeam-channel-0.5.12)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-01 17:31:12 +00:00
dependabot[bot] 39c07b7b4c build(deps): bump lscolors from 0.16.0 to 0.17.0
Bumps [lscolors](https://github.com/sharkdp/lscolors) from 0.16.0 to 0.17.0.
- [Release notes](https://github.com/sharkdp/lscolors/releases)
- [Commits](https://github.com/sharkdp/lscolors/compare/0.16.0...v0.17.0)

---
updated-dependencies:
- dependency-name: lscolors
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-01 17:31:06 +00:00
dependabot[bot] 5910285db0 build(deps): bump aho-corasick from 1.1.2 to 1.1.3
Bumps [aho-corasick](https://github.com/BurntSushi/aho-corasick) from 1.1.2 to 1.1.3.
- [Commits](https://github.com/BurntSushi/aho-corasick/compare/1.1.2...1.1.3)

---
updated-dependencies:
- dependency-name: aho-corasick
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-01 17:31:00 +00:00
Thayne McCombs 68fe31da3f Merge pull request #1517 from one230six/master
refactor: Optimize code based on cargo clippy suggestions
2024-03-13 22:27:48 -06:00
Jian Wang f875ea9a52 Set default path separator to '/' in MSYS/MSYS2
The environments of MSYS: [[https://www.msys2.org/docs/environments/]]
2024-03-13 19:32:13 +01:00
one230six 138919907b refactor: Optimize code based on cargo clippy suggestions
Signed-off-by: one230six <723682061@qq.com>
2024-03-13 15:37:24 +08:00
Thayne McCombs b8744626e7 Merge pull request #1515 from sharkdp/dependabot/github_actions/softprops/action-gh-release-2
build(deps): bump softprops/action-gh-release from 1 to 2
2024-03-11 11:55:43 -06:00
dependabot[bot] b08d78f6fc build(deps): bump softprops/action-gh-release from 1 to 2
Bumps [softprops/action-gh-release](https://github.com/softprops/action-gh-release) from 1 to 2.
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](https://github.com/softprops/action-gh-release/compare/v1...v2)

---
updated-dependencies:
- dependency-name: softprops/action-gh-release
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-11 17:45:08 +00:00
Tavian Barnes 4efc05ef27 Merge pull request #1510 from garlic-hub/clippy
Clean up clippy warnings
2024-03-08 16:23:38 -05:00
garlic-hub 0788c43c3f Clean up clippy warnings 2024-03-08 10:46:24 -08:00
Thayne McCombs 3b2fd158b5 Merge pull request #1502 from sharkdp/dependabot/cargo/tempfile-3.10.1
build(deps): bump tempfile from 3.9.0 to 3.10.1
2024-03-01 11:16:34 -07:00
Thayne McCombs c38dbacbd0 Merge pull request #1500 from sharkdp/dependabot/cargo/libc-0.2.153
build(deps): bump libc from 0.2.151 to 0.2.153
2024-03-01 11:15:55 -07:00
Thayne McCombs 728b3200c0 Merge pull request #1503 from sharkdp/dependabot/cargo/chrono-0.4.34
build(deps): bump chrono from 0.4.31 to 0.4.34
2024-03-01 11:15:23 -07:00
dependabot[bot] 7f74cd9e56 build(deps): bump chrono from 0.4.31 to 0.4.34
Bumps [chrono](https://github.com/chronotope/chrono) from 0.4.31 to 0.4.34.
- [Release notes](https://github.com/chronotope/chrono/releases)
- [Changelog](https://github.com/chronotope/chrono/blob/main/CHANGELOG.md)
- [Commits](https://github.com/chronotope/chrono/compare/v0.4.31...v0.4.34)

---
updated-dependencies:
- dependency-name: chrono
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-01 17:42:05 +00:00
dependabot[bot] 6ae8da6a39 build(deps): bump tempfile from 3.9.0 to 3.10.1
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.9.0 to 3.10.1.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.9.0...v3.10.1)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-01 17:41:57 +00:00
dependabot[bot] f699c8bb6a build(deps): bump libc from 0.2.151 to 0.2.153
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.151 to 0.2.153.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.151...0.2.153)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-03-01 17:41:45 +00:00
Nathan Bellows ffde94c10e Run formatting 2024-02-12 02:12:58 -08:00
Nathan Bellows b0a8848f68 Add support for @%s time format 2024-02-12 02:05:41 -08:00
AlbydS d651a595d4 Add installation instructions for more Linux distributions in README
Added installation instructions for Arch AUR, ALT Linux and Solus and did a few minor changes
2024-02-11 21:25:33 +01:00
David Peter 969316cc0e More whitespace 2024-02-07 09:32:16 +01:00
David Peter 5b46867507 Add Terminal Trove sponsorship 2024-02-07 09:30:20 +01:00
Thayne McCombs e117a373a7 Merge pull request #1488 from sharkdp/dependabot/cargo/nu-ansi-term-0.50.0
build(deps): bump nu-ansi-term from 0.49.0 to 0.50.0
2024-02-01 15:18:00 -07:00
dependabot[bot] a4aed14337 build(deps): bump nu-ansi-term from 0.49.0 to 0.50.0
Bumps [nu-ansi-term](https://github.com/nushell/nu-ansi-term) from 0.49.0 to 0.50.0.
- [Release notes](https://github.com/nushell/nu-ansi-term/releases)
- [Changelog](https://github.com/nushell/nu-ansi-term/blob/main/CHANGELOG.md)
- [Commits](https://github.com/nushell/nu-ansi-term/compare/v0.49.0...v0.50.0)

---
updated-dependencies:
- dependency-name: nu-ansi-term
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 20:50:41 +00:00
Thayne McCombs 9cde3c12a2 Merge pull request #1490 from sharkdp/dependabot/cargo/clap_complete-4.4.9
build(deps): bump clap_complete from 4.4.6 to 4.4.9
2024-02-01 13:50:25 -07:00
Thayne McCombs 906e7a933e Merge pull request #1489 from sharkdp/dependabot/cargo/ignore-0.4.22
build(deps): bump ignore from 0.4.21 to 0.4.22
2024-02-01 13:50:04 -07:00
dependabot[bot] 077d28d13a build(deps): bump ignore from 0.4.21 to 0.4.22
Bumps [ignore](https://github.com/BurntSushi/ripgrep) from 0.4.21 to 0.4.22.
- [Release notes](https://github.com/BurntSushi/ripgrep/releases)
- [Changelog](https://github.com/BurntSushi/ripgrep/blob/master/CHANGELOG.md)
- [Commits](https://github.com/BurntSushi/ripgrep/compare/ignore-0.4.21...ignore-0.4.22)

---
updated-dependencies:
- dependency-name: ignore
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 18:34:09 +00:00
dependabot[bot] b55bb1e9be build(deps): bump clap_complete from 4.4.6 to 4.4.9
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.4.6 to 4.4.9.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.4.6...clap_complete-v4.4.9)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 18:33:20 +00:00
Thayne McCombs 7a6cc92d6d Merge pull request #1486 from sharkdp/dependabot/cargo/regex-1.10.3
build(deps): bump regex from 1.10.2 to 1.10.3
2024-02-01 11:33:08 -07:00
Thayne McCombs b694c6e673 Merge pull request #1487 from sharkdp/dependabot/cargo/crossbeam-channel-0.5.11
build(deps): bump crossbeam-channel from 0.5.10 to 0.5.11
2024-02-01 11:32:41 -07:00
dependabot[bot] 17895538a0 build(deps): bump crossbeam-channel from 0.5.10 to 0.5.11
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.10 to 0.5.11.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.10...crossbeam-channel-0.5.11)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 17:54:58 +00:00
dependabot[bot] 72ff1f9a87 build(deps): bump regex from 1.10.2 to 1.10.3
Bumps [regex](https://github.com/rust-lang/regex) from 1.10.2 to 1.10.3.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/1.10.2...1.10.3)

---
updated-dependencies:
- dependency-name: regex
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-02-01 17:54:48 +00:00
Thayne McCombs ef3194a510 Merge pull request #1483 from ognevny/patch-1
Makefile: use `--locked` for build
2024-01-26 00:25:04 -07:00
Maksim Bondarenkov 8773402246 Makefile: use --locked for build
to be ensured that Cargo.lock is up to date. also it's needed for disributions
2024-01-20 17:44:38 +03:00
Rob ff3fc81db4 Add target aarch64-unknown-linux-musl 2024-01-16 20:32:41 +01:00
Tavian Barnes 0dc3342c33 Merge pull request #1472 from tmccombs/clap-update
Update clap version
2024-01-08 10:36:43 -05:00
Thayne McCombs c66fc812ac Update clap version
Fixes: #1407
2024-01-08 02:03:39 -07:00
Thayne McCombs 14ed023875 Merge pull request #1464 from Ato2207/dir_alias
Added alias --type dir
2024-01-07 12:03:24 -07:00
Tavian Barnes 58284b8dbe Merge pull request #1470 from sharkdp/dependabot/cargo/crossbeam-channel-0.5.10
build(deps): bump crossbeam-channel from 0.5.8 to 0.5.10
2024-01-01 23:38:31 -05:00
Tavian Barnes 60889d0b99 Merge pull request #1468 from sharkdp/dependabot/cargo/tempfile-3.9.0
build(deps): bump tempfile from 3.8.1 to 3.9.0
2024-01-01 23:36:01 -05:00
dependabot[bot] 7e19bad0a4 build(deps): bump tempfile from 3.8.1 to 3.9.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.8.1 to 3.9.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.8.1...v3.9.0)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 18:07:49 +00:00
Thayne McCombs 4b1d73d39d Merge pull request #1469 from sharkdp/dependabot/cargo/filetime-0.2.23
build(deps): bump filetime from 0.2.22 to 0.2.23
2024-01-01 11:07:14 -07:00
dependabot[bot] 03e19a1ad2 build(deps): bump crossbeam-channel from 0.5.8 to 0.5.10
Bumps [crossbeam-channel](https://github.com/crossbeam-rs/crossbeam) from 0.5.8 to 0.5.10.
- [Release notes](https://github.com/crossbeam-rs/crossbeam/releases)
- [Changelog](https://github.com/crossbeam-rs/crossbeam/blob/master/CHANGELOG.md)
- [Commits](https://github.com/crossbeam-rs/crossbeam/compare/crossbeam-channel-0.5.8...crossbeam-channel-0.5.10)

---
updated-dependencies:
- dependency-name: crossbeam-channel
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 18:04:12 +00:00
Thayne McCombs 8fb9499c20 Merge pull request #1466 from sharkdp/dependabot/cargo/libc-0.2.151
build(deps): bump libc from 0.2.150 to 0.2.151
2024-01-01 11:03:48 -07:00
Thayne McCombs 38fb6a5958 Merge pull request #1467 from sharkdp/dependabot/cargo/clap_complete-4.4.5
build(deps): bump clap_complete from 4.4.4 to 4.4.5
2024-01-01 11:03:17 -07:00
dependabot[bot] 49cd62d65e build(deps): bump filetime from 0.2.22 to 0.2.23
Bumps [filetime](https://github.com/alexcrichton/filetime) from 0.2.22 to 0.2.23.
- [Commits](https://github.com/alexcrichton/filetime/compare/0.2.22...0.2.23)

---
updated-dependencies:
- dependency-name: filetime
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 17:33:54 +00:00
dependabot[bot] 24bb5216bb build(deps): bump clap_complete from 4.4.4 to 4.4.5
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.4.4 to 4.4.5.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.4.4...clap_complete-v4.4.5)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 17:33:45 +00:00
dependabot[bot] 7f8760fd1f build(deps): bump libc from 0.2.150 to 0.2.151
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.150 to 0.2.151.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.150...0.2.151)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-01 17:33:39 +00:00
Alexandru-Constantin Atomei 3cb6b9d93a Updated CHANGELOG.md, man page and made alias visible in fd -h too 2024-01-01 17:14:32 +02:00
Atomei Alexandru c591106b86 Merge branch 'master' into dir_alias 2023-12-30 22:58:10 +02:00
Alexandru-Constantin Atomei 9f096737db Added explicit documentation about the possibility of using dir 2023-12-30 22:54:57 +02:00
Alexandru-Constantin Atomei 1bda165b25 Added alias --type dir 2023-12-30 22:14:53 +02:00
Thayne McCombs f48372624d Merge pull request #1463 from Roshanjossey/patch-1
Format notes in Readme
2023-12-27 22:25:00 -07:00
Roshan Jossy 5cd15536b6 Format notes in Readme 2023-12-28 00:50:02 +01:00
Sayan Goswami aeb4a5fdad Fixes typo in README
Fixes a tiny typo: ~defautl~ to default.
2023-12-27 14:32:00 -05:00
Thayne McCombs 9529f30129 fix: Respect NO_COLOR with --list-details option
Fixes: #1455
2023-12-23 21:32:33 +01:00
Thayne McCombs 266311ca33 Merge pull request #1454 from tavianator/thats-a-lot-of-issues
CHANGELOG: Fix issue number typo
2023-12-19 13:37:47 -07:00
Tavian Barnes 954a3900b9 CHANGELOG: Fix issue number typo 2023-12-19 14:04:01 -05:00
David Peter 07343b5baf Update troubleshooting section 2023-12-19 11:45:09 +01:00
David Peter a03ed8b300 Update license information 2023-12-19 11:44:20 +01:00
David Peter 13a93e5cbe Add new unreleased section 2023-12-19 11:42:27 +01:00
David Peter d9c4e6239f Fix names for ARM Debian packages 2023-12-19 11:28:59 +01:00
David Peter 61ebd9be6a Update benchmark results 2023-12-19 11:28:59 +01:00
David Peter e3b40208d5 Preprations for fd 9 release 2023-12-19 11:28:59 +01:00
Tavian Barnes 16c2d1e1d0 walk: Flush stdout in batches
The previous behaviour was designed to mimic the output buffering of
typical UNIX tools: line-buffered if stdout is a TTY, and fully-buffered
otherwise.  More precicely, when printing to a terminal, fd would flush
explicitly after printing any buffered results, then flush after every
single result once streaming mode started.  When not printing to a
terminal, fd never explicitly flushed, so writes would only happen as
the BufWriter filled up.

The new behaviour actually unifies the TTY and non-TTY cases: we flush
after printing the buffered results, then once we start streaming, we
flush after each batch, but *only when the channel is empty*.  This
provides a good balance: if the channel is empty, the receiver thread
might as well flush before it goes to sleep waiting for more results.
If the channel is non-empty, we might as well process those results
before deciding to flush.

For TTYs, this should improve performance by consolidating write() calls
without sacrificing interactivity.  For non-TTYs, we'll be flushing more
often, but only when the receiver would otherwise have nothing to do,
thus improving interactivity without sacrificing performance.  This is
particularly handy when fd is piped into another command (such as head
or grep): with the old behaviour, fd could wait for the whole traversal
to finish before printing anything.  With the new behaviour, fd will
print those results soon after they are received.

Fixes #1313.
2023-12-18 22:01:11 +01:00
Tavian Barnes fea1622724 cli: Tweak default thread count logic 2023-12-18 21:55:18 +01:00
David Peter 00b64f3ccb Suggest to use -u instead of -HI 2023-12-08 13:37:03 +01:00
Thayne McCombs 74b850a642 Merge pull request #1436 from sharkdp/dependabot/cargo/clap-4.4.10
build(deps): bump clap from 4.4.7 to 4.4.10
2023-12-01 11:18:35 -07:00
dependabot[bot] 4202f3939e build(deps): bump test-case from 3.2.1 to 3.3.1
Bumps [test-case](https://github.com/frondeus/test-case) from 3.2.1 to 3.3.1.
- [Release notes](https://github.com/frondeus/test-case/releases)
- [Changelog](https://github.com/frondeus/test-case/blob/master/CHANGELOG.md)
- [Commits](https://github.com/frondeus/test-case/compare/v3.2.1...v3.3.1)

---
updated-dependencies:
- dependency-name: test-case
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-01 18:39:13 +01:00
dependabot[bot] e1ecba2ce4 build(deps): bump lscolors from 0.15.0 to 0.16.0
Bumps [lscolors](https://github.com/sharkdp/lscolors) from 0.15.0 to 0.16.0.
- [Release notes](https://github.com/sharkdp/lscolors/releases)
- [Commits](https://github.com/sharkdp/lscolors/compare/v0.15.0...0.16.0)

---
updated-dependencies:
- dependency-name: lscolors
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-01 18:38:29 +01:00
dependabot[bot] 0853e35e1f build(deps): bump libc from 0.2.149 to 0.2.150
Bumps [libc](https://github.com/rust-lang/libc) from 0.2.149 to 0.2.150.
- [Release notes](https://github.com/rust-lang/libc/releases)
- [Commits](https://github.com/rust-lang/libc/compare/0.2.149...0.2.150)

---
updated-dependencies:
- dependency-name: libc
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-01 18:37:58 +01:00
dependabot[bot] 4b4a74c988 build(deps): bump clap from 4.4.7 to 4.4.10
Bumps [clap](https://github.com/clap-rs/clap) from 4.4.7 to 4.4.10.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.4.7...v4.4.10)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-12-01 17:25:38 +00:00
Tavian Barnes 84f032eba8 Merge pull request #1422 from tavianator/batch
walk: Send WorkerResults in batches
2023-11-29 10:57:19 -05:00
Tavian Barnes b8a5f95cf2 walk: Limit batch sizes in --exec mode 2023-11-28 15:51:33 -05:00
Tavian Barnes 73260c0e35 walk: Send WorkerResults in batches 2023-11-28 15:51:33 -05:00
Tavian Barnes 5903dec289 Merge pull request #1429 from tavianator/ignore-0.4.21
Bump ignore to 0.4.21
2023-11-26 16:28:55 -05:00
Tavian Barnes 571ebb349b Bump ignore to 0.4.21
This includes all the patches from #1420, so switch back to the official
release.
2023-11-26 14:39:25 -05:00
Tavian Barnes d62bbbbcd1 Merge pull request #1421 from acuteenvy/fix-no-color
fix: display color when `NO_COLOR` is an empty string
2023-11-07 13:29:50 -05:00
Lena ad5fb44ddc fix: display color when NO_COLOR is an empty string 2023-11-04 15:07:10 +01:00
Tavian Barnes 8bbbd7679b walk: New WorkerState struct shared by the worker threads 2023-11-02 17:07:38 +01:00
David Peter cd32a3827d Update lockfile 2023-11-02 08:07:39 +01:00
Tavian Barnes 66c0637c90 Use a patched version of ignore for perf improvements
- https://github.com/BurntSushi/ripgrep/commit/d938e955af7a39ac0245b1ce84924f7f4a2141ac
- https://github.com/BurntSushi/ripgrep/pull/2624
- https://github.com/BurntSushi/ripgrep/pull/2642
2023-11-01 21:20:54 +01:00
Tavian Barnes c9df4296f9 Merge pull request #1419 from sharkdp/dependabot/cargo/clap_complete-4.4.4
build(deps): bump clap_complete from 4.4.3 to 4.4.4
2023-11-01 14:07:43 -04:00
Tavian Barnes 7c5cf28ace Merge pull request #1418 from sharkdp/dependabot/cargo/clap-4.4.7
build(deps): bump clap from 4.4.6 to 4.4.7
2023-11-01 14:07:26 -04:00
Tavian Barnes 51002c842d Merge pull request #1417 from sharkdp/dependabot/cargo/nix-0.27.1
build(deps): bump nix from 0.26.4 to 0.27.1
2023-11-01 13:40:57 -04:00
Tavian Barnes 8e582971fa Merge pull request #1416 from sharkdp/dependabot/cargo/regex-syntax-0.8.2
build(deps): bump regex-syntax from 0.7.5 to 0.8.2
2023-11-01 13:36:58 -04:00
Tavian Barnes 6daa72f929 Merge pull request #1415 from sharkdp/dependabot/cargo/tempfile-3.8.1
build(deps): bump tempfile from 3.8.0 to 3.8.1
2023-11-01 13:36:14 -04:00
dependabot[bot] 8355d78359 build(deps): bump clap_complete from 4.4.3 to 4.4.4
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.4.3 to 4.4.4.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/clap_complete-v4.4.3...clap_complete-v4.4.4)

---
updated-dependencies:
- dependency-name: clap_complete
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-01 17:20:14 +00:00
dependabot[bot] dbc1818073 build(deps): bump clap from 4.4.6 to 4.4.7
Bumps [clap](https://github.com/clap-rs/clap) from 4.4.6 to 4.4.7.
- [Release notes](https://github.com/clap-rs/clap/releases)
- [Changelog](https://github.com/clap-rs/clap/blob/master/CHANGELOG.md)
- [Commits](https://github.com/clap-rs/clap/compare/v4.4.6...v4.4.7)

---
updated-dependencies:
- dependency-name: clap
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-01 17:20:06 +00:00
dependabot[bot] e57ce7f2a4 build(deps): bump nix from 0.26.4 to 0.27.1
Bumps [nix](https://github.com/nix-rust/nix) from 0.26.4 to 0.27.1.
- [Changelog](https://github.com/nix-rust/nix/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nix-rust/nix/compare/v0.26.4...v0.27.1)

---
updated-dependencies:
- dependency-name: nix
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-01 17:19:59 +00:00
dependabot[bot] d8f89fa59e build(deps): bump regex-syntax from 0.7.5 to 0.8.2
Bumps [regex-syntax](https://github.com/rust-lang/regex) from 0.7.5 to 0.8.2.
- [Release notes](https://github.com/rust-lang/regex/releases)
- [Changelog](https://github.com/rust-lang/regex/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rust-lang/regex/compare/regex-syntax-0.7.5...regex-syntax-0.8.2)

---
updated-dependencies:
- dependency-name: regex-syntax
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-01 17:19:54 +00:00
dependabot[bot] 350003d8da build(deps): bump tempfile from 3.8.0 to 3.8.1
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.8.0 to 3.8.1.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/commits)

---
updated-dependencies:
- dependency-name: tempfile
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-11-01 17:19:49 +00:00
tkb-github 15329f9cfa Update RHEL package info 2023-11-01 16:25:25 +01:00
Thayne McCombs 95b4dff379 Merge pull request #1412 from tmccombs/limit-default-threads
Limit default threads
2023-10-27 23:26:31 -06:00
Thayne McCombs c96b1af3be Merge pull request #1410 from tmccombs/available-parallelism
Replace num_cpus with `std::thread::available_parallelism`
2023-10-27 23:25:51 -06:00
Thayne McCombs 5ee6365510 Set maximum default threads
Set a limit of how many threads fd will use by default. On hosts that
have a large number of cores, using additional threads has diminishing
returns, and having large numbers of threads increases the setup cost.
Thus we don't necessarily want to use the same number of threads as we
have cores.

Fixes: #1203
2023-10-26 00:48:30 -06:00
Thayne McCombs 1d57b3a064 Simplify parsing number of threads. 2023-10-25 23:56:59 -06:00
Thayne McCombs 325d419e39 Replace num_cpus with std::thread::available_parallelism
I think this might help startup time a little bit, since it looks like
on linux at least the std implementation uses syscalls to determine the
parallelism, whereas num_cpus was processing the /proc/cpuinfo file.

It also removes another dependency.
2023-10-25 02:00:31 -06:00
Thayne McCombs 8b5532d8dd Merge pull request #1409 from marcospb19/fix-docs-typo
Fix docs typos
2023-10-23 22:10:05 -06:00
João Marcos P. Bezerra 7263b5e01d Fix docs typos 2023-10-24 00:40:12 -03:00
Thayne McCombs c6fcdbe000 docs: Explicitly warn against relying on result order for exec
Supersedes: #1230
Fixes: #1228
2023-10-23 08:34:15 +02:00
Thayne McCombs 306dacd0b4 tests: Add more tests cases for ignoring .git 2023-10-23 08:34:03 +02:00
Thayne McCombs 08910e4e3f docs: Some tweaks from review 2023-10-23 08:34:03 +02:00
Thayne McCombs 8897659607 tests: Add tests for ignoring .git/ 2023-10-23 08:34:03 +02:00
Thayne McCombs 53fd416c47 docs: Document exclusion of .git/ 2023-10-23 08:34:03 +02:00
Thayne McCombs 5e0018fb1f Merge pull request #1402 from tmccombs/nix-users
maint: Remove use of unmaintained users crate
2023-10-22 01:35:47 -06:00
Thayne McCombs 054bae01ef maint: Remove use of unmaintained users crate
The users crate is no longer maintained. There is a maintained fork
called uzers, but we already have a dependency on nix, and that has the
functionality we need.
2023-10-21 23:37:32 -06:00
David Peter 8f32a758a4 Update lock file 2023-10-21 22:16:15 +02:00
David Peter 0fc8facfb7 Fix --help text 2023-10-21 22:16:15 +02:00
Thayne McCombs 069b181625 Fix documentation for brace escapes 2023-10-21 22:16:15 +02:00
Thayne McCombs d9b69c8405 feat: Add a way to escape { and }in exec templates.
fixes #1303
2023-10-21 22:16:15 +02:00
Thayne McCombs a11f8426d4 Fix deprecation warning from chrono
Also change logic to use the latest time if the local time is ambiguous
(for example due to daylight savings)
2023-10-21 14:07:50 +02:00
Thayne McCombs e6aa8e82f6 Add Upcoming Release to changelog 2023-10-21 14:06:52 +02:00
sitiom 978866d983 Change Winget Releaser job to ubuntu-latest 2023-10-21 14:06:25 +02:00
Christian Göttsche 36bc84041b Support character and block device file types 2023-10-21 13:56:33 +02:00
Thayne McCombs 3ed4ea7538 Merge pull request #1396 from skoriop/default-ignore-git-folder
feat: ignore `.git/` by default
2023-10-20 22:35:22 -06:00
Karthik Prakash 9df9a489f0 refactor: replace map_err with expect
Co-authored-by: Thayne McCombs <astrothayne@gmail.com>
2023-10-18 13:06:51 +05:30
skoriop 8c50bc733d docs: update CHANGELOG.md 2023-10-15 11:25:30 +05:30
skoriop 3f9794cd1a feat: ignore .git/ by default 2023-10-15 11:11:53 +05:30
47 changed files with 3798 additions and 1597 deletions
+9
View File
@@ -0,0 +1,9 @@
# On Windows MSVC, statically link the C runtime so that the resulting EXE does
# not depend on the vcruntime DLL.
#
# See: https://github.com/sharkdp/fd/issues/1874
[target.x86_64-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]
[target.i686-pc-windows-msvc]
rustflags = ["-C", "target-feature=+crt-static"]
+4
View File
@@ -4,7 +4,11 @@ updates:
directory: "/"
schedule:
interval: "monthly"
cooldown:
default-days: 7
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
cooldown:
default-days: 7
+106 -181
View File
@@ -13,12 +13,17 @@ on:
tags:
- '*'
permissions:
contents: read
jobs:
crate_metadata:
name: Extract crate metadata
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- name: Extract crate information
id: crate_metadata
run: |
@@ -36,21 +41,37 @@ jobs:
ensure_cargo_fmt:
name: Ensure 'cargo fmt' has been run
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
steps:
- uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- uses: actions/checkout@v4
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- run: cargo fmt -- --check
lint_check:
name: Ensure 'cargo clippy' has no warnings
runs-on: ubuntu-latest
steps:
- uses: dtolnay/rust-toolchain@stable
with:
components: clippy
- uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- run: cargo clippy --all-targets --all-features -- -Dwarnings
min_version:
name: Minimum supported rust version
runs-on: ubuntu-20.04
runs-on: ubuntu-22.04
needs: crate_metadata
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- name: Install rust toolchain (v${{ needs.crate_metadata.outputs.msrv }})
uses: dtolnay/rust-toolchain@master
@@ -58,39 +79,50 @@ jobs:
toolchain: ${{ needs.crate_metadata.outputs.msrv }}
components: clippy
- name: Run clippy (on minimum supported rust version to prevent warnings we can't fix)
run: cargo clippy --locked --all-targets ${{ env.MSRV_FEATURES }}
run: cargo clippy --locked --all-targets "${MSRV_FEATURES}"
- name: Run tests
run: cargo test --locked ${{ env.MSRV_FEATURES }}
run: cargo test --locked "${MSRV_FEATURES}"
build:
name: ${{ matrix.job.target }} (${{ matrix.job.os }})
name: '${{ matrix.job.target }} (${{ matrix.job.os }})'
runs-on: ${{ matrix.job.os }}
needs: crate_metadata
permissions:
id-token: write
contents: write
attestations: write
strategy:
fail-fast: false
matrix:
job:
- { target: aarch64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
- { target: arm-unknown-linux-gnueabihf , os: ubuntu-20.04, use-cross: true }
- { target: arm-unknown-linux-musleabihf, os: ubuntu-20.04, use-cross: true }
- { target: i686-pc-windows-msvc , os: windows-2019 }
- { target: i686-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
- { target: i686-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
- { target: x86_64-apple-darwin , os: macos-12 }
- { target: x86_64-pc-windows-gnu , os: windows-2019 }
- { target: x86_64-pc-windows-msvc , os: windows-2019 }
- { target: x86_64-unknown-linux-gnu , os: ubuntu-20.04, use-cross: true }
- { target: x86_64-unknown-linux-musl , os: ubuntu-20.04, use-cross: true }
- { target: aarch64-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true }
- { target: aarch64-unknown-linux-musl , os: ubuntu-24.04, use-cross: true }
- { target: arm-unknown-linux-gnueabihf , os: ubuntu-24.04, use-cross: true }
- { target: arm-unknown-linux-musleabihf, os: ubuntu-24.04, use-cross: true }
- { target: i686-pc-windows-msvc , os: windows-2025 }
- { target: i686-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true }
- { target: i686-unknown-linux-musl , os: ubuntu-24.04, use-cross: true }
- { target: x86_64-apple-darwin , os: macos-26-intel }
- { target: aarch64-apple-darwin , os: macos-26 }
- { target: x86_64-pc-windows-gnu , os: windows-2025 }
- { target: x86_64-pc-windows-msvc , os: windows-2025 }
- { target: aarch64-pc-windows-msvc , os: windows-11-arm }
- { target: x86_64-unknown-linux-gnu , os: ubuntu-24.04, use-cross: true }
- { target: x86_64-unknown-linux-musl , os: ubuntu-24.04, use-cross: true }
env:
BUILD_CMD: cargo
BUILD_CMD: "${{ matrix.job.use-cross && 'cross' || 'cargo' }}"
target: ${{ matrix.job.target }}
name: ${{ needs.crate_metadata.outputs.name }}
steps:
- name: Checkout source code
uses: actions/checkout@v4
uses: actions/checkout@v7.0.1
with:
persist-credentials: false
- name: Install prerequisites
shell: bash
run: |
case ${{ matrix.job.target }} in
case ${target} in
arm-unknown-linux-*) sudo apt-get -y update ; sudo apt-get -y install gcc-arm-linux-gnueabihf ;;
aarch64-unknown-linux-gnu) sudo apt-get -y update ; sudo apt-get -y install gcc-aarch64-linux-gnu ;;
esac
@@ -99,18 +131,22 @@ jobs:
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.job.target }}
toolchain: "stable"
- name: Install cross
if: matrix.job.use-cross
uses: taiki-e/install-action@v2
with:
tool: cross
- name: Overwrite build command env variable
if: matrix.job.use-cross
shell: bash
run: echo "BUILD_CMD=cross" >> $GITHUB_ENV
env:
cross_version: "v0.2.5"
package_name: "cross-x86_64-unknown-linux-gnu.tar.gz"
GH_TOKEN: "${{ github.token }}"
run: |
dir="$HOME/.local/bin/"
mkdir -p "$dir"
gh release download --repo cross-rs/cross \
--pattern "${package_name}" -O - "${cross_version}" \
| tar -C "$dir" -xz
echo "$dir" >> $GITHUB_PATH
echo "Installed cross $cross_version" >> $GITHUB_STEP_SUMMARY
- name: Show version information (Rust, cargo, GCC)
shell: bash
run: |
@@ -123,7 +159,7 @@ jobs:
- name: Build
shell: bash
run: $BUILD_CMD build --locked --release --target=${{ matrix.job.target }}
run: $BUILD_CMD build --locked --release --target="${target}"
- name: Set binary name & path
id: bin
@@ -131,13 +167,13 @@ jobs:
run: |
# Figure out suffix of binary
EXE_suffix=""
case ${{ matrix.job.target }} in
case ${target} in
*-pc-windows-*) EXE_suffix=".exe" ;;
esac;
# Setup paths
BIN_NAME="${{ needs.crate_metadata.outputs.name }}${EXE_suffix}"
BIN_PATH="target/${{ matrix.job.target }}/release/${BIN_NAME}"
BIN_NAME="${name}${EXE_suffix}"
BIN_PATH="target/${target}/release/${BIN_NAME}"
# Let subsequent steps know where to find the binary
echo "BIN_PATH=${BIN_PATH}" >> $GITHUB_OUTPUT
@@ -149,12 +185,17 @@ jobs:
run: |
# test only library unit tests and binary for arm-type targets
unset CARGO_TEST_OPTIONS
unset CARGO_TEST_OPTIONS ; case ${{ matrix.job.target }} in arm-* | aarch64-*) CARGO_TEST_OPTIONS="--bin ${{ needs.crate_metadata.outputs.name }}" ;; esac;
case ${target} in
arm-* | aarch64-*)
CARGO_TEST_OPTIONS="--bin=${name}" ;;
esac
echo "CARGO_TEST_OPTIONS=${CARGO_TEST_OPTIONS}" >> $GITHUB_OUTPUT
- name: Run tests
shell: bash
run: $BUILD_CMD test --locked --target=${{ matrix.job.target }} ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
env:
cargo_test_options: ${{ steps.test-options.outputs.CARGO_TEST_OPTIONS}}
run: $BUILD_CMD test --locked --target="${target}" "${cargo_test_options}"
- name: Generate completions
id: completions
@@ -164,163 +205,39 @@ jobs:
- name: Create tarball
id: package
shell: bash
run: |
PKG_suffix=".tar.gz" ; case ${{ matrix.job.target }} in *-pc-windows-*) PKG_suffix=".zip" ;; esac;
PKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-v${{ needs.crate_metadata.outputs.version }}-${{ matrix.job.target }}
PKG_NAME=${PKG_BASENAME}${PKG_suffix}
echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT
PKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/package"
ARCHIVE_DIR="${PKG_STAGING}/${PKG_BASENAME}/"
mkdir -p "${ARCHIVE_DIR}"
# Binary
cp "${{ steps.bin.outputs.BIN_PATH }}" "$ARCHIVE_DIR"
# README, LICENSE and CHANGELOG files
cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$ARCHIVE_DIR"
# Man page
cp 'doc/${{ needs.crate_metadata.outputs.name }}.1' "$ARCHIVE_DIR"
# Autocompletion files
cp -r autocomplete "${ARCHIVE_DIR}"
# base compressed package
pushd "${PKG_STAGING}/" >/dev/null
case ${{ matrix.job.target }} in
*-pc-windows-*) 7z -y a "${PKG_NAME}" "${PKG_BASENAME}"/* | tail -2 ;;
*) tar czf "${PKG_NAME}" "${PKG_BASENAME}"/* ;;
esac;
popd >/dev/null
# Let subsequent steps know where to find the compressed package
echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT
run: bash scripts/create-archive.sh
env:
BIN_PATH: ${{ steps.bin.outputs.BIN_PATH }}
TARGET: ${{ env.target }}
ARCHIVE_NAME: ${{ env.name }}-v${{ needs.crate_metadata.outputs.version }}-${{ env.target }}
PKG_STAGING: "${{ env.CICD_INTERMEDIATES_DIR }}/package"
- name: Create Debian package
id: debian-package
shell: bash
if: startsWith(matrix.job.os, 'ubuntu')
run: |
COPYRIGHT_YEARS="2018 - "$(date "+%Y")
DPKG_STAGING="${{ env.CICD_INTERMEDIATES_DIR }}/debian-package"
DPKG_DIR="${DPKG_STAGING}/dpkg"
mkdir -p "${DPKG_DIR}"
DPKG_BASENAME=${{ needs.crate_metadata.outputs.name }}
DPKG_CONFLICTS=${{ needs.crate_metadata.outputs.name }}-musl
case ${{ matrix.job.target }} in *-musl) DPKG_BASENAME=${{ needs.crate_metadata.outputs.name }}-musl ; DPKG_CONFLICTS=${{ needs.crate_metadata.outputs.name }} ;; esac;
DPKG_VERSION=${{ needs.crate_metadata.outputs.version }}
unset DPKG_ARCH
case ${{ matrix.job.target }} in
aarch64-*-linux-*) DPKG_ARCH=arm64 ;;
arm-*-linux-*hf) DPKG_ARCH=armhf ;;
i686-*-linux-*) DPKG_ARCH=i686 ;;
x86_64-*-linux-*) DPKG_ARCH=amd64 ;;
*) DPKG_ARCH=notset ;;
esac;
DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb"
echo "DPKG_NAME=${DPKG_NAME}" >> $GITHUB_OUTPUT
# Binary
install -Dm755 "${{ steps.bin.outputs.BIN_PATH }}" "${DPKG_DIR}/usr/bin/${{ steps.bin.outputs.BIN_NAME }}"
# Man page
install -Dm644 'doc/${{ needs.crate_metadata.outputs.name }}.1' "${DPKG_DIR}/usr/share/man/man1/${{ needs.crate_metadata.outputs.name }}.1"
gzip -n --best "${DPKG_DIR}/usr/share/man/man1/${{ needs.crate_metadata.outputs.name }}.1"
# Autocompletion files
install -Dm644 'autocomplete/fd.bash' "${DPKG_DIR}/usr/share/bash-completion/completions/${{ needs.crate_metadata.outputs.name }}"
install -Dm644 'autocomplete/fd.fish' "${DPKG_DIR}/usr/share/fish/vendor_completions.d/${{ needs.crate_metadata.outputs.name }}.fish"
install -Dm644 'autocomplete/_fd' "${DPKG_DIR}/usr/share/zsh/vendor-completions/_${{ needs.crate_metadata.outputs.name }}"
# README and LICENSE
install -Dm644 "README.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/README.md"
install -Dm644 "LICENSE-MIT" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-MIT"
install -Dm644 "LICENSE-APACHE" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-APACHE"
install -Dm644 "CHANGELOG.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/changelog"
gzip -n --best "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/changelog"
cat > "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright" <<EOF
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: ${{ needs.crate_metadata.outputs.name }}
Source: ${{ needs.crate_metadata.outputs.homepage }}
Files: *
Copyright: ${{ needs.crate_metadata.outputs.maintainer }}
Copyright: $COPYRIGHT_YEARS ${{ needs.crate_metadata.outputs.maintainer }}
License: Apache-2.0 or MIT
License: Apache-2.0
On Debian systems, the complete text of the Apache-2.0 can be found in the
file /usr/share/common-licenses/Apache-2.0.
License: MIT
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
.
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
EOF
chmod 644 "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright"
# control file
mkdir -p "${DPKG_DIR}/DEBIAN"
cat > "${DPKG_DIR}/DEBIAN/control" <<EOF
Package: ${DPKG_BASENAME}
Version: ${DPKG_VERSION}
Section: utils
Priority: optional
Maintainer: ${{ needs.crate_metadata.outputs.maintainer }}
Homepage: ${{ needs.crate_metadata.outputs.homepage }}
Architecture: ${DPKG_ARCH}
Provides: ${{ needs.crate_metadata.outputs.name }}
Conflicts: ${DPKG_CONFLICTS}
Description: simple, fast and user-friendly alternative to find
fd is a program to find entries in your filesystem.
It is a simple, fast and user-friendly alternative to find.
While it does not aim to support all of finds powerful functionality, it provides
sensible (opinionated) defaults for a majority of use cases.
EOF
DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}"
echo "DPKG_PATH=${DPKG_PATH}" >> $GITHUB_OUTPUT
# build dpkg
fakeroot dpkg-deb --build "${DPKG_DIR}" "${DPKG_PATH}"
run: bash scripts/create-deb.sh
env:
TARGET: ${{ matrix.job.target }}
DPKG_VERSION: ${{ needs.crate_metadata.version }}
BIN_PATH: ${{ steps.bin.outputs.BIN_PATH }}
- name: "Artifact upload: tarball"
uses: actions/upload-artifact@master
id: upload-tarball
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ${{ steps.package.outputs.PKG_NAME }}
path: ${{ steps.package.outputs.PKG_PATH }}
compression-level: 0 # tarball is already compressed
- name: "Artifact upload: Debian package"
uses: actions/upload-artifact@master
id: upload-deb
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
if: steps.debian-package.outputs.DPKG_NAME
with:
name: ${{ steps.debian-package.outputs.DPKG_NAME }}
path: ${{ steps.debian-package.outputs.DPKG_PATH }}
compression-level: 0 # deb files are already compressed
- name: Check for release
id: is-release
@@ -329,8 +246,16 @@ jobs:
unset IS_RELEASE ; if [[ $GITHUB_REF =~ ^refs/tags/v[0-9].* ]]; then IS_RELEASE='true' ; fi
echo "IS_RELEASE=${IS_RELEASE}" >> $GITHUB_OUTPUT
- name: "Attest artifacts"
uses: actions/attest@508db95dd578ae2727ebd6217d5ba78e4fbda05d # v4
if: steps.is-release.outputs.IS_RELEASE
with:
subject-path: |
${{ steps.package.outputs.PKG_PATH }}
${{ steps.debian-package.outputs.DPKG_PATH }}
- name: Publish archives and packages
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@3d0d9888cb7fd7b750713d6e236d1fcb99157228 # v3.0.2
if: steps.is-release.outputs.IS_RELEASE
with:
files: |
@@ -341,11 +266,11 @@ jobs:
winget:
name: Publish to Winget
runs-on: windows-latest # Action can only run on Windows
runs-on: ubuntu-latest
needs: build
if: startsWith(github.ref, 'refs/tags/v')
steps:
- uses: vedantmgoyal2009/winget-releaser@v2
- uses: vedantmgoyal9/winget-releaser@4ffc7888bffd451b357355dc214d43bb9f23917e # v2
with:
identifier: sharkdp.fd
installers-regex: '-pc-windows-msvc\.zip$'
+1
View File
@@ -1,3 +1,4 @@
target/
/autocomplete/
/package/
**/*.rs.bk
+181
View File
@@ -1,3 +1,184 @@
# Upcoming Release
## Features
-
## Bugfixes
-
# 10.5.0
## Features
- Add `--ignore-parent` option to override `--no-ignore-parent`, see #1958 (@tmchow)
- Add `--exact` option to match the entire filename exactly (literal, non-substring).
## Bugfixes
- Sanitize control characters and bidirectional override characters in filenames
when output goes to a terminal, to prevent terminal escape-sequence injection.
Also reject a placeholder as the executable for `--exec-batch`, while still
allowing it for `--exec`.
- Handle invalid working directories gracefully when using `--full-path`, see #1900 (@Xavrir).
- Fire the "search pattern contains a path separator" diagnostic for any pattern containing `/`, not just patterns that happen to name an existing directory. Preserves the legacy Windows behaviour that also flags native `\` separators when the pattern resolves to a real directory. See #1873.
- Also fire the "search pattern contains a path separator" diagnostic for `--and` patterns, not only the primary positional pattern. `--and` patterns are matched against the file name just like the primary pattern, so a path separator in them silently returned zero results. See #1873.
- Fix bug where passing "-" as a directory argument didn't actually search that directory, see #849 (@Sean-Kenneth-Doherty).
- Fix panic when `--changed-before`/`--changed-within` is given an out-of-range `@` Unix timestamp; the value is now rejected gracefully, see #2081 (@nikolauspschuetz).
# 10.4.2
## Bugfixes
- Fixed performance regression due to `--ignore-contain`; see #1913 and #1914
# 10.4.1
This is just a re-release of 10.4.0 due to an issue with the 10.4.0 release.
# 10.4.0
## Features
- Add `--ignore-contain` option to ignore directories containing a named entry (e.g. to ignore [`CACHEDIR.TAG`](https://bford.info/cachedir/)); see #1727 (@fischman).
## Bugfixes
- Fix Windows hyperlink generation for paths with spaces. (#1872)
- `--print0` combined with `--exec` will now print a `\0` between the output of each entry. Note that if there are multiple instances
of `--exec`, the `\0` will be between each _set_ of commands, _not_ between each individual command run. Fixes #1797.
- Several bugs were fixed by an update to the `ignore` library used for handling ignore rules
- #1506
- #1667
- #1813
- Fix completions for alias `fdfind` in deb release, see #1888 (@skane-lukas)
## Changes
- Minimum required rust version has been increased to 1.90.0. Notably, this means dropping fully support for intel Mac and Windows 7.
- Statically link the CRT for MSVC builds via Cargo config to avoid runtime DLL dependencies, see #1874 (@FidelSch)
# 10.3.0
## Features
- Add a hidden `--mindepth` alias for `--min-depth`. (#1617)
## Bugfixes
## Changes
- Replace `humantime` crate and `chrono` crate with `jiff` crate, see #1690 (@sorairolake). This has some small changes to the
way dates given to options such `--changed-within` and `--changed-before` including:
- 'M' no longer means "month", as that could be confusing with minutes. Use "mo", "mos", "month" or "months" instead.
- month and year now account for variability in the calander rather than being a hard-coded number of seconds. That is probably
what you would expect, but it is a slight change in behavior.
- aarch64 Windows was added to CI and release artifacts
- Many dependencies were updated
- Better support building on Illumos (there is no automated testing, but some known issues were fixed)
## Other
This will be the last release that has been tested on x86_64 Mac OS, since GitHub is
dropping support for runners with that hardware.
It may also be the last release to use a version of Rust with tier-1 support for
x86_64/intel Macs and Windows 7.
# 10.2.0
## Features
- Add --hyperlink option to add OSC 8 hyperlinks to output
## Bugfixes
## Changes
- Build windows releases with rust 1.77 so windows 7 is still supported
- Deb packages now include symlink for fdfind to be more consistent with official packages
## Other
# 10.1.0
## Features
- Allow passing an optional argument to `--strip-cwd-prefix` of "always", "never", or "auto". to force whether the cwd prefix is stripped or not.
- Add a `--format` option which allows using a format template for direct ouput similar to the template used for `--exec`. (#1043)
## Bugfixes
- Fix aarch64 page size again. This time it should actually work. (#1085, #1549) (@tavianator)
## Other
- aarch64-apple-darwin target added to builds on the release page. Note that this is a tier 2 rust target.
# v10.0.0
## Features
- Add `dir` as an alias to `directory` when using `-t` \ `--type`, see #1460 and #1464 (@Ato2207).
- Add support for @%s date format in time filters similar to GNU date (seconds since Unix epoch for --older/--newer), see #1493 (@nabellows)
- Breaking: No longer automatically ignore `.git` when using `--hidden` with vcs ignore enabled. This reverts the change in v9.0.0. While this feature
was often useful, it also broke some existing workflows, and there wasn't a good way to opt out of it. And there isn't really a good way for us to add
a way to opt out of it. And you can easily get similar behavior by adding `.git/` to your global fdignore file.
See #1457.
## Bugfixes
- Respect NO_COLOR environment variable with `--list-details` option. (#1455)
- Fix bug that would cause hidden files to be included despite gitignore rules
if search path is "." (#1461, BurntSushi/ripgrep#2711).
- aarch64 builds now use 64k page sizes with jemalloc. This fixes issues on some systems, such as ARM Macs that
have a larger system page size than the system that the binary was built on. (#1547)
- Address [CVE-2024-24576](https://blog.rust-lang.org/2024/04/09/cve-2024-24576.html), by increasing minimum rust version.
## Changes
- Minimum supported rust version is now 1.77.2
# v9.0.0
## Performance
- Performance has been *significantly improved*, both due to optimizations in the underlying `ignore`
crate (#1429), and in `fd` itself (#1422, #1408, #1362) - @tavianator.
[Benchmarks results](https://gist.github.com/tavianator/32edbe052f33ef60570cf5456b59de81) show gains
of 6-8x for full traversals of smaller directories (100k files) and up to 13x for larger directories (1M files).
- The default number of threads is now constrained to be at most 64. This should improve startup time on
systems with many CPU cores. (#1203, #1410, #1412, #1431) - @tmccombs and @tavianator
- New flushing behavior when writing output to stdout, providing better performance for TTY and non-TTY
use cases, see #1452 and #1313 (@tavianator).
## Features
- Support character and block device file types, see #1213 and #1336 (@cgzones)
- Breaking: `.git/` is now ignored by default when using `--hidden` / `-H`, use `--no-ignore` / `-I` or
`--no-ignore-vcs` to override, see #1387 and #1396 (@skoriop)
## Bugfixes
- Fix `NO_COLOR` support, see #1421 (@acuteenvy)
## Other
- Fixed documentation typos, see #1409 (@marcospb19)
## Thanks
Special thanks to @tavianator for his incredible work on performance in the `ignore` crate and `fd` itself.
# v8.7.1
## Bugfixes
+18 -1
View File
@@ -1,6 +1,6 @@
## Contributing to *fd*
**Thank you very much for considering to contribute to this project!**
**Thank you very much for considering contributing to this project!**
We welcome any form of contribution:
@@ -10,6 +10,23 @@ We welcome any form of contribution:
**Note**: Before you take the time to open a pull request, please open a ticket first. This will
give us the chance to discuss any potential changes first.
## Pull Request Expectations
1. Your contribution should be high quality, and best effort. In particular, please don't make a Pull Request
that was created using generative AI unless you have reviewed it yourself and understand what it does, and be
able to meaningfully answer questions and make changes to it as needed.
2. Your code should successfully compile and pass tests before publishing a Pull Request. It's understandable
if tests fail on one or two specific targets, but if the build doesn't pass for any targets, that is a signal
that the PR is low effort.
3. It is your responsibility to ensure that the generated code does not violate any copyrights or patents. This is
true of all contributions, but is especially relevant when using an LLM that may be generating output that is
very similar or even identical to existing code with an incompatible license.
4. If an AI coding assistant or other LLM tool was used, you must indicate that an AI tool was used, and to what extent it was used.
5. AI should not be used to generate comments when communicating with maintainers. We expect communication with the maintainers,
including PR descriptions and comments, to be from humans, not from an AI. Using an AI to assist with grammar, spelling, and
proofreading or translating is acceptable, as long as the content and voice of the
message is your own.
## Add an entry to the changelog
If your contribution changes the behavior of `fd` (as opposed to a typo-fix
Generated
+617 -396
View File
File diff suppressed because it is too large Load Diff
+54 -34
View File
@@ -1,10 +1,10 @@
[package]
authors = ["David Peter <mail@david-peter.de>"]
build = "build.rs"
categories = ["command-line-utilities"]
description = "fd is a simple, fast and user-friendly alternative to find."
exclude = ["/benchmarks/*"]
homepage = "https://github.com/sharkdp/fd"
documentation = "https://docs.rs/fd-find"
keywords = [
"search",
"find",
@@ -16,9 +16,9 @@ license = "MIT OR Apache-2.0"
name = "fd-find"
readme = "README.md"
repository = "https://github.com/sharkdp/fd"
version = "8.7.1"
edition= "2021"
rust-version = "1.70.0"
version = "10.5.0"
edition= "2024"
rust-version = "1.90.0"
[badges.appveyor]
repository = "sharkdp/fd"
@@ -30,43 +30,34 @@ repository = "sharkdp/fd"
name = "fd"
path = "src/main.rs"
[build-dependencies]
version_check = "0.9"
[dependencies]
nu-ansi-term = "0.49"
argmax = "0.3.1"
ignore = "0.4.20"
num_cpus = "1.16"
regex = "1.9.6"
regex-syntax = "0.7"
ctrlc = "3.2"
humantime = "2.1"
aho-corasick = "1.1"
nu-ansi-term = "0.50"
argmax = "0.4.0"
ignore = "0.4.25"
regex = "1.12.2"
regex-syntax = "0.8"
ctrlc = "3.5"
globset = "0.4"
anyhow = "1.0"
etcetera = "0.8"
normpath = "1.1.1"
crossbeam-channel = "0.5.8"
clap_complete = {version = "4.4.1", optional = true}
etcetera = "0.11"
normpath = "1.5.1"
crossbeam-channel = "0.5.15"
clap_complete = {version = "4.6.5", optional = true}
faccess = "0.2.4"
jiff = "0.2.27"
[dependencies.clap]
version = "4.4.6"
version = "4.6.1"
features = ["suggestions", "color", "wrap_help", "cargo", "derive"]
[dependencies.chrono]
version = "0.4.28"
default-features = false
features = ["std", "clock"]
[dependencies.lscolors]
version = "0.15"
version = "0.21"
default-features = false
features = ["nu-ansi-term"]
[target.'cfg(unix)'.dependencies]
users = "0.11.0"
nix = { version = "0.26.2", default-features = false, features = ["signal"] }
nix = { version = "0.31.1", default-features = false, features = ["signal", "user", "hostname"] }
[target.'cfg(all(unix, not(target_os = "redox")))'.dependencies]
libc = "0.2"
@@ -74,14 +65,26 @@ libc = "0.2"
# FIXME: Re-enable jemalloc on macOS
# jemalloc is currently disabled on macOS due to a bug in jemalloc in combination with macOS
# Catalina. See https://github.com/sharkdp/fd/issues/498 for details.
[target.'cfg(all(not(windows), not(target_os = "android"), not(target_os = "macos"), not(target_os = "freebsd"), not(target_os = "openbsd"), not(all(target_env = "musl", target_pointer_width = "32")), not(target_arch = "riscv64")))'.dependencies]
jemallocator = {version = "0.5.4", optional = true}
# This has to be kept in sync with src/main.rs where the allocator for
# the program is set.
[target.'cfg(all(not(windows), not(target_os = "android"), not(target_os = "macos"), not(target_os = "freebsd"), not(target_os = "openbsd"), not(target_os = "illumos"), not(all(target_env = "musl", target_pointer_width = "32")), not(target_arch = "riscv64")))'.dependencies]
tikv-jemallocator = {version = "0.7.0", optional = true}
[dev-dependencies]
diff = "0.1"
tempfile = "3.6"
tempfile = "3.27"
filetime = "0.2"
test-case = "3.1"
test-case = "3.3"
[profile.dev]
debug = "line-tables-only"
[profile.dev.package."*"]
debug = false
[profile.debugging]
inherits = "dev"
debug = true
[profile.release]
lto = true
@@ -89,7 +92,24 @@ strip = true
codegen-units = 1
[features]
use-jemalloc = ["jemallocator"]
use-jemalloc = ["tikv-jemallocator"]
completions = ["clap_complete"]
base = ["use-jemalloc"]
default = ["use-jemalloc", "completions"]
default = ["completions"]
[package.metadata.binstall]
pkg-url = "{ repo }/releases/download/v{ version }/{ name }-v{ version }-{ target }.{ archive-format }"
bin-dir = "{ bin }-v{ version }-{ target }/{ bin }{ binary-ext }"
pkg-fmt = "tgz"
[package.metadata.binstall.overrides.x86_64-pc-windows-msvc]
pkg-fmt = "zip"
[package.metadata.binstall.overrides.x86_64-pc-windows-gnu]
pkg-fmt = "zip"
[package.metadata.binstall.overrides.i686-pc-windows-msvc]
pkg-fmt = "zip"
[package.metadata.binstall.overrides.aarch64-pc-windows-msvc]
pkg-fmt = "zip"
+6
View File
@@ -0,0 +1,6 @@
# https://github.com/sharkdp/fd/issues/1085
[target.aarch64-unknown-linux-gnu.env]
passthrough = ["JEMALLOC_SYS_WITH_LG_PAGE=16"]
[target.aarch64-unknown-linux-musl.env]
passthrough = ["JEMALLOC_SYS_WITH_LG_PAGE=16"]
+32 -5
View File
@@ -1,15 +1,22 @@
PROFILE=release
PROFILE?=release
EXE=target/$(PROFILE)/fd
prefix=/usr/local
bindir=$(prefix)/bin
datadir=$(prefix)/share
exe_name=fd
ifdef VERSION
ARCHIVE_NAME = fd-v$(VERSION)
else
ARCHIVE_NAME = fd
endif
export ARCHIVE_NAME
archive_path=package/$(ARCHIVE_NAME).tar.gz
$(EXE): Cargo.toml src/**/*.rs
cargo build --profile $(PROFILE)
cargo build --profile $(PROFILE) --locked
.PHONY: completions
completions: autocomplete/fd.bash autocomplete/fd.fish autocomplete/fd.ps1 autocomplete/_fd
completions: autocomplete/fd.bash autocomplete/fd.fish autocomplete/_fd.ps1 autocomplete/_fd autocomplete/_fdfind autocomplete/fdfind.bash autocomplete/fdfind.fish
comp_dir=@mkdir -p autocomplete
@@ -21,7 +28,7 @@ autocomplete/fd.fish: $(EXE)
$(comp_dir)
$(EXE) --gen-completions fish > $@
autocomplete/fd.ps1: $(EXE)
autocomplete/_fd.ps1: $(EXE)
$(comp_dir)
$(EXE) --gen-completions powershell > $@
@@ -29,9 +36,29 @@ autocomplete/_fd: contrib/completion/_fd
$(comp_dir)
cp $< $@
autocomplete/_fdfind: contrib/completion/_fdfind
$(comp_dir)
cp $< $@
autocomplete/fdfind.bash: contrib/completion/fdfind.bash
$(comp_dir)
cp $< $@
autocomplete/fdfind.fish: contrib/completion/fdfind.fish
$(comp_dir)
cp $< $@
archive: $(archive_path)
$(archive_path): completions $(EXE)
bash scripts/create-archive.sh
install: $(EXE) completions
install -Dm755 $(EXE) $(DESTDIR)$(bindir)/fd
install -Dm644 autocomplete/fd.bash $(DESTDIR)/$(datadir)/bash-completion/completions/$(exe_name)
install -Dm644 autocomplete/fd.fish $(DESTDIR)/$(datadir)/fish/vendor_completions.d/$(exe_name).fish
install -Dm644 autocomplete/_fd $(DESTDIR)/$(datadir)/zsh/site-functions/_$(exe_name)
install -Dm644 autocomplete/_fd $(DESTDIR)/$(datadir)/zsh/site-functions/_fd
install -Dm644 autocomplete/fdfind.bash $(DESTDIR)/$(datadir)/zsh/site-functions/fdfind.bash
install -Dm644 autocomplete/fdfind.fish $(DESTDIR)/$(datadir)/zsh/site-functions/fdfind.fish
install -Dm644 autocomplete/_fdfind $(DESTDIR)/$(datadir)/zsh/site-functions/_fdfind
install -Dm644 doc/fd.1 $(DESTDIR)/$(datadir)/man/man1/$(exe_name).1
+150 -74
View File
@@ -10,10 +10,7 @@ It is a simple, fast and user-friendly alternative to [`find`](https://www.gnu.o
While it does not aim to support all of `find`'s powerful functionality, it provides sensible
(opinionated) defaults for a majority of use cases.
Quick links:
* [How to use](#how-to-use)
* [Installation](#installation)
* [Troubleshooting](#troubleshooting)
[Installation](#installation) • [How to use](#how-to-use) • [Troubleshooting](#troubleshooting)
## Features
@@ -63,7 +60,7 @@ X11/xinit/xinitrc
X11/xinit/xserverrc
```
The regular expression syntax used by `fd` is [documented here](https://docs.rs/regex/1.0.0/regex/#syntax).
The regular expression syntax used by `fd` is [documented here](https://docs.rs/regex/latest/regex/#syntax).
### Specifying the root directory
@@ -143,14 +140,14 @@ target/debug/deps/libnum_cpus-f5ce7ef99006aa05.rlib
```
To really search *all* files and directories, simply combine the hidden and ignore features to show
everything (`-HI`).
everything (`-HI`) or use `-u`/`--unrestricted`.
### Matching the full path
By default, *fd* only matches the filename of each file. However, using the `--full-path` or `-p` option,
you can match against the full path.
```bash
> fd -p -g '**/.git/config'
> fd -u -p -g '**/.git/config'
> fd -p '.*/lesson-\d+/[a-z]+.(jpg|png)'
```
@@ -179,6 +176,12 @@ fd -e h -e cpp -x clang-format -i
Note how the `-i` option to `clang-format` can be passed as a separate argument. This is why
we put the `-x` option last.
Any positional arguments after `-x` belong to the command template, not to `fd` itself. If you
also want to pass a pattern or search path, put `-x` last:
``` bash
fd pattern path -x echo
```
Find all `test_*.py` files and open them in your favorite editor:
``` bash
fd -g 'test_*.py' -X vim
@@ -209,7 +212,7 @@ See below for more details on the placeholder syntax.
The terminal output of commands run from parallel threads using `-x` will not be interlaced or garbled,
so `fd -x` can be used to rudimentarily parallelize a task run over many files.
An example of this is calculating the checksum of each individual file within a directory.
```
``` bash
fd -tf -x md5sum > file_checksums.txt
```
@@ -218,6 +221,9 @@ fd -tf -x md5sum > file_checksums.txt
The `-x` and `-X` options take a *command template* as a series of arguments (instead of a single string).
If you want to add additional options to `fd` after the command template, you can terminate it with a `\;`.
For example, `fd -x echo \; pattern path` treats `pattern path` as `fd` arguments instead of
passing them to `echo`. In practice, it is often clearer to write `fd pattern path -x echo`.
The syntax for generating commands is similar to that of [GNU Parallel](https://www.gnu.org/software/parallel/):
- `{}`: A placeholder token that will be replaced with the path of the search result
@@ -261,12 +267,17 @@ To make exclude-patterns like these permanent, you can create a `.fdignore` file
/mnt/external-drive
*.bak
```
Note: `fd` also supports `.ignore` files that are used by other programs such as `rg` or `ag`.
> [!NOTE]
> `fd` also supports `.ignore` files that are used by other programs such as `rg` or `ag`.
If you want `fd` to ignore these patterns globally, you can put them in `fd`'s global ignore file.
This is usually located in `~/.config/fd/ignore` in macOS or Linux, and `%APPDATA%\fd\ignore` in
Windows.
You may wish to include `.git/` in your `fd/ignore` file so that `.git` directories, and their contents
are not included in output if you use the `--hidden` option.
### Deleting files
You can use `fd` to remove all files and directories that are matched by your search pattern.
@@ -284,7 +295,8 @@ option:
If you also want to remove a certain class of directories, you can use the same technique. You will
have to use `rm`s `--recursive`/`-r` flag to remove directories.
Note: there are scenarios where using `fd … -X rm -r` can cause race conditions: if you have a
> [!NOTE]
> There are scenarios where using `fd … -X rm -r` can cause race conditions: if you have a
path like `…/foo/bar/foo/…` and want to remove all directories named `foo`, you can end up in a
situation where the outer `foo` directory is removed first, leading to (harmless) *"'foo/bar/foo':
No such file or directory"* errors in the `rm` call.
@@ -295,7 +307,7 @@ This is the output of `fd -h`. To see the full set of command-line options, use
also includes a much more detailed help text.
```
Usage: fd [OPTIONS] [pattern] [path]...
Usage: fd [OPTIONS] [pattern [path]...]
Arguments:
[pattern] the search pattern (a regular expression, unless '--glob' is used; optional)
@@ -312,82 +324,87 @@ Options:
-L, --follow Follow symbolic links
-p, --full-path Search full abs. path (default: filename only)
-d, --max-depth <depth> Set maximum search depth (default: none)
-E, --exclude <pattern> Exclude entries that match the given glob pattern
-t, --type <filetype> Filter by type: file (f), directory (d), symlink (l),
executable (x), empty (e), socket (s), pipe (p)
-e, --extension <ext> Filter by file extension
-E, --exclude <glob> Exclude entries that match the given glob pattern
-t, --type <filetype> Filter by type: file (f), directory (d/dir), symlink (l),
executable (x), empty (e), socket (s), pipe (p), char-device
(c), block-device (b)
-e, --extension <ext> Filter by extension
-S, --size <size> Limit results based on the size of files
--changed-within <date|dur> Filter by file modification time (newer than)
--changed-before <date|dur> Filter by file modification time (older than)
-o, --owner <user:group> Filter by owning user and/or group
--format <fmt> Print results according to template
-x, --exec <cmd>... Execute a command for each search result
-X, --exec-batch <cmd>... Execute a command with all search results at once
-c, --color <when> When to use colors [default: auto] [possible values: auto,
always, never]
--hyperlink[=<when>] Add hyperlinks to output paths [default: never] [possible
values: auto, always, never]
--ignore-contain <name> Ignore directories containing the named entry
-h, --help Print help (see more with '--help')
-V, --version Print version
```
Note that options can be given after the pattern and/or path as well.
## Benchmark
Let's search my home folder for files that end in `[0-9].jpg`. It contains ~190.000
subdirectories and about a million files. For averaging and statistical analysis, I'm using
Let's search my home folder for files that end in `[0-9].jpg`. It contains ~750,000
subdirectories and about a 4 million files. For averaging and statistical analysis, I'm using
[hyperfine](https://github.com/sharkdp/hyperfine). The following benchmarks are performed
with a "warm"/pre-filled disk-cache (results for a "cold" disk-cache show the same trends).
Let's start with `find`:
```
Benchmark #1: find ~ -iregex '.*[0-9]\.jpg$'
Time (mean ± σ): 7.236 s ± 0.090 s
Range (min … max): 7.133 s … 7.385 s
Benchmark 1: find ~ -iregex '.*[0-9]\.jpg$'
Time (mean ± σ): 19.922 s ± 0.109 s
Range (min … max): 19.765 s … 20.065 s
```
`find` is much faster if it does not need to perform a regular-expression search:
```
Benchmark #2: find ~ -iname '*[0-9].jpg'
Time (mean ± σ): 3.914 s ± 0.027 s
Range (min … max): 3.876 s … 3.964 s
Benchmark 2: find ~ -iname '*[0-9].jpg'
Time (mean ± σ): 11.226 s ± 0.104 s
Range (min … max): 11.119 s … 11.466 s
```
Now let's try the same for `fd`. Note that `fd` *always* performs a regular expression
search. The options `--hidden` and `--no-ignore` are needed for a fair comparison,
otherwise `fd` does not have to traverse hidden folders and ignored paths (see below):
Now let's try the same for `fd`. Note that `fd` performs a regular expression
search by default. The options `-u`/`--unrestricted` option is needed here for
a fair comparison. Otherwise `fd` does not have to traverse hidden folders and
ignored paths (see below):
```
Benchmark #3: fd -HI '.*[0-9]\.jpg$' ~
Time (mean ± σ): 811.6 ms ± 26.9 ms
Range (min … max): 786.0 ms … 870.7 ms
Benchmark 3: fd -u '[0-9]\.jpg$' ~
Time (mean ± σ): 854.8 ms ± 10.0 ms
Range (min … max): 839.2 ms … 868.9 ms
```
For this particular example, `fd` is approximately nine times faster than `find -iregex`
and about five times faster than `find -iname`. By the way, both tools found the exact
same 20880 files :smile:.
For this particular example, `fd` is approximately **23 times faster** than `find -iregex`
and about **13 times faster** than `find -iname`. By the way, both tools found the exact
same 546 files :smile:.
Finally, let's run `fd` without `--hidden` and `--no-ignore` (this can lead to different
search results, of course). If *fd* does not have to traverse the hidden and git-ignored
folders, it is almost an order of magnitude faster:
```
Benchmark #4: fd '[0-9]\.jpg$' ~
Time (mean ± σ): 123.7 ms ± 6.0 ms
Range (min … max): 118.8 ms … 140.0 ms
```
**Note**: This is *one particular* benchmark on *one particular* machine. While I have
performed quite a lot of different tests (and found consistent results), things might
be different for you! I encourage everyone to try it out on their own. See
**Note**: This is *one particular* benchmark on *one particular* machine. While we have
performed a lot of different tests (and found consistent results), things might
be different for you! We encourage everyone to try it out on their own. See
[this repository](https://github.com/sharkdp/fd-benchmarks) for all necessary scripts.
Concerning *fd*'s speed, the main credit goes to the `regex` and `ignore` crates that are also used
in [ripgrep](https://github.com/BurntSushi/ripgrep) (check it out!).
Concerning *fd*'s speed, a lot of credit goes to the `regex` and `ignore` crates that are
also used in [ripgrep](https://github.com/BurntSushi/ripgrep) (check it out!).
## Troubleshooting
### `fd` does not find my file!
Remember that `fd` ignores hidden directories and files by default. It also ignores patterns
from `.gitignore` files. If you want to make sure to find absolutely every possible file, always
use the options `-u`/`--unrestricted` option (or `-HI` to enable hidden and ignored files):
``` bash
> fd -u …
```
Also remember that by default, `fd` only searches based on the filename and
doesn't compare the pattern to the full path. If you want to search based on the
full path (similar to the `-path` option of `find`) you need to use the `--full-path`
(or `-p`) option.
### Colorized output
`fd` can colorize files by extension, just like `ls`. In order for this to work, the environment
@@ -401,15 +418,6 @@ for alternative, more complete (or more colorful) variants, see [here](https://g
`fd` also honors the [`NO_COLOR`](https://no-color.org/) environment variable.
### `fd` does not find my file!
Remember that `fd` ignores hidden directories and files by default. It also ignores patterns
from `.gitignore` files. If you want to make sure to find absolutely every possible file, always
use the options `-H` and `-I` to disable these two features:
``` bash
> fd -HI …
```
### `fd` doesn't seem to interpret my regex pattern correctly
A lot of special regex characters (like `[]`, `^`, `$`, ..) are also special characters in your
@@ -436,6 +444,11 @@ you can use `export -f my_function` to make available to child processes. You wo
need to call `fd -x bash -c 'my_function "$1"' bash`. For other use cases or shells, use
a (temporary) shell script.
### Placeholders in `-x`/`-X`
Depending on your shell, you may need to quote the placeholders (`{}`, `{/}`, `{//}`,
`{.}`, `{/.}`) to prevent the shell from interpreting them before `fd` sees them.
## Integration with other programs
### Using fd with `fzf`
@@ -532,7 +545,7 @@ newlines). In the same way, the `-0` option of `xargs` tells it to read the inpu
If you run Ubuntu 19.04 (Disco Dingo) or newer, you can install the
[officially maintained package](https://packages.ubuntu.com/fd-find):
```
sudo apt install fd-find
apt install fd-find
```
Note that the binary is called `fdfind` as the binary name `fd` is already used by another package.
It is recommended that after installation, you add a link to `fd` by executing command
@@ -542,21 +555,25 @@ Make sure that `$HOME/.local/bin` is in your `$PATH`.
If you use an older version of Ubuntu, you can download the latest `.deb` package from the
[release page](https://github.com/sharkdp/fd/releases) and install it via:
``` bash
sudo dpkg -i fd_8.7.1_amd64.deb # adapt version number and architecture
dpkg -i fd_9.0.0_amd64.deb # adapt version number and architecture
```
Note that the .deb packages on the release page for this project still name the executable `fd`.
### On Debian
If you run Debian Buster or newer, you can install the
[officially maintained Debian package](https://tracker.debian.org/pkg/rust-fd-find):
```
sudo apt-get install fd-find
apt-get install fd-find
```
Note that the binary is called `fdfind` as the binary name `fd` is already used by another package.
It is recommended that after installation, you add a link to `fd` by executing command
`ln -s $(which fdfind) ~/.local/bin/fd`, in order to use `fd` in the same way as in this documentation.
Make sure that `$HOME/.local/bin` is in your `$PATH`.
Note that the .deb packages on the release page for this project still name the executable `fd`.
### On Fedora
Starting with Fedora 28, you can install `fd` from the official package sources:
@@ -574,10 +591,12 @@ apk add fd
### On Arch Linux
You can install [the fd package](https://www.archlinux.org/packages/community/x86_64/fd/) from the official repos:
You can install [the fd package](https://www.archlinux.org/packages/extra/x86_64/fd/) from the official repos:
```
pacman -S fd
```
You can also install fd [from the AUR](https://aur.archlinux.org/packages/fd-git).
### On Gentoo Linux
You can use [the fd ebuild](https://packages.gentoo.org/packages/sys-apps/fd) from the official repo:
@@ -599,7 +618,21 @@ You can install `fd` via xbps-install:
xbps-install -S fd
```
### On RedHat Enterprise Linux 8 (RHEL8), Almalinux 8, EuroLinux 8 or Rocky Linux 8
### On ALT Linux
You can install [the fd package](https://packages.altlinux.org/en/sisyphus/srpms/fd/) from the official repo:
```
apt-get install fd
```
### On Solus
You can install [the fd package](https://github.com/getsolus/packages/tree/main/packages/f/fd) from the official repo:
```
eopkg install fd
```
### On RedHat Enterprise Linux (RHEL) 8/9/10, Almalinux 8/9/10, EuroLinux 8/9 or Rocky Linux 8/9/10
You can install [the `fd` package](https://copr.fedorainfracloud.org/coprs/tkbcopr/fd/) from Fedora Copr.
@@ -608,7 +641,7 @@ dnf copr enable tkbcopr/fd
dnf install fd
```
A different version using the [slower](https://github.com/sharkdp/fd/pull/481#issuecomment-534494592) malloc [instead of jemalloc](https://bugzilla.redhat.com/show_bug.cgi?id=2216193#c1) is also available from the EPEL8 repo.
A different version using the [slower](https://github.com/sharkdp/fd/pull/481#issuecomment-534494592) malloc [instead of jemalloc](https://bugzilla.redhat.com/show_bug.cgi?id=2216193#c1) is also available from the EPEL8/9 repo as the package `fd-find`.
### On macOS
@@ -619,7 +652,7 @@ brew install fd
… or with MacPorts:
```
sudo port install fd
port install fd
```
### On Windows
@@ -648,6 +681,13 @@ You can install [the fd package](https://guix.gnu.org/en/packages/fd-8.1.1/) fro
guix install fd
```
### On Mise
You can use [mise](https://github.com/jdx/mise) to install `fd` with a command like this:
```
mise use -g fd@latest
```
### On NixOS / via Nix
You can use the [Nix package manager](https://nixos.org/nix/) to install `fd`:
@@ -655,6 +695,13 @@ You can use the [Nix package manager](https://nixos.org/nix/) to install `fd`:
nix-env -i fd
```
### Via Flox
You can use [Flox](https://flox.dev) to install `fd` into a Flox environment:
```
flox install fd
```
### On FreeBSD
You can install [the fd-find package](https://www.freshports.org/sysutils/fd) from the official repo:
@@ -664,7 +711,7 @@ pkg install fd-find
### From npm
On linux and macOS, you can install the [fd-find](https://npm.im/fd-find) package:
On Linux and macOS, you can install the [fd-find](https://npm.im/fd-find) package:
```
npm install -g fd-find
@@ -676,7 +723,7 @@ With Rust's package manager [cargo](https://github.com/rust-lang/cargo), you can
```
cargo install fd-find
```
Note that rust version *1.64.0* or later is required.
Note that rust version *1.90.0* or later is required.
`make` is also needed for the build.
@@ -699,6 +746,37 @@ cargo test
cargo install --path .
```
### Completions
#### From Release Archives
Pre-built completion files are included in the release archives (`.tar.gz`/`.zip`) on the
[Releases page](https://github.com/sharkdp/fd/releases), in the `autocomplete` directory.
To use these completions:
- **bash**: Source the `fd.bash` file in your `~/.bashrc`, or place it in a directory that gets sourced automatically.
- **zsh**: Move `_fd` to a directory in your `fpath` (e.g., `~/.zfunc`).
- **fish**: Copy `fd.fish` to `~/.config/fish/completions/`.
- **powershell**: Source `_fd.ps1` from one of your [profile scripts](https://learn.microsoft.com/en-us/powershell/scripting/learn/shell/creating-profiles?view=powershell-7.5).
#### Generate from fd
You can also generate completions directly using `fd --gen-completions <shell>`:
```bash
# Bash
fd --gen-completions bash > ~/.local/share/bash-completion/completions/fd
# Zsh (ensure ~/.zfunc is in your fpath)
fd --gen-completions zsh > ~/.zfunc/_fd
# Fish
fd --gen-completions fish > ~/.config/fish/completions/fd.fish
# PowerShell
fd --gen-completions powershell >> $PROFILE
```
## Maintainers
- [sharkdp](https://github.com/sharkdp)
@@ -707,8 +785,6 @@ cargo install --path .
## License
Copyright (c) 2017-2021 The fd developers
`fd` is distributed under the terms of both the MIT License and the Apache License 2.0.
See the [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) files for license details.
+33
View File
@@ -0,0 +1,33 @@
# Security Reporting
If you wish to report a security vulnerability privately, we appreciate your diligence. Please follow the guidelines below to submit your report.
## Reporting
To report a security vulnerability, please provide the following information:
1. **PROJECT**
- Include the URL of the project repository - Example: <https://github.com/sharkdp/fd>
2. **PUBLIC**
- Indicate whether this vulnerability has already been publicly discussed or disclosed.
- If so, provide relevant links.
3. **DESCRIPTION**
- Provide a detailed description of the security vulnerability.
- Include as much information as possible to help us understand and address the issue.
Send this information, along with any additional relevant details, to our [vulnerability reporting form](https://github.com/sharkdp/fd/security/advisories/new).
## Confidentiality
We kindly ask you to keep the report confidential until a public announcement is made.
## Notes
- Vulnerabilities will be handled on a best-effort basis.
- You may request an advance copy of the patched release, but we cannot guarantee early access before the public release.
- You will be notified via email simultaneously with the public announcement.
- We will respond within a few weeks to confirm whether your report has been accepted or rejected.
Thank you for helping to improve the security of our project!
-12
View File
@@ -1,12 +0,0 @@
fn main() {
let min_version = "1.64";
match version_check::is_min_version(min_version) {
Some(true) => {}
// rustc version too small or can't figure it out
_ => {
eprintln!("'fd' requires rustc >= {}", min_version);
std::process::exit(1);
}
}
}
+5 -1
View File
@@ -26,6 +26,8 @@ _fd() {
{l,symlink}'\:"symbolic links"'
{e,empty}'\:"empty files or directories"'
{x,executable}'\:"executable (files)"'
{b,block-device}'\:"block devices"'
{c,char-device}'\:"character devices"'
{s,socket}'\:"sockets"'
{p,pipe}'\:"named pipes (FIFOs)"'
)
@@ -137,6 +139,8 @@ _fd() {
always\:"always use colorized output"
))'
'--hyperlink=-[add hyperlinks to output paths]::when:(auto never always)'
+ '(threads)'
{-j+,--threads=}'[set the number of threads for searching and executing]:number of threads'
@@ -160,7 +164,7 @@ _fd() {
$no'(*)*--search-path=[set search path (instead of positional <path> arguments)]:directory:_files -/'
+ strip-cwd-prefix
$no'(strip-cwd-prefix exec-cmds)--strip-cwd-prefix[Strip ./ prefix when output is redirected]'
$no'(strip-cwd-prefix exec-cmds)--strip-cwd-prefix=-[When to strip ./]::when:(always never auto)'
+ and
'--and=[additional required search path]:pattern'
+2
View File
@@ -0,0 +1,2 @@
#compdef fdfind
_fd "$@"
+8
View File
@@ -0,0 +1,8 @@
# Source fd completions
source /usr/share/bash-completion/completions/fd
if [[ "${BASH_VERSINFO[0]}" -eq 4 && "${BASH_VERSINFO[1]}" -ge 4 || "${BASH_VERSINFO[0]}" -gt 4 ]]; then
complete -F _fd -o nosort -o bashdefault -o default fdfind
else
complete -F _fd -o bashdefault -o default fdfind
fi
+1
View File
@@ -0,0 +1 @@
complete -c fdfind --wraps fd
Vendored
+150 -43
View File
@@ -18,8 +18,8 @@ fd \- find entries in the filesystem
.IR num ]
.RB [ \-x
.IR cmd ]
.RI [ pattern ]
.RI [ path... ]
.RI [ pattern
.RI [ path... ]]
.SH DESCRIPTION
.B fd
is a simple, fast and user-friendly alternative to
@@ -29,11 +29,25 @@ By default
.B fd
uses regular expressions for the pattern. However, this can be changed to use simple glob patterns
with the '\-\-glob' option.
.P
By default
.B fd
will exclude hidden files and directories, as well as any files that match gitignore rules
or ignore rules in .ignore or .fdignore files.
.P
If you wish to search all files in a specific directory, you can use '' or . as the search pattern,
to match all files. Or you can use the '\-\-search\-path' option to specify the path(s) instead of
the positional parameter.
.P
Options may be given anywhere on the command line.
.SH OPTIONS
.TP
.B \-H, \-\-hidden
Include hidden files and directories in the search results
(default: hidden files and directories are skipped). The flag can be overridden with '--no-hidden'.
.IP
Ignored files are still excluded unless \-\-no\-ignore or \-\-no\-ignore\-vcs
is also used.
.TP
.B \-I, \-\-no\-ignore
Show search results from files and directories that would otherwise be ignored by
@@ -100,7 +114,14 @@ Perform a regular-expression based search (default). This can be used to overrid
.TP
.B \-F, \-\-fixed\-strings
Treat the pattern as a literal string instead of a regular expression. Note that this also
performs substring comparison. If you want to match on an exact filename, consider using '\-\-glob'.
performs substring comparison. If you want to match on an exact filename, consider using '\-\-glob'
or '\-\-exact'.
.TP
.B \-\-exact
Perform an exact match. This is equivalent to '\-\-fixed\-strings' but requires the pattern to
match the entire filename (or the full path if '\-\-full\-path' is used), rather than a substring.
Special regex characters in the pattern are treated as literal characters.
Cannot be used together with '\-\-glob' or '\-\-fixed\-strings'.
.TP
.BI "\-\-and " pattern
Add additional required search patterns, all of which must be matched. Multiple additional
@@ -148,9 +169,20 @@ can be used as an alias.
Enable the display of filesystem errors for situations such as insufficient
permissions or dead symlinks.
.TP
.B \-\-strip-cwd-prefix
By default, relative paths are prefixed with './' when the output goes to a non interactive terminal
(TTY). Use this flag to disable this behaviour.
.B \-\-strip-cwd-prefix [when]
By default, relative paths are prefixed with './' when -x/--exec,
-X/--exec-batch, or -0/--print0 are given, to reduce the risk of a
path starting with '-' being treated as a command line option. Use
this flag to change this behavior. If this flag is used without a value,
it is equivalent to passing "always". Possible values are:
.RS
.IP never
Never strip the ./ at the beginning of paths
.IP always
Always strip the ./ at the beginning of paths
.IP auto
Only strip if used with --exec, --exec-batch, or --print0. That is, it resets to the default behavior.
.RE
.TP
.B \-\-one\-file\-system, \-\-mount, \-\-xdev
By default, fd will traverse the file system tree as far as other options dictate. With this flag, fd ensures that it does not descend into a different file system than the one it started in. Comparable to the -mount or -xdev filters of find(1).
@@ -180,10 +212,14 @@ Filter search by type:
.RS
.IP "f, file"
regular files
.IP "d, directory"
.IP "d, dir, directory"
directories
.IP "l, symlink"
symbolic links
.IP "b, block-device"
block devices
.IP "c, char-device"
character devices
.IP "s, socket"
sockets
.IP "p, pipe"
@@ -221,14 +257,16 @@ Examples:
.RE
.TP
.BI "\-e, \-\-extension " ext
Filter search results by file extension
Filter search results by extension
.IR ext .
This option can be used repeatedly to allow for multiple possible file extensions.
This option can be used repeatedly to allow for multiple possible extensions.
By default, extension filters apply to both files and directories. Use
\fB\-\-type\fR to restrict the search to specific types.
If you want to search for files without extension, you can use the regex '^[^.]+$'
as a normal search pattern.
.TP
.BI "\-E, \-\-exclude " pattern
.BI "\-E, \-\-exclude " glob
Exclude files/directories that match the given glob pattern.
This overrides any other ignore logic.
Multiple exclude patterns can be specified.
@@ -236,6 +274,10 @@ Examples:
\-\-exclude '*.pyc'
\-\-exclude node_modules
.TP
.BI "\-\-ignore-contain " name
Exclude directories that (directly) contain the given name.
This option can be specified multiple times.
.TP
.BI "\-\-ignore-file " path
Add a custom ignore-file in '.gitignore' format.
These files have a low precedence.
@@ -253,6 +295,24 @@ Do not colorize output.
Always colorize output.
.RE
.TP
.B "\-\-hyperlink
Specify whether the output should use terminal escape codes to indicate a hyperlink to a
file url pointing to the path.
The value can be auto, always, or never.
Currently, the default is "never", and if the option is used without an argument "auto" is
used. In the future this may be changed to "auto" and "always".
.RS
.IP auto
Only output hyperlinks if color is also enabled, as a proxy for whether terminal escape
codes are acceptable.
.IP never
Never output hyperlink escapes.
.IP always
Always output hyperlink escapes, regardless of color settings.
.RE
.TP
.BI "\-j, \-\-threads " num
Set number of threads to use for searching & executing (default: number of available CPU cores).
.TP
@@ -295,10 +355,11 @@ tebibytes
.TP
.BI "\-\-changed-within " date|duration
Filter results based on the file modification time.
Files with modification times greater than the argument will be returned.
Files with modification timestamps greater than the argument will be returned.
The argument can be provided as a duration (\fI10h, 1d, 35min\fR) or as a specific point
in time in either full RFC3339 format with time zone, or as a date or datetime in the
local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR).
in time as full RFC3339 format with time zone, as a date or datetime in the
local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR), or as the prefix '@'
followed by the number of seconds since the Unix epoch (@[0-9]+).
\fB\-\-change-newer-than\fR,
.B --newer
or
@@ -309,13 +370,15 @@ Examples:
\-\-changed-within 2weeks
\-\-change-newer-than "2018-10-27 10:00:00"
\-\-newer 2018-10-27
\-\-changed-after @1704067200
.TP
.BI "\-\-changed-before " date|duration
Filter results based on the file modification time.
Files with modification times less than the argument will be returned.
Files with modification timestamps less than the argument will be returned.
The argument can be provided as a duration (\fI10h, 1d, 35min\fR) or as a specific point
in time in either full RFC3339 format with time zone, or as a date or datetime in the
local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR).
in time as full RFC3339 format with time zone, as a date or datetime in the
local time zone (\fIYYYY-MM-DD\fR or \fIYYYY-MM-DD HH:MM:SS\fR), or as the prefix '@'
followed by the number of seconds since the Unix epoch (@[0-9]+).
.B --change-older-than
or
.B --older
@@ -324,6 +387,7 @@ can be used as aliases.
Examples:
\-\-changed-before "2018-10-27 10:00:00"
\-\-change-older-than 2weeks
\-\-older @1704067200
.TP
.BI "-o, \-\-owner " [user][:group]
Filter files by their user and/or group. Format: [(user|uid)][:(group|gid)]. Either side
@@ -334,7 +398,7 @@ Examples:
\-\-owner :students
\-\-owner "!john:students"
.TP
.BI "\-\-base\-directory " path
.BI "-C, \-\-base\-directory " path
Change the current working directory of fd to the provided path. This means that search results will
be shown with respect to the given base path. Note that relative paths which are passed to fd via the
positional \fIpath\fR argument or the \fB\-\-search\-path\fR option will also be resolved relative to
@@ -348,6 +412,30 @@ Set the path separator to use when printing file paths. The default is the OS-sp
Provide paths to search as an alternative to the positional \fIpath\fR argument. Changes the usage to
\'fd [FLAGS/OPTIONS] \-\-search\-path PATH \-\-search\-path PATH2 [PATTERN]\'
.TP
.BI "\-\-format " fmt
Specify a template string that is used for printing a line for each file found.
The following placeholders are substituted into the string for each file before printing:
.RS
.IP {}
path (of the current search result)
.IP {/}
basename
.IP {//}
parent directory
.IP {.}
path without file extension
.IP {/.}
basename without file extension
.IP {{
literal '{' (an escape sequence)
.IP }}
literal '}' (an escape sequence)
.P
Notice that you can use "{{" and "}}" to escape "{" and "}" respectively, which is especially
useful if you need to include the literal text of one of the above placeholders.
.RE
.TP
.BI "\-x, \-\-exec " command
.RS
Execute
@@ -364,22 +452,19 @@ This option can be specified multiple times, in which case all commands are run
file found, in the order they are provided. In that case, you must supply a ';' argument for
all but the last commands.
The following placeholders are substituted before the command is executed:
.RS
.IP {}
path (of the current search result)
.IP {/}
basename
.IP {//}
parent directory
.IP {.}
path without file extension
.IP {/.}
basename without file extension
.RE
If parallelism is enabled, the order commands will be executed in is non-deterministic. And even with
--threads=1, the order is determined by the operating system and may not be what you expect. Thus, it is
recommended that you don't rely on any ordering of the results.
Before executing the command, any placeholder patterns in the command are replaced with the
corresponding values for the current file. The same placeholders are used as in the "\-\-format"
option.
If no placeholder is present, an implicit "{}" at the end is assumed.
If --print0 is also given, then a null character (\\0) will be printed between the output for each found entry.
This allows another program to easily distinguish the output for each file if the command(s) produce multiple lines.
Examples:
- find all *.zip files and unzip them:
@@ -393,6 +478,10 @@ Examples:
- Convert all *.jpg files to *.png files:
fd -e jpg -x convert {} {.}.png
- Run stat for each *.txt file, separated by null characters
fd -0 -e txt -x stat
.RE
.TP
.BI "\-X, \-\-exec-batch " command
@@ -400,22 +489,19 @@ Examples:
Execute
.I command
once, with all search results as arguments.
One of the following placeholders is substituted before the command is executed:
.RS
.IP {}
path (of all search results)
.IP {/}
basename
.IP {//}
parent directory
.IP {.}
path without file extension
.IP {/.}
basename without file extension
.RE
The order of the arguments is non-deterministic and should not be relied upon.
This uses the same placeholders as "\-\-format" and "\-\-exec", but instead of expanding
once per command invocation each argument containing a placeholder is expanding for every
file in a batch and passed as separate arguments.
If no placeholder is present, an implicit "{}" at the end is assumed.
Like \-\-exec, subsequent arguments are assumed to be part of
.I command
until either the end of command arguments or a ';' argument. See above.
Like \-\-exec, this can be used multiple times, in which case each command will be run in
the order given.
@@ -461,6 +547,17 @@ is set, use
.IR $XDG_CONFIG_HOME/fd/ignore .
Otherwise, use
.IR $HOME/.config/fd/ignore .
.SH FILES
.TP
.B .fdignore
This file works similarly to a .gitignore file anywhere in the searched tree and specifies patterns
that should be excluded from the search. However, this file is specific to fd, and will be used even
if the --no-ignore-vcs option is used.
.TP
.B $XDG_CONFIG_HOME/fd/ignore
Global ignore file. Unless ignore mode is turned off (such as with --no-ignore)
ignore entries in this file will be ignored, as if it was an .fdignore file in the
current directory.
.SH EXAMPLES
.TP
.RI "Find files and directories that match the pattern '" needle "':"
@@ -474,6 +571,16 @@ $ fd -e py
.TP
.RI "Open all search results with vim:"
$ fd pattern -X vim
.SH Tips and Tricks
.IP \[bu]
If you add ".git/" to your global ignore file ($XDG_CONFIG_HOME/fd/ignore), then
".git" folders will be ignored by default, even when the --hidden option is used.
.IP \[bu]
You can use a shell alias or a wrapper script in order to pass desired flags to fd
by default. For example if you do not like the default behavior of respecting gitignore,
you can use
`alias fd="/usr/bin/fd --no-ignore-vcs"`
in your .bashrc to create an alias for fd that doesn't ignore git files by default.
.SH BUGS
Bugs can be reported on GitHub: https://github.com/sharkdp/fd/issues
.SH SEE ALSO
+5 -2
View File
@@ -5,11 +5,14 @@ necessary changes for the upcoming release.
## Version bump
This section can be done by running `scripts/version-bump.sh` with the new version
as an argument.
- [ ] Create a new branch for the required changes for this release.
- [ ] Update version in `Cargo.toml`. Run `cargo build` to update `Cargo.lock`.
Make sure to `git add` the `Cargo.lock` changes as well.
- [ ] Find the current min. supported Rust version by running
`grep '^\s*MIN_SUPPORTED_RUST_VERSION' .github/workflows/CICD.yml`.
`grep rust-version Cargo.toml`.
- [ ] Update the `fd` version and the min. supported Rust version in `README.md`.
- [ ] Update `CHANGELOG.md`. Change the heading of the *"Upcoming release"* section
to the version of this release.
@@ -21,7 +24,7 @@ necessary changes for the upcoming release.
new version).
- [ ] Review `-h`, `--help`, and the `man` page.
- [ ] Run `fd -h` and copy the output to the *"Command-line options"* section in
the README
the README. This can be done by running `gawk -i inplace -f scripts/update-help.awk README.md`.
- [ ] Push all changes and wait for CI to succeed (before continuing with the
next section).
- [ ] Optional: manually test the new features and command-line options described
+12
View File
@@ -0,0 +1,12 @@
## Sponsors
`fd` development is sponsored by many individuals and companies. Thank you very much!
Please note, that being sponsored does not affect the individuality of the `fd`
project or affect the maintainers' actions in any way.
We remain impartial and continue to assess pull requests solely on merit - the
features added, bugs solved, and effect on the overall complexity of the code.
No issue will have a different priority based on sponsorship status of the
reporter.
Contributions from anybody are most welcomed, please see our [`CONTRIBUTING.md`](../CONTRIBUTING.md) guide.
+67
View File
@@ -0,0 +1,67 @@
#!/bin/bash
#
# Create a .tar.gz archive of the fd project for distribution
#
# Expected environment variables:
#
# TARGET: rust target to publish. Defaults to default rustc target
# BIN_PATH: path to fd binary
# PKG_STAGING: directory to use for staging files to include in the archive
# ARCHIVE_NAME: Name of output file, minus extension, defaults to "fd" with a version appended
# if VERSION is specified
# VERSION: version to publish
# GITHUB_OUTPUT: file to store github output variables in
if [[ -z "$TARGET" ]]; then
TARGET="$(rustc -vV | sed -n 's/host: //p')"
fi
PKG_suffix=".tar.gz"
EXE_suffix=""
case ${TARGET} in
*-pc-windows-*)
PKG_suffix=".zip"
EXE_suffix=".exe"
;;
esac
if [[ -z $BIN_PATH ]]; then
BIN_PATH=target/${PROFILE:-release}/fd
fi
if [[ -z "$ARCHIVE_NAME" ]]; then
ARCHIVE_NAME=fd
[[ -n "$VERSION" ]] && ARCHIVE_NAME+="-v$VERSION"
fi
PKG_NAME=${ARCHIVE_NAME}${PKG_suffix}
staging_dir="${PKG_STAGING:-package}"
ARCHIVE_DIR="${staging_dir}/${ARCHIVE_NAME}/"
mkdir -p "${ARCHIVE_DIR}"
# Binary
cp "${BIN_PATH}" "$ARCHIVE_DIR"
# README, LICENSE and CHANGELOG files
cp "README.md" "LICENSE-MIT" "LICENSE-APACHE" "CHANGELOG.md" "$ARCHIVE_DIR"
# Man page
cp "doc/fd.1" "$ARCHIVE_DIR"
# Autocompletion files
cp -r autocomplete "${ARCHIVE_DIR}"
# base compressed package
pushd "${staging_dir}/" >/dev/null
case ${TARGET} in
*-pc-windows-*) 7z -y a "${PKG_NAME}" "${ARCHIVE_NAME}"/* | tail -2 ;;
*) tar czf "${PKG_NAME}" "${ARCHIVE_NAME}"/* ;;
esac;
popd >/dev/null
if [[ -n "$GITHUB_OUTPUT" ]]; then
echo "PKG_NAME=${PKG_NAME}" >> $GITHUB_OUTPUT
# Let subsequent steps know where to find the compressed package
echo "PKG_PATH=${PKG_STAGING}/${PKG_NAME}" >> $GITHUB_OUTPUT
fi
+135
View File
@@ -0,0 +1,135 @@
#!/bin/bash
COPYRIGHT_YEARS="2018 - "$(date "+%Y")
MAINTAINER="David Peter <mail@david-peter.de>"
REPO="https://github.com/sharkdp/fd"
DPKG_STAGING="${CICD_INTERMEDIATES_DIR:-.}/debian-package"
DPKG_DIR="${DPKG_STAGING}/dpkg"
mkdir -p "${DPKG_DIR}"
if [[ -z "$TARGET" ]]; then
TARGET="$(rustc -vV | sed -n 's|host: \(.*\)|\1|p')"
fi
case "$TARGET" in
*-musl*)
DPKG_BASENAME=fd-musl
DPKG_CONFLICTS="fd, fd-find"
;;
*)
DPKG_BASENAME=fd
DPKG_CONFLICTS="fd-musl, fd-find"
;;
esac
if [[ -z "$DPKG_VERSION" ]]; then
DPKG_VERSION=$(cargo metadata --no-deps --format-version 1 | jq -r .packages[0].version)
fi
unset DPKG_ARCH
case "${TARGET}" in
aarch64-*-linux-*) DPKG_ARCH=arm64 ;;
arm-*-linux-*hf) DPKG_ARCH=armhf ;;
i686-*-linux-*) DPKG_ARCH=i686 ;;
x86_64-*-linux-*) DPKG_ARCH=amd64 ;;
*) DPKG_ARCH=notset ;;
esac;
DPKG_NAME="${DPKG_BASENAME}_${DPKG_VERSION}_${DPKG_ARCH}.deb"
BIN_PATH=${BIN_PATH:-target/${TARGET}/release/fd}
# Binary
install -Dm755 "${BIN_PATH}" "${DPKG_DIR}/usr/bin/fd"
# Man page
install -Dm644 'doc/fd.1' "${DPKG_DIR}/usr/share/man/man1/fd.1"
gzip -n --best "${DPKG_DIR}/usr/share/man/man1/fd.1"
# Autocompletion files
install -Dm644 'autocomplete/fd.bash' "${DPKG_DIR}/usr/share/bash-completion/completions/fd"
install -Dm644 'autocomplete/fd.fish' "${DPKG_DIR}/usr/share/fish/vendor_completions.d/fd.fish"
install -Dm644 'autocomplete/_fd' "${DPKG_DIR}/usr/share/zsh/vendor-completions/_fd"
# README and LICENSE
install -Dm644 "README.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/README.md"
install -Dm644 "LICENSE-MIT" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-MIT"
install -Dm644 "LICENSE-APACHE" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/LICENSE-APACHE"
install -Dm644 "CHANGELOG.md" "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/changelog"
gzip -n --best "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/changelog"
# Create symlink and completions so fdfind can be used as well:
ln -s "/usr/bin/fd" "${DPKG_DIR}/usr/bin/fdfind"
install -Dm644 'autocomplete/fdfind.bash' "${DPKG_DIR}/usr/share/bash-completion/completions/fdfind"
install -Dm644 'autocomplete/fdfind.fish' "${DPKG_DIR}/usr/share/fish/vendor_completions.d/fdfind.fish"
install -Dm644 'autocomplete/_fdfind' "${DPKG_DIR}/usr/share/zsh/vendor-completions/_fdfind"
cat > "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright" <<EOF
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: fd
Source: ${REPO}
Files: *
Copyright: ${MAINTAINER}
Copyright: $COPYRIGHT_YEARS ${MAINTAINER}
License: Apache-2.0 or MIT
License: Apache-2.0
On Debian systems, the complete text of the Apache-2.0 can be found in the
file /usr/share/common-licenses/Apache-2.0.
License: MIT
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
.
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
EOF
chmod 644 "${DPKG_DIR}/usr/share/doc/${DPKG_BASENAME}/copyright"
# control file
mkdir -p "${DPKG_DIR}/DEBIAN"
cat > "${DPKG_DIR}/DEBIAN/control" <<EOF
Package: ${DPKG_BASENAME}
Version: ${DPKG_VERSION}
Section: utils
Priority: optional
Maintainer: ${MAINTAINER}
Homepage: ${REPO}
Architecture: ${DPKG_ARCH}
Provides: fd
Conflicts: ${DPKG_CONFLICTS}
Description: simple, fast and user-friendly alternative to find
fd is a program to find entries in your filesystem.
It is a simple, fast and user-friendly alternative to find.
While it does not aim to support all of finds powerful functionality, it provides
sensible (opinionated) defaults for a majority of use cases.
EOF
DPKG_PATH="${DPKG_STAGING}/${DPKG_NAME}"
if [[ -n $GITHUB_OUTPUT ]]; then
echo "DPKG_NAME=${DPKG_NAME}" >> "$GITHUB_OUTPUT"
echo "DPKG_PATH=${DPKG_PATH}" >> "$GITHUB_OUTPUT"
fi
# build dpkg
fakeroot dpkg-deb --build "${DPKG_DIR}" "${DPKG_PATH}"
+41
View File
@@ -0,0 +1,41 @@
#!/usr/bin/gawk -f
BEGIN {
inSection = 0
inBlock = 0
}
/Command-line options/ { inSection=1 }
inSection && /^```/ {
inBlock=1
inSection=0
# print the starting fence then move to next line
print
next
}
inBlock && /^```/ {
cmd="cargo run --release --quiet -- -h"
# Output the results of fd -h
u=0
while (cmd | getline line) {
# Skip everything before the usage line
if (line ~ /^Usage/) {
u=1;
}
if (u) {
print line
}
}
status = close(cmd)
if (status) {
print "failed to generate help output" > "/dev/stderr"
exit 1
}
inBlock = 0
}
!inBlock
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/bash
set -eu
# This script automates the "Version bump" section
version="$1"
if [[ -z $version ]]; then
echo "Usage: must supply version as first argument" >&2
exit 1
fi
git switch -C "release-$version"
sed -i -e "0,/^\[badges/{s/^version =.*/version = \"$version\"/}" Cargo.toml
msrv="$(grep -F rust-version Cargo.toml | sed -e 's/^rust-version= "\(.*\)"/\1/')"
sed -i -e "s/Note that rust version \*[0-9.]+\* or later/Note that rust version *$msrv* or later/" README.md
sed -i -e "s/^# Upcoming release/# $version/" CHANGELOG.md
+157 -48
View File
@@ -1,10 +1,11 @@
use std::num::NonZeroUsize;
use std::path::{Path, PathBuf};
use std::time::Duration;
use anyhow::anyhow;
use clap::{
error::ErrorKind, value_parser, Arg, ArgAction, ArgGroup, ArgMatches, Command, Parser,
ValueEnum,
Arg, ArgAction, ArgGroup, ArgMatches, Command, Parser, ValueEnum, error::ErrorKind,
value_parser,
};
#[cfg(feature = "completions")]
use clap_complete::Shell;
@@ -21,7 +22,7 @@ use crate::filter::SizeFilter;
#[command(
name = "fd",
version,
about = "A program to find entries in your filesystem",
about = "A program to find entries in your filesystem with regex and glob based matching. By default, fd respects gitignore rules, ignores hidden directories, and is case insensitive.",
after_long_help = "Bugs can be reported on GitHub: https://github.com/sharkdp/fd/issues",
max_term_width = 98,
args_override_self = true,
@@ -32,6 +33,8 @@ pub struct Opts {
/// Include hidden directories and files in the search results (default:
/// hidden files and directories are skipped). Files and directories are
/// considered to be hidden if their name starts with a `.` sign (dot).
/// Any files or directories that are ignored due to the rules described by
/// --no-ignore are still ignored unless otherwise specified.
/// The flag can be overridden with --no-hidden.
#[arg(
long,
@@ -46,7 +49,7 @@ pub struct Opts {
no_hidden: (),
/// Show search results from files and directories that would otherwise be
/// ignored by '.gitignore', '.ignore', '.fdignore', or the global ignore file.
/// ignored by '.gitignore', '.ignore', '.fdignore', or the global ignore file,
/// The flag can be overridden with --ignore.
#[arg(
long,
@@ -60,8 +63,9 @@ pub struct Opts {
#[arg(long, overrides_with = "no_ignore", hide = true, action = ArgAction::SetTrue)]
ignore: (),
///Show search results from files and directories that would otherwise be
/// ignored by '.gitignore' files. The flag can be overridden with --ignore-vcs.
///Show search results from files and directories that
///would otherwise be ignored by '.gitignore' files.
///The flag can be overridden with --ignore-vcs.
#[arg(
long,
hide_short_help = true,
@@ -98,6 +102,7 @@ pub struct Opts {
/// Show search results from files and directories that would otherwise be
/// ignored by '.gitignore', '.ignore', or '.fdignore' files in parent directories.
/// The flag can be overridden with --ignore-parent.
#[arg(
long,
hide_short_help = true,
@@ -106,6 +111,10 @@ pub struct Opts {
)]
pub no_ignore_parent: bool,
/// Overrides --no-ignore-parent
#[arg(long, overrides_with = "no_ignore_parent", hide = true, action = ArgAction::SetTrue)]
ignore_parent: (),
/// Do not respect the global ignore file
#[arg(long, hide = true)]
pub no_global_ignore_file: bool,
@@ -164,17 +173,30 @@ pub struct Opts {
/// Treat the pattern as a literal string instead of a regular expression. Note
/// that this also performs substring comparison. If you want to match on an
/// exact filename, consider using '--glob'.
/// exact filename, consider using '--glob' or '--exact' instead.
#[arg(
long,
short = 'F',
alias = "literal",
hide_short_help = true,
help = "Treat pattern as literal string stead of regex",
help = "Treat pattern as literal string instead of regex",
long_help
)]
pub fixed_strings: bool,
/// Perform an exact match. This is equivalent to '--fixed-strings' but requires
/// the pattern to match the entire filename (or path if '--full-path' is used),
/// rather than a substring. Special regex characters in the pattern are treated
/// as literal characters.
#[arg(
long,
conflicts_with_all(["glob", "fixed_strings"]),
hide_short_help = true,
help = "Match the entire filename exactly (literal, non-substring)",
long_help
)]
pub exact: bool,
/// Add additional required search patterns, all of which must be matched. Multiple
/// additional patterns can be specified. The patterns are regular
/// expressions, unless '--glob' or '--fixed-strings' is used.
@@ -222,7 +244,7 @@ pub struct Opts {
alias = "dereference",
long_help = "By default, fd does not descend into symlinked directories. Using this \
flag, symbolic links are also traversed. \
Flag can be overriden with --no-follow."
Flag can be overridden with --no-follow."
)]
pub follow: bool,
@@ -271,6 +293,7 @@ pub struct Opts {
long,
value_name = "depth",
hide_short_help = true,
alias("mindepth"),
help = "Only show search results starting at the given depth.",
long_help
)]
@@ -294,7 +317,7 @@ pub struct Opts {
#[arg(
long,
short = 'E',
value_name = "pattern",
value_name = "glob",
help = "Exclude entries that match the given glob pattern",
long_help
)]
@@ -309,10 +332,12 @@ pub struct Opts {
/// Filter the search by type:
/// {n} 'f' or 'file': regular files
/// {n} 'd' or 'directory': directories
/// {n} 'd' or 'dir' or 'directory': directories
/// {n} 'l' or 'symlink': symbolic links
/// {n} 's' or 'socket': socket
/// {n} 'p' or 'pipe': named pipe (FIFO)
/// {n} 'b' or 'block-device': block device
/// {n} 'c' or 'char-device': character device
/// {n}{n} 'x' or 'executable': executables
/// {n} 'e' or 'empty': empty files or directories
///
@@ -345,14 +370,16 @@ pub struct Opts {
value_name = "filetype",
hide_possible_values = true,
value_enum,
help = "Filter by type: file (f), directory (d), symlink (l), \
executable (x), empty (e), socket (s), pipe (p)",
help = "Filter by type: file (f), directory (d/dir), symlink (l), \
executable (x), empty (e), socket (s), pipe (p), \
char-device (c), block-device (b)",
long_help
)]
pub filetype: Option<Vec<FileType>>,
/// (Additionally) filter search results by their file extension. Multiple
/// allowable file extensions can be specified.
/// Filter results by extension. By default, this matches all entry types
/// (including directories whose names end with the extension). Use `--type`
/// to restrict the search to specific types. Multiple extensions can be specified.
///
/// If you want to search for files without extension,
/// you can use the regex '^[^.]+$' as a normal search pattern.
@@ -360,7 +387,7 @@ pub struct Opts {
long = "extension",
short = 'e',
value_name = "ext",
help = "Filter by file extension",
help = "Filter by extension",
long_help
)]
pub extensions: Option<Vec<String>>,
@@ -391,7 +418,7 @@ pub struct Opts {
/// Filter results based on the file modification time. Files with modification times
/// greater than the argument are returned. The argument can be provided
/// as a specific point in time (YYYY-MM-DD HH:MM:SS) or as a duration (10h, 1d, 35min).
/// as a specific point in time (YYYY-MM-DD HH:MM:SS or @timestamp) or as a duration (10h, 1d, 35min).
/// If the time is not specified, it defaults to 00:00:00.
/// '--change-newer-than', '--newer', or '--changed-after' can be used as aliases.
///
@@ -413,7 +440,7 @@ pub struct Opts {
/// Filter results based on the file modification time. Files with modification times
/// less than the argument are returned. The argument can be provided
/// as a specific point in time (YYYY-MM-DD HH:MM:SS) or as a duration (10h, 1d, 35min).
/// as a specific point in time (YYYY-MM-DD HH:MM:SS or @timestamp) or as a duration (10h, 1d, 35min).
/// '--change-older-than' or '--older' can be used as aliases.
///
/// Examples:
@@ -445,6 +472,20 @@ pub struct Opts {
)]
pub owner: Option<OwnerFilter>,
/// Instead of printing the file normally, print the format string with the following placeholders replaced:
/// '{}': path (of the current search result)
/// '{/}': basename
/// '{//}': parent directory
/// '{.}': path without file extension
/// '{/.}': basename without file extension
#[arg(
long,
value_name = "fmt",
help = "Print results according to template",
conflicts_with = "list_details"
)]
pub format: Option<String>,
#[command(flatten)]
pub exec: Exec,
@@ -488,10 +529,32 @@ pub struct Opts {
)]
pub color: ColorWhen,
/// Add a terminal hyperlink to a file:// url for each path in the output.
///
/// Auto mode is used if no argument is given to this option.
///
/// This doesn't do anything for --exec and --exec-batch.
#[arg(
long,
alias = "hyper",
value_name = "when",
require_equals = true,
value_enum,
default_value_t = HyperlinkWhen::Never,
default_missing_value = "auto",
num_args = 0..=1,
help = "Add hyperlinks to output paths"
)]
pub hyperlink: HyperlinkWhen,
/// Ignore directories containing the named entry.
#[arg(long, value_name = "name")]
pub ignore_contain: Vec<String>,
/// Set number of threads to use for searching & executing (default: number
/// of available CPU cores)
#[arg(long, short = 'j', value_name = "num", hide_short_help = true, value_parser = clap::value_parser!(u32).range(1..))]
pub threads: Option<u32>,
#[arg(long, short = 'j', value_name = "num", hide_short_help = true, value_parser = str::parse::<NonZeroUsize>)]
pub threads: Option<NonZeroUsize>,
/// Milliseconds to buffer before streaming search results to console
///
@@ -554,6 +617,7 @@ pub struct Opts {
/// relative to this directory.
#[arg(
long,
short = 'C',
value_name = "path",
hide_short_help = true,
help = "Change current working directory",
@@ -610,9 +674,10 @@ pub struct Opts {
/// By default, relative paths are prefixed with './' when -x/--exec,
/// -X/--exec-batch, or -0/--print0 are given, to reduce the risk of a
/// path starting with '-' being treated as a command line option. Use
/// this flag to disable this behaviour.
#[arg(long, conflicts_with_all(&["path", "search_path"]), hide_short_help = true, long_help)]
pub strip_cwd_prefix: bool,
/// this flag to change this behavior. If this flag is used without a value,
/// it is equivalent to passing "always".
#[arg(long, conflicts_with_all(&["path", "search_path"]), value_name = "when", hide_short_help = true, require_equals = true, long_help)]
strip_cwd_prefix: Option<Option<StripCwdWhen>>,
/// By default, fd will traverse the file system tree as far as other options
/// dictate. With this flag, fd ensures that it does not descend into a
@@ -635,7 +700,7 @@ impl Opts {
} else if !self.search_path.is_empty() {
&self.search_path
} else {
let current_directory = Path::new(".");
let current_directory = Path::new("./");
ensure_current_directory_exists(current_directory)?;
return Ok(vec![self.normalize_path(current_directory)]);
};
@@ -658,6 +723,13 @@ impl Opts {
fn normalize_path(&self, path: &Path) -> PathBuf {
if self.absolute_path {
filesystem::absolute_path(path.normalize().unwrap().as_path()).unwrap()
} else if path == Path::new(".") {
// Change "." to "./" as a workaround for https://github.com/BurntSushi/ripgrep/pull/2711
PathBuf::from("./")
} else if path == Path::new("-") {
// Prefix "-" so the underlying walker treats it as a path.
// See sharkdp/fd#849.
Path::new(".").join(path)
} else {
path.to_path_buf()
}
@@ -680,17 +752,8 @@ impl Opts {
self.min_depth.or(self.exact_depth)
}
pub fn threads(&self) -> usize {
// This will panic if the number of threads passed in is more than usize::MAX in an environment
// where usize is less than 32 bits (for example 16-bit architectures). It's pretty
// unlikely fd will be running in such an environment, and even more unlikely someone would
// be trying to use that many threads on such an environment, so I think panicing is an
// appropriate way to handle that.
std::cmp::max(
self.threads
.map_or_else(num_cpus::get, |n| n.try_into().expect("too many threads")),
1,
)
pub fn threads(&self) -> NonZeroUsize {
self.threads.unwrap_or_else(default_num_threads)
}
pub fn max_results(&self) -> Option<usize> {
@@ -699,6 +762,16 @@ impl Opts {
.or_else(|| self.max_one_result.then_some(1))
}
pub fn strip_cwd_prefix<P: FnOnce() -> bool>(&self, auto_pred: P) -> bool {
use self::StripCwdWhen::*;
self.no_search_paths()
&& match self.strip_cwd_prefix.map_or(Auto, |o| o.unwrap_or(Always)) {
Auto => auto_pred(),
Always => true,
Never => false,
}
}
#[cfg(feature = "completions")]
pub fn gen_completions(&self) -> anyhow::Result<Option<Shell>> {
self.gen_completions
@@ -712,14 +785,32 @@ impl Opts {
}
}
/// Get the default number of threads to use, if not explicitly specified.
fn default_num_threads() -> NonZeroUsize {
// If we can't get the amount of parallelism for some reason, then
// default to a single thread, because that is safe.
let fallback = NonZeroUsize::MIN;
// To limit startup overhead on massively parallel machines, don't use more
// than 64 threads.
let limit = NonZeroUsize::new(64).unwrap();
std::thread::available_parallelism()
.unwrap_or(fallback)
.min(limit)
}
#[derive(Copy, Clone, PartialEq, Eq, ValueEnum)]
pub enum FileType {
#[value(alias = "f")]
File,
#[value(alias = "d")]
#[value(alias = "d", alias = "dir")]
Directory,
#[value(alias = "l")]
Symlink,
#[value(alias = "b")]
BlockDevice,
#[value(alias = "c")]
CharDevice,
/// A file which is executable by the current effective user
#[value(alias = "x")]
Executable,
@@ -741,15 +832,24 @@ pub enum ColorWhen {
Never,
}
impl ColorWhen {
pub fn as_str(&self) -> &'static str {
use ColorWhen::*;
match *self {
Auto => "auto",
Never => "never",
Always => "always",
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, ValueEnum)]
pub enum StripCwdWhen {
/// Use the default behavior
Auto,
/// Always strip the ./ at the beginning of paths
Always,
/// Never strip the ./
Never,
}
#[derive(Copy, Clone, PartialEq, Eq, Debug, ValueEnum)]
pub enum HyperlinkWhen {
/// Use hyperlinks only if color is enabled
Auto,
/// Always use hyperlinks when printing file paths
Always,
/// Never use hyperlinks
Never,
}
// there isn't a derive api for getting grouped values yet,
@@ -793,20 +893,26 @@ impl clap::Args for Exec {
.help("Execute a command for each search result")
.long_help(
"Execute a command for each search result in parallel (use --threads=1 for sequential command execution). \
There is no guarantee of the order commands are executed in, and the order should not be depended upon. \
All positional arguments following --exec are considered to be arguments to the command - not to fd. \
It is therefore recommended to place the '-x'/'--exec' option last.\n\
It is therefore recommended to place the '-x'/'--exec' option last. \
Use '\\;' to terminate the command template if you need to continue passing fd arguments afterwards.\n\
The following placeholders are substituted before the command is executed:\n \
'{}': path (of the current search result)\n \
'{/}': basename\n \
'{//}': parent directory\n \
'{.}': path without file extension\n \
'{/.}': basename without file extension\n\n\
'{/.}': basename without file extension\n \
'{{': literal '{' (for escaping)\n \
'}}': literal '}' (for escaping)\n\n\
If no placeholder is present, an implicit \"{}\" at the end is assumed.\n\n\
Examples:\n\n \
- find all *.zip files and unzip them:\n\n \
fd -e zip -x unzip\n\n \
- find *.h and *.cpp files and run \"clang-format -i ..\" for each of them:\n\n \
fd -e h -e cpp -x clang-format -i\n\n \
- search within `src/` and echo each match (place `-x` last):\n\n \
fd . src -x echo\n\n \
- Convert all *.jpg files to *.png files:\n\n \
fd -e jpg -x convert {} {.}.png\
",
@@ -825,12 +931,15 @@ impl clap::Args for Exec {
.help("Execute a command with all search results at once")
.long_help(
"Execute the given command once, with all search results as arguments.\n\
The order of the arguments is non-deterministic, and should not be relied upon.\n\
One of the following placeholders is substituted before the command is executed:\n \
'{}': path (of all search results)\n \
'{/}': basename\n \
'{//}': parent directory\n \
'{.}': path without file extension\n \
'{/.}': basename without file extension\n\n\
'{/.}': basename without file extension\n \
'{{': literal '{' (for escaping)\n \
'}}': literal '}' (for escaping)\n\n\
If no placeholder is present, an implicit \"{}\" at the end is assumed.\n\n\
Examples:\n\n \
- Find all test_*.py files and open them in your favorite editor:\n\n \
+14 -3
View File
@@ -8,15 +8,16 @@ use crate::filetypes::FileTypes;
#[cfg(unix)]
use crate::filter::OwnerFilter;
use crate::filter::{SizeFilter, TimeFilter};
use crate::fmt::FormatTemplate;
/// Configuration options for *fd*.
pub struct Config {
/// Whether the search is case-sensitive or case-insensitive.
pub case_sensitive: bool,
/// Whether to search within the full file path or just the base name (filename or directory
/// name).
pub search_full_path: bool,
/// Cached current working directory for absolute path construction.
/// Populated when `--full-path` is set; `None` means search by filename only.
pub full_path_base: Option<PathBuf>,
/// Whether to ignore hidden files and directories (or not).
pub ignore_hidden: bool,
@@ -74,6 +75,7 @@ pub struct Config {
pub ls_colors: Option<LsColors>,
/// Whether or not we are writing to an interactive terminal
#[cfg_attr(not(unix), allow(unused))]
pub interactive_terminal: bool,
/// The type of file to search for. If set to `None`, all file types are displayed. If
@@ -85,6 +87,9 @@ pub struct Config {
/// The value (if present) will be a lowercase string without leading dots.
pub extensions: Option<RegexSet>,
/// A format string to use to format results, similarly to exec
pub format: Option<FormatTemplate>,
/// If a value is supplied, each item found will be used to generate and execute commands.
pub command: Option<Arc<CommandSet>>,
@@ -122,6 +127,12 @@ pub struct Config {
/// Whether or not to strip the './' prefix for search results
pub strip_cwd_prefix: bool,
/// Whether or not to use hyperlinks on paths
pub hyperlink: bool,
/// Names that should stop traversal down their parent. (e.g. https://bford.info/cachedir/).
pub ignore_contain: Vec<String>,
}
impl Config {
+40 -4
View File
@@ -8,11 +8,13 @@ use lscolors::{Colorable, LsColors, Style};
use crate::config::Config;
use crate::filesystem::strip_current_dir;
#[derive(Debug)]
enum DirEntryInner {
Normal(ignore::DirEntry),
BrokenSymlink(PathBuf),
}
#[derive(Debug)]
pub struct DirEntry {
inner: DirEntryInner,
metadata: OnceCell<Option<Metadata>>,
@@ -52,11 +54,19 @@ impl DirEntry {
}
/// Returns the path as it should be presented to the user.
/// When stripping `./` would leave the path starting with `-`, keep the original
/// (with `./`) so downstream tools don't interpret it as an option.
pub fn stripped_path(&self, config: &Config) -> &Path {
let path = self.path();
if config.strip_cwd_prefix {
strip_current_dir(self.path())
let stripped = strip_current_dir(path);
if starts_with_dash(stripped) {
path
} else {
stripped
}
} else {
self.path()
path
}
}
@@ -99,6 +109,10 @@ impl DirEntry {
}
}
fn starts_with_dash(path: &Path) -> bool {
path.as_os_str().as_encoded_bytes().first() == Some(&b'-')
}
impl PartialEq for DirEntry {
#[inline]
fn eq(&self, other: &Self) -> bool {
@@ -111,7 +125,7 @@ impl Eq for DirEntry {}
impl PartialOrd for DirEntry {
#[inline]
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
self.path().partial_cmp(other.path())
Some(self.cmp(other))
}
}
@@ -135,7 +149,7 @@ impl Colorable for DirEntry {
// but we want it for all component types, so we open code it.
// Copied from LsColors::style_for_path_with_metadata().
path.components()
.last()
.next_back()
.map(|c| c.as_os_str())
.unwrap_or_else(|| path.as_os_str())
}
@@ -151,3 +165,25 @@ impl Colorable for DirEntry {
self.metadata().cloned()
}
}
#[cfg(test)]
mod tests {
use super::starts_with_dash;
use std::path::Path;
#[test]
fn dash_prefixed_paths_detected() {
assert!(starts_with_dash(Path::new("-rf")));
assert!(starts_with_dash(Path::new("--delete")));
assert!(starts_with_dash(Path::new("-")));
}
#[test]
fn safe_paths_not_flagged() {
assert!(!starts_with_dash(Path::new("foo")));
assert!(!starts_with_dash(Path::new("./foo")));
assert!(!starts_with_dash(Path::new("sub/-rf")));
assert!(!starts_with_dash(Path::new("")));
assert!(!starts_with_dash(Path::new(" -rf")));
}
}
+7 -1
View File
@@ -1,3 +1,9 @@
use std::io::IsTerminal;
use crate::sanitize::maybe_sanitize;
pub fn print_error(msg: impl Into<String>) {
eprintln!("[fd error]: {}", msg.into());
let msg = msg.into();
let safe = maybe_sanitize(&msg, std::io::stderr().is_terminal());
eprintln!("[fd error]: {safe}");
}
+19 -14
View File
@@ -1,6 +1,5 @@
use std::io;
use std::io::Write;
use std::sync::Mutex;
use argmax::Command;
@@ -11,15 +10,15 @@ struct Outputs {
stdout: Vec<u8>,
stderr: Vec<u8>,
}
struct OutputBuffer<'a> {
output_permission: &'a Mutex<()>,
pub struct OutputBuffer {
null_separator: bool,
outputs: Vec<Outputs>,
}
impl<'a> OutputBuffer<'a> {
fn new(output_permission: &'a Mutex<()>) -> Self {
impl OutputBuffer {
pub fn new(null_separator: bool) -> Self {
Self {
output_permission,
null_separator,
outputs: Vec::new(),
}
}
@@ -29,17 +28,19 @@ impl<'a> OutputBuffer<'a> {
}
fn write(self) {
// avoid taking the lock if there is nothing to do
if self.outputs.is_empty() {
// Avoid taking the lock if there is nothing to do.
// If null_separator is true, then we still need to write the
// null separator, because the output may have been written directly
// to stdout
if self.outputs.is_empty() && !self.null_separator {
return;
}
// While this lock is active, this thread will be the only thread allowed
// to write its outputs.
let _lock = self.output_permission.lock().unwrap();
let stdout = io::stdout();
let stderr = io::stderr();
// While we hold these locks, only this thread will be able
// to write its outputs.
let mut stdout = stdout.lock();
let mut stderr = stderr.lock();
@@ -47,16 +48,20 @@ impl<'a> OutputBuffer<'a> {
let _ = stdout.write_all(&output.stdout);
let _ = stderr.write_all(&output.stderr);
}
if self.null_separator {
// If null_separator is enabled, then we should write a \0 at the end
// of the output for this entry
let _ = stdout.write_all(b"\0");
}
}
}
/// Executes a command.
pub fn execute_commands<I: Iterator<Item = io::Result<Command>>>(
cmds: I,
out_perm: &Mutex<()>,
mut output_buffer: OutputBuffer,
enable_output_buffering: bool,
) -> ExitCode {
let mut output_buffer = OutputBuffer::new(out_perm);
for result in cmds {
let mut cmd = match result {
Ok(cmd) => cmd,
@@ -103,7 +108,7 @@ pub fn handle_cmd_error(cmd: Option<&Command>, err: io::Error) -> ExitCode {
ExitCode::GeneralError
}
(_, err) => {
print_error(format!("Problem while executing command: {}", err));
print_error(format!("Problem while executing command: {err}"));
ExitCode::GeneralError
}
}
+18 -20
View File
@@ -1,11 +1,6 @@
use std::sync::Mutex;
use crossbeam_channel::Receiver;
use crate::config::Config;
use crate::dir_entry::DirEntry;
use crate::error::print_error;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::exit_codes::{ExitCode, merge_exitcodes};
use crate::walk::WorkerResult;
use super::CommandSet;
@@ -14,43 +9,46 @@ use super::CommandSet;
/// generate a command with the supplied command template. The generated command will then
/// be executed, and this process will continue until the receiver's sender has closed.
pub fn job(
rx: Receiver<WorkerResult>,
results: impl IntoIterator<Item = WorkerResult>,
cmd: &CommandSet,
out_perm: &Mutex<()>,
config: &Config,
) -> ExitCode {
// Output should be buffered when only running a single thread
let buffer_output: bool = config.threads > 1;
let mut results: Vec<ExitCode> = Vec::new();
loop {
let mut ret = ExitCode::Success;
for result in results {
// Obtain the next result from the receiver, else if the channel
// has closed, exit from the loop
let dir_entry: DirEntry = match rx.recv() {
Ok(WorkerResult::Entry(dir_entry)) => dir_entry,
Ok(WorkerResult::Error(err)) => {
let dir_entry = match result {
WorkerResult::Entry(dir_entry) => dir_entry,
WorkerResult::Error(err) => {
if config.show_filesystem_errors {
print_error(err.to_string());
}
continue;
}
Err(_) => break,
};
// Generate a command, execute it and store its exit code.
results.push(cmd.execute(
let code = cmd.execute(
dir_entry.stripped_path(config),
config.path_separator.as_deref(),
out_perm,
config.null_separator,
buffer_output,
))
);
ret = merge_exitcodes([ret, code]);
}
// Returns error in case of any error.
merge_exitcodes(results)
ret
}
pub fn batch(rx: Receiver<WorkerResult>, cmd: &CommandSet, config: &Config) -> ExitCode {
let paths = rx
pub fn batch(
results: impl IntoIterator<Item = WorkerResult>,
cmd: &CommandSet,
config: &Config,
) -> ExitCode {
let paths = results
.into_iter()
.filter_map(|worker_result| match worker_result {
WorkerResult::Entry(dir_entry) => Some(dir_entry.into_stripped_path(config)),
+75 -186
View File
@@ -1,26 +1,21 @@
mod command;
mod input;
mod job;
mod token;
use std::borrow::Cow;
use std::ffi::{OsStr, OsString};
use std::ffi::OsString;
use std::io;
use std::iter;
use std::path::{Component, Path, PathBuf, Prefix};
use std::path::{Path, PathBuf};
use std::process::Stdio;
use std::sync::{Mutex, OnceLock};
use anyhow::{bail, Result};
use anyhow::{Result, bail};
use argmax::Command;
use regex::Regex;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::exec::command::OutputBuffer;
use crate::exit_codes::{ExitCode, merge_exitcodes};
use crate::fmt::{FormatTemplate, Token};
use self::command::{execute_commands, handle_cmd_error};
use self::input::{basename, dirname, remove_extension};
pub use self::job::{batch, job};
use self::token::Token;
/// Execution mode of the command
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -48,7 +43,7 @@ impl CommandSet {
mode: ExecutionMode::OneByOne,
commands: input
.into_iter()
.map(CommandTemplate::new)
.map(|args| CommandTemplate::new(args, ExecutionMode::OneByOne))
.collect::<Result<_>>()?,
})
}
@@ -64,13 +59,10 @@ impl CommandSet {
commands: input
.into_iter()
.map(|args| {
let cmd = CommandTemplate::new(args)?;
let cmd = CommandTemplate::new(args, ExecutionMode::Batch)?;
if cmd.number_of_tokens() > 1 {
bail!("Only one placeholder allowed for batch commands");
}
if cmd.args[0].has_tokens() {
bail!("First argument of exec-batch is expected to be a fixed executable");
}
Ok(cmd)
})
.collect::<Result<Vec<_>>>()?,
@@ -85,14 +77,14 @@ impl CommandSet {
&self,
input: &Path,
path_separator: Option<&str>,
out_perm: &Mutex<()>,
null_separator: bool,
buffer_output: bool,
) -> ExitCode {
let commands = self
.commands
.iter()
.map(|c| c.generate(input, path_separator));
execute_commands(commands, out_perm, buffer_output)
execute_commands(commands, OutputBuffer::new(null_separator), buffer_output)
}
pub fn execute_batch<I>(&self, paths: I, limit: usize, path_separator: Option<&str>) -> ExitCode
@@ -132,7 +124,7 @@ impl CommandSet {
#[derive(Debug)]
struct CommandBuilder {
pre_args: Vec<OsString>,
path_arg: ArgumentTemplate,
path_arg: FormatTemplate,
post_args: Vec<OsString>,
cmd: Command,
count: usize,
@@ -221,61 +213,24 @@ impl CommandBuilder {
/// `generate_and_execute()` method will be used to generate a command and execute it.
#[derive(Debug, Clone, PartialEq)]
struct CommandTemplate {
args: Vec<ArgumentTemplate>,
args: Vec<FormatTemplate>,
}
impl CommandTemplate {
fn new<I, S>(input: I) -> Result<CommandTemplate>
fn new<I, S>(input: I, mode: ExecutionMode) -> Result<CommandTemplate>
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
static PLACEHOLDER_PATTERN: OnceLock<Regex> = OnceLock::new();
let mut args = Vec::new();
let mut has_placeholder = false;
for arg in input {
let arg = arg.as_ref();
let mut tokens = Vec::new();
let mut start = 0;
let pattern =
PLACEHOLDER_PATTERN.get_or_init(|| Regex::new(r"\{(/?\.?|//)\}").unwrap());
for placeholder in pattern.find_iter(arg) {
// Leading text before the placeholder.
if placeholder.start() > start {
tokens.push(Token::Text(arg[start..placeholder.start()].to_owned()));
}
start = placeholder.end();
match placeholder.as_str() {
"{}" => tokens.push(Token::Placeholder),
"{.}" => tokens.push(Token::NoExt),
"{/}" => tokens.push(Token::Basename),
"{//}" => tokens.push(Token::Parent),
"{/.}" => tokens.push(Token::BasenameNoExt),
_ => unreachable!("Unhandled placeholder"),
}
has_placeholder = true;
}
// Without a placeholder, the argument is just fixed text.
if tokens.is_empty() {
args.push(ArgumentTemplate::Text(arg.to_owned()));
continue;
}
if start < arg.len() {
// Trailing text after last placeholder.
tokens.push(Token::Text(arg[start..].to_owned()));
}
args.push(ArgumentTemplate::Tokens(tokens));
let tmpl = FormatTemplate::parse(arg);
has_placeholder |= tmpl.has_tokens();
args.push(tmpl);
}
// We need to check that we have at least one argument, because if not
@@ -287,9 +242,14 @@ impl CommandTemplate {
bail!("No executable provided for --exec or --exec-batch");
}
// A placeholder as the executable is meaningful for `--exec` but never for `--exec-batch`.
if mode == ExecutionMode::Batch && args[0].has_tokens() {
bail!("First argument of --exec-batch must be a fixed executable, not a placeholder");
}
// If a placeholder token was not supplied, append one at the end of the command.
if !has_placeholder {
args.push(ArgumentTemplate::Tokens(vec![Token::Placeholder]));
args.push(FormatTemplate::Tokens(vec![Token::Placeholder]));
}
Ok(CommandTemplate { args })
@@ -312,115 +272,18 @@ impl CommandTemplate {
}
}
/// Represents a template for a single command argument.
///
/// The argument is either a collection of `Token`s including at least one placeholder variant, or
/// a fixed text.
#[derive(Clone, Debug, PartialEq)]
enum ArgumentTemplate {
Tokens(Vec<Token>),
Text(String),
}
impl ArgumentTemplate {
pub fn has_tokens(&self) -> bool {
matches!(self, ArgumentTemplate::Tokens(_))
}
/// Generate an argument from this template. If path_separator is Some, then it will replace
/// the path separator in all placeholder tokens. Text arguments and tokens are not affected by
/// path separator substitution.
pub fn generate(&self, path: impl AsRef<Path>, path_separator: Option<&str>) -> OsString {
use self::Token::*;
let path = path.as_ref();
match *self {
ArgumentTemplate::Tokens(ref tokens) => {
let mut s = OsString::new();
for token in tokens {
match *token {
Basename => s.push(Self::replace_separator(basename(path), path_separator)),
BasenameNoExt => s.push(Self::replace_separator(
&remove_extension(basename(path).as_ref()),
path_separator,
)),
NoExt => s.push(Self::replace_separator(
&remove_extension(path),
path_separator,
)),
Parent => s.push(Self::replace_separator(&dirname(path), path_separator)),
Placeholder => {
s.push(Self::replace_separator(path.as_ref(), path_separator))
}
Text(ref string) => s.push(string),
}
}
s
}
ArgumentTemplate::Text(ref text) => OsString::from(text),
}
}
/// Replace the path separator in the input with the custom separator string. If path_separator
/// is None, simply return a borrowed Cow<OsStr> of the input. Otherwise, the input is
/// interpreted as a Path and its components are iterated through and re-joined into a new
/// OsString.
fn replace_separator<'a>(path: &'a OsStr, path_separator: Option<&str>) -> Cow<'a, OsStr> {
// fast-path - no replacement necessary
if path_separator.is_none() {
return Cow::Borrowed(path);
}
let path_separator = path_separator.unwrap();
let mut out = OsString::with_capacity(path.len());
let mut components = Path::new(path).components().peekable();
while let Some(comp) = components.next() {
match comp {
// Absolute paths on Windows are tricky. A Prefix component is usually a drive
// letter or UNC path, and is usually followed by RootDir. There are also
// "verbatim" prefixes beginning with "\\?\" that skip normalization. We choose to
// ignore verbatim path prefixes here because they're very rare, might be
// impossible to reach here, and there's no good way to deal with them. If users
// are doing something advanced involving verbatim windows paths, they can do their
// own output filtering with a tool like sed.
Component::Prefix(prefix) => {
if let Prefix::UNC(server, share) = prefix.kind() {
// Prefix::UNC is a parsed version of '\\server\share'
out.push(path_separator);
out.push(path_separator);
out.push(server);
out.push(path_separator);
out.push(share);
} else {
// All other Windows prefix types are rendered as-is. This results in e.g. "C:" for
// drive letters. DeviceNS and Verbatim* prefixes won't have backslashes converted,
// but they're not returned by directories fd can search anyway so we don't worry
// about them.
out.push(comp.as_os_str());
}
}
// Root directory is always replaced with the custom separator.
Component::RootDir => out.push(path_separator),
// Everything else is joined normally, with a trailing separator if we're not last
_ => {
out.push(comp.as_os_str());
if components.peek().is_some() {
out.push(path_separator);
}
}
}
}
Cow::Owned(out)
}
}
#[cfg(test)]
mod tests {
use super::*;
fn generate_str(template: &CommandTemplate, input: &str) -> Vec<String> {
template
.args
.iter()
.map(|arg| arg.generate(input, None).into_string().unwrap())
.collect()
}
#[test]
fn tokens_with_placeholder() {
assert_eq!(
@@ -428,9 +291,9 @@ mod tests {
CommandSet {
commands: vec![CommandTemplate {
args: vec![
ArgumentTemplate::Text("echo".into()),
ArgumentTemplate::Text("${SHELL}:".into()),
ArgumentTemplate::Tokens(vec![Token::Placeholder]),
FormatTemplate::Text("echo".into()),
FormatTemplate::Text("${SHELL}:".into()),
FormatTemplate::Tokens(vec![Token::Placeholder]),
]
}],
mode: ExecutionMode::OneByOne,
@@ -445,8 +308,8 @@ mod tests {
CommandSet {
commands: vec![CommandTemplate {
args: vec![
ArgumentTemplate::Text("echo".into()),
ArgumentTemplate::Tokens(vec![Token::NoExt]),
FormatTemplate::Text("echo".into()),
FormatTemplate::Tokens(vec![Token::NoExt]),
],
}],
mode: ExecutionMode::OneByOne,
@@ -461,8 +324,8 @@ mod tests {
CommandSet {
commands: vec![CommandTemplate {
args: vec![
ArgumentTemplate::Text("echo".into()),
ArgumentTemplate::Tokens(vec![Token::Basename]),
FormatTemplate::Text("echo".into()),
FormatTemplate::Tokens(vec![Token::Basename]),
],
}],
mode: ExecutionMode::OneByOne,
@@ -477,8 +340,8 @@ mod tests {
CommandSet {
commands: vec![CommandTemplate {
args: vec![
ArgumentTemplate::Text("echo".into()),
ArgumentTemplate::Tokens(vec![Token::Parent]),
FormatTemplate::Text("echo".into()),
FormatTemplate::Tokens(vec![Token::Parent]),
],
}],
mode: ExecutionMode::OneByOne,
@@ -493,8 +356,8 @@ mod tests {
CommandSet {
commands: vec![CommandTemplate {
args: vec![
ArgumentTemplate::Text("echo".into()),
ArgumentTemplate::Tokens(vec![Token::BasenameNoExt]),
FormatTemplate::Text("echo".into()),
FormatTemplate::Tokens(vec![Token::BasenameNoExt]),
],
}],
mode: ExecutionMode::OneByOne,
@@ -502,6 +365,23 @@ mod tests {
);
}
#[test]
fn tokens_with_literal_braces() {
let template =
CommandTemplate::new(vec!["{{}}", "{{", "{.}}"], ExecutionMode::OneByOne).unwrap();
assert_eq!(
generate_str(&template, "foo"),
vec!["{}", "{", "{.}", "foo"]
);
}
#[test]
fn tokens_with_literal_braces_and_placeholder() {
let template =
CommandTemplate::new(vec!["echo", "{{{},end}"], ExecutionMode::OneByOne).unwrap();
assert_eq!(generate_str(&template, "foo"), vec!["echo", "{foo,end}"]);
}
#[test]
fn tokens_multiple() {
assert_eq!(
@@ -509,9 +389,9 @@ mod tests {
CommandSet {
commands: vec![CommandTemplate {
args: vec![
ArgumentTemplate::Text("cp".into()),
ArgumentTemplate::Tokens(vec![Token::Placeholder]),
ArgumentTemplate::Tokens(vec![
FormatTemplate::Text("cp".into()),
FormatTemplate::Tokens(vec![Token::Placeholder]),
FormatTemplate::Tokens(vec![
Token::BasenameNoExt,
Token::Text(".ext".into())
]),
@@ -529,8 +409,8 @@ mod tests {
CommandSet {
commands: vec![CommandTemplate {
args: vec![
ArgumentTemplate::Text("echo".into()),
ArgumentTemplate::Tokens(vec![Token::NoExt]),
FormatTemplate::Text("echo".into()),
FormatTemplate::Tokens(vec![Token::NoExt]),
],
}],
mode: ExecutionMode::Batch,
@@ -545,7 +425,9 @@ mod tests {
#[test]
fn template_no_args() {
assert!(CommandTemplate::new::<Vec<_>, &'static str>(vec![]).is_err());
assert!(
CommandTemplate::new::<Vec<_>, &'static str>(vec![], ExecutionMode::OneByOne).is_err()
);
}
#[test]
@@ -553,9 +435,16 @@ mod tests {
assert!(CommandSet::new(vec![vec!["echo"], vec![]]).is_err());
}
#[test]
fn placeholder_as_executable_rejected() {
assert!(CommandSet::new(vec![vec!["{}"]]).is_ok());
assert!(CommandSet::new(vec![vec!["{/}", "arg"]]).is_ok());
assert!(CommandSet::new_batch(vec![vec!["{}"]]).is_err());
}
#[test]
fn generate_custom_path_separator() {
let arg = ArgumentTemplate::Tokens(vec![Token::Placeholder]);
let arg = FormatTemplate::Tokens(vec![Token::Placeholder]);
macro_rules! check {
($input:expr, $expected:expr) => {
assert_eq!(arg.generate($input, Some("#")), OsString::from($expected));
@@ -570,7 +459,7 @@ mod tests {
#[cfg(windows)]
#[test]
fn generate_custom_path_separator_windows() {
let arg = ArgumentTemplate::Tokens(vec![Token::Placeholder]);
let arg = FormatTemplate::Tokens(vec![Token::Placeholder]);
macro_rules! check {
($input:expr, $expected:expr) => {
assert_eq!(arg.generate($input, Some("#")), OsString::from($expected));
-29
View File
@@ -1,29 +0,0 @@
use std::fmt::{self, Display, Formatter};
/// Designates what should be written to a buffer
///
/// Each `Token` contains either text, or a placeholder variant, which will be used to generate
/// commands after all tokens for a given command template have been collected.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Token {
Placeholder,
Basename,
Parent,
NoExt,
BasenameNoExt,
Text(String),
}
impl Display for Token {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Token::Placeholder => f.write_str("{}")?,
Token::Basename => f.write_str("{/}")?,
Token::Parent => f.write_str("{//}")?,
Token::NoExt => f.write_str("{.}")?,
Token::BasenameNoExt => f.write_str("{/.}")?,
Token::Text(ref string) => f.write_str(string)?,
}
Ok(())
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
use std::process;
#[cfg(unix)]
use nix::sys::signal::{raise, signal, SigHandler, Signal};
use nix::sys::signal::{SigHandler, Signal, raise, signal};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ExitCode {
+25 -7
View File
@@ -59,6 +59,26 @@ pub fn is_empty(entry: &dir_entry::DirEntry) -> bool {
}
}
#[cfg(any(unix, target_os = "redox"))]
pub fn is_block_device(ft: fs::FileType) -> bool {
ft.is_block_device()
}
#[cfg(windows)]
pub fn is_block_device(_: fs::FileType) -> bool {
false
}
#[cfg(any(unix, target_os = "redox"))]
pub fn is_char_device(ft: fs::FileType) -> bool {
ft.is_char_device()
}
#[cfg(windows)]
pub fn is_char_device(_: fs::FileType) -> bool {
false
}
#[cfg(any(unix, target_os = "redox"))]
pub fn is_socket(ft: fs::FileType) -> bool {
ft.is_socket()
@@ -80,13 +100,13 @@ pub fn is_pipe(_: fs::FileType) -> bool {
}
#[cfg(any(unix, target_os = "redox"))]
pub fn osstr_to_bytes(input: &OsStr) -> Cow<[u8]> {
pub fn osstr_to_bytes(input: &OsStr) -> Cow<'_, [u8]> {
use std::os::unix::ffi::OsStrExt;
Cow::Borrowed(input.as_bytes())
}
#[cfg(windows)]
pub fn osstr_to_bytes(input: &OsStr) -> Cow<[u8]> {
pub fn osstr_to_bytes(input: &OsStr) -> Cow<'_, [u8]> {
let string = input.to_string_lossy();
match string {
@@ -108,13 +128,11 @@ pub fn strip_current_dir(path: &Path) -> &Path {
pub fn default_path_separator() -> Option<String> {
if cfg!(windows) {
let msystem = env::var("MSYSTEM").ok()?;
match msystem.as_str() {
"MINGW64" | "MINGW32" | "MSYS" => Some("/".to_owned()),
_ => None,
if !msystem.is_empty() {
return Some("/".to_owned());
}
} else {
None
}
None
}
#[cfg(test)]
+6
View File
@@ -9,6 +9,8 @@ pub struct FileTypes {
pub files: bool,
pub directories: bool,
pub symlinks: bool,
pub block_devices: bool,
pub char_devices: bool,
pub sockets: bool,
pub pipes: bool,
pub executables_only: bool,
@@ -21,6 +23,8 @@ impl FileTypes {
(!self.files && entry_type.is_file())
|| (!self.directories && entry_type.is_dir())
|| (!self.symlinks && entry_type.is_symlink())
|| (!self.block_devices && filesystem::is_block_device(*entry_type))
|| (!self.char_devices && filesystem::is_char_device(*entry_type))
|| (!self.sockets && filesystem::is_socket(*entry_type))
|| (!self.pipes && filesystem::is_pipe(*entry_type))
|| (self.executables_only && !entry.path().executable())
@@ -28,6 +32,8 @@ impl FileTypes {
|| !(entry_type.is_file()
|| entry_type.is_dir()
|| entry_type.is_symlink()
|| filesystem::is_block_device(*entry_type)
|| filesystem::is_char_device(*entry_type)
|| filesystem::is_socket(*entry_type)
|| filesystem::is_pipe(*entry_type))
} else {
+16 -9
View File
@@ -1,4 +1,5 @@
use anyhow::{anyhow, Result};
use anyhow::{Result, anyhow};
use nix::unistd::{Group, User};
use std::fs;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -35,16 +36,22 @@ impl OwnerFilter {
}
let uid = Check::parse(fst, |s| {
s.parse()
.ok()
.or_else(|| users::get_user_by_name(s).map(|user| user.uid()))
.ok_or_else(|| anyhow!("'{}' is not a recognized user name", s))
if let Ok(uid) = s.parse() {
Ok(uid)
} else {
User::from_name(s)?
.map(|user| user.uid.as_raw())
.ok_or_else(|| anyhow!("'{}' is not a recognized user name", s))
}
})?;
let gid = Check::parse(snd, |s| {
s.parse()
.ok()
.or_else(|| users::get_group_by_name(s).map(|group| group.gid()))
.ok_or_else(|| anyhow!("'{}' is not a recognized group name", s))
if let Ok(gid) = s.parse() {
Ok(gid)
} else {
Group::from_name(s)?
.map(|group| group.gid.as_raw())
.ok_or_else(|| anyhow!("'{}' is not a recognized group name", s))
}
})?;
Ok(OwnerFilter { uid, gid })
+163 -84
View File
@@ -1,6 +1,6 @@
use chrono::{offset::TimeZone, DateTime, Local, NaiveDate};
use jiff::{Span, Timestamp, Zoned, civil::DateTime, tz::TimeZone};
use std::time::SystemTime;
use std::time::{Duration, SystemTime, UNIX_EPOCH};
/// Filter based on time ranges.
#[derive(Debug, PartialEq, Eq)]
@@ -9,32 +9,49 @@ pub enum TimeFilter {
After(SystemTime),
}
#[cfg(not(test))]
fn now() -> Zoned {
Zoned::now()
}
#[cfg(test)]
thread_local! {
static TESTTIME: std::cell::RefCell<Option<Zoned>> = None.into();
}
/// This allows us to set a specific time when running tests
#[cfg(test)]
fn now() -> Zoned {
TESTTIME.with_borrow(|reftime| reftime.as_ref().cloned().unwrap_or_else(Zoned::now))
}
impl TimeFilter {
fn from_str(ref_time: &SystemTime, s: &str) -> Option<SystemTime> {
humantime::parse_duration(s)
.map(|duration| *ref_time - duration)
.ok()
.or_else(|| {
DateTime::parse_from_rfc3339(s)
.map(|dt| dt.into())
.ok()
.or_else(|| {
NaiveDate::parse_from_str(s, "%F")
.ok()
.and_then(|nd| nd.and_hms_opt(0, 0, 0))
.and_then(|ndt| Local.from_local_datetime(&ndt).single())
})
.or_else(|| Local.datetime_from_str(s, "%F %T").ok())
.map(|dt| dt.into())
})
fn from_str(s: &str) -> Option<SystemTime> {
if let Ok(span) = s.parse::<Span>() {
let datetime = now().checked_sub(span).ok()?;
Some(datetime.into())
} else if let Ok(timestamp) = s.parse::<Timestamp>() {
Some(timestamp.into())
} else if let Ok(datetime) = s.parse::<DateTime>() {
Some(
TimeZone::system()
.to_ambiguous_zoned(datetime)
.later()
.ok()?
.into(),
)
} else {
let timestamp_secs: u64 = s.strip_prefix('@')?.parse().ok()?;
UNIX_EPOCH.checked_add(Duration::from_secs(timestamp_secs))
}
}
pub fn before(ref_time: &SystemTime, s: &str) -> Option<TimeFilter> {
TimeFilter::from_str(ref_time, s).map(TimeFilter::Before)
pub fn before(s: &str) -> Option<TimeFilter> {
TimeFilter::from_str(s).map(TimeFilter::Before)
}
pub fn after(ref_time: &SystemTime, s: &str) -> Option<TimeFilter> {
TimeFilter::from_str(ref_time, s).map(TimeFilter::After)
pub fn after(s: &str) -> Option<TimeFilter> {
TimeFilter::from_str(s).map(TimeFilter::After)
}
pub fn applies_to(&self, t: &SystemTime) -> bool {
@@ -50,82 +67,144 @@ mod tests {
use super::*;
use std::time::Duration;
struct TestTime(SystemTime);
impl TestTime {
fn new(time: Zoned) -> Self {
TESTTIME.with_borrow_mut(|t| *t = Some(time.clone()));
TestTime(time.into())
}
fn set(&mut self, time: Zoned) {
TESTTIME.with_borrow_mut(|t| *t = Some(time.clone()));
self.0 = time.into();
}
fn timestamp(&self) -> SystemTime {
self.0
}
}
impl Drop for TestTime {
fn drop(&mut self) {
// Stop using manually set times
TESTTIME.with_borrow_mut(|t| *t = None);
}
}
#[test]
fn is_time_filter_applicable() {
let ref_time = Local
.datetime_from_str("2010-10-10 10:10:10", "%F %T")
.unwrap()
.into();
let local_tz = TimeZone::system();
let mut test_time = TestTime::new(
local_tz
.to_ambiguous_zoned("2010-10-10 10:10:10".parse::<DateTime>().unwrap())
.later()
.unwrap(),
);
let mut ref_time = test_time.timestamp();
assert!(TimeFilter::after(&ref_time, "1min")
.unwrap()
.applies_to(&ref_time));
assert!(!TimeFilter::before(&ref_time, "1min")
.unwrap()
.applies_to(&ref_time));
assert!(TimeFilter::after("1min").unwrap().applies_to(&ref_time));
assert!(!TimeFilter::before("1min").unwrap().applies_to(&ref_time));
let t1m_ago = ref_time - Duration::from_secs(60);
assert!(!TimeFilter::after(&ref_time, "30sec")
.unwrap()
.applies_to(&t1m_ago));
assert!(TimeFilter::after(&ref_time, "2min")
.unwrap()
.applies_to(&t1m_ago));
assert!(!TimeFilter::after("30sec").unwrap().applies_to(&t1m_ago));
assert!(TimeFilter::after("2min").unwrap().applies_to(&t1m_ago));
assert!(TimeFilter::before(&ref_time, "30sec")
.unwrap()
.applies_to(&t1m_ago));
assert!(!TimeFilter::before(&ref_time, "2min")
.unwrap()
.applies_to(&t1m_ago));
assert!(TimeFilter::before("30sec").unwrap().applies_to(&t1m_ago));
assert!(!TimeFilter::before("2min").unwrap().applies_to(&t1m_ago));
let t10s_before = "2010-10-10 10:10:00";
assert!(!TimeFilter::before(&ref_time, t10s_before)
.unwrap()
.applies_to(&ref_time));
assert!(TimeFilter::before(&ref_time, t10s_before)
.unwrap()
.applies_to(&t1m_ago));
assert!(
!TimeFilter::before(t10s_before)
.unwrap()
.applies_to(&ref_time)
);
assert!(
TimeFilter::before(t10s_before)
.unwrap()
.applies_to(&t1m_ago)
);
assert!(TimeFilter::after(&ref_time, t10s_before)
.unwrap()
.applies_to(&ref_time));
assert!(!TimeFilter::after(&ref_time, t10s_before)
.unwrap()
.applies_to(&t1m_ago));
assert!(
TimeFilter::after(t10s_before)
.unwrap()
.applies_to(&ref_time)
);
assert!(!TimeFilter::after(t10s_before).unwrap().applies_to(&t1m_ago));
let same_day = "2010-10-10";
assert!(!TimeFilter::before(&ref_time, same_day)
.unwrap()
.applies_to(&ref_time));
assert!(!TimeFilter::before(&ref_time, same_day)
.unwrap()
.applies_to(&t1m_ago));
assert!(!TimeFilter::before(same_day).unwrap().applies_to(&ref_time));
assert!(!TimeFilter::before(same_day).unwrap().applies_to(&t1m_ago));
assert!(TimeFilter::after(&ref_time, same_day)
.unwrap()
.applies_to(&ref_time));
assert!(TimeFilter::after(&ref_time, same_day)
.unwrap()
.applies_to(&t1m_ago));
assert!(TimeFilter::after(same_day).unwrap().applies_to(&ref_time));
assert!(TimeFilter::after(same_day).unwrap().applies_to(&t1m_ago));
let ref_time = DateTime::parse_from_rfc3339("2010-10-10T10:10:10+00:00")
.unwrap()
.into();
test_time.set(
"2010-10-10T10:10:10+00:00"
.parse::<Timestamp>()
.unwrap()
.to_zoned(local_tz.clone()),
);
ref_time = test_time.timestamp();
let t1m_ago = ref_time - Duration::from_secs(60);
let t10s_before = "2010-10-10T10:10:00+00:00";
assert!(!TimeFilter::before(&ref_time, t10s_before)
.unwrap()
.applies_to(&ref_time));
assert!(TimeFilter::before(&ref_time, t10s_before)
.unwrap()
.applies_to(&t1m_ago));
assert!(
!TimeFilter::before(t10s_before)
.unwrap()
.applies_to(&ref_time)
);
assert!(
TimeFilter::before(t10s_before)
.unwrap()
.applies_to(&t1m_ago)
);
assert!(TimeFilter::after(&ref_time, t10s_before)
.unwrap()
.applies_to(&ref_time));
assert!(!TimeFilter::after(&ref_time, t10s_before)
.unwrap()
.applies_to(&t1m_ago));
assert!(
TimeFilter::after(t10s_before)
.unwrap()
.applies_to(&ref_time)
);
assert!(!TimeFilter::after(t10s_before).unwrap().applies_to(&t1m_ago));
let ref_timestamp = 1707723412u64; // Mon Feb 12 07:36:52 UTC 2024
test_time.set(
"2024-02-12T07:36:52+00:00"
.parse::<Timestamp>()
.unwrap()
.to_zoned(local_tz),
);
ref_time = test_time.timestamp();
let t1m_ago = ref_time - Duration::from_secs(60);
let t1s_later = ref_time + Duration::from_secs(1);
// Timestamp only supported via '@' prefix
assert!(TimeFilter::before(&ref_timestamp.to_string()).is_none());
assert!(
TimeFilter::before(&format!("@{ref_timestamp}"))
.unwrap()
.applies_to(&t1m_ago)
);
assert!(
!TimeFilter::before(&format!("@{ref_timestamp}"))
.unwrap()
.applies_to(&t1s_later)
);
assert!(
!TimeFilter::after(&format!("@{ref_timestamp}"))
.unwrap()
.applies_to(&t1m_ago)
);
assert!(
TimeFilter::after(&format!("@{ref_timestamp}"))
.unwrap()
.applies_to(&t1s_later)
);
}
#[test]
fn out_of_range_unix_timestamp_is_rejected() {
// A '@' timestamp large enough to overflow SystemTime must return
// None rather than panicking.
assert!(TimeFilter::before(&format!("@{}", u64::MAX)).is_none());
assert!(TimeFilter::after(&format!("@{}", u64::MAX)).is_none());
}
}
+2 -2
View File
@@ -34,10 +34,10 @@ pub fn dirname(path: &Path) -> OsString {
#[cfg(test)]
mod path_tests {
use super::*;
use std::path::MAIN_SEPARATOR;
use std::path::MAIN_SEPARATOR_STR;
fn correct(input: &str) -> String {
input.replace('/', &MAIN_SEPARATOR.to_string())
input.replace('/', MAIN_SEPARATOR_STR)
}
macro_rules! func_tests {
+281
View File
@@ -0,0 +1,281 @@
mod input;
use std::borrow::Cow;
use std::ffi::{OsStr, OsString};
use std::fmt::{self, Display, Formatter};
use std::path::{Component, Path, Prefix};
use std::sync::OnceLock;
use aho_corasick::AhoCorasick;
use self::input::{basename, dirname, remove_extension};
/// Designates what should be written to a buffer
///
/// Each `Token` contains either text, or a placeholder variant, which will be used to generate
/// commands after all tokens for a given command template have been collected.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Token {
Placeholder,
Basename,
Parent,
NoExt,
BasenameNoExt,
Text(String),
}
impl Display for Token {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match *self {
Token::Placeholder => f.write_str("{}")?,
Token::Basename => f.write_str("{/}")?,
Token::Parent => f.write_str("{//}")?,
Token::NoExt => f.write_str("{.}")?,
Token::BasenameNoExt => f.write_str("{/.}")?,
Token::Text(ref string) => f.write_str(string)?,
}
Ok(())
}
}
/// A parsed format string
///
/// This is either a collection of `Token`s including at least one placeholder variant,
/// or a fixed text.
#[derive(Clone, Debug, PartialEq)]
pub enum FormatTemplate {
Tokens(Vec<Token>),
Text(String),
}
static PLACEHOLDERS: OnceLock<AhoCorasick> = OnceLock::new();
impl FormatTemplate {
pub fn has_tokens(&self) -> bool {
matches!(self, FormatTemplate::Tokens(_))
}
pub fn parse(fmt: &str) -> Self {
// NOTE: we assume that { and } have the same length
const BRACE_LEN: usize = '{'.len_utf8();
let mut tokens = Vec::new();
let mut remaining = fmt;
let mut buf = String::new();
let placeholders = PLACEHOLDERS.get_or_init(|| {
AhoCorasick::new(["{{", "}}", "{}", "{/}", "{//}", "{.}", "{/.}"]).unwrap()
});
while let Some(m) = placeholders.find(remaining) {
match m.pattern().as_u32() {
0 | 1 => {
// we found an escaped {{ or }}, so add
// everything up to the first char to the buffer
// then skip the second one.
buf += &remaining[..m.start() + BRACE_LEN];
remaining = &remaining[m.end()..];
}
id if !remaining[m.end()..].starts_with('}') => {
buf += &remaining[..m.start()];
if !buf.is_empty() {
tokens.push(Token::Text(std::mem::take(&mut buf)));
}
tokens.push(token_from_pattern_id(id));
remaining = &remaining[m.end()..];
}
_ => {
// We got a normal pattern, but the final "}"
// is escaped, so add up to that to the buffer, then
// skip the final }
buf += &remaining[..m.end()];
remaining = &remaining[m.end() + BRACE_LEN..];
}
}
}
// Add the rest of the string to the buffer, and add the final buffer to the tokens
if !remaining.is_empty() {
buf += remaining;
}
if tokens.is_empty() {
// No placeholders were found, so just return the text
return FormatTemplate::Text(buf);
}
// Add final text segment
if !buf.is_empty() {
tokens.push(Token::Text(buf));
}
debug_assert!(!tokens.is_empty());
FormatTemplate::Tokens(tokens)
}
/// Generate a result string from this template. If path_separator is Some, then it will replace
/// the path separator in all placeholder tokens. Fixed text and tokens are not affected by
/// path separator substitution.
pub fn generate(&self, path: impl AsRef<Path>, path_separator: Option<&str>) -> OsString {
use Token::*;
let path = path.as_ref();
match *self {
Self::Tokens(ref tokens) => {
let mut s = OsString::new();
for token in tokens {
match token {
Basename => s.push(Self::replace_separator(basename(path), path_separator)),
BasenameNoExt => s.push(Self::replace_separator(
&remove_extension(basename(path).as_ref()),
path_separator,
)),
NoExt => s.push(Self::replace_separator(
&remove_extension(path),
path_separator,
)),
Parent => s.push(Self::replace_separator(&dirname(path), path_separator)),
Placeholder => {
s.push(Self::replace_separator(path.as_ref(), path_separator))
}
Text(string) => s.push(string),
}
}
s
}
Self::Text(ref text) => OsString::from(text),
}
}
/// Replace the path separator in the input with the custom separator string. If path_separator
/// is None, simply return a borrowed Cow<OsStr> of the input. Otherwise, the input is
/// interpreted as a Path and its components are iterated through and re-joined into a new
/// OsString.
fn replace_separator<'a>(path: &'a OsStr, path_separator: Option<&str>) -> Cow<'a, OsStr> {
// fast-path - no replacement necessary
if path_separator.is_none() {
return Cow::Borrowed(path);
}
let path_separator = path_separator.unwrap();
let mut out = OsString::with_capacity(path.len());
let mut components = Path::new(path).components().peekable();
while let Some(comp) = components.next() {
match comp {
// Absolute paths on Windows are tricky. A Prefix component is usually a drive
// letter or UNC path, and is usually followed by RootDir. There are also
// "verbatim" prefixes beginning with "\\?\" that skip normalization. We choose to
// ignore verbatim path prefixes here because they're very rare, might be
// impossible to reach here, and there's no good way to deal with them. If users
// are doing something advanced involving verbatim windows paths, they can do their
// own output filtering with a tool like sed.
Component::Prefix(prefix) => {
if let Prefix::UNC(server, share) = prefix.kind() {
// Prefix::UNC is a parsed version of '\\server\share'
out.push(path_separator);
out.push(path_separator);
out.push(server);
out.push(path_separator);
out.push(share);
} else {
// All other Windows prefix types are rendered as-is. This results in e.g. "C:" for
// drive letters. DeviceNS and Verbatim* prefixes won't have backslashes converted,
// but they're not returned by directories fd can search anyway so we don't worry
// about them.
out.push(comp.as_os_str());
}
}
// Root directory is always replaced with the custom separator.
Component::RootDir => out.push(path_separator),
// Everything else is joined normally, with a trailing separator if we're not last
_ => {
out.push(comp.as_os_str());
if components.peek().is_some() {
out.push(path_separator);
}
}
}
}
Cow::Owned(out)
}
}
// Convert the id from an aho-corasick match to the
// appropriate token
fn token_from_pattern_id(id: u32) -> Token {
use Token::*;
match id {
2 => Placeholder,
3 => Basename,
4 => Parent,
5 => NoExt,
6 => BasenameNoExt,
_ => unreachable!(),
}
}
#[cfg(test)]
mod fmt_tests {
use super::*;
use std::path::PathBuf;
#[test]
fn parse_no_placeholders() {
let templ = FormatTemplate::parse("This string has no placeholders");
assert_eq!(
templ,
FormatTemplate::Text("This string has no placeholders".into())
);
}
#[test]
fn parse_only_brace_escapes() {
let templ = FormatTemplate::parse("This string only has escapes like {{ and }}");
assert_eq!(
templ,
FormatTemplate::Text("This string only has escapes like { and }".into())
);
}
#[test]
fn all_placeholders() {
use Token::*;
let templ = FormatTemplate::parse(
"{{path={} \
basename={/} \
parent={//} \
noExt={.} \
basenameNoExt={/.} \
}}",
);
assert_eq!(
templ,
FormatTemplate::Tokens(vec![
Text("{path=".into()),
Placeholder,
Text(" basename=".into()),
Basename,
Text(" parent=".into()),
Parent,
Text(" noExt=".into()),
NoExt,
Text(" basenameNoExt=".into()),
BasenameNoExt,
Text(" }".into()),
])
);
let mut path = PathBuf::new();
path.push("a");
path.push("folder");
path.push("file.txt");
let expanded = templ.generate(&path, Some("/")).into_string().unwrap();
assert_eq!(
expanded,
"{path=a/folder/file.txt \
basename=file.txt \
parent=a/folder \
noExt=a/folder/file \
basenameNoExt=file }"
);
}
}
+87
View File
@@ -0,0 +1,87 @@
use crate::filesystem::absolute_path;
use std::fmt::{self, Formatter, Write};
use std::path::{Path, PathBuf};
pub(crate) struct PathUrl(PathBuf);
impl PathUrl {
pub(crate) fn new(path: &Path) -> Option<PathUrl> {
Some(PathUrl(absolute_path(path).ok()?))
}
}
impl fmt::Display for PathUrl {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "file://{}", host())?;
let bytes = self.0.as_os_str().as_encoded_bytes();
for &byte in bytes.iter() {
encode(f, byte)?;
}
Ok(())
}
}
fn encode(f: &mut Formatter, byte: u8) -> fmt::Result {
// NOTE:
// Most terminals can handle non-ascii unicode characters in a file url fine. But on some OSes (notably
// windows), the encoded bytes of the path may not be valid UTF-8. Since we don't know if a
// byte >= 128 is part of a valid UTF-8 encoding or not, we just percent encode any non-ascii
// byte.
// Percent encoding these bytes is probably safer anyway.
match byte {
b'0'..=b'9' | b'A'..=b'Z' | b'a'..=b'z' | b'/' | b':' | b'-' | b'.' | b'_' | b'~' => {
f.write_char(byte.into())
}
#[cfg(windows)]
b'\\' => f.write_char('/'),
_ => {
write!(f, "%{byte:02X}")
}
}
}
#[cfg(unix)]
fn host() -> &'static str {
use std::sync::OnceLock;
static HOSTNAME: OnceLock<String> = OnceLock::new();
HOSTNAME
.get_or_init(|| {
nix::unistd::gethostname()
.ok()
.and_then(|h| h.into_string().ok())
.unwrap_or_default()
})
.as_ref()
}
#[cfg(not(unix))]
const fn host() -> &'static str {
"/"
}
#[cfg(test)]
mod test {
use super::*;
// This allows us to test the encoding without having to worry about the host, or absolute path
struct Encoded(&'static str);
impl fmt::Display for Encoded {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for byte in self.0.bytes() {
encode(f, byte)?;
}
Ok(())
}
}
#[test]
fn test_unicode_encoding() {
assert_eq!(
Encoded("$*\x1bßé/∫😃\x07").to_string(),
"%24%2A%1B%C3%9F%C3%A9/%E2%88%AB%F0%9F%98%83%07",
);
}
}
+112 -28
View File
@@ -7,23 +7,25 @@ mod exit_codes;
mod filesystem;
mod filetypes;
mod filter;
mod fmt;
mod hyperlink;
mod output;
mod regex_helper;
mod sanitize;
mod walk;
use std::env;
use std::io::IsTerminal;
use std::path::Path;
use std::sync::Arc;
use std::time;
use anyhow::{anyhow, bail, Context, Result};
use anyhow::{Context, Result, anyhow, bail};
use clap::{CommandFactory, Parser};
use globset::GlobBuilder;
use lscolors::LsColors;
use regex::bytes::{Regex, RegexBuilder, RegexSetBuilder};
use crate::cli::{ColorWhen, Opts};
use crate::cli::{ColorWhen, HyperlinkWhen, Opts};
use crate::config::Config;
use crate::exec::CommandSet;
use crate::exit_codes::ExitCode;
@@ -35,18 +37,21 @@ use crate::regex_helper::{pattern_has_uppercase_char, pattern_matches_strings_wi
// We use jemalloc for performance reasons, see https://github.com/sharkdp/fd/pull/481
// FIXME: re-enable jemalloc on macOS, see comment in Cargo.toml file for more infos
// This has to be kept in sync with the Cargo.toml file section that declares a
// dependency on tikv-jemallocator.
#[cfg(all(
not(windows),
not(target_os = "android"),
not(target_os = "macos"),
not(target_os = "freebsd"),
not(target_os = "openbsd"),
not(target_os = "illumos"),
not(all(target_env = "musl", target_pointer_width = "32")),
not(target_arch = "riscv64"),
feature = "use-jemalloc"
))]
#[global_allocator]
static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
// vivid --color-mode 8-bit generate molokai
const DEFAULT_LS_COLORS: &str = "
@@ -61,7 +66,7 @@ fn main() {
exit_code.exit();
}
Err(err) => {
eprintln!("[fd error]: {:#}", err);
crate::error::print_error(format!("{err:#}"));
ExitCode::GeneralError.exit();
}
}
@@ -103,7 +108,7 @@ fn run() -> Result<ExitCode> {
.map(|pat| build_regex(pat, &config))
.collect::<Result<Vec<Regex>>>()?;
walk::scan(&search_paths, Arc::new(regexps), Arc::new(config))
walk::scan(&search_paths, regexps, config)
}
#[cfg(feature = "completions")]
@@ -141,21 +146,69 @@ fn set_working_dir(opts: &Opts) -> Result<()> {
Ok(())
}
/// Detect if the user accidentally supplied a path instead of a search pattern
/// Detect if the user accidentally supplied a path instead of a search pattern.
///
/// Without `--full-path`, fd matches patterns against file names, so any pattern
/// containing a path separator can never match. This applies to the primary
/// positional pattern *and* to every `--and` pattern, since all of them are
/// chained together and matched against the file name (see `run`). Two cases per
/// pattern are worth a friendly error rather than silent "no results":
///
/// 1. The pattern contains '/'. '/' is always a path separator (including on
/// Windows) and has no regex meaning, so flagging it is safe and catches the
/// common Linux/macOS mistake of pasting a full path as the pattern.
/// 2. On Windows only, the pattern contains the native `\` separator *and*
/// names an existing directory on disk. We can't treat `\` as a pure
/// path-separator signal there because it is also the regex escape char,
/// so valid regex patterns like `\Ac` or `\d+` must still run. Requiring
/// that the pattern resolves to a real directory avoids those false
/// positives while preserving the legacy diagnostic for operators who
/// literally typed a directory path.
///
/// See https://github.com/sharkdp/fd/issues/1873.
fn ensure_search_pattern_is_not_a_path(opts: &Opts) -> Result<()> {
if !opts.full_path
&& opts.pattern.contains(std::path::MAIN_SEPARATOR)
&& Path::new(&opts.pattern).is_dir()
if opts.full_path {
return Ok(());
}
// Check the primary pattern and every `--and` pattern. They are all matched
// against the file name (see `run`), so a path separator in any of them is
// the same silent "no results" footgun.
for pattern in std::iter::once(&opts.pattern).chain(opts.exprs.iter().flatten()) {
ensure_single_search_pattern_is_not_a_path(pattern)?;
}
Ok(())
}
/// Apply the path-separator diagnostic to a single pattern. See
/// [`ensure_search_pattern_is_not_a_path`] for the rationale of each case.
fn ensure_single_search_pattern_is_not_a_path(pattern: &str) -> Result<()> {
// Start with the cheap check: '/' is always a path separator, including on
// Windows, and has no regex meaning, so flagging it is safe and catches the
// Linux/macOS mistake of pasting a full path as the pattern.
#[cfg_attr(not(windows), allow(unused_mut))]
let mut should_warn = pattern.contains('/');
// On Windows we additionally accept the native `\` separator, but only when
// the pattern actually resolves to an existing directory - `\` is also the
// regex escape char there, so valid patterns like `\Ac` or `\d+` must still
// run. The is_dir syscall is only needed when `should_warn` is still false,
// so short-circuit via `||` to avoid the stat call on the happy path.
#[cfg(windows)]
{
should_warn = should_warn
|| (pattern.contains(std::path::MAIN_SEPARATOR) && Path::new(pattern).is_dir());
}
if should_warn {
Err(anyhow!(
"The search pattern '{pattern}' contains a path-separation character ('{sep}') \
"The search pattern '{pattern}' contains a path-separation character \
and will not lead to any search results.\n\n\
If you want to search for all files inside the '{pattern}' directory, use a match-all pattern:\n\n \
fd . '{pattern}'\n\n\
Instead, if you want your pattern to match the full file path, use:\n\n \
fd --full-path '{pattern}'",
pattern = &opts.pattern,
sep = std::path::MAIN_SEPARATOR,
pattern = pattern,
))
} else {
Ok(())
@@ -166,6 +219,10 @@ fn build_pattern_regex(pattern: &str, opts: &Opts) -> Result<String> {
Ok(if opts.glob && !pattern.is_empty() {
let glob = GlobBuilder::new(pattern).literal_separator(true).build()?;
glob.regex().to_owned()
} else if opts.exact {
// Anchor the escaped pattern so the full filename (or path) must match exactly.
// Literal. No substring matching.
format!("^{}$", regex::escape(pattern))
} else if opts.fixed_strings {
// Treat pattern as literal string if '--fixed-strings' is used
regex::escape(pattern)
@@ -218,11 +275,13 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
let ansi_colors_support = true;
let interactive_terminal = std::io::stdout().is_terminal();
let colored_output = match opts.color {
ColorWhen::Always => true,
ColorWhen::Never => false,
ColorWhen::Auto => {
ansi_colors_support && env::var_os("NO_COLOR").is_none() && interactive_terminal
let no_color = env::var_os("NO_COLOR").is_some_and(|x| !x.is_empty());
ansi_colors_support && !no_color && interactive_terminal
}
};
@@ -231,12 +290,26 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
} else {
None
};
let hyperlink = match opts.hyperlink {
HyperlinkWhen::Always => true,
HyperlinkWhen::Never => false,
HyperlinkWhen::Auto => colored_output,
};
let command = extract_command(&mut opts, colored_output)?;
let has_command = command.is_some();
let full_path_base = if opts.full_path {
Some(env::current_dir().context(
"Could not determine current directory. \
This is required for --full-path.",
)?)
} else {
None
};
Ok(Config {
case_sensitive,
search_full_path: opts.full_path,
full_path_base,
ignore_hidden: !(opts.hidden || opts.rg_alias_ignore()),
read_fdignore: !(opts.no_ignore || opts.rg_alias_ignore()),
read_vcsignore: !(opts.no_ignore || opts.rg_alias_ignore() || opts.no_ignore_vcs),
@@ -252,9 +325,10 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
max_depth: opts.max_depth(),
min_depth: opts.min_depth(),
prune: opts.prune,
threads: opts.threads(),
threads: opts.threads().get(),
max_buffer_time: opts.max_buffer_time,
ls_colors,
hyperlink,
interactive_terminal,
file_types: opts.filetype.as_ref().map(|values| {
use crate::cli::FileType::*;
@@ -269,6 +343,8 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
file_types.files = true;
}
Empty => file_types.empty_only = true,
BlockDevice => file_types.block_devices = true,
CharDevice => file_types.char_devices = true,
Socket => file_types.sockets = true,
Pipe => file_types.pipes = true,
}
@@ -295,6 +371,10 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
.build()
})
.transpose()?,
format: opts
.format
.as_deref()
.map(crate::fmt::FormatTemplate::parse),
command: command.map(Arc::new),
batch_size: opts.batch_size,
exclude_patterns: opts.exclude.iter().map(|p| String::from("!") + p).collect(),
@@ -307,8 +387,8 @@ fn construct_config(mut opts: Opts, pattern_regexps: &[String]) -> Result<Config
path_separator,
actual_path_separator,
max_results: opts.max_results(),
strip_cwd_prefix: (opts.no_search_paths()
&& (opts.strip_cwd_prefix || !(opts.null_separator || has_command))),
strip_cwd_prefix: opts.strip_cwd_prefix(|| !(opts.null_separator || has_command)),
ignore_contain: opts.ignore_contain,
})
}
@@ -321,18 +401,22 @@ fn extract_command(opts: &mut Opts, colored_output: bool) -> Result<Option<Comma
if !opts.list_details {
return None;
}
let color_arg = format!("--color={}", opts.color.as_str());
let res = determine_ls_command(&color_arg, colored_output)
let res = determine_ls_command(colored_output)
.map(|cmd| CommandSet::new_batch([cmd]).unwrap());
Some(res)
})
.transpose()
}
fn determine_ls_command(color_arg: &str, colored_output: bool) -> Result<Vec<&str>> {
fn determine_ls_command(colored_output: bool) -> Result<Vec<&'static str>> {
#[allow(unused)]
let gnu_ls = |command_name| {
let color_arg = if colored_output {
"--color=always"
} else {
"--color=never"
};
// Note: we use short options here (instead of --long-options) to support more
// platforms (like BusyBox).
vec![
@@ -354,7 +438,7 @@ fn determine_ls_command(color_arg: &str, colored_output: bool) -> Result<Vec<&st
// Assume ls is GNU ls
gnu_ls("ls")
} else {
// MacOS, DragonFlyBSD, FreeBSD
// macOS, DragonFlyBSD, FreeBSD
use std::process::{Command, Stdio};
// Use GNU ls, if available (support for --color=auto, better LS_COLORS support)
@@ -410,10 +494,9 @@ fn determine_ls_command(color_arg: &str, colored_output: bool) -> Result<Vec<&st
}
fn extract_time_constraints(opts: &Opts) -> Result<Vec<TimeFilter>> {
let now = time::SystemTime::now();
let mut time_constraints: Vec<TimeFilter> = Vec::new();
if let Some(ref t) = opts.changed_within {
if let Some(f) = TimeFilter::after(&now, t) {
if let Some(f) = TimeFilter::after(t) {
time_constraints.push(f);
} else {
return Err(anyhow!(
@@ -423,7 +506,7 @@ fn extract_time_constraints(opts: &Opts) -> Result<Vec<TimeFilter>> {
}
}
if let Some(ref t) = opts.changed_before {
if let Some(f) = TimeFilter::before(&now, t) {
if let Some(f) = TimeFilter::before(t) {
time_constraints.push(f);
} else {
return Err(anyhow!(
@@ -462,10 +545,11 @@ fn build_regex(pattern_regex: String, config: &Config) -> Result<regex::bytes::R
.build()
.map_err(|e| {
anyhow!(
"{}\n\nNote: You can use the '--fixed-strings' option to search for a \
literal string instead of a regular expression. Alternatively, you can \
"{}\n\nNote: You can search for literal substrings with '--fixed-strings' \
or literal strings with '--exact' options (instead of a regular expression). \
Alternatively, you can \
also use the '--glob' option to match on a glob pattern.",
e.to_string()
e
)
})
}
+55 -33
View File
@@ -5,29 +5,40 @@ use lscolors::{Indicator, LsColors, Style};
use crate::config::Config;
use crate::dir_entry::DirEntry;
use crate::error::print_error;
use crate::exit_codes::ExitCode;
use crate::fmt::FormatTemplate;
use crate::hyperlink::PathUrl;
use crate::sanitize::maybe_sanitize;
fn replace_path_separator(path: &str, new_path_separator: &str) -> String {
path.replace(std::path::MAIN_SEPARATOR, new_path_separator)
}
// TODO: this function is performance critical and can probably be optimized
pub fn print_entry<W: Write>(stdout: &mut W, entry: &DirEntry, config: &Config) {
let r = if let Some(ref ls_colors) = config.ls_colors {
print_entry_colorized(stdout, entry, config, ls_colors)
pub fn print_entry<W: Write>(stdout: &mut W, entry: &DirEntry, config: &Config) -> io::Result<()> {
let mut has_hyperlink = false;
if config.hyperlink
&& let Some(url) = PathUrl::new(entry.path())
{
write!(stdout, "\x1B]8;;{url}\x1B\\")?;
has_hyperlink = true;
}
if let Some(ref format) = config.format {
print_entry_format(stdout, entry, config, format)?;
} else if let Some(ref ls_colors) = config.ls_colors {
print_entry_colorized(stdout, entry, config, ls_colors)?;
} else {
print_entry_uncolorized(stdout, entry, config)
print_entry_uncolorized(stdout, entry, config)?;
};
if let Err(e) = r {
if e.kind() == ::std::io::ErrorKind::BrokenPipe {
// Exit gracefully in case of a broken pipe (e.g. 'fd ... | head -n 3').
ExitCode::Success.exit();
} else {
print_error(format!("Could not write to output: {}", e));
ExitCode::GeneralError.exit();
}
if has_hyperlink {
write!(stdout, "\x1B]8;;\x1B\\")?;
}
if config.null_separator {
write!(stdout, "\0")
} else {
writeln!(stdout)
}
}
@@ -41,7 +52,7 @@ fn print_trailing_slash<W: Write>(
config: &Config,
style: Option<&Style>,
) -> io::Result<()> {
if entry.file_type().map_or(false, |ft| ft.is_dir()) {
if entry.file_type().is_some_and(|ft| ft.is_dir()) {
write!(
stdout,
"{}",
@@ -54,6 +65,26 @@ fn print_trailing_slash<W: Write>(
Ok(())
}
// TODO: this function is performance critical and can probably be optimized
fn print_entry_format<W: Write>(
stdout: &mut W,
entry: &DirEntry,
config: &Config,
format: &FormatTemplate,
) -> io::Result<()> {
let output = format.generate(
entry.stripped_path(config),
config.path_separator.as_deref(),
);
// TODO: support writing raw bytes on unix?
let s = output.to_string_lossy();
write!(
stdout,
"{}",
maybe_sanitize(&s, config.interactive_terminal)
)
}
// TODO: this function is performance critical and can probably be optimized
fn print_entry_colorized<W: Write>(
stdout: &mut W,
@@ -61,7 +92,6 @@ fn print_entry_colorized<W: Write>(
config: &Config,
ls_colors: &LsColors,
) -> io::Result<()> {
// Split the path between the parent and the last component
let mut offset = 0;
let path = entry.stripped_path(config);
let path_str = path.to_string_lossy();
@@ -87,14 +117,16 @@ fn print_entry_colorized<W: Write>(
.style_for_indicator(Indicator::Directory)
.map(Style::to_nu_ansi_term_style)
.unwrap_or_default();
write!(stdout, "{}", style.paint(parent_str))?;
let safe_parent = maybe_sanitize(&parent_str, config.interactive_terminal);
write!(stdout, "{}", style.paint(safe_parent.as_ref()))?;
}
let style = entry
.style(ls_colors)
.map(Style::to_nu_ansi_term_style)
.unwrap_or_default();
write!(stdout, "{}", style.paint(&path_str[offset..]))?;
let safe_basename = maybe_sanitize(&path_str[offset..], config.interactive_terminal);
write!(stdout, "{}", style.paint(safe_basename.as_ref()))?;
print_trailing_slash(
stdout,
@@ -103,12 +135,6 @@ fn print_entry_colorized<W: Write>(
ls_colors.style_for_indicator(Indicator::Directory),
)?;
if config.null_separator {
write!(stdout, "\0")?;
} else {
writeln!(stdout)?;
}
Ok(())
}
@@ -118,16 +144,15 @@ fn print_entry_uncolorized_base<W: Write>(
entry: &DirEntry,
config: &Config,
) -> io::Result<()> {
let separator = if config.null_separator { "\0" } else { "\n" };
let path = entry.stripped_path(config);
let mut path_string = path.to_string_lossy();
if let Some(ref separator) = config.path_separator {
*path_string.to_mut() = replace_path_separator(&path_string, separator);
}
write!(stdout, "{}", path_string)?;
print_trailing_slash(stdout, entry, config, None)?;
write!(stdout, "{}", separator)
let safe = maybe_sanitize(&path_string, config.interactive_terminal);
write!(stdout, "{safe}")?;
print_trailing_slash(stdout, entry, config, None)
}
#[cfg(not(unix))]
@@ -148,13 +173,10 @@ fn print_entry_uncolorized<W: Write>(
use std::os::unix::ffi::OsStrExt;
if config.interactive_terminal || config.path_separator.is_some() {
// Fall back to the base implementation
print_entry_uncolorized_base(stdout, entry, config)
} else {
// Print path as raw bytes, allowing invalid UTF-8 filenames to be passed to other processes
let separator = if config.null_separator { b"\0" } else { b"\n" };
// Piped output: raw bytes so invalid UTF-8 filenames reach downstream tools intact.
stdout.write_all(entry.stripped_path(config).as_os_str().as_bytes())?;
print_trailing_slash(stdout, entry, config, None)?;
stdout.write_all(separator)
print_trailing_slash(stdout, entry, config, None)
}
}
+3 -3
View File
@@ -1,5 +1,5 @@
use regex_syntax::hir::Hir;
use regex_syntax::ParserBuilder;
use regex_syntax::hir::Hir;
/// Determine if a regex pattern contains a literal uppercase character.
pub fn pattern_has_uppercase_char(pattern: &str) -> bool {
@@ -16,7 +16,7 @@ fn hir_has_uppercase_char(hir: &Hir) -> bool {
use regex_syntax::hir::*;
match hir.kind() {
HirKind::Literal(Literal(bytes)) => match std::str::from_utf8(&bytes) {
HirKind::Literal(Literal(bytes)) => match std::str::from_utf8(bytes) {
Ok(s) => s.chars().any(|c| c.is_uppercase()),
Err(_) => bytes.iter().any(|b| char::from(*b).is_uppercase()),
},
@@ -67,7 +67,7 @@ fn hir_matches_strings_with_leading_dot(hir: &Hir) -> bool {
if let Some(hir) = hirs.next() {
match hir.kind() {
HirKind::Literal(Literal(bytes)) => bytes.starts_with(&[b'.']),
HirKind::Literal(Literal(bytes)) => bytes.starts_with(b"."),
_ => false,
}
} else {
+168
View File
@@ -0,0 +1,168 @@
//! TTY-output sanitization to prevent terminal escape injection via filenames.
use std::borrow::Cow;
use std::fmt::Write;
/// True for any char that is neither printable nor permitted whitespace (only HT).
/// Covers C0/C1/DEL, bidi overrides, zero-width and format chars, and tag chars.
#[inline]
fn needs_escape(c: char) -> bool {
if c == '\t' {
return false;
}
c.is_control()
|| matches!(c,
'\u{00AD}' // soft hyphen (invisible)
| '\u{180E}' // Mongolian vowel separator
| '\u{200B}'..='\u{200F}' // zero-width + LRM/RLM
| '\u{202A}'..='\u{202E}' // bidi embedding/override
| '\u{2060}'..='\u{206F}' // word joiner, invisibles, deprecated formats
| '\u{FEFF}' // BOM / zero-width no-break space
| '\u{FFF9}'..='\u{FFFB}' // interlinear annotation
| '\u{E0000}'..='\u{E007F}' // language tags
)
}
/// Returns a `Cow<str>` borrowing `s` when no escaping is needed, otherwise an owned
/// escaped copy. Use this when an owned `&str`/`String` is required (e.g. ANSI paint).
pub fn sanitize_for_terminal(s: &str) -> Cow<'_, str> {
if !s.chars().any(needs_escape) {
return Cow::Borrowed(s);
}
let mut out = String::with_capacity(s.len());
for c in s.chars() {
if needs_escape(c) {
let v = c as u32;
if v <= 0xFF {
let _ = write!(out, "\\x{v:02X}");
} else {
let _ = write!(out, "\\u{{{v:04X}}}");
}
} else {
out.push(c);
}
}
Cow::Owned(out)
}
/// Sanitize for terminal output only; raw bytes pass through on pipes/files.
pub fn maybe_sanitize<'a>(s: &'a str, is_terminal: bool) -> Cow<'a, str> {
if is_terminal {
sanitize_for_terminal(s)
} else {
Cow::Borrowed(s)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn preserves_safe_content() {
for s in [
"hello.txt",
"résumé.pdf",
"文档.txt",
"🦀.rs",
"a\tb",
"a\u{FFFD}b",
] {
assert!(
matches!(sanitize_for_terminal(s), Cow::Borrowed(_)),
"{s:?}"
);
assert_eq!(sanitize_for_terminal(s), s);
}
}
#[test]
fn strips_osc52_clipboard_payload() {
let attack = "innocent\x1b]52;c;cHduZWQ=\x1b\\.txt";
let safe = sanitize_for_terminal(attack);
assert!(!safe.contains('\x1b'));
assert_eq!(safe, "innocent\\x1B]52;c;cHduZWQ=\\x1B\\.txt");
}
#[test]
fn strips_cr_output_forgery() {
assert_eq!(sanitize_for_terminal("A\rFAKE OUTPUT"), "A\\x0DFAKE OUTPUT");
}
#[test]
fn strips_osc8_hyperlink_injection() {
let attack = "phish\x1b]8;;https:evil.example\x1b\\phony.txt";
assert!(!sanitize_for_terminal(attack).contains('\x1b'));
}
#[test]
fn strips_del() {
assert_eq!(sanitize_for_terminal("a\x7fb"), "a\\x7Fb");
}
#[test]
fn strips_bel_and_null() {
assert_eq!(sanitize_for_terminal("a\x07b"), "a\\x07b");
assert_eq!(sanitize_for_terminal("a\0b"), "a\\x00b");
}
#[test]
fn strips_newline() {
assert_eq!(sanitize_for_terminal("a\nb"), "a\\x0Ab");
}
#[test]
fn escape_preserves_information() {
let s = "name\x1bX\x07Y.txt";
assert_eq!(sanitize_for_terminal(s), "name\\x1BX\\x07Y.txt");
}
#[test]
fn strips_c1_csi_and_osc_initiators() {
// U+009B is CSI, U+009D is OSC; dangerous on 8-bit-control terminals.
assert_eq!(sanitize_for_terminal("\u{9b}31m"), "\\x9B31m");
assert_eq!(
sanitize_for_terminal("\u{9d}0;pwned\u{9c}"),
"\\x9D0;pwned\\x9C"
);
}
#[test]
fn strips_bidi_overrides_and_zero_width() {
// Trojan-Source style RLO/LRO that flip rendered order of filename text.
assert_eq!(
sanitize_for_terminal("safe\u{202E}fil\u{202D}gnp.exe"),
"safe\\u{202E}fil\\u{202D}gnp.exe"
);
// Zero-width space and BOM are also format chars used to disguise filenames.
assert_eq!(sanitize_for_terminal("a\u{200B}b"), "a\\u{200B}b");
assert_eq!(sanitize_for_terminal("\u{FEFF}name"), "\\u{FEFF}name");
}
#[test]
fn keeps_legitimate_unicode_features() {
// Variation selectors (U+FE0F, U+E0100..) modify preceding glyphs in CJK/emoji
// and are legitimate in filenames. Private-use chars are used by icon fonts.
for s in [
"heart\u{2764}\u{FE0F}.txt",
"icon\u{E000}.cfg",
"cjk\u{6F22}\u{E0101}.txt",
] {
assert!(
matches!(sanitize_for_terminal(s), Cow::Borrowed(_)),
"{s:?}"
);
}
}
#[test]
fn maybe_sanitize_passthrough_when_not_terminal() {
let attack = "x\x1by";
// Pipe context: bytes pass through unchanged (zero-copy).
let out = maybe_sanitize(attack, false);
assert!(matches!(out, Cow::Borrowed(_)));
assert_eq!(out, attack);
// TTY context: escapes apply.
assert_eq!(maybe_sanitize(attack, true), "x\\x1By");
}
}
+514 -315
View File
@@ -1,25 +1,25 @@
use std::borrow::Cow;
use std::ffi::OsStr;
use std::io;
use std::io::{self, Write};
use std::mem;
use std::path::PathBuf;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
use std::sync::{Arc, Mutex, MutexGuard};
use std::thread;
use std::time::{Duration, Instant};
use std::{borrow::Cow, io::Write};
use anyhow::{anyhow, Result};
use crossbeam_channel::{bounded, Receiver, RecvTimeoutError, Sender};
use anyhow::{Result, anyhow};
use crossbeam_channel::{Receiver, RecvTimeoutError, SendError, Sender, bounded};
use etcetera::BaseStrategy;
use ignore::overrides::OverrideBuilder;
use ignore::{self, WalkBuilder};
use ignore::overrides::{Override, OverrideBuilder};
use ignore::{WalkBuilder, WalkParallel, WalkState};
use regex::bytes::Regex;
use crate::config::Config;
use crate::dir_entry::DirEntry;
use crate::error::print_error;
use crate::exec;
use crate::exit_codes::{merge_exitcodes, ExitCode};
use crate::exit_codes::{ExitCode, merge_exitcodes};
use crate::filesystem;
use crate::output;
@@ -36,6 +36,7 @@ enum ReceiverMode {
/// The Worker threads can result in a valid entry having PathBuf or an error.
#[allow(clippy::large_enum_variant)]
#[derive(Debug)]
pub enum WorkerResult {
// Errors should be rare, so it's probably better to allow large_enum_variant than
// to box the Entry variant
@@ -43,131 +44,98 @@ pub enum WorkerResult {
Error(ignore::Error),
}
/// Maximum size of the output buffer before flushing results to the console
pub const MAX_BUFFER_LENGTH: usize = 1000;
/// Default duration until output buffering switches to streaming.
pub const DEFAULT_MAX_BUFFER_TIME: Duration = Duration::from_millis(100);
/// A batch of WorkerResults to send over a channel.
#[derive(Clone)]
struct Batch {
items: Arc<Mutex<Option<Vec<WorkerResult>>>>,
}
/// Recursively scan the given search path for files / pathnames matching the patterns.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(paths: &[PathBuf], patterns: Arc<Vec<Regex>>, config: Arc<Config>) -> Result<ExitCode> {
let first_path = &paths[0];
// Channel capacity was chosen empircally to perform similarly to an unbounded channel
let (tx, rx) = bounded(0x4000 * config.threads);
let mut override_builder = OverrideBuilder::new(first_path);
for pattern in &config.exclude_patterns {
override_builder
.add(pattern)
.map_err(|e| anyhow!("Malformed exclude pattern: {}", e))?;
}
let overrides = override_builder
.build()
.map_err(|_| anyhow!("Mismatch in exclude patterns"))?;
let mut walker = WalkBuilder::new(first_path);
walker
.hidden(config.ignore_hidden)
.ignore(config.read_fdignore)
.parents(config.read_parent_ignore && (config.read_fdignore || config.read_vcsignore))
.git_ignore(config.read_vcsignore)
.git_global(config.read_vcsignore)
.git_exclude(config.read_vcsignore)
.require_git(config.require_git_to_read_vcsignore)
.overrides(overrides)
.follow_links(config.follow_links)
// No need to check for supported platforms, option is unavailable on unsupported ones
.same_file_system(config.one_file_system)
.max_depth(config.max_depth);
if config.read_fdignore {
walker.add_custom_ignore_filename(".fdignore");
}
if config.read_global_ignore {
if let Ok(basedirs) = etcetera::choose_base_strategy() {
let global_ignore_file = basedirs.config_dir().join("fd").join("ignore");
if global_ignore_file.is_file() {
let result = walker.add_ignore(global_ignore_file);
match result {
Some(ignore::Error::Partial(_)) => (),
Some(err) => {
print_error(format!("Malformed pattern in global ignore file. {}.", err));
}
None => (),
}
}
impl Batch {
fn new() -> Self {
Self {
items: Arc::new(Mutex::new(Some(vec![]))),
}
}
for ignore_file in &config.ignore_files {
let result = walker.add_ignore(ignore_file);
match result {
Some(ignore::Error::Partial(_)) => (),
Some(err) => {
print_error(format!("Malformed pattern in custom ignore file. {}.", err));
}
None => (),
}
}
for path in &paths[1..] {
walker.add(path);
}
let parallel_walker = walker.threads(config.threads).build_parallel();
// Flag for cleanly shutting down the parallel walk
let quit_flag = Arc::new(AtomicBool::new(false));
// Flag specifically for quitting due to ^C
let interrupt_flag = Arc::new(AtomicBool::new(false));
if config.ls_colors.is_some() && config.is_printing() {
let quit_flag = Arc::clone(&quit_flag);
let interrupt_flag = Arc::clone(&interrupt_flag);
ctrlc::set_handler(move || {
quit_flag.store(true, Ordering::Relaxed);
if interrupt_flag.fetch_or(true, Ordering::Relaxed) {
// Ctrl-C has been pressed twice, exit NOW
ExitCode::KilledBySigint.exit();
}
})
.unwrap();
}
// Spawn the thread that receives all results through the channel.
let receiver_thread = spawn_receiver(&config, &quit_flag, &interrupt_flag, rx);
// Spawn the sender threads.
spawn_senders(&config, &quit_flag, patterns, parallel_walker, tx);
// Wait for the receiver thread to print out all results.
let exit_code = receiver_thread.join().unwrap();
if interrupt_flag.load(Ordering::Relaxed) {
Ok(ExitCode::KilledBySigint)
} else {
Ok(exit_code)
fn lock(&self) -> MutexGuard<'_, Option<Vec<WorkerResult>>> {
self.items.lock().unwrap()
}
}
impl IntoIterator for Batch {
type Item = WorkerResult;
type IntoIter = std::vec::IntoIter<WorkerResult>;
fn into_iter(self) -> Self::IntoIter {
self.lock().take().unwrap().into_iter()
}
}
/// Wrapper that sends batches of items at once over a channel.
struct BatchSender {
batch: Batch,
tx: Sender<Batch>,
limit: usize,
}
impl BatchSender {
fn new(tx: Sender<Batch>, limit: usize) -> Self {
Self {
batch: Batch::new(),
tx,
limit,
}
}
/// Check if we need to flush a batch.
fn needs_flush(&self, batch: Option<&Vec<WorkerResult>>) -> bool {
match batch {
// Limit the batch size to provide some backpressure
Some(vec) => vec.len() >= self.limit,
// Batch was already taken by the receiver, so make a new one
None => true,
}
}
/// Add an item to a batch.
fn send(&mut self, item: WorkerResult) -> Result<(), SendError<()>> {
let mut batch = self.batch.lock();
if self.needs_flush(batch.as_ref()) {
drop(batch);
self.batch = Batch::new();
batch = self.batch.lock();
}
let items = batch.as_mut().unwrap();
items.push(item);
if items.len() == 1 {
// New batch, send it over the channel
self.tx
.send(self.batch.clone())
.map_err(|_| SendError(()))?;
}
Ok(())
}
}
/// Maximum size of the output buffer before flushing results to the console
const MAX_BUFFER_LENGTH: usize = 1000;
/// Default duration until output buffering switches to streaming.
const DEFAULT_MAX_BUFFER_TIME: Duration = Duration::from_millis(100);
/// Wrapper for the receiver thread's buffering behavior.
struct ReceiverBuffer<W> {
struct ReceiverBuffer<'a, W> {
/// The configuration.
config: Arc<Config>,
config: &'a Config,
/// For shutting down the senders.
quit_flag: Arc<AtomicBool>,
quit_flag: &'a AtomicBool,
/// The ^C notifier.
interrupt_flag: Arc<AtomicBool>,
interrupt_flag: &'a AtomicBool,
/// Receiver for worker results.
rx: Receiver<WorkerResult>,
rx: Receiver<Batch>,
/// Standard output.
stdout: W,
/// The current buffer mode.
@@ -180,15 +148,12 @@ struct ReceiverBuffer<W> {
num_results: usize,
}
impl<W: Write> ReceiverBuffer<W> {
impl<'a, W: Write> ReceiverBuffer<'a, W> {
/// Create a new receiver buffer.
fn new(
config: Arc<Config>,
quit_flag: Arc<AtomicBool>,
interrupt_flag: Arc<AtomicBool>,
rx: Receiver<WorkerResult>,
stdout: W,
) -> Self {
fn new(state: &'a WorkerState, rx: Receiver<Batch>, stdout: W) -> Self {
let config = &state.config;
let quit_flag = state.quit_flag.as_ref();
let interrupt_flag = state.interrupt_flag.as_ref();
let max_buffer_time = config.max_buffer_time.unwrap_or(DEFAULT_MAX_BUFFER_TIME);
let deadline = Instant::now() + max_buffer_time;
@@ -216,7 +181,7 @@ impl<W: Write> ReceiverBuffer<W> {
}
/// Receive the next worker result.
fn recv(&self) -> Result<WorkerResult, RecvTimeoutError> {
fn recv(&self) -> Result<Batch, RecvTimeoutError> {
match self.mode {
ReceiverMode::Buffering => {
// Wait at most until we should switch to streaming
@@ -232,34 +197,44 @@ impl<W: Write> ReceiverBuffer<W> {
/// Wait for a result or state change.
fn poll(&mut self) -> Result<(), ExitCode> {
match self.recv() {
Ok(WorkerResult::Entry(dir_entry)) => {
if self.config.quiet {
return Err(ExitCode::HasResults(true));
}
Ok(batch) => {
for result in batch {
match result {
WorkerResult::Entry(dir_entry) => {
if self.config.quiet {
return Err(ExitCode::HasResults(true));
}
match self.mode {
ReceiverMode::Buffering => {
self.buffer.push(dir_entry);
if self.buffer.len() > MAX_BUFFER_LENGTH {
self.stream()?;
match self.mode {
ReceiverMode::Buffering => {
self.buffer.push(dir_entry);
if self.buffer.len() > MAX_BUFFER_LENGTH {
self.stream()?;
}
}
ReceiverMode::Streaming => {
self.print(&dir_entry)?;
}
}
self.num_results += 1;
if let Some(max_results) = self.config.max_results
&& self.num_results >= max_results
{
return self.stop();
}
}
WorkerResult::Error(err) => {
if self.config.show_filesystem_errors {
print_error(err.to_string());
}
}
}
ReceiverMode::Streaming => {
self.print(&dir_entry)?;
self.flush()?;
}
}
self.num_results += 1;
if let Some(max_results) = self.config.max_results {
if self.num_results >= max_results {
return self.stop();
}
}
}
Ok(WorkerResult::Error(err)) => {
if self.config.show_filesystem_errors {
print_error(err.to_string());
// If we don't have another batch ready, flush before waiting
if self.mode == ReceiverMode::Streaming && self.rx.is_empty() {
self.flush()?;
}
}
Err(RecvTimeoutError::Timeout) => {
@@ -275,7 +250,12 @@ impl<W: Write> ReceiverBuffer<W> {
/// Output a path.
fn print(&mut self, entry: &DirEntry) -> Result<(), ExitCode> {
output::print_entry(&mut self.stdout, entry, &self.config);
if let Err(e) = output::print_entry(&mut self.stdout, entry, self.config)
&& e.kind() != ::std::io::ErrorKind::BrokenPipe
{
print_error(format!("Could not write to output: {e}"));
return Err(ExitCode::GeneralError);
}
if self.interrupt_flag.load(Ordering::Relaxed) {
// Ignore any errors on flush, because we're about to exit anyway
@@ -314,7 +294,7 @@ impl<W: Write> ReceiverBuffer<W> {
/// Flush stdout if necessary.
fn flush(&mut self) -> Result<(), ExitCode> {
if self.config.interactive_terminal && self.stdout.flush().is_err() {
if self.stdout.flush().is_err() {
// Probably a broken pipe. Exit gracefully.
return Err(ExitCode::GeneralError);
}
@@ -322,33 +302,127 @@ impl<W: Write> ReceiverBuffer<W> {
}
}
fn spawn_receiver(
config: &Arc<Config>,
quit_flag: &Arc<AtomicBool>,
interrupt_flag: &Arc<AtomicBool>,
rx: Receiver<WorkerResult>,
) -> thread::JoinHandle<ExitCode> {
let config = Arc::clone(config);
let quit_flag = Arc::clone(quit_flag);
let interrupt_flag = Arc::clone(interrupt_flag);
/// State shared by the sender and receiver threads.
struct WorkerState {
/// The search patterns.
patterns: Vec<Regex>,
/// The command line configuration.
config: Config,
/// Flag for cleanly shutting down the parallel walk
quit_flag: Arc<AtomicBool>,
/// Flag specifically for quitting due to ^C
interrupt_flag: Arc<AtomicBool>,
}
impl WorkerState {
fn new(patterns: Vec<Regex>, config: Config) -> Self {
let quit_flag = Arc::new(AtomicBool::new(false));
let interrupt_flag = Arc::new(AtomicBool::new(false));
Self {
patterns,
config,
quit_flag,
interrupt_flag,
}
}
fn build_overrides(&self, paths: &[PathBuf]) -> Result<Override> {
let first_path = &paths[0];
let config = &self.config;
let mut builder = OverrideBuilder::new(first_path);
for pattern in &config.exclude_patterns {
builder
.add(pattern)
.map_err(|e| anyhow!("Malformed exclude pattern: {}", e))?;
}
builder
.build()
.map_err(|_| anyhow!("Mismatch in exclude patterns"))
}
fn build_walker(&self, paths: &[PathBuf]) -> Result<WalkParallel> {
let first_path = &paths[0];
let config = &self.config;
let overrides = self.build_overrides(paths)?;
let mut builder = WalkBuilder::new(first_path);
builder
.hidden(config.ignore_hidden)
.ignore(config.read_fdignore)
.parents(config.read_parent_ignore && (config.read_fdignore || config.read_vcsignore))
.git_ignore(config.read_vcsignore)
.git_global(config.read_vcsignore)
.git_exclude(config.read_vcsignore)
.require_git(config.require_git_to_read_vcsignore)
.overrides(overrides)
.follow_links(config.follow_links)
// No need to check for supported platforms, option is unavailable on unsupported ones
.same_file_system(config.one_file_system)
.max_depth(config.max_depth);
if config.read_fdignore {
builder.add_custom_ignore_filename(".fdignore");
}
if config.read_global_ignore
&& let Ok(basedirs) = etcetera::choose_base_strategy()
{
let global_ignore_file = basedirs.config_dir().join("fd").join("ignore");
if global_ignore_file.is_file() {
let result = builder.add_ignore(global_ignore_file);
match result {
Some(ignore::Error::Partial(_)) => (),
Some(err) => {
print_error(format!("Malformed pattern in global ignore file. {err}."));
}
None => (),
}
}
}
for ignore_file in &config.ignore_files {
let result = builder.add_ignore(ignore_file);
match result {
Some(ignore::Error::Partial(_)) => (),
Some(err) => {
print_error(format!("Malformed pattern in custom ignore file. {err}."));
}
None => (),
}
}
for path in &paths[1..] {
builder.add(path);
}
let walker = builder.threads(config.threads).build_parallel();
Ok(walker)
}
/// Run the receiver work, either on this thread or a pool of background
/// threads (for --exec).
fn receive(&self, rx: Receiver<Batch>) -> ExitCode {
let config = &self.config;
let threads = config.threads;
thread::spawn(move || {
// This will be set to `Some` if the `--exec` argument was supplied.
if let Some(ref cmd) = config.command {
if cmd.in_batch_mode() {
exec::batch(rx, cmd, &config)
exec::batch(rx.into_iter().flatten(), cmd, config)
} else {
let out_perm = Mutex::new(());
thread::scope(|scope| {
// Each spawned job will store it's thread handle in here.
// Each spawned job will store its thread handle in here.
let threads = config.threads;
let mut handles = Vec::with_capacity(threads);
for _ in 0..threads {
let rx = rx.clone();
// Spawn a job thread that will listen for and execute inputs.
let handle = scope.spawn(|| exec::job(rx, cmd, &out_perm, &config));
let handle =
scope.spawn(|| exec::job(rx.into_iter().flatten(), cmd, config));
// Push the handle of the spawned thread into the vector for later joining.
handles.push(handle);
@@ -358,188 +432,313 @@ fn spawn_receiver(
})
}
} else {
let stdout = io::stdout();
let stdout = stdout.lock();
let stdout = io::stdout().lock();
let stdout = io::BufWriter::new(stdout);
let mut rxbuffer = ReceiverBuffer::new(config, quit_flag, interrupt_flag, rx, stdout);
rxbuffer.process()
ReceiverBuffer::new(self, rx, stdout).process()
}
})
}
}
fn spawn_senders(
config: &Arc<Config>,
quit_flag: &Arc<AtomicBool>,
patterns: Arc<Vec<Regex>>,
parallel_walker: ignore::WalkParallel,
tx: Sender<WorkerResult>,
) {
parallel_walker.run(|| {
let config = Arc::clone(config);
let patterns = Arc::clone(&patterns);
let tx_thread = tx.clone();
let quit_flag = Arc::clone(quit_flag);
/// Spawn the sender threads.
fn spawn_senders(&self, walker: WalkParallel, tx: Sender<Batch>) {
walker.run(|| {
let patterns = &self.patterns;
let config = &self.config;
let quit_flag = self.quit_flag.as_ref();
Box::new(move |entry_o| {
if quit_flag.load(Ordering::Relaxed) {
return ignore::WalkState::Quit;
let mut limit = 0x100;
if let Some(cmd) = &config.command
&& !cmd.in_batch_mode()
&& config.threads > 1
{
// Evenly distribute work between multiple receivers
limit = 1;
}
let mut tx = BatchSender::new(tx.clone(), limit);
let entry = match entry_o {
Ok(ref e) if e.depth() == 0 => {
// Skip the root directory entry.
return ignore::WalkState::Continue;
Box::new(move |entry| {
if quit_flag.load(Ordering::Relaxed) {
return WalkState::Quit;
}
Ok(e) => DirEntry::normal(e),
Err(ignore::Error::WithPath {
path,
err: inner_err,
}) => match inner_err.as_ref() {
ignore::Error::Io(io_error)
if io_error.kind() == io::ErrorKind::NotFound
&& path
.symlink_metadata()
.ok()
.map_or(false, |m| m.file_type().is_symlink()) =>
if let Ok(e) = &entry {
// If the entry is a directory that contains a
// "ignore contain" file", we want to skip this
// directory.
// Check the filetype first to avoid unnecessary
// syscalls.
if e.file_type().is_some_and(|t| t.is_dir()) {
let entry_path = e.path();
if config
.ignore_contain
.iter()
.any(|ic| entry_path.join(ic).exists())
{
return WalkState::Skip;
}
}
if e.depth() == 0 {
// Skip the root directory entry.
return WalkState::Continue;
}
}
let entry = match entry {
Ok(e) => DirEntry::normal(e),
Err(ignore::Error::WithPath {
path,
err: inner_err,
}) if inner_err
.io_error()
.is_some_and(|io_error| io_error.kind() == io::ErrorKind::NotFound)
&& path
.symlink_metadata()
.ok()
.is_some_and(|m| m.file_type().is_symlink()) =>
{
DirEntry::broken_symlink(path)
}
_ => {
return match tx_thread.send(WorkerResult::Error(ignore::Error::WithPath {
path,
err: inner_err,
})) {
Ok(_) => ignore::WalkState::Continue,
Err(_) => ignore::WalkState::Quit,
}
}
},
Err(err) => {
return match tx_thread.send(WorkerResult::Error(err)) {
Ok(_) => ignore::WalkState::Continue,
Err(_) => ignore::WalkState::Quit,
Err(err) => {
return match tx.send(WorkerResult::Error(err)) {
Ok(_) => WalkState::Continue,
Err(_) => WalkState::Quit,
};
}
};
if let Some(min_depth) = config.min_depth
&& entry.depth().is_none_or(|d| d < min_depth)
{
return WalkState::Continue;
}
};
if let Some(min_depth) = config.min_depth {
if entry.depth().map_or(true, |d| d < min_depth) {
return ignore::WalkState::Continue;
// Check the name first, since it doesn't require metadata
let entry_path = entry.path();
let search_str = search_str_for_entry(entry_path, config.full_path_base.as_deref());
if !patterns
.iter()
.all(|pat| pat.is_match(&filesystem::osstr_to_bytes(search_str.as_ref())))
{
return WalkState::Continue;
}
}
// Check the name first, since it doesn't require metadata
let entry_path = entry.path();
let search_str: Cow<OsStr> = if config.search_full_path {
let path_abs_buf = filesystem::path_absolute_form(entry_path)
.expect("Retrieving absolute path succeeds");
Cow::Owned(path_abs_buf.as_os_str().to_os_string())
} else {
match entry_path.file_name() {
Some(filename) => Cow::Borrowed(filename),
None => unreachable!(
"Encountered file system entry without a file name. This should only \
happen for paths like 'foo/bar/..' or '/' which are not supposed to \
appear in a file system traversal."
),
}
};
if !patterns
.iter()
.all(|pat| pat.is_match(&filesystem::osstr_to_bytes(search_str.as_ref())))
{
return ignore::WalkState::Continue;
}
// Filter out unwanted extensions.
if let Some(ref exts_regex) = config.extensions {
if let Some(path_str) = entry_path.file_name() {
if !exts_regex.is_match(&filesystem::osstr_to_bytes(path_str)) {
return ignore::WalkState::Continue;
}
} else {
return ignore::WalkState::Continue;
}
}
// Filter out unwanted file types.
if let Some(ref file_types) = config.file_types {
if file_types.should_ignore(&entry) {
return ignore::WalkState::Continue;
}
}
#[cfg(unix)]
{
if let Some(ref owner_constraint) = config.owner_constraint {
if let Some(metadata) = entry.metadata() {
if !owner_constraint.matches(metadata) {
return ignore::WalkState::Continue;
// Filter out unwanted extensions.
if let Some(ref exts_regex) = config.extensions {
if let Some(path_str) = entry_path.file_name() {
if !exts_regex.is_match(&filesystem::osstr_to_bytes(path_str)) {
return WalkState::Continue;
}
} else {
return ignore::WalkState::Continue;
return WalkState::Continue;
}
}
}
// Filter out unwanted sizes if it is a file and we have been given size constraints.
if !config.size_constraints.is_empty() {
if entry_path.is_file() {
if let Some(metadata) = entry.metadata() {
let file_size = metadata.len();
if config
.size_constraints
.iter()
.any(|sc| !sc.is_within(file_size))
{
return ignore::WalkState::Continue;
// Filter out unwanted file types.
if let Some(ref file_types) = config.file_types
&& file_types.should_ignore(&entry)
{
return WalkState::Continue;
}
#[cfg(unix)]
{
if let Some(ref owner_constraint) = config.owner_constraint {
if let Some(metadata) = entry.metadata() {
if !owner_constraint.matches(metadata) {
return WalkState::Continue;
}
} else {
return WalkState::Continue;
}
}
}
// Filter out unwanted sizes if it is a file and we have been given size constraints.
if !config.size_constraints.is_empty() {
if entry_path.is_file() {
if let Some(metadata) = entry.metadata() {
let file_size = metadata.len();
if config
.size_constraints
.iter()
.any(|sc| !sc.is_within(file_size))
{
return WalkState::Continue;
}
} else {
return WalkState::Continue;
}
} else {
return ignore::WalkState::Continue;
return WalkState::Continue;
}
} else {
return ignore::WalkState::Continue;
}
}
// Filter out unwanted modification times
if !config.time_constraints.is_empty() {
let mut matched = false;
if let Some(metadata) = entry.metadata() {
if let Ok(modified) = metadata.modified() {
// Filter out unwanted modification times
if !config.time_constraints.is_empty() {
let mut matched = false;
if let Some(metadata) = entry.metadata()
&& let Ok(modified) = metadata.modified()
{
matched = config
.time_constraints
.iter()
.all(|tf| tf.applies_to(&modified));
}
if !matched {
return WalkState::Continue;
}
}
if !matched {
return ignore::WalkState::Continue;
}
}
if config.is_printing() {
if let Some(ls_colors) = &config.ls_colors {
if config.is_printing()
&& let Some(ls_colors) = &config.ls_colors
{
// Compute colors in parallel
entry.style(ls_colors);
}
}
let send_result = tx_thread.send(WorkerResult::Entry(entry));
let send_result = tx.send(WorkerResult::Entry(entry));
if send_result.is_err() {
return ignore::WalkState::Quit;
}
if send_result.is_err() {
return WalkState::Quit;
}
// Apply pruning.
if config.prune {
return ignore::WalkState::Skip;
}
// Apply pruning.
if config.prune {
return WalkState::Skip;
}
ignore::WalkState::Continue
})
});
WalkState::Continue
})
});
}
/// Perform the recursive scan.
fn scan(&self, paths: &[PathBuf]) -> Result<ExitCode> {
let config = &self.config;
let walker = self.build_walker(paths)?;
if config.ls_colors.is_some() && config.is_printing() {
let quit_flag = Arc::clone(&self.quit_flag);
let interrupt_flag = Arc::clone(&self.interrupt_flag);
ctrlc::set_handler(move || {
quit_flag.store(true, Ordering::Relaxed);
if interrupt_flag.fetch_or(true, Ordering::Relaxed) {
// Ctrl-C has been pressed twice, exit NOW
ExitCode::KilledBySigint.exit();
}
})
.unwrap();
}
let (tx, rx) = bounded(2 * config.threads);
let exit_code = thread::scope(|scope| {
// Spawn the receiver thread(s)
let receiver = scope.spawn(|| self.receive(rx));
// Spawn the sender threads.
self.spawn_senders(walker, tx);
receiver.join().unwrap()
});
if self.interrupt_flag.load(Ordering::Relaxed) {
Ok(ExitCode::KilledBySigint)
} else {
Ok(exit_code)
}
}
}
fn search_str_for_entry<'a>(
entry_path: &'a std::path::Path,
full_path_base: Option<&std::path::Path>,
) -> Cow<'a, OsStr> {
if let Some(cwd) = full_path_base {
// If full_path_base is some, that means that we need to return
// the absolute path
if entry_path.is_absolute() {
return Cow::Borrowed(entry_path.as_os_str());
}
let path = entry_path.strip_prefix(".").unwrap_or(entry_path);
Cow::Owned(cwd.join(path).into())
} else {
match entry_path.file_name() {
Some(filename) => Cow::Borrowed(filename),
None => unreachable!(
"Encountered file system entry without a file name. This should only \
happen for paths like 'foo/bar/..' or '/' which are not supposed to \
appear in a file system traversal."
),
}
}
}
/// Recursively scan the given search path for files / pathnames matching the patterns.
///
/// If the `--exec` argument was supplied, this will create a thread pool for executing
/// jobs in parallel from a given command line and the discovered paths. Otherwise, each
/// path will simply be written to standard output.
pub fn scan(paths: &[PathBuf], patterns: Vec<Regex>, config: Config) -> Result<ExitCode> {
WorkerState::new(patterns, config).scan(paths)
}
#[cfg(test)]
mod tests {
use super::search_str_for_entry;
use std::path::{Path, PathBuf};
#[test]
fn search_str_for_entry_with_relative_path() {
let full_path_base = Some(Path::new("/home/user"));
assert_eq!(
search_str_for_entry(Path::new("foo/bar"), full_path_base),
PathBuf::from("/home/user/foo/bar")
);
}
#[test]
fn search_str_for_entry_strips_dot_prefix() {
let full_path_base = Some(Path::new("/home/user"));
assert_eq!(
search_str_for_entry(Path::new("./foo/bar"), full_path_base),
PathBuf::from("/home/user/foo/bar")
);
}
#[test]
fn search_str_for_entry_with_absolute_path() {
let full_path_base = Some(Path::new("/home/user"));
assert_eq!(
search_str_for_entry(Path::new("/absolute/path"), full_path_base),
PathBuf::from("/absolute/path")
);
}
#[test]
fn search_str_no_base_dir() {
assert_eq!(
search_str_for_entry(Path::new("./foo/bar"), None),
PathBuf::from("bar")
);
}
#[test]
fn search_str_no_base_dir_with_plain_relative_path() {
assert_eq!(
search_str_for_entry(Path::new("foo/bar"), None),
PathBuf::from("bar")
);
}
#[test]
fn search_str_no_base_dir_with_file_in_current_dir() {
assert_eq!(
search_str_for_entry(Path::new("foo"), None),
PathBuf::from("foo")
);
}
}
+10 -17
View File
@@ -74,18 +74,8 @@ fn create_config_directory_with_global_ignore(ignore_file_content: &str) -> io::
/// Find the *fd* executable.
fn find_fd_exe() -> PathBuf {
// Tests exe is in target/debug/deps, the *fd* exe is in target/debug
let root = env::current_exe()
.expect("tests executable")
.parent()
.expect("tests executable directory")
.parent()
.expect("fd executable directory")
.to_path_buf();
let exe_name = if cfg!(windows) { "fd.exe" } else { "fd" };
root.join(exe_name)
// Read the location of the fd executable from the environment
PathBuf::from(env::var("CARGO_BIN_EXE_fd").unwrap_or(env!("CARGO_BIN_EXE_fd").to_string()))
}
/// Format an error message for when *fd* did not exit successfully.
@@ -104,9 +94,9 @@ fn format_output_error(args: &[&str], expected: &str, actual: &str) -> String {
let diff_text = diff::lines(expected, actual)
.into_iter()
.map(|diff| match diff {
diff::Result::Left(l) => format!("-{}", l),
diff::Result::Both(l, _) => format!(" {}", l),
diff::Result::Right(r) => format!("+{}", r),
diff::Result::Left(l) => format!("-{l}"),
diff::Result::Both(l, _) => format!(" {l}"),
diff::Result::Right(r) => format!("+{r}"),
})
.collect::<Vec<_>>()
.join("\n");
@@ -129,7 +119,7 @@ fn normalize_output(s: &str, trim_start: bool, normalize_line: bool) -> String {
.lines()
.map(|line| {
let line = if trim_start { line.trim_start() } else { line };
let line = line.replace('/', &std::path::MAIN_SEPARATOR.to_string());
let line = line.replace('/', std::path::MAIN_SEPARATOR_STR);
if normalize_line {
let mut words: Vec<_> = line.split_whitespace().collect();
words.sort_unstable();
@@ -290,7 +280,7 @@ impl TestEnv {
pub fn assert_failure_with_error(&self, args: &[&str], expected: &str) {
let status = self.assert_error_subdirectory(".", args, Some(expected));
if status.success() {
panic!("error '{}' did not occur.", expected);
panic!("error '{expected}' did not occur.");
}
}
@@ -316,6 +306,9 @@ impl TestEnv {
} else {
cmd.arg("--no-global-ignore-file");
}
// Make sure LS_COLORS is unset to ensure consistent
// color output
cmd.env("LS_COLORS", "");
cmd.args(args);
// Run *fd*.
+366 -44
View File
@@ -1,11 +1,14 @@
mod testenv;
#[cfg(unix)]
use nix::unistd::{Gid, Group, Uid, User};
use std::fs;
use std::io::Write;
use std::path::Path;
use std::time::{Duration, SystemTime};
use test_case::test_case;
use jiff::Timestamp;
use normpath::PathExt;
use regex::escape;
@@ -371,6 +374,74 @@ fn test_multi_file_with_missing() {
);
}
/// Without --full-path, a pattern containing '/' should always produce the
/// path-separator diagnostic, even if the pattern does not name an existing
/// directory. Before the fix for sharkdp/fd#1873 this only fired when the
/// pattern happened to resolve to a real directory, so the common typo of
/// pasting a full path silently returned zero matches.
#[test]
fn test_pattern_with_forward_slash_is_rejected() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
// Pattern that is NOT a real directory; old behaviour: no warning.
te.assert_failure_with_error(
&["nonexistent/path"],
"[fd error]: The search pattern 'nonexistent/path' contains a path-separation character and will not lead to any search results.",
);
// Pattern that IS a real directory; old behaviour: warning. Must still fire.
te.assert_failure_with_error(
&["one/two/three"],
"[fd error]: The search pattern 'one/two/three' contains a path-separation character and will not lead to any search results.",
);
}
/// --full-path is the user's explicit opt-in to regex-over-full-path matching,
/// so a path-separation character in the pattern is expected and must not
/// trigger the diagnostic.
///
/// Gated off Windows: the actual match is regex-over-the-full-path, so a
/// forward-slash pattern only matches Unix-style paths. On Windows the OS
/// uses `\` and `one/two/c` (as a literal regex) does not match a real
/// entry — the behaviour this test is pinning (the diagnostic does not
/// fire) is covered by the fact that the invocation does not error.
#[test]
#[cfg(not(windows))]
fn test_pattern_with_forward_slash_allowed_with_full_path() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--full-path", "one/two/c"],
"one/two/c.foo
one/two/C.Foo2",
);
}
/// `--and` patterns are matched against the file name exactly like the primary
/// pattern, so a path separator in any of them is the same silent "no results"
/// footgun and must trigger the same diagnostic. Regression for the sibling of
/// #1873 left unchecked by #1975 (only the positional pattern was validated).
#[test]
fn test_and_pattern_with_forward_slash_is_rejected() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
// Clean primary pattern, but a `--and` pattern carrying a path separator.
te.assert_failure_with_error(
&["foo", "--and", "nonexistent/path"],
"[fd error]: The search pattern 'nonexistent/path' contains a path-separation character and will not lead to any search results.",
);
// `--full-path` is the explicit opt-in and must still suppress the
// diagnostic for `--and` patterns too (the invocation runs and matches
// instead of erroring on the path separator).
#[cfg(not(windows))]
te.assert_output(
&["--full-path", "one/two/c", "--and", "two/c"],
"one/two/c.foo
one/two/C.Foo2",
);
}
/// Explicit root path
#[test]
fn test_explicit_root_path() {
@@ -413,6 +484,13 @@ fn test_explicit_root_path() {
);
}
#[test]
fn test_single_dash_root_path() {
let te = TestEnv::new(&["-"], &["-/foo"]);
te.assert_output(&[".", "-"], "./-/foo");
}
/// Regex searches
#[test]
fn test_regex_searches() {
@@ -593,10 +671,7 @@ fn test_full_path() {
let prefix = escape(&root.to_string_lossy());
te.assert_output(
&[
"--full-path",
&format!("^{prefix}.*three.*foo$", prefix = prefix),
],
&["--full-path", &format!("^{prefix}.*three.*foo$")],
"one/two/three/d.foo
one/two/three/directory_foo/",
);
@@ -1199,7 +1274,7 @@ fn test_absolute_path() {
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo/
{abs_path}/symlink",
abs_path = &abs_path
abs_path = abs_path
),
);
@@ -1212,7 +1287,7 @@ fn test_absolute_path() {
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo/",
abs_path = &abs_path
abs_path = abs_path
),
);
}
@@ -1231,7 +1306,7 @@ fn test_implicit_absolute_path() {
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo/",
abs_path = &abs_path
abs_path = abs_path
),
);
}
@@ -1251,7 +1326,7 @@ fn test_normalized_absolute_path() {
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo/",
abs_path = &abs_path
abs_path = abs_path
),
);
}
@@ -1302,14 +1377,15 @@ fn test_type_executable() {
// This test assumes the current user isn't root
// (otherwise if the executable bit is set for any level, it is executable for the current
// user)
if users::get_current_uid() == 0 {
if Uid::current().is_root() {
return;
}
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
fs::OpenOptions::new()
.create(true)
.create_new(true)
.truncate(true)
.write(true)
.mode(0o777)
.open(te.test_root().join("executable-file.sh"))
@@ -1317,6 +1393,7 @@ fn test_type_executable() {
fs::OpenOptions::new()
.create(true)
.truncate(true)
.write(true)
.mode(0o645)
.open(te.test_root().join("not-user-executable-file.sh"))
@@ -1483,7 +1560,7 @@ fn test_symlink_as_root() {
{dir}/one/two/three/d.foo
{dir}/one/two/three/directory_foo/
{dir}/symlink",
dir = &parent_parent
dir = parent_parent
),
);
}
@@ -1503,7 +1580,7 @@ fn test_symlink_and_absolute_path() {
{abs_path}/{expected_path}/three/
{abs_path}/{expected_path}/three/d.foo
{abs_path}/{expected_path}/three/directory_foo/",
abs_path = &abs_path,
abs_path = abs_path,
expected_path = expected_path
),
);
@@ -1514,14 +1591,14 @@ fn test_symlink_as_absolute_root() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["", &format!("{abs_path}/symlink", abs_path = abs_path)],
&["", &format!("{abs_path}/symlink")],
&format!(
"{abs_path}/symlink/c.foo
{abs_path}/symlink/C.Foo2
{abs_path}/symlink/three/
{abs_path}/symlink/three/d.foo
{abs_path}/symlink/three/directory_foo/",
abs_path = &abs_path
abs_path = abs_path
),
);
}
@@ -1539,13 +1616,13 @@ fn test_symlink_and_full_path() {
&[
"--absolute-path",
"--full-path",
&format!("^{prefix}.*three", prefix = prefix),
&format!("^{prefix}.*three"),
],
&format!(
"{abs_path}/{expected_path}/three/
{abs_path}/{expected_path}/three/d.foo
{abs_path}/{expected_path}/three/directory_foo/",
abs_path = &abs_path,
abs_path = abs_path,
expected_path = expected_path
),
);
@@ -1559,14 +1636,14 @@ fn test_symlink_and_full_path_abs_path() {
te.assert_output(
&[
"--full-path",
&format!("^{prefix}.*symlink.*three", prefix = prefix),
&format!("{abs_path}/symlink", abs_path = abs_path),
&format!("^{prefix}.*symlink.*three"),
&format!("{abs_path}/symlink"),
],
&format!(
"{abs_path}/symlink/three/
{abs_path}/symlink/three/d.foo
{abs_path}/symlink/three/directory_foo/",
abs_path = &abs_path
abs_path = abs_path
),
);
}
@@ -1620,6 +1697,66 @@ fn test_excludes() {
);
}
#[test]
fn format() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["--format", "path={}", "--path-separator=/"],
"path=a.foo
path=e1 e2
path=one
path=one/b.foo
path=one/two
path=one/two/C.Foo2
path=one/two/c.foo
path=one/two/three
path=one/two/three/d.foo
path=one/two/three/directory_foo
path=symlink",
);
te.assert_output(
&["foo", "--format", "noExt={.}", "--path-separator=/"],
"noExt=a
noExt=one/b
noExt=one/two/C
noExt=one/two/c
noExt=one/two/three/d
noExt=one/two/three/directory_foo",
);
te.assert_output(
&["foo", "--format", "basename={/}", "--path-separator=/"],
"basename=a.foo
basename=b.foo
basename=C.Foo2
basename=c.foo
basename=d.foo
basename=directory_foo",
);
te.assert_output(
&["foo", "--format", "name={/.}", "--path-separator=/"],
"name=a
name=b
name=C
name=c
name=d
name=directory_foo",
);
te.assert_output(
&["foo", "--format", "parent={//}", "--path-separator=/"],
"parent=.
parent=one
parent=one/two
parent=one/two
parent=one/two/three
parent=one/two/three",
);
}
/// Shell script execution (--exec)
#[test]
fn test_exec() {
@@ -1635,7 +1772,7 @@ fn test_exec() {
{abs_path}/one/two/c.foo
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo",
abs_path = &abs_path
abs_path = abs_path
),
);
@@ -1703,12 +1840,10 @@ fn test_exec() {
}
}
// TODO test for windows
#[cfg(not(windows))]
#[test]
fn test_exec_multi() {
// TODO test for windows
if cfg!(windows) {
return;
}
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
@@ -1736,7 +1871,7 @@ fn test_exec_multi() {
test c.foo
test d.foo
test directory_foo",
abs_path = &abs_path
abs_path = abs_path
),
);
@@ -1751,9 +1886,11 @@ fn test_exec_multi() {
e1 e2",
);
// We use printf here because we need to suppress a newline and
// echo -n is not POSIX-compliant.
te.assert_output(
&[
"foo", "--exec", "echo", "-n", "{/}: ", ";", "--exec", "echo", "{//}",
"foo", "--exec", "printf", "%s", "{/}: ", ";", "--exec", "printf", "%s\\n", "{//}",
],
"a.foo: .
b.foo: ./one
@@ -1764,6 +1901,21 @@ fn test_exec_multi() {
);
}
#[cfg(not(windows))]
#[test]
fn test_exec_nulls() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
te.assert_output(
&["foo", "--print0", "--exec", "printf", "p=%s"],
"p=./a.fooNULL
p=./one/b.fooNULL
p=./one/two/C.Foo2NULL
p=./one/two/c.fooNULL
p=./one/two/three/d.fooNULL
p=./one/two/three/directory_fooNULL",
);
}
#[test]
fn test_exec_batch() {
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
@@ -1775,7 +1927,7 @@ fn test_exec_batch() {
&["--absolute-path", "foo", "--exec-batch", "echo"],
&format!(
"{abs_path}/a.foo {abs_path}/one/b.foo {abs_path}/one/two/C.Foo2 {abs_path}/one/two/c.foo {abs_path}/one/two/three/d.foo {abs_path}/one/two/three/directory_foo",
abs_path = &abs_path
abs_path = abs_path
),
);
@@ -1829,7 +1981,7 @@ fn test_exec_batch() {
te.assert_failure_with_error(
&["foo", "--exec-batch", "echo {}"],
"error: First argument of exec-batch is expected to be a fixed executable\n\
"error: First argument of --exec-batch must be a fixed executable, not a placeholder\n\
\n\
Usage: fd [OPTIONS] [pattern] [path]...\n\
\n\
@@ -2058,14 +2210,57 @@ fn test_fixed_strings() {
// Regex search, parens are treated as group
te.assert_output(&["download (1)"], "");
// Literal search, parens are treated as characters
// Literal search, parens are treated as characters. Case-insensitive by default.
te.assert_output(
&["--fixed-strings", "download (1)"],
"test2/Download (1).tar.gz",
);
// Combine with --case-sensitive
// Combine with --case-sensitive (unmatched).
te.assert_output(&["--fixed-strings", "--case-sensitive", "download (1)"], "");
// Combine with --case-sensitive (matched).
te.assert_output(
&["--fixed-strings", "--case-sensitive", "Download (1)"],
"test2/Download (1).tar.gz",
);
}
/// Literal search, non-substring (--exact)
#[test]
fn test_exact_literal_nonsubstring() {
let dirs = &["test1", "test2"];
let files = &[
"test1/a.foo",
"test1/aa.foo",
"test1/a.food",
"test1/ca.food",
"test1/a_foo",
"test2/Download (1).tar.gz",
];
let te = TestEnv::new(dirs, files);
// Literal search, dot is treated as character. Should match only the exact name,
// not "aa.foo", "a.food", or "ca.food".
te.assert_output(&["--exact", "a.foo"], "test1/a.foo");
// Literal search, parens are treated as characters. Substring should not match.
te.assert_output(&["--exact", "download (1)"], "");
// Literal search, parens are treated as characters. Case-insensitive by default.
te.assert_output(
&["--exact", "download (1).tar.gz"],
"test2/Download (1).tar.gz",
);
// Combine with --case-sensitive, should not match due to case mismatch.
te.assert_output(&["--exact", "--case-sensitive", "download (1).tar.gz"], "");
// Combine with --case-sensitive, exact match should match.
te.assert_output(
&["--exact", "--case-sensitive", "Download (1).tar.gz"],
"test2/Download (1).tar.gz",
);
}
/// Filenames with invalid UTF-8 sequences
@@ -2227,7 +2422,10 @@ fn test_modified_relative() {
#[cfg(test)]
fn change_file_modified<P: AsRef<Path>>(path: P, iso_date: &str) {
let st = humantime::parse_rfc3339(iso_date).expect("invalid date");
let st = iso_date
.parse::<Timestamp>()
.map(SystemTime::from)
.expect("invalid date");
let ft = filetime::FileTime::from_system_time(st);
filetime::set_file_times(path, ft, ft).expect("time modification failde");
}
@@ -2261,10 +2459,10 @@ fn test_owner_ignore_all() {
#[test]
fn test_owner_current_user() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
let uid = users::get_current_uid();
let uid = Uid::current();
te.assert_output(&["--owner", &uid.to_string(), "a.foo"], "a.foo");
if let Some(username) = users::get_current_username().map(|u| u.into_string().unwrap()) {
te.assert_output(&["--owner", &username, "a.foo"], "a.foo");
if let Ok(Some(user)) = User::from_uid(uid) {
te.assert_output(&["--owner", &user.name, "a.foo"], "a.foo");
}
}
@@ -2272,10 +2470,10 @@ fn test_owner_current_user() {
#[test]
fn test_owner_current_group() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
let gid = users::get_current_gid();
te.assert_output(&["--owner", &format!(":{}", gid), "a.foo"], "a.foo");
if let Some(groupname) = users::get_current_groupname().map(|u| u.into_string().unwrap()) {
te.assert_output(&["--owner", &format!(":{}", groupname), "a.foo"], "a.foo");
let gid = Gid::current();
te.assert_output(&["--owner", &format!(":{gid}"), "a.foo"], "a.foo");
if let Ok(Some(group)) = Group::from_gid(gid) {
te.assert_output(&["--owner", &format!(":{}", group.name), "a.foo"], "a.foo");
}
}
@@ -2283,7 +2481,7 @@ fn test_owner_current_group() {
#[test]
fn test_owner_root() {
// This test assumes the current user isn't root
if users::get_current_uid() == 0 || users::get_current_gid() == 0 {
if Uid::current().is_root() || Gid::current() == Gid::from_raw(0) {
return;
}
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
@@ -2341,7 +2539,7 @@ fn test_base_directory() {
// Ignore base directory when absolute path is used
let (te, abs_path) = get_test_env_with_abs_path(DEFAULT_DIRS, DEFAULT_FILES);
let abs_base_dir = &format!("{abs_path}/one/two/", abs_path = &abs_path);
let abs_base_dir = &format!("{abs_path}/one/two/", abs_path = abs_path);
te.assert_output(
&["--base-directory", abs_base_dir, "foo", &abs_path],
&format!(
@@ -2351,7 +2549,7 @@ fn test_base_directory() {
{abs_path}/one/two/C.Foo2
{abs_path}/one/two/three/d.foo
{abs_path}/one/two/three/directory_foo/",
abs_path = &abs_path
abs_path = abs_path
),
);
}
@@ -2385,7 +2583,7 @@ fn test_max_results() {
assert_just_one_result_with_option("--max-results=1");
assert_just_one_result_with_option("-1");
// check that --max-results & -1 conflic with --exec
// check that --max-results & -1 conflict with --exec
te.assert_failure(&["thing", "--max-results=0", "--exec=cat"]);
te.assert_failure(&["thing", "-1", "--exec=cat"]);
te.assert_failure(&["thing", "--max-results=1", "-1", "--exec=cat"]);
@@ -2463,6 +2661,7 @@ fn test_number_parsing_errors() {
te.assert_failure(&["--threads=0"]);
te.assert_failure(&["--min-depth=a"]);
te.assert_failure(&["--mindepth=a"]);
te.assert_failure(&["--max-depth=a"]);
te.assert_failure(&["--maxdepth=a"]);
te.assert_failure(&["--exact-depth=a"]);
@@ -2535,7 +2734,7 @@ fn test_strip_cwd_prefix() {
/// When fd is ran from a non-existent working directory, but an existent
/// directory is passed in the arguments, it should still run fine
#[test]
#[cfg(not(windows))]
#[cfg(all(not(windows), not(target_os = "illumos")))]
fn test_invalid_cwd() {
let te = TestEnv::new(&[], &[]);
@@ -2551,6 +2750,129 @@ fn test_invalid_cwd() {
.unwrap();
if !output.status.success() {
panic!("{:?}", output);
panic!("{output:?}");
}
}
/// Test behavior of .git directory with various flags
#[test]
fn test_git_dir() {
let te = TestEnv::new(
&[".git/one", "other_dir/.git", "nested/dir/.git"],
&[
".git/one/foo.a",
".git/.foo",
".git/a.foo",
"other_dir/.git/foo1",
"nested/dir/.git/foo2",
],
);
te.assert_output(
&["--hidden", "foo"],
".git/one/foo.a
.git/.foo
.git/a.foo
other_dir/.git/foo1
nested/dir/.git/foo2",
);
te.assert_output(&["--no-ignore", "foo"], "");
te.assert_output(
&["--hidden", "--no-ignore", "foo"],
".git/one/foo.a
.git/.foo
.git/a.foo
other_dir/.git/foo1
nested/dir/.git/foo2",
);
te.assert_output(
&["--hidden", "--no-ignore-vcs", "foo"],
".git/one/foo.a
.git/.foo
.git/a.foo
other_dir/.git/foo1
nested/dir/.git/foo2",
);
}
#[test]
fn test_gitignore_parent() {
let te = TestEnv::new(&["sub"], &[".abc", "sub/.abc"]);
fs::File::create(te.test_root().join(".gitignore"))
.unwrap()
.write_all(b".abc\n")
.unwrap();
te.assert_output_subdirectory("sub", &["--hidden"], "");
te.assert_output_subdirectory("sub", &["--hidden", "--search-path", "."], "");
}
#[test]
fn test_hyperlink() {
let te = TestEnv::new(DEFAULT_DIRS, DEFAULT_FILES);
#[cfg(unix)]
let hostname = nix::unistd::gethostname().unwrap().into_string().unwrap();
#[cfg(not(unix))]
let hostname = "/";
let expected = format!(
"\x1b]8;;file://{}{}/a.foo\x1b\\a.foo\x1b]8;;\x1b\\",
hostname,
get_absolute_root_path(&te),
);
te.assert_output(&["--hyperlink=always", "a.foo"], &expected);
}
#[test]
fn test_ignore_contain() {
let te = TestEnv::new(
&["include", "exclude", "exclude/sub", "other"],
&[
"top",
"include/foo",
"exclude/CACHEDIR.TAG",
"exclude/sub/nope",
"other/ignoremyparent",
],
);
let expected = "include/
include/foo
symlink
top";
te.assert_output(
&[
"--ignore-contain=CACHEDIR.TAG",
"--ignore-contain=ignoremyparent",
".",
],
expected,
);
}
#[test]
fn test_ignore_contain_precedence_over_depth_check() {
let te = TestEnv::new(
&["include", "exclude", "exclude/sub"],
&[
"top",
"include/foo",
"exclude/CACHEDIR.TAG",
"exclude/sub/nope",
],
);
let expected = "include/foo";
te.assert_output(
&["--ignore-contain=CACHEDIR.TAG", "--min-depth=2", "."],
expected,
);
}
#[test]
fn test_ignore_contain_precedence_over_root_check() {
let te = TestEnv::new(&["include"], &["CACHEDIR.TAG", "top", "include/foo"]);
let expected = "";
te.assert_output(&["--ignore-contain=CACHEDIR.TAG", "."], expected);
}