122 Commits

Author SHA1 Message Date
Sylvestre Ledru e3f4224f12 prepare version 0.7.0 2024-09-08 10:04:46 +02:00
Sylvestre Ledru 8fc5ddb299 Merge pull request #450 from cakebaker/find_fix_clippy_warning
find: use array instead of closure
2024-09-06 08:53:55 +02:00
Daniel Hofstetter b4f22f0747 find: use array instead of closure
fix warning from manual_pattern_char_comparison lint
2024-09-06 07:44:59 +02:00
hanbings db8e265547 Clean up unused generated during Windows platform build process. (#448)
* Fix Windows' warning in build.

* Fix Windows' warning in build.

* Fix Windows' warning in build.

* Run cargo fmt.
2024-09-05 10:10:34 +02:00
hanbings f9d74ada2e Implement -ls and -fls (#435) 2024-09-05 09:06:54 +02:00
Daniel Hofstetter 907f3841ab Merge pull request #449 from uutils/dependabot/cargo/clap-4.5.17
build(deps): bump clap from 4.5.16 to 4.5.17
2024-09-05 07:11:53 +02:00
dependabot[bot] 888d3cd516 build(deps): bump clap from 4.5.16 to 4.5.17
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.16 to 4.5.17.
- [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.17)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-09-05 03:38:19 +00:00
Daniel Hofstetter f2e49d8d48 Merge pull request #447 from uutils/dependabot/cargo/filetime-0.2.25
build(deps): bump filetime from 0.2.24 to 0.2.25
2024-08-28 07:05:08 +02:00
dependabot[bot] d847a7bf7e 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-08-28 03:28:47 +00:00
Tavian Barnes abf851dd7d ci: Update bfs to 4.0 (#446)
And fix diff-bfs.sh for the new test result format.
2024-08-17 08:13:30 +01:00
Daniel Hofstetter d9d2a4e865 Merge pull request #445 from uutils/dependabot/cargo/clap-4.5.16
build(deps): bump clap from 4.5.15 to 4.5.16
2024-08-16 09:28:56 +02:00
dependabot[bot] 9b0fea9880 build(deps): bump clap from 4.5.15 to 4.5.16
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.15 to 4.5.16.
- [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.15...clap_complete-v4.5.16)

---
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-16 03:39:20 +00:00
Tavian Barnes a7a73c325d Wrap walkdir::DirEntry in a new type (#436)
* Add -follow support.

* tests/find: Serialize find_time()

find_time() relies on the working directory, but e.g.
delete_on_dot_dir() will temporarily change directories, causing
find_time() to fail when run in parallel.

* find: Don't use uutils::error::set_exit_code()

The global exit code can polute the results of other tests.

Link: https://github.com/uutils/coreutils/issues/5777

* find: New WalkEntry wrapper

The new type wraps DirEntry when possible, but also lets us pass a valid
entry to matchers when walkdir returns a broken symlink error.  It also
implements a Metadata cache (part of #430).

* find: Implement -H, -L, -P flags

* find: Fix -follow -samefile

* find: Fix -follow -newer

* find: Implement -xtype

* find: Fix -delete error handling

---------

Co-authored-by: hanbings <hanbings@hanbings.io>
2024-08-15 04:01:19 +08:00
Daniel Hofstetter 465856ce24 Merge pull request #442 from uutils/dependabot/cargo/filetime-0.2.24
build(deps): bump filetime from 0.2.23 to 0.2.24
2024-08-12 08:16:29 +02:00
Daniel Hofstetter e456c23d5c Merge pull request #441 from uutils/dependabot/cargo/clap-4.5.15
build(deps): bump clap from 4.5.14 to 4.5.15
2024-08-12 08:14:51 +02:00
dependabot[bot] 4dc350e5fb build(deps): bump filetime from 0.2.23 to 0.2.24
Bumps [filetime](https://github.com/alexcrichton/filetime) from 0.2.23 to 0.2.24.
- [Commits](https://github.com/alexcrichton/filetime/compare/0.2.23...0.2.24)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-12 03:51:06 +00:00
dependabot[bot] fcc929a978 build(deps): bump clap from 4.5.14 to 4.5.15
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.14 to 4.5.15.
- [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.14...v4.5.15)

---
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-12 03:51:01 +00:00
hanbings 423453eaf8 Implement -fprint (#421) 2024-08-11 09:38:05 +02:00
Daniel Hofstetter 79986a26f2 Merge pull request #437 from uutils/dependabot/cargo/assert_cmd-2.0.16
build(deps): bump assert_cmd from 2.0.15 to 2.0.16
2024-08-09 08:07:12 +02:00
Daniel Hofstetter de1bc84812 Merge pull request #438 from uutils/dependabot/cargo/clap-4.5.14
build(deps): bump clap from 4.5.13 to 4.5.14
2024-08-09 08:05:59 +02:00
dependabot[bot] f0cd3748b8 build(deps): bump clap from 4.5.13 to 4.5.14
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.13 to 4.5.14.
- [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.13...v4.5.14)

---
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-09 03:24:36 +00:00
dependabot[bot] 780d106b34 build(deps): bump assert_cmd from 2.0.15 to 2.0.16
Bumps [assert_cmd](https://github.com/assert-rs/assert_cmd) from 2.0.15 to 2.0.16.
- [Changelog](https://github.com/assert-rs/assert_cmd/blob/master/CHANGELOG.md)
- [Commits](https://github.com/assert-rs/assert_cmd/compare/v2.0.15...v2.0.16)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-09 03:24:28 +00:00
Daniel Hofstetter 4043c00bde Merge pull request #434 from uutils/dependabot/cargo/tempfile-3.12.0
build(deps): bump tempfile from 3.11.0 to 3.12.0
2024-08-07 08:01:56 +02:00
dependabot[bot] f0c3562aca build(deps): bump tempfile from 3.11.0 to 3.12.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.11.0 to 3.12.0.
- [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-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-07 03:44:37 +00:00
dependabot[bot] d7bf7da4a1 build(deps): bump predicates from 3.1.0 to 3.1.2 (#424)
Bumps [predicates](https://github.com/assert-rs/predicates-rs) from 3.1.0 to 3.1.2.
- [Changelog](https://github.com/assert-rs/predicates-rs/blob/master/CHANGELOG.md)
- [Commits](https://github.com/assert-rs/predicates-rs/compare/v3.1.0...v3.1.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: hanbings <hanbings@hanbings.io>
2024-08-06 00:39:50 +08:00
dependabot[bot] 73dcd94827 build(deps): bump assert_cmd from 2.0.14 to 2.0.15 (#426)
Bumps [assert_cmd](https://github.com/assert-rs/assert_cmd) from 2.0.14 to 2.0.15.
- [Changelog](https://github.com/assert-rs/assert_cmd/blob/master/CHANGELOG.md)
- [Commits](https://github.com/assert-rs/assert_cmd/compare/v2.0.14...v2.0.15)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: hanbings <hanbings@hanbings.io>
2024-08-06 00:29:40 +08:00
Tavian Barnes 60e4a8cf92 find: -daystart returns true (#428) 2024-08-06 00:22:42 +08:00
Daniel Hofstetter 8b295e7d8a Merge pull request #433 from uutils/dependabot/cargo/tempfile-3.11.0
build(deps): bump tempfile from 3.10.1 to 3.11.0
2024-08-05 07:59:49 +02:00
Daniel Hofstetter 2dc916f980 Merge pull request #432 from uutils/dependabot/cargo/regex-1.10.6
build(deps): bump regex from 1.10.5 to 1.10.6
2024-08-05 07:58:59 +02:00
dependabot[bot] 19012452e1 build(deps): bump tempfile from 3.10.1 to 3.11.0
Bumps [tempfile](https://github.com/Stebalien/tempfile) from 3.10.1 to 3.11.0.
- [Changelog](https://github.com/Stebalien/tempfile/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Stebalien/tempfile/compare/v3.10.1...v3.11.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-08-05 03:55:36 +00:00
dependabot[bot] 6042d5a47f build(deps): bump regex from 1.10.5 to 1.10.6
Bumps [regex](https://github.com/rust-lang/regex) from 1.10.5 to 1.10.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/1.10.5...1.10.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-08-05 03:55:28 +00:00
Daniel Hofstetter 45e5964e6a Merge pull request #429 from uutils/dependabot/cargo/clap-4.5.13
build(deps): bump clap from 4.5.10 to 4.5.13
2024-08-01 09:33:03 +02:00
dependabot[bot] 9544f78977 build(deps): bump clap from 4.5.10 to 4.5.13
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.10 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.10...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 03:35:21 +00:00
Sylvestre Ledru 5be00c85d7 Merge pull request #427 from tavianator/simplify-matcher-io
Remove unnecessary lifetime parameter from Dependencies
2024-07-28 09:53:25 +02:00
Tavian Barnes 8771861b0c Remove unnecessary lifetime parameter from Dependencies 2024-07-27 19:54:28 -04:00
Daniel Hofstetter c4a56e9c3f find: fix needless borrow clippy warning (#423) 2024-07-26 03:15:07 +08:00
Daniel Hofstetter 3b222d6040 Merge pull request #422 from uutils/dependabot/cargo/clap-4.5.10
build(deps): bump clap from 4.5.9 to 4.5.10
2024-07-24 07:27:06 +02:00
dependabot[bot] 6f53585a4c build(deps): bump clap from 4.5.9 to 4.5.10
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.9 to 4.5.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/clap_complete-v4.5.9...v4.5.10)

---
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-24 03:12:02 +00:00
hanbings 1b9904eb5f Implement -daystart (#413) 2024-07-21 16:06:15 +02:00
Tavian Barnes 4807264faa find: ctime is "changed" time, not "created" time (#416)
Fixes #358
2024-07-17 21:14:00 +08:00
Chen Chen 9f44977270 Implement simple caching for -fstype (#419)
* Implement simple caching for -fstype

* Using lstat instead of stat in -fstype
2024-07-13 01:43:56 +08:00
Sylvestre Ledru 7f4423e703 Merge pull request #417 from tavianator/options-return-true
options return true
2024-07-11 21:49:40 +02:00
Tavian Barnes e9634f1ed4 find: Stop parsing after we see -help or -version
GNU find accepts things like

    $ find \( -help -foo -not
2024-07-10 11:55:14 -04:00
Tavian Barnes 37a543b9d6 find: Options like -maxdepth return true
Previously, this would give an error:

    $ find -maxdepth 0 -a -print
    Error: invalid expression; you have used a binary operator '-a' with nothing before it.

Now, options are treated like other primary expressions:

    $ find -maxdepth 0 -a print
    .
2024-07-10 11:42:58 -04:00
hanbings 9c11f11045 Implement -noleaf (#414) 2024-07-09 23:27:18 +02:00
Daniel Hofstetter a0b5713b61 Merge pull request #415 from uutils/dependabot/cargo/clap-4.5.9
build(deps): bump clap from 4.5.8 to 4.5.9
2024-07-09 08:23:11 +02:00
dependabot[bot] 5d4b9ca5e2 build(deps): bump clap from 4.5.8 to 4.5.9
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.8 to 4.5.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/v4.5.8...v4.5.9)

---
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-09 03:09:20 +00:00
Daniel Hofstetter 3bf5567397 Merge pull request #410 from uutils/dependabot/cargo/clap-4.5.8
build(deps): bump clap from 4.5.7 to 4.5.8
2024-07-01 07:41:29 +02:00
dependabot[bot] bbc9f06543 build(deps): bump clap from 4.5.7 to 4.5.8
Bumps [clap](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...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 03:30:04 +00:00
Sylvestre Ledru 8bfa9d200b Revert "cargo-dist: generate more targets"
it fails with:
```
  error occurred: Failed to find tool. Is `aarch64-linux-musl-gcc` installed?
```
and
```
          /usr/bin/ld: /home/runner/work/findutils/findutils/target/aarch64-unknown-linux-gnu/dist/deps/find-c77ccffa664800a0.49era2xhdewepevi.rcgu.o: error adding symbols: file in wrong format
```

This reverts commit b5e7dd52d9.
2024-06-29 10:49:11 +02:00
Sylvestre Ledru a235b35ac3 Revert "Fix cargo-dist generation of arm64 linux"
This reverts commit ca252c9727.
2024-06-29 10:48:01 +02:00
Sylvestre Ledru ca252c9727 Fix cargo-dist generation of arm64 linux
See:
https://github.com/axodotdev/cargo-dist/issues/74#issuecomment-2053680080
2024-06-29 10:37:01 +02:00
Sylvestre Ledru c995e25eb4 prepare version 0.6.0 2024-06-29 10:16:34 +02:00
Tavian Barnes fd54f9f72a samefile: Cache FileInformation for the target (#409)
And don't follow symlinks.
2024-06-28 15:53:52 +08:00
hanbings f145469cfd Comments are only sent when GNU/BFS test compatibility changes. (#407) 2024-06-28 08:56:32 +02:00
hanbings f2202dc23f find: Implement -fstype (#408)
---------

Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
2024-06-27 08:26:27 +02:00
hanbings fa4cce8a95 find: Implement -samefile (#389)
.

---------

Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
2024-06-27 07:55:31 +02:00
Sylvestre Ledru 7136628c45 Merge pull request #405 from hanbings/implement-371
find: Implement `-uid` and `-gid`
2024-06-26 22:48:23 +02:00
hanbings db9d69f8eb Merge branch 'main' into implement-371 2024-06-26 16:35:17 -04:00
Daniel Hofstetter 42075f53f0 find: make InodeMatcher & LinksMatcher unix-only (#393) 2024-06-24 09:35:14 +02:00
Daniel Hofstetter 57b670680c Bump regex from 1.7 to 1.10 (#391) 2024-06-24 08:19:10 +02:00
Daniel Hofstetter cf8a29d73b Merge pull request #406 from uutils/dependabot/cargo/uucore-0.0.27
build(deps): bump uucore from 0.0.26 to 0.0.27
2024-06-24 07:52:40 +02:00
dependabot[bot] bc715f84fa build(deps): bump uucore from 0.0.26 to 0.0.27
Bumps [uucore](https://github.com/uutils/coreutils) from 0.0.26 to 0.0.27.
- [Release notes](https://github.com/uutils/coreutils/releases)
- [Commits](https://github.com/uutils/coreutils/compare/0.0.26...0.0.27)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-24 03:06:45 +00:00
hanbings 8736cde582 Run cargo fmt. 2024-06-23 19:00:57 -04:00
hanbings af1741ba85 implement -uid and -gid features. 2024-06-23 18:57:57 -04:00
hanbings 5b19ea2125 Fix CI code for comment.yml (#404) 2024-06-24 00:29:26 +02:00
hanbings d329702b69 Provide GNU test comparison comments for PRs in Github Actions. (#400) 2024-06-23 19:02:12 +02:00
Y.D.X. 84e4be85c1 xargs: support args with conflicts 2024-06-23 18:23:25 +02:00
Y.D.X. 1979483175 xargs: split input only at newlines if replace 2024-06-23 18:23:25 +02:00
Y.D.X. a750b3225a xargs: do not merge extra args before replacing
Resolves #362
2024-06-23 18:23:25 +02:00
hanbings a2e350ce96 find: Implement -[no]user and -[no]group predicates. (#368)
---------

Co-authored-by: Sylvestre Ledru <sylvestre@debian.org>
2024-06-23 10:04:29 +02:00
Daniel Hofstetter d35aebf5ed find: fix usage of legacy numeric methods (#403) 2024-06-14 11:25:02 +02:00
Daniel Hofstetter 9502a7c4eb Merge pull request #402 from uutils/dependabot/github_actions/dawidd6/action-download-artifact-6
build(deps): bump dawidd6/action-download-artifact from 5 to 6
2024-06-13 07:09:36 +02:00
dependabot[bot] f74ef7c2af build(deps): bump dawidd6/action-download-artifact from 5 to 6
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 5 to 6.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-13 03:26:29 +00:00
Daniel Hofstetter 3ec8d4da46 Merge pull request #401 from uutils/dependabot/cargo/clap-4.5.7
build(deps): bump clap from 4.5.6 to 4.5.7
2024-06-11 07:09:10 +02:00
dependabot[bot] 62e370179b build(deps): bump clap from 4.5.6 to 4.5.7
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.6 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/v4.5.6...v4.5.7)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-11 03:48:06 +00:00
Daniel Hofstetter 98fd45a182 Merge pull request #399 from uutils/dependabot/cargo/clap-4.5.6
build(deps): bump clap from 4.5.4 to 4.5.6
2024-06-07 07:26:25 +02:00
dependabot[bot] 665165b297 build(deps): bump clap from 4.5.4 to 4.5.6
Bumps [clap](https://github.com/clap-rs/clap) from 4.5.4 to 4.5.6.
- [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.6)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-07 03:06:14 +00:00
Daniel Hofstetter d78f44a923 Merge pull request #398 from uutils/dependabot/github_actions/dawidd6/action-download-artifact-5
build(deps): bump dawidd6/action-download-artifact from 4 to 5
2024-06-05 07:13:18 +02:00
dependabot[bot] a2631ae925 build(deps): bump dawidd6/action-download-artifact from 4 to 5
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 4 to 5.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-05 03:53:18 +00:00
Daniel Hofstetter c2279ffae8 Merge pull request #397 from uutils/dependabot/github_actions/dawidd6/action-download-artifact-4
build(deps): bump dawidd6/action-download-artifact from 3 to 4
2024-06-04 07:22:34 +02:00
dependabot[bot] fba701b928 build(deps): bump dawidd6/action-download-artifact from 3 to 4
Bumps [dawidd6/action-download-artifact](https://github.com/dawidd6/action-download-artifact) from 3 to 4.
- [Release notes](https://github.com/dawidd6/action-download-artifact/releases)
- [Commits](https://github.com/dawidd6/action-download-artifact/compare/v3...v4)

---
updated-dependencies:
- dependency-name: dawidd6/action-download-artifact
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-06-04 03:05:07 +00:00
hanbings d7057e09b9 find: Implement -amin -cmin -mmin age ranges. (#355) 2024-06-01 10:34:47 +02:00
Sylvestre Ledru add14dbebf Merge pull request #394 from hanbings/fix-windows-test
find: Fix `-newerXY` test code for Windows platform.
2024-05-30 23:13:07 +02:00
Sylvestre Ledru ed97c851aa Merge pull request #395 from cakebaker/find_remove_unused_import
find: remove unused import on Windows
2024-05-30 23:12:20 +02:00
Sylvestre Ledru 0ca2450ab2 Merge pull request #396 from cakebaker/xargs_allow_dead_code
xargs: use `#[allow(dead_code)]` for enum
2024-05-30 23:12:04 +02:00
Daniel Hofstetter 52ee81296c xargs: use #[allow(dead_code)] for enum 2024-05-30 10:43:35 +02:00
Daniel Hofstetter a0c9f2dfd4 find: remove unused import on Windows 2024-05-30 09:05:17 +02:00
hanbings bd759d5e21 Fix test code for Windows platform. 2024-05-29 19:39:03 +08:00
Sylvestre Ledru 3badb05772 Merge pull request #392 from cakebaker/ci_run_tests
ci: run `cargo test` instead of `cargo check` in "cargo test" jobs
2024-05-28 16:51:54 +02:00
Daniel Hofstetter ab1c2bacb7 ci: run "cargo test" in "cargo test" jobs
instead of "cargo check"
2024-05-28 16:28:43 +02:00
Daniel Hofstetter 393f0b9672 Merge pull request #390 from uutils/dependabot/cargo/nix-0.29.0
build(deps): bump nix from 0.28.0 to 0.29.0
2024-05-27 06:59:45 +02:00
dependabot[bot] 18dfc9b0cc 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-05-27 03:35:27 +00:00
hanbings 0693242553 find: Implement -anewer and -cnewer. (#386)
* Add short args support for -newer.

* Add unit tests.

* Add integration tests.

* Clean up duplicate code.

* Clean up duplicate code.

* Clean up duplicate code.
2024-05-22 16:57:43 +02:00
Sylvestre Ledru aa6ff46078 release 0.5.1 2024-05-19 19:07:24 +02:00
Daniel Hofstetter ab03198152 Merge pull request #388 from sylvestre/cargo-dist
cargo-dist: generate more targets
2024-05-19 12:40:29 +02:00
Sylvestre Ledru b5e7dd52d9 cargo-dist: generate more targets 2024-05-19 11:58:13 +02:00
Sylvestre Ledru b91820de17 Merge pull request #385 from cakebaker/find_replace_zip_with_nested_loops
find: replace `zip` with nested loops in tests
2024-05-16 10:54:45 +02:00
Daniel Hofstetter 6fe2c9c649 find: replace zip with nested loops in tests 2024-05-16 10:44:16 +02:00
Sylvestre Ledru 70b7b3633e Merge pull request #361 from hanbings/fix-355
find: Fix `convert_arg_to_comparable_value()` function parsing unexpected characters.
2024-05-16 10:43:43 +02:00
Daniel Hofstetter 92c60597ec Merge pull request #364 from uutils/dependabot/cargo/serial_test-3.1.1
build(deps): bump serial_test from 3.1.0 to 3.1.1
2024-04-29 07:03:43 +02:00
Daniel Hofstetter 0cfb381cd9 Merge pull request #365 from uutils/dependabot/cargo/uucore-0.0.26
build(deps): bump uucore from 0.0.25 to 0.0.26
2024-04-29 07:01:53 +02:00
dependabot[bot] ec0fff41e3 build(deps): bump uucore from 0.0.25 to 0.0.26
Bumps [uucore](https://github.com/uutils/coreutils) from 0.0.25 to 0.0.26.
- [Release notes](https://github.com/uutils/coreutils/releases)
- [Commits](https://github.com/uutils/coreutils/compare/0.0.25...0.0.26)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-29 03:53:10 +00:00
dependabot[bot] 288f7f07a2 build(deps): bump serial_test from 3.1.0 to 3.1.1
Bumps [serial_test](https://github.com/palfrey/serial_test) from 3.1.0 to 3.1.1.
- [Release notes](https://github.com/palfrey/serial_test/releases)
- [Commits](https://github.com/palfrey/serial_test/compare/v3.1.0...v3.1.1)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-29 03:53:03 +00:00
hanbings c0b8cd0b3b Add integration tests. 2024-04-24 21:17:57 +08:00
hanbings 5370f7f999 Fix convert_arg_to_comparable_value function parsing unexpected characters. 2024-04-24 02:43:40 +08:00
Sylvestre Ledru baa09baf47 Merge pull request #359 from cakebaker/ci_use_clippy_all_targets
ci: use `--all-targets` when running clippy
2024-04-23 08:49:02 +02:00
Daniel Hofstetter bb667e388a Merge pull request #357 from hanbings/clippy
clippy: Fix clippy warning.
2024-04-23 07:41:54 +02:00
Daniel Hofstetter 415d17deed ci: use --all-targets when running clippy 2024-04-23 07:29:39 +02:00
hanbings acd5c4b8b2 Fix clippy warning. 2024-04-23 00:54:18 +08:00
Daniel Hofstetter 2084d9d91b Merge pull request #356 from uutils/dependabot/cargo/serial_test-3.1.0
build(deps): bump serial_test from 3.0.0 to 3.1.0
2024-04-22 07:17:10 +02:00
dependabot[bot] 14d4629519 build(deps): bump serial_test from 3.0.0 to 3.1.0
Bumps [serial_test](https://github.com/palfrey/serial_test) from 3.0.0 to 3.1.0.
- [Release notes](https://github.com/palfrey/serial_test/releases)
- [Commits](https://github.com/palfrey/serial_test/compare/v3.0.0...v3.1.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-22 03:01:35 +00:00
hanbings 6a8379520f find: Fix unexpectedly accepted empty expression. (#353)
* Check for expression that contain only empty parentheses.

* Add an empty expression test in the test file.
2024-04-18 16:32:32 +02:00
Daniel Hofstetter d4c40acb9c Merge pull request #354 from uutils/dependabot/cargo/chrono-0.4.38
build(deps): bump chrono from 0.4.37 to 0.4.38
2024-04-16 07:07:37 +02:00
dependabot[bot] 89ca20cba5 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-04-16 03:49:44 +00:00
hanbings d8e2ce20ce find: Changed exit code when an error is encountered in process_dir(). (#352)
* Add an error flag to process_dir().

* Added no permission file error test.

* Restore files after no permission file test.

* Adjust the timing of matcher_io creation in process_dir().

* Use uucore::error to set global return code.
2024-04-08 15:24:25 +02:00
hanbings d94a8e9093 find: Fix panic when piped into head (#351)
* Ignore the SIGPIPE signal.

* Add description of calling mute_sigpipe_panic().
2024-04-04 11:00:46 +02:00
Sylvestre Ledru f32425a83c Merge pull request #350 from sylvestre/release
use cargo-dist + prepare 0.5.0
2024-04-04 00:25:48 +02:00
Sylvestre Ledru fd8ef0bb26 release: version 0.5.0 2024-04-04 00:19:57 +02:00
Sylvestre Ledru 93469e6f97 chore: wow shiny new cargo-dist CI 2024-04-04 00:19:57 +02:00
Sylvestre Ledru b801c97830 Merge pull request #349 from sylvestre/clipp2
Run clippy pedantic fixes on the recent changes
2024-04-04 00:19:48 +02:00
Sylvestre Ledru da0de660ae Run clippy pedantic fixes on the recent changes 2024-04-03 23:23:40 +02:00
41 changed files with 4033 additions and 823 deletions
+5 -5
View File
@@ -53,9 +53,9 @@ jobs:
- run: echo "LIBCLANG_PATH=$((gcm clang).source -replace "clang.exe")" >> $env:GITHUB_ENV
if: matrix.os == 'windows-latest'
- name: Check
- name: Test
run: |
cargo check
cargo test
fmt:
name: cargo fmt --all -- --check
@@ -86,7 +86,7 @@ jobs:
- run: rustup component add clippy
- name: cargo clippy
run: |
cargo clippy -- -D warnings
cargo clippy --all-targets -- -D warnings
grcov:
name: Code coverage
@@ -117,8 +117,8 @@ jobs:
cargo test --all --no-fail-fast ${{ matrix.cargo_flags }}
env:
CARGO_INCREMENTAL: "0"
RUSTFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort -Cdebug-assertions=off'
RUSTDOCFLAGS: '-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort -Cdebug-assertions=off'
RUSTFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort -Cdebug-assertions=off"
RUSTDOCFLAGS: "-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort -Cdebug-assertions=off"
- name: Generate coverage data
id: grcov
+76
View File
@@ -0,0 +1,76 @@
on:
workflow_run:
workflows: [External-testsuites]
types: [completed]
name: Comment Test results on the PR
permissions: {}
jobs:
upload-pr-comment:
if: ${{ github.event.workflow_run.event == 'pull_request' }}
name: Upload PR comment
runs-on: ubuntu-latest
permissions:
actions: read
pull-requests: write
steps:
- name: List Annotations
uses: actions/github-script@v7
with:
script: |
let artifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: ${{ github.event.workflow_run.id }},
});
// List all artifacts
let matchArtifact = artifacts.data.artifacts.filter((artifact) => {
return artifact.name == "comment"
})[0];
// Download the artifact to github.workspace
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
let fs = require('fs');
fs.writeFileSync('${{ github.workspace }}/comment.zip', Buffer.from(download.data));
- run: unzip comment.zip
- name: Comment on PR
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
let fs = require('fs');
let annotations = JSON.parse(fs.readFileSync('./annotations.json', 'utf8'));
let annotationContent = annotations
.data
.map(annotation => `${annotation.run}: ${annotation.annotation.message}`)
.join('\n');
// check if no changes
let gnuTestReport = annotationContent.includes('Run GNU findutils tests: Gnu tests No changes');
let bfsTestReport = annotationContent.includes('Run BFS tests: BFS tests No changes');
if (gnuTestReport && bfsTestReport) {
console.log('No changes');
return;
}
// Comment on the PR
github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: annotations.pull_request_number,
body: 'Commit ${{ github.event.workflow_run.head_sha }} has GNU testsuite comparison:\n```\n' + annotationContent + '\n```\n'
});
+187 -136
View File
@@ -1,149 +1,200 @@
on: [push, pull_request]
name: External testsuites
name: External-testsuites
jobs:
gnu-tests:
name: Run GNU findutils tests
runs-on: ubuntu-latest
steps:
- name: Checkout findutils
uses: actions/checkout@v4
with:
path: findutils
- name: Checkout GNU findutils
uses: actions/checkout@v4
with:
repository: gnu-mirror-unofficial/findutils
path: findutils.gnu
ref: 5768a03ddfb5e18b1682e339d6cdd24ff721c510
submodules: true
- name: Install `rust` toolchain
run: |
## Install `rust` toolchain
rustup toolchain install stable --no-self-update -c rustfmt --profile minimal
rustup default stable
- name: Install dependencies
shell: bash
run: |
# Enable sources & install dependencies
sudo find /etc/apt/sources.list* -type f -exec sed -i 'p; s/^deb /deb-src /' '{}' +
sudo apt-get update
sudo apt-get build-dep findutils
- name: Run GNU tests
shell: bash
run: |
cd findutils
bash util/build-gnu.sh ||:
- name: Extract testing info
shell: bash
run: |
- name: Upload gnu-test-report
uses: actions/upload-artifact@v4
with:
name: gnu-test-report
path: |
findutils.gnu/find/testsuite/*.log
findutils.gnu/xargs/testsuite/*.log
findutils.gnu/tests/**/*.log
- name: Upload gnu-result
uses: actions/upload-artifact@v4
with:
name: gnu-result
path: gnu-result.json
- name: Download the result
uses: dawidd6/action-download-artifact@v3
with:
workflow: compat.yml
workflow_conclusion: completed
name: gnu-result
repo: uutils/findutils
branch: main
path: dl
- name: Download the log
uses: dawidd6/action-download-artifact@v3
with:
workflow: compat.yml
workflow_conclusion: completed
name: gnu-test-report
repo: uutils/findutils
branch: main
path: dl
- name: Compare failing tests against master
shell: bash
run: |
./findutils/util/diff-gnu.sh ./dl ./findutils.gnu
- name: Compare against main results
shell: bash
run: |
mv dl/gnu-result.json latest-gnu-result.json
python findutils/util/compare_gnu_result.py
- name: Checkout findutils
uses: actions/checkout@v4
with:
path: findutils
- name: Checkout GNU findutils
uses: actions/checkout@v4
with:
repository: gnu-mirror-unofficial/findutils
path: findutils.gnu
ref: 5768a03ddfb5e18b1682e339d6cdd24ff721c510
submodules: true
- name: Install `rust` toolchain
run: |
## Install `rust` toolchain
rustup toolchain install stable --no-self-update -c rustfmt --profile minimal
rustup default stable
- name: Install dependencies
shell: bash
run: |
# Enable sources & install dependencies
sudo find /etc/apt/sources.list* -type f -exec sed -i 'p; s/^deb /deb-src /' '{}' +
sudo apt-get update
sudo apt-get build-dep findutils
- name: Run GNU tests
shell: bash
run: |
cd findutils
bash util/build-gnu.sh ||:
- name: Extract testing info
shell: bash
run: |
- name: Upload gnu-test-report
uses: actions/upload-artifact@v4
with:
name: gnu-test-report
path: |
findutils.gnu/find/testsuite/*.log
findutils.gnu/xargs/testsuite/*.log
findutils.gnu/tests/**/*.log
- name: Upload gnu-result
uses: actions/upload-artifact@v4
with:
name: gnu-result
path: gnu-result.json
- name: Download the result
uses: dawidd6/action-download-artifact@v6
with:
workflow: compat.yml
workflow_conclusion: completed
name: gnu-result
repo: uutils/findutils
branch: main
path: dl
- name: Download the log
uses: dawidd6/action-download-artifact@v6
with:
workflow: compat.yml
workflow_conclusion: completed
name: gnu-test-report
repo: uutils/findutils
branch: main
path: dl
- name: Compare failing tests against master
shell: bash
run: |
./findutils/util/diff-gnu.sh ./dl ./findutils.gnu
- name: Compare against main results
shell: bash
run: |
mv dl/gnu-result.json latest-gnu-result.json
python findutils/util/compare_gnu_result.py
bfs-tests:
name: Run BFS tests
runs-on: ubuntu-latest
steps:
- name: Checkout findutils
uses: actions/checkout@v4
with:
path: findutils
- name: Checkout BFS
uses: actions/checkout@v4
with:
repository: tavianator/bfs
path: bfs
ref: '3.1.3'
- name: Install `rust` toolchain
run: |
## Install `rust` toolchain
rustup toolchain install stable --no-self-update -c rustfmt --profile minimal
rustup default stable
- name: Install dependencies
shell: bash
run: |
# Enable sources & install dependencies
sudo find /etc/apt/sources.list* -type f -exec sed -i 'p; s/^deb /deb-src /' '{}' +
sudo apt-get update
sudo apt-get build-dep bfs
- name: Run BFS tests
shell: bash
run: |
cd findutils
bash util/build-bfs.sh ||:
- name: Upload bfs-test-report
uses: actions/upload-artifact@v4
with:
name: bfs-test-report
path: bfs/tests.log
- name: Upload bfs-result
uses: actions/upload-artifact@v4
with:
name: bfs-result
path: bfs-result.json
- name: Download the result
uses: dawidd6/action-download-artifact@v3
with:
workflow: compat.yml
workflow_conclusion: completed
name: bfs-result
repo: uutils/findutils
branch: main
path: dl
- name: Download the log
uses: dawidd6/action-download-artifact@v3
with:
workflow: compat.yml
workflow_conclusion: completed
name: bfs-test-report
repo: uutils/findutils
branch: main
path: dl
- name: Compare failing tests against main
shell: bash
run: |
./findutils/util/diff-bfs.sh dl/tests.log bfs/tests.log
- name: Compare against main results
shell: bash
run: |
mv dl/bfs-result.json latest-bfs-result.json
python findutils/util/compare_bfs_result.py
- name: Checkout findutils
uses: actions/checkout@v4
with:
path: findutils
- name: Checkout BFS
uses: actions/checkout@v4
with:
repository: tavianator/bfs
path: bfs
ref: "4.0"
- name: Install `rust` toolchain
run: |
## Install `rust` toolchain
rustup toolchain install stable --no-self-update -c rustfmt --profile minimal
rustup default stable
- name: Install dependencies
shell: bash
run: |
# Enable sources & install dependencies
sudo find /etc/apt/sources.list* -type f -exec sed -i 'p; s/^deb /deb-src /' '{}' +
sudo apt-get update
sudo apt-get build-dep bfs
- name: Run BFS tests
shell: bash
run: |
cd findutils
bash util/build-bfs.sh ||:
- name: Upload bfs-test-report
uses: actions/upload-artifact@v4
with:
name: bfs-test-report
path: bfs/tests.log
- name: Upload bfs-result
uses: actions/upload-artifact@v4
with:
name: bfs-result
path: bfs-result.json
- name: Download the result
uses: dawidd6/action-download-artifact@v6
with:
workflow: compat.yml
workflow_conclusion: completed
name: bfs-result
repo: uutils/findutils
branch: main
path: dl
- name: Download the log
uses: dawidd6/action-download-artifact@v6
with:
workflow: compat.yml
workflow_conclusion: completed
name: bfs-test-report
repo: uutils/findutils
branch: main
path: dl
- name: Compare failing tests against main
shell: bash
run: |
./findutils/util/diff-bfs.sh dl/tests.log bfs/tests.log
- name: Compare against main results
shell: bash
run: |
mv dl/bfs-result.json latest-bfs-result.json
python findutils/util/compare_bfs_result.py
upload-annotations:
name: Upload annotations
runs-on: ubuntu-latest
needs: [gnu-tests, bfs-tests]
if: ${{ github.event_name == 'pull_request' }}
steps:
- name: List Annotations
uses: actions/github-script@v7
with:
script: |
let runs = await github.rest.checks.listForRef({
owner: context.repo.owner,
repo: context.repo.repo,
ref: '${{ github.event.pull_request.head.sha }}'
});
let names = ['Run GNU findutils tests', 'Run BFS tests'];
let results = [];
runs.data.check_runs.filter(check => names.includes(check.name)).forEach(run => results.push(run));
let annotations = { data: [], pull_request_number: '${{ github.event.number }}' };
for (let result of results) {
let run = await github.rest.checks.listAnnotations({
owner: context.repo.owner,
repo: context.repo.repo,
check_run_id: result.id
});
run.data.forEach(data => {
annotations.data.push({
run: result.name,
annotation: data
});
});
}
// Remove duplicate items.
annotations.data = annotations.data.filter((value, index, self) =>
self.findIndex(v => v.annotation.message === value.annotation.message) === index);
let fs = require('fs');
fs.writeFileSync('${{ github.workspace }}/annotations.json', JSON.stringify(annotations));
- name: Upload annotations
uses: actions/upload-artifact@v4
with:
name: comment
path: annotations.json
Generated
+164 -114
View File
File diff suppressed because it is too large Load Diff
+13 -7
View File
@@ -1,6 +1,6 @@
[package]
name = "findutils"
version = "0.5.0"
version = "0.7.0"
homepage = "https://github.com/uutils/findutils"
repository = "https://github.com/uutils/findutils"
edition = "2021"
@@ -10,21 +10,22 @@ description = "Rust implementation of GNU findutils"
authors = ["uutils developers"]
[dependencies]
chrono = "0.4.37"
chrono = "0.4.38"
clap = "4.5"
faccess = "0.2.4"
walkdir = "2.5"
regex = "1.7"
regex = "1.10"
once_cell = "1.19"
onig = { version = "6.4", default-features = false }
uucore = { version = "0.0.25", features = ["entries", "fs", "fsext", "mode"] }
uucore = { version = "0.0.27", features = ["entries", "fs", "fsext", "mode"] }
nix = { version = "0.29", features = ["fs", "user"] }
[dev-dependencies]
assert_cmd = "2"
filetime = "0.2"
nix = { version = "0.28", features = ["fs"] }
nix = { version = "0.29", features = ["fs"] }
predicates = "3"
serial_test = "3.0"
serial_test = "3.1"
tempfile = "3"
pretty_assertions = "1.4.0"
@@ -54,6 +55,11 @@ ci = ["github"]
# The installers to generate for each app
installers = []
# Target platforms to build apps for (Rust target-triple syntax)
targets = ["aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-unknown-linux-gnu", "x86_64-pc-windows-msvc"]
targets = [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
"x86_64-unknown-linux-gnu",
"x86_64-pc-windows-msvc",
]
# Publish jobs to run in CI
pr-run-mode = "plan"
+5
View File
@@ -5,6 +5,11 @@
// https://opensource.org/licenses/MIT.
fn main() {
// Ignores the SIGPIPE signal.
// This is to solve the problem that when find is used with a pipe character,
// the downstream software of the standard output stream closes the pipe and triggers a panic.
uucore::panic::mute_sigpipe_panic();
let args = std::env::args().collect::<Vec<String>>();
let strs: Vec<&str> = args.iter().map(std::convert::AsRef::as_ref).collect();
let deps = findutils::find::StandardDependencies::new();
+2 -3
View File
@@ -5,9 +5,8 @@
// https://opensource.org/licenses/MIT.
use faccess::PathExt;
use walkdir::DirEntry;
use super::{Matcher, MatcherIO};
use super::{Matcher, MatcherIO, WalkEntry};
/// Matcher for -{read,writ,execut}able.
pub enum AccessMatcher {
@@ -17,7 +16,7 @@ pub enum AccessMatcher {
}
impl Matcher for AccessMatcher {
fn matches(&self, file_info: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
let path = file_info.path();
match self {
+9 -11
View File
@@ -7,13 +7,10 @@
* file that was distributed with this source code.
*/
use std::fs::{self, FileType};
use std::fs;
use std::io::{self, stderr, Write};
use std::path::Path;
use walkdir::DirEntry;
use super::{Matcher, MatcherIO};
use super::{Matcher, MatcherIO, WalkEntry};
pub struct DeleteMatcher;
@@ -22,17 +19,17 @@ impl DeleteMatcher {
DeleteMatcher
}
fn delete(&self, file_path: &Path, file_type: FileType) -> io::Result<()> {
if file_type.is_dir() {
fs::remove_dir(file_path)
fn delete(&self, entry: &WalkEntry) -> io::Result<()> {
if entry.file_type().is_dir() && !entry.path_is_symlink() {
fs::remove_dir(entry.path())
} else {
fs::remove_file(file_path)
fs::remove_file(entry.path())
}
}
}
impl Matcher for DeleteMatcher {
fn matches(&self, file_info: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, file_info: &WalkEntry, matcher_io: &mut MatcherIO) -> bool {
let path = file_info.path();
let path_str = path.to_string_lossy();
@@ -43,9 +40,10 @@ impl Matcher for DeleteMatcher {
return true;
}
match self.delete(path, file_info.file_type()) {
match self.delete(file_info) {
Ok(()) => true,
Err(e) => {
matcher_io.set_exit_code(1);
writeln!(&mut stderr(), "Failed to delete {path_str}: {e}").unwrap();
false
}
+2 -2
View File
@@ -9,7 +9,7 @@ use std::{
io::{stderr, Write},
};
use super::Matcher;
use super::{Matcher, MatcherIO, WalkEntry};
pub struct EmptyMatcher;
@@ -20,7 +20,7 @@ impl EmptyMatcher {
}
impl Matcher for EmptyMatcher {
fn matches(&self, file_info: &walkdir::DirEntry, _: &mut super::MatcherIO) -> bool {
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
if file_info.file_type().is_file() {
match file_info.metadata() {
Ok(meta) => meta.len() == 0,
+343
View File
@@ -0,0 +1,343 @@
//! Paths encountered during a walk.
use std::cell::OnceCell;
use std::error::Error;
use std::ffi::OsStr;
use std::fmt::{self, Display, Formatter};
use std::fs::{self, Metadata};
use std::io::{self, ErrorKind};
#[cfg(unix)]
use std::os::unix::fs::FileTypeExt;
use std::path::{Path, PathBuf};
use walkdir::DirEntry;
use super::Follow;
/// Wrapper for a directory entry.
#[derive(Debug)]
enum Entry {
/// Wraps an explicit path and depth.
Explicit(PathBuf, usize),
/// Wraps a WalkDir entry.
WalkDir(DirEntry),
}
/// File types.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum FileType {
Unknown,
Fifo,
CharDevice,
Directory,
BlockDevice,
Regular,
Symlink,
Socket,
}
impl FileType {
pub fn is_dir(self) -> bool {
self == Self::Directory
}
pub fn is_file(self) -> bool {
self == Self::Regular
}
pub fn is_symlink(self) -> bool {
self == Self::Symlink
}
}
impl From<fs::FileType> for FileType {
fn from(t: fs::FileType) -> FileType {
if t.is_dir() {
return FileType::Directory;
}
if t.is_file() {
return FileType::Regular;
}
if t.is_symlink() {
return FileType::Symlink;
}
#[cfg(unix)]
{
if t.is_fifo() {
return FileType::Fifo;
}
if t.is_char_device() {
return FileType::CharDevice;
}
if t.is_block_device() {
return FileType::BlockDevice;
}
if t.is_socket() {
return FileType::Socket;
}
}
FileType::Unknown
}
}
/// An error encountered while walking a file system.
#[derive(Clone, Debug)]
pub struct WalkError {
/// The path that caused the error, if known.
path: Option<PathBuf>,
/// The depth below the root path, if known.
depth: Option<usize>,
/// The io::Error::raw_os_error(), if known.
raw: Option<i32>,
}
impl WalkError {
/// Get the path this error occurred on, if known.
pub fn path(&self) -> Option<&Path> {
self.path.as_deref()
}
/// Get the traversal depth when this error occurred, if known.
pub fn depth(&self) -> Option<usize> {
self.depth
}
/// Get the kind of I/O error.
pub fn kind(&self) -> ErrorKind {
io::Error::from(self).kind()
}
/// Check for ErrorKind::{NotFound,NotADirectory}.
pub fn is_not_found(&self) -> bool {
if self.kind() == ErrorKind::NotFound {
return true;
}
// NotADirectory is nightly-only
#[cfg(unix)]
{
if self.raw == Some(uucore::libc::ENOTDIR) {
return true;
}
}
false
}
/// Check for ErrorKind::FilesystemLoop.
pub fn is_loop(&self) -> bool {
#[cfg(unix)]
return self.raw == Some(uucore::libc::ELOOP);
#[cfg(not(unix))]
return false;
}
}
impl Display for WalkError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
let ioe = io::Error::from(self);
if let Some(path) = &self.path {
write!(f, "{}: {}", path.display(), ioe)
} else {
write!(f, "{}", ioe)
}
}
}
impl Error for WalkError {}
impl From<io::Error> for WalkError {
fn from(e: io::Error) -> WalkError {
WalkError::from(&e)
}
}
impl From<&io::Error> for WalkError {
fn from(e: &io::Error) -> WalkError {
WalkError {
path: None,
depth: None,
raw: e.raw_os_error(),
}
}
}
impl From<walkdir::Error> for WalkError {
fn from(e: walkdir::Error) -> WalkError {
WalkError::from(&e)
}
}
impl From<&walkdir::Error> for WalkError {
fn from(e: &walkdir::Error) -> WalkError {
WalkError {
path: e.path().map(|p| p.to_owned()),
depth: Some(e.depth()),
raw: e.io_error().and_then(|e| e.raw_os_error()),
}
}
}
impl From<WalkError> for io::Error {
fn from(e: WalkError) -> io::Error {
io::Error::from(&e)
}
}
impl From<&WalkError> for io::Error {
fn from(e: &WalkError) -> io::Error {
e.raw
.map(io::Error::from_raw_os_error)
.unwrap_or_else(|| ErrorKind::Other.into())
}
}
/// A path encountered while walking a file system.
#[derive(Debug)]
pub struct WalkEntry {
/// The wrapped path/dirent.
inner: Entry,
/// Whether to follow symlinks.
follow: Follow,
/// Cached metadata.
meta: OnceCell<Result<Metadata, WalkError>>,
}
impl WalkEntry {
/// Create a new WalkEntry for a specific file.
pub fn new(path: impl Into<PathBuf>, depth: usize, follow: Follow) -> Self {
Self {
inner: Entry::Explicit(path.into(), depth),
follow,
meta: OnceCell::new(),
}
}
/// Convert a [walkdir::DirEntry] to a [WalkEntry]. Errors due to broken symbolic links will be
/// converted to valid entries, but other errors will be propagated.
pub fn from_walkdir(
result: walkdir::Result<DirEntry>,
follow: Follow,
) -> Result<WalkEntry, WalkError> {
let result = result.map_err(WalkError::from);
match result {
Ok(entry) => {
let ret = if entry.depth() == 0 && follow != Follow::Never {
// DirEntry::file_type() is wrong for root symlinks when follow_root_links is set
Self::new(entry.path(), 0, follow)
} else {
Self {
inner: Entry::WalkDir(entry),
follow,
meta: OnceCell::new(),
}
};
Ok(ret)
}
Err(e) if e.is_not_found() => {
// Detect broken symlinks and replace them with explicit entries
if let (Some(path), Some(depth)) = (e.path(), e.depth()) {
if let Ok(meta) = path.symlink_metadata() {
return Ok(WalkEntry {
inner: Entry::Explicit(path.into(), depth),
follow: Follow::Never,
meta: Ok(meta).into(),
});
}
}
Err(e)
}
Err(e) => Err(e),
}
}
/// Get the path to this entry.
pub fn path(&self) -> &Path {
match &self.inner {
Entry::Explicit(path, _) => path.as_path(),
Entry::WalkDir(ent) => ent.path(),
}
}
/// Get the path to this entry.
pub fn into_path(self) -> PathBuf {
match self.inner {
Entry::Explicit(path, _) => path,
Entry::WalkDir(ent) => ent.into_path(),
}
}
/// Get the name of this entry.
pub fn file_name(&self) -> &OsStr {
match &self.inner {
Entry::Explicit(path, _) => {
// Path::file_name() only works if the last component is normal
path.components()
.last()
.map(|c| c.as_os_str())
.unwrap_or_else(|| path.as_os_str())
}
Entry::WalkDir(ent) => ent.file_name(),
}
}
/// Get the depth of this entry below the root.
pub fn depth(&self) -> usize {
match &self.inner {
Entry::Explicit(_, depth) => *depth,
Entry::WalkDir(ent) => ent.depth(),
}
}
/// Get whether symbolic links are followed for this entry.
pub fn follow(&self) -> bool {
self.follow.follow_at_depth(self.depth())
}
/// Get the metadata on a cache miss.
fn get_metadata(&self) -> Result<Metadata, WalkError> {
self.follow.metadata_at_depth(self.path(), self.depth())
}
/// Get the [Metadata] for this entry, following symbolic links if appropriate.
/// Multiple calls to this function will cache and re-use the same [Metadata].
pub fn metadata(&self) -> Result<&Metadata, WalkError> {
let result = self.meta.get_or_init(|| match &self.inner {
Entry::Explicit(_, _) => Ok(self.get_metadata()?),
Entry::WalkDir(ent) => Ok(ent.metadata()?),
});
result.as_ref().map_err(|e| e.clone())
}
/// Get the file type of this entry.
pub fn file_type(&self) -> FileType {
match &self.inner {
Entry::Explicit(_, _) => self
.metadata()
.map(|m| m.file_type().into())
.unwrap_or(FileType::Unknown),
Entry::WalkDir(ent) => ent.file_type().into(),
}
}
/// Check whether this entry is a symbolic link, regardless of whether links
/// are being followed.
pub fn path_is_symlink(&self) -> bool {
match &self.inner {
Entry::Explicit(path, _) => {
if self.follow() {
path.symlink_metadata()
.is_ok_and(|m| m.file_type().is_symlink())
} else {
self.file_type().is_symlink()
}
}
Entry::WalkDir(ent) => ent.path_is_symlink(),
}
}
}
+3 -4
View File
@@ -9,9 +9,8 @@ use std::ffi::OsString;
use std::io::{stderr, Write};
use std::path::Path;
use std::process::Command;
use walkdir::DirEntry;
use super::{Matcher, MatcherIO};
use super::{Matcher, MatcherIO, WalkEntry};
enum Arg {
FileArg(Vec<OsString>),
@@ -52,7 +51,7 @@ impl SingleExecMatcher {
}
impl Matcher for SingleExecMatcher {
fn matches(&self, file_info: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
let mut command = Command::new(&self.executable);
let path_to_file = if self.exec_in_parent_dir {
if let Some(f) = file_info.path().file_name() {
@@ -67,7 +66,7 @@ impl Matcher for SingleExecMatcher {
for arg in &self.args {
match *arg {
Arg::LiteralArg(ref a) => command.arg(a.as_os_str()),
Arg::FileArg(ref parts) => command.arg(&parts.join(path_to_file.as_os_str())),
Arg::FileArg(ref parts) => command.arg(parts.join(path_to_file.as_os_str())),
};
}
if self.exec_in_parent_dir {
+188
View File
@@ -0,0 +1,188 @@
// This file is part of the uutils findutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use super::{Matcher, MatcherIO, WalkEntry};
/// The latest mapping from dev_id to fs_type, used for saving mount info reads
#[cfg(unix)]
pub struct Cache {
dev_id: String,
fs_type: String,
}
/// Get the filesystem type of a file.
/// 1. get the metadata of the file
/// 2. get the device ID of the metadata
/// 3. search the cache, then the filesystem list
///
/// Returns an empty string when no file system list matches.
///
/// # Errors
/// Returns an error if the metadata could not be read.
/// Returns an error if the filesystem list could not be read.
///
/// This is only supported on Unix.
#[cfg(unix)]
use std::{
cell::RefCell,
error::Error,
io::{stderr, Write},
path::Path,
};
#[cfg(unix)]
pub fn get_file_system_type(
path: &Path,
cache: &RefCell<Option<Cache>>,
) -> Result<String, Box<dyn Error>> {
use std::os::unix::fs::MetadataExt;
// use symlink_metadata (lstat under the hood) instead of metadata (stat) to make sure that it
// does not return an error when there is a (broken) symlink; this is aligned with GNU find.
let metadata = match path.symlink_metadata() {
Ok(metadata) => metadata,
Err(err) => Err(err)?,
};
let dev_id = metadata.dev().to_string();
if let Some(cache) = cache.borrow().as_ref() {
if cache.dev_id == dev_id {
return Ok(cache.fs_type.clone());
}
}
let fs_list = match uucore::fsext::read_fs_list() {
Ok(fs_list) => fs_list,
Err(err) => Err(err)?,
};
let result = fs_list
.into_iter()
.find(|fs| fs.dev_id == dev_id)
.map_or_else(String::new, |fs| fs.fs_type);
// cache the latest query if not a match before
cache.replace(Some(Cache {
dev_id,
fs_type: result.clone(),
}));
Ok(result)
}
/// This matcher handles the -fstype argument.
/// It matches the filesystem type of the file.
///
/// This is only supported on Unix.
pub struct FileSystemMatcher {
#[cfg(unix)]
fs_text: String,
#[cfg(unix)]
cache: RefCell<Option<Cache>>,
}
impl FileSystemMatcher {
#[cfg(unix)]
pub fn new(fs_text: String) -> Self {
Self {
fs_text,
cache: RefCell::new(None),
}
}
#[cfg(not(unix))]
pub fn new(_fs_text: String) -> Self {
Self {}
}
}
impl Matcher for FileSystemMatcher {
#[cfg(unix)]
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
match get_file_system_type(file_info.path(), &self.cache) {
Ok(result) => result == self.fs_text,
Err(_) => {
writeln!(
&mut stderr(),
"Error getting filesystem type for {}",
file_info.path().to_string_lossy()
)
.unwrap();
false
}
}
}
#[cfg(not(unix))]
fn matches(&self, _file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
false
}
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(unix)]
fn test_fs_matcher() {
use crate::find::{
matchers::{
fs::{get_file_system_type, Cache},
tests::get_dir_entry_for,
Matcher,
},
tests::FakeDependencies,
};
use std::cell::RefCell;
use std::fs::File;
use tempfile::Builder;
let deps = FakeDependencies::new();
let mut matcher_io = deps.new_matcher_io();
// create temp file and get its fs type
// We pass this file and the corresponding file system type into the Matcher for comparison.
let temp_dir = Builder::new().prefix("fs_matcher").tempdir().unwrap();
let foo_path = temp_dir.path().join("foo");
let _ = File::create(foo_path).expect("create temp file");
let file_info = get_dir_entry_for(&temp_dir.path().to_string_lossy(), "foo");
// create an empty cache for initial fs type lookup
let empty_cache = RefCell::new(None);
let target_fs_type = get_file_system_type(file_info.path(), &empty_cache).unwrap();
// should work with unmatched cache, and the cache should be set to the last query result
let unmatched_cache = RefCell::new(Some(Cache {
dev_id: "foo".to_string(),
fs_type: "bar".to_string(),
}));
let target_fs_type_unmatched_cache =
get_file_system_type(file_info.path(), &unmatched_cache).unwrap();
assert_eq!(
target_fs_type, target_fs_type_unmatched_cache,
"get_file_system_type should return correct result with unmatched cache"
);
assert_eq!(
unmatched_cache.borrow().as_ref().unwrap().fs_type,
target_fs_type,
"get_file_system_type should set the cache to the last query result"
);
// should match fs type
let matcher = super::FileSystemMatcher::new(target_fs_type.clone());
assert!(
matcher.matches(&file_info, &mut matcher_io),
"{} should match {}",
file_info.path().to_string_lossy(),
target_fs_type
);
// should not match fs type
let matcher = super::FileSystemMatcher::new(target_fs_type.clone() + "foo");
assert!(
!matcher.matches(&file_info, &mut matcher_io),
"{} should not match {}",
file_info.path().to_string_lossy(),
target_fs_type
);
}
}
+166
View File
@@ -0,0 +1,166 @@
// This file is part of the uutils findutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use super::{Matcher, MatcherIO, WalkEntry};
#[cfg(unix)]
use nix::unistd::Group;
#[cfg(unix)]
use std::os::unix::fs::MetadataExt;
pub struct GroupMatcher {
gid: Option<u32>,
}
impl GroupMatcher {
#[cfg(unix)]
pub fn from_group_name(group: &str) -> GroupMatcher {
// get gid from group name
let Ok(group) = Group::from_name(group) else {
return GroupMatcher { gid: None };
};
let Some(group) = group else {
// This if branch is to determine whether a certain group exists in the system.
// If a certain group does not exist in the system,
// the result will need to be returned according to
// the flag bit of whether to invert the result.
return GroupMatcher { gid: None };
};
GroupMatcher {
gid: Some(group.gid.as_raw()),
}
}
#[cfg(unix)]
pub fn from_gid(gid: u32) -> GroupMatcher {
GroupMatcher { gid: Some(gid) }
}
#[cfg(windows)]
pub fn from_group_name(_group: &str) -> GroupMatcher {
GroupMatcher { gid: None }
}
#[cfg(windows)]
pub fn from_gid(_gid: u32) -> GroupMatcher {
GroupMatcher { gid: None }
}
pub fn gid(&self) -> &Option<u32> {
&self.gid
}
}
impl Matcher for GroupMatcher {
#[cfg(unix)]
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
let Ok(metadata) = file_info.metadata() else {
return false;
};
let file_gid = metadata.gid();
// When matching the -group parameter in find/matcher/mod.rs,
// it has been judged that the group does not exist and an error is returned.
// So use unwarp() directly here.
self.gid.unwrap() == file_gid
}
#[cfg(windows)]
fn matches(&self, _file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
// The user group acquisition function for Windows systems is not implemented in MetadataExt,
// so it is somewhat difficult to implement it. :(
false
}
}
pub struct NoGroupMatcher {}
impl Matcher for NoGroupMatcher {
#[cfg(unix)]
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
use nix::unistd::Gid;
if file_info.path().is_symlink() {
return false;
}
let Ok(metadata) = file_info.metadata() else {
return true;
};
let Ok(gid) = Group::from_gid(Gid::from_raw(metadata.gid())) else {
return true;
};
let Some(_group) = gid else {
return true;
};
false
}
#[cfg(windows)]
fn matches(&self, _file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
false
}
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(unix)]
fn test_group_matcher() {
use crate::find::matchers::{group::GroupMatcher, tests::get_dir_entry_for, Matcher};
use crate::find::tests::FakeDependencies;
use chrono::Local;
use nix::unistd::{Gid, Group};
use std::fs::File;
use std::os::unix::fs::MetadataExt;
use tempfile::Builder;
let deps = FakeDependencies::new();
let mut matcher_io = deps.new_matcher_io();
let temp_dir = Builder::new().prefix("group_matcher").tempdir().unwrap();
let foo_path = temp_dir.path().join("foo");
let _ = File::create(foo_path).expect("create temp file");
let file_info = get_dir_entry_for(&temp_dir.path().to_string_lossy(), "foo");
let file_gid = file_info.metadata().unwrap().gid();
let file_group = Group::from_gid(Gid::from_raw(file_gid))
.unwrap()
.unwrap()
.name;
let matcher = super::GroupMatcher::from_group_name(file_group.as_str());
assert!(
matcher.matches(&file_info, &mut matcher_io),
"group should match"
);
// Testing a non-existent group name
let time_string = Local::now().format("%Y%m%d%H%M%S").to_string();
let matcher = GroupMatcher::from_group_name(time_string.as_str());
assert!(
matcher.gid().is_none(),
"group name {} should not exist",
time_string
);
// Testing group id
let matcher = GroupMatcher::from_gid(file_gid);
assert!(
matcher.gid().is_some(),
"group id {} should exist",
file_gid
);
assert!(
matcher.matches(&file_info, &mut matcher_io),
"group id should match"
);
}
}
+3 -5
View File
@@ -7,12 +7,10 @@
use std::io::{stderr, Write};
use std::path::PathBuf;
use walkdir::DirEntry;
use super::glob::Pattern;
use super::{Matcher, MatcherIO};
use super::{Matcher, MatcherIO, WalkEntry};
fn read_link_target(file_info: &DirEntry) -> Option<PathBuf> {
fn read_link_target(file_info: &WalkEntry) -> Option<PathBuf> {
match file_info.path().read_link() {
Ok(target) => Some(target),
Err(err) => {
@@ -47,7 +45,7 @@ impl LinkNameMatcher {
}
impl Matcher for LinkNameMatcher {
fn matches(&self, file_info: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
if let Some(target) = read_link_target(file_info) {
self.pattern.matches(&target.to_string_lossy())
} else {
+9 -10
View File
@@ -11,9 +11,8 @@
//! to "-foo -o ( -bar -baz )", not "( -foo -o -bar ) -baz").
use std::error::Error;
use std::path::Path;
use walkdir::DirEntry;
use super::{Matcher, MatcherIO};
use super::{Matcher, MatcherIO, WalkEntry};
/// This matcher contains a collection of other matchers. A file only matches
/// if it matches ALL the contained sub-matchers. For sub-matchers that have
@@ -33,7 +32,7 @@ impl Matcher for AndMatcher {
/// Returns true if all sub-matchers return true. Short-circuiting does take
/// place. If the nth sub-matcher returns false, then we immediately return
/// and don't make any further calls.
fn matches(&self, dir_entry: &DirEntry, matcher_io: &mut MatcherIO) -> bool {
fn matches(&self, dir_entry: &WalkEntry, matcher_io: &mut MatcherIO) -> bool {
for matcher in &self.submatchers {
if !matcher.matches(dir_entry, matcher_io) {
return false;
@@ -109,7 +108,7 @@ impl Matcher for OrMatcher {
/// Returns true if any sub-matcher returns true. Short-circuiting does take
/// place. If the nth sub-matcher returns true, then we immediately return
/// and don't make any further calls.
fn matches(&self, dir_entry: &DirEntry, matcher_io: &mut MatcherIO) -> bool {
fn matches(&self, dir_entry: &WalkEntry, matcher_io: &mut MatcherIO) -> bool {
for matcher in &self.submatchers {
if matcher.matches(dir_entry, matcher_io) {
return true;
@@ -206,7 +205,7 @@ impl ListMatcher {
impl Matcher for ListMatcher {
/// Calls matches on all submatcher objects, with no short-circuiting.
/// Returns the result of the call to the final submatcher
fn matches(&self, dir_entry: &DirEntry, matcher_io: &mut MatcherIO) -> bool {
fn matches(&self, dir_entry: &WalkEntry, matcher_io: &mut MatcherIO) -> bool {
let mut rc = false;
for matcher in &self.submatchers {
rc = matcher.matches(dir_entry, matcher_io);
@@ -311,7 +310,7 @@ impl ListMatcherBuilder {
pub struct TrueMatcher;
impl Matcher for TrueMatcher {
fn matches(&self, _dir_entry: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, _dir_entry: &WalkEntry, _: &mut MatcherIO) -> bool {
true
}
}
@@ -320,7 +319,7 @@ impl Matcher for TrueMatcher {
pub struct FalseMatcher;
impl Matcher for FalseMatcher {
fn matches(&self, _dir_entry: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, _dir_entry: &WalkEntry, _: &mut MatcherIO) -> bool {
false
}
}
@@ -339,7 +338,7 @@ impl NotMatcher {
}
impl Matcher for NotMatcher {
fn matches(&self, dir_entry: &DirEntry, matcher_io: &mut MatcherIO) -> bool {
fn matches(&self, dir_entry: &WalkEntry, matcher_io: &mut MatcherIO) -> bool {
!self.submatcher.matches(dir_entry, matcher_io)
}
@@ -370,7 +369,7 @@ mod tests {
pub struct HasSideEffects;
impl Matcher for HasSideEffects {
fn matches(&self, _: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, _: &WalkEntry, _: &mut MatcherIO) -> bool {
false
}
@@ -383,7 +382,7 @@ mod tests {
struct Counter(Rc<RefCell<u32>>);
impl Matcher for Counter {
fn matches(&self, _: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, _: &WalkEntry, _: &mut MatcherIO) -> bool {
*self.0.borrow_mut() += 1;
true
}
+294
View File
@@ -0,0 +1,294 @@
// This file is part of the uutils findutils package.
//
// For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code.
use chrono::DateTime;
use std::{
fs::File,
io::{stderr, Write},
};
use super::{Matcher, MatcherIO, WalkEntry};
#[cfg(unix)]
fn format_permissions(mode: uucore::libc::mode_t) -> String {
let file_type = match mode & (uucore::libc::S_IFMT as uucore::libc::mode_t) {
uucore::libc::S_IFDIR => "d",
uucore::libc::S_IFREG => "-",
_ => "?",
};
// S_$$USR means "user permissions"
let user_perms = format!(
"{}{}{}",
if mode & uucore::libc::S_IRUSR != 0 {
"r"
} else {
"-"
},
if mode & uucore::libc::S_IWUSR != 0 {
"w"
} else {
"-"
},
if mode & uucore::libc::S_IXUSR != 0 {
"x"
} else {
"-"
}
);
// S_$$GRP means "group permissions"
let group_perms = format!(
"{}{}{}",
if mode & uucore::libc::S_IRGRP != 0 {
"r"
} else {
"-"
},
if mode & uucore::libc::S_IWGRP != 0 {
"w"
} else {
"-"
},
if mode & uucore::libc::S_IXGRP != 0 {
"x"
} else {
"-"
}
);
// S_$$OTH means "other permissions"
let other_perms = format!(
"{}{}{}",
if mode & uucore::libc::S_IROTH != 0 {
"r"
} else {
"-"
},
if mode & uucore::libc::S_IWOTH != 0 {
"w"
} else {
"-"
},
if mode & uucore::libc::S_IXOTH != 0 {
"x"
} else {
"-"
}
);
format!("{}{}{}{}", file_type, user_perms, group_perms, other_perms)
}
#[cfg(windows)]
fn format_permissions(file_attributes: u32) -> String {
let mut attributes = Vec::new();
// https://learn.microsoft.com/en-us/windows/win32/fileio/file-attribute-constants
if file_attributes & 0x0001 != 0 {
attributes.push("read-only");
}
if file_attributes & 0x0002 != 0 {
attributes.push("hidden");
}
if file_attributes & 0x0004 != 0 {
attributes.push("system");
}
if file_attributes & 0x0020 != 0 {
attributes.push("archive");
}
if file_attributes & 0x0040 != 0 {
attributes.push("compressed");
}
if file_attributes & 0x0080 != 0 {
attributes.push("offline");
}
attributes.join(", ")
}
pub struct Ls {
output_file: Option<File>,
}
impl Ls {
pub fn new(output_file: Option<File>) -> Self {
Self { output_file }
}
#[cfg(unix)]
fn print(&self, file_info: &WalkEntry, mut out: impl Write, print_error_message: bool) {
use nix::unistd::{Gid, Group, Uid, User};
use std::os::unix::fs::{MetadataExt, PermissionsExt};
let metadata = file_info.metadata().unwrap();
let inode_number = metadata.ino();
let number_of_blocks = {
let size = metadata.size();
let number_of_blocks = size / 1024;
let remainder = number_of_blocks % 4;
if remainder == 0 {
if number_of_blocks == 0 {
4
} else {
number_of_blocks
}
} else {
number_of_blocks + (4 - (remainder))
}
};
let permission =
{ format_permissions(metadata.permissions().mode() as uucore::libc::mode_t) };
let hard_links = metadata.nlink();
let user = {
let uid = metadata.uid();
User::from_uid(Uid::from_raw(uid)).unwrap().unwrap().name
};
let group = {
let gid = metadata.gid();
Group::from_gid(Gid::from_raw(gid)).unwrap().unwrap().name
};
let size = metadata.size();
let last_modified = {
let system_time = metadata.modified().unwrap();
let now_utc: DateTime<chrono::Utc> = system_time.into();
now_utc.format("%b %e %H:%M")
};
let path = file_info.path().to_string_lossy();
match writeln!(
out,
" {:<4} {:>6} {:<10} {:>3} {:<8} {:<8} {:>8} {} {}",
inode_number,
number_of_blocks,
permission,
hard_links,
user,
group,
size,
last_modified,
path,
) {
Ok(_) => {}
Err(e) => {
if print_error_message {
writeln!(
&mut stderr(),
"Error writing {:?} for {}",
file_info.path().to_string_lossy(),
e
)
.unwrap();
uucore::error::set_exit_code(1);
}
}
}
}
#[cfg(windows)]
fn print(&self, file_info: &WalkEntry, mut out: impl Write, print_error_message: bool) {
use std::os::windows::fs::MetadataExt;
let metadata = file_info.metadata().unwrap();
let inode_number = 0;
let number_of_blocks = {
let size = metadata.file_size();
let number_of_blocks = size / 1024;
let remainder = number_of_blocks % 4;
if remainder == 0 {
if number_of_blocks == 0 {
4
} else {
number_of_blocks
}
} else {
number_of_blocks + (4 - (remainder))
}
};
let permission = { format_permissions(metadata.file_attributes()) };
let hard_links = 0;
let user = 0;
let group = 0;
let size = metadata.file_size();
let last_modified = {
let system_time = metadata.modified().unwrap();
let now_utc: DateTime<chrono::Utc> = system_time.into();
now_utc.format("%b %e %H:%M")
};
let path = file_info.path().to_string_lossy();
match write!(
out,
" {:<4} {:>6} {:<10} {:>3} {:<8} {:<8} {:>8} {} {}\n",
inode_number,
number_of_blocks,
permission,
hard_links,
user,
group,
size,
last_modified,
path,
) {
Ok(_) => {}
Err(e) => {
if print_error_message {
writeln!(
&mut stderr(),
"Error writing {:?} for {}",
file_info.path().to_string_lossy(),
e
)
.unwrap();
uucore::error::set_exit_code(1);
}
}
}
}
}
impl Matcher for Ls {
fn matches(&self, file_info: &WalkEntry, matcher_io: &mut MatcherIO) -> bool {
if let Some(file) = &self.output_file {
self.print(file_info, file, true);
} else {
self.print(
file_info,
&mut *matcher_io.deps.get_output().borrow_mut(),
false,
);
}
true
}
fn has_side_effects(&self) -> bool {
true
}
}
#[cfg(test)]
mod tests {
#[test]
#[cfg(unix)]
fn test_format_permissions() {
use super::format_permissions;
let mode: uucore::libc::mode_t = 0o100644;
let expected = "-rw-r--r--";
assert_eq!(format_permissions(mode), expected);
let mode: uucore::libc::mode_t = 0o040755;
let expected = "drwxr-xr-x";
assert_eq!(format_permissions(mode), expected);
let mode: uucore::libc::mode_t = 0o100777;
let expected = "-rwxrwxrwx";
assert_eq!(format_permissions(mode), expected);
}
}
+487 -78
View File
File diff suppressed because it is too large Load Diff
+2 -4
View File
@@ -4,10 +4,8 @@
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
use walkdir::DirEntry;
use super::glob::Pattern;
use super::{Matcher, MatcherIO};
use super::{Matcher, MatcherIO, WalkEntry};
/// This matcher makes a comparison of the name against a shell wildcard
/// pattern. See `glob::Pattern` for details on the exact syntax.
@@ -23,7 +21,7 @@ impl NameMatcher {
}
impl Matcher for NameMatcher {
fn matches(&self, file_info: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
let name = file_info.file_name().to_string_lossy();
self.pattern.matches(&name)
}
+2 -4
View File
@@ -4,10 +4,8 @@
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
use walkdir::DirEntry;
use super::glob::Pattern;
use super::{Matcher, MatcherIO};
use super::{Matcher, MatcherIO, WalkEntry};
/// This matcher makes a comparison of the path against a shell wildcard
/// pattern. See `glob::Pattern` for details on the exact syntax.
@@ -23,7 +21,7 @@ impl PathMatcher {
}
impl Matcher for PathMatcher {
fn matches(&self, file_info: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
let path = file_info.path().to_string_lossy();
self.pattern.matches(&path)
}
+3 -4
View File
@@ -12,9 +12,8 @@ use std::error::Error;
use std::io::{stderr, Write};
#[cfg(unix)]
use uucore::mode::{parse_numeric, parse_symbolic};
use walkdir::DirEntry;
use super::{Matcher, MatcherIO};
use super::{Matcher, MatcherIO, WalkEntry};
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg(unix)]
@@ -101,7 +100,7 @@ impl PermMatcher {
impl Matcher for PermMatcher {
#[cfg(unix)]
fn matches(&self, file_info: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
use std::os::unix::fs::PermissionsExt;
match file_info.metadata() {
Ok(metadata) => {
@@ -127,7 +126,7 @@ impl Matcher for PermMatcher {
}
#[cfg(not(unix))]
fn matches(&self, _dummy_file_info: &DirEntry, _: &mut MatcherIO) -> bool {
fn matches(&self, _dummy_file_info: &WalkEntry, _: &mut MatcherIO) -> bool {
writeln!(
&mut stderr(),
"Permission matching not available on this platform!"

Some files were not shown because too many files have changed in this diff Show More