Merge branch 'main' into printf-rewrite

This commit is contained in:
Terts Diepraam 2023-11-20 13:53:11 +01:00
commit 6d2698b802
179 changed files with 2883 additions and 2016 deletions

View file

@ -461,17 +461,18 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
job: job:
# { os , target , cargo-options , features , use-cross , toolchain } # - { os , target , cargo-options , features , use-cross , toolchain, skip-tests }
- { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf, features: feat_os_unix_gnueabihf, use-cross: use-cross, } - { os: ubuntu-latest , target: arm-unknown-linux-gnueabihf, features: feat_os_unix_gnueabihf, use-cross: use-cross, }
- { os: ubuntu-latest , target: aarch64-unknown-linux-gnu , features: feat_os_unix_gnueabihf , use-cross: use-cross } - { os: ubuntu-latest , target: aarch64-unknown-linux-gnu , features: feat_os_unix_gnueabihf , use-cross: use-cross }
# - { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: feat_selinux , use-cross: use-cross } # - { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: feat_selinux , use-cross: use-cross }
- { os: ubuntu-latest , target: i686-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross } - { os: ubuntu-latest , target: i686-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross }
- { os: ubuntu-latest , target: i686-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross } - { os: ubuntu-latest , target: i686-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross }
- { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross } - { os: ubuntu-latest , target: x86_64-unknown-linux-gnu , features: feat_os_unix , use-cross: use-cross }
- { os: ubuntu-latest , target: x86_64-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross } - { os: ubuntu-latest , target: x86_64-unknown-linux-musl , features: feat_os_unix_musl , use-cross: use-cross }
- { os: macos-latest , target: aarch64-apple-darwin , features: feat_os_macos , use-cross: use-cross, skip-tests: true} # Hopefully github provides free M1 runners soon...
- { os: macos-latest , target: x86_64-apple-darwin , features: feat_os_macos } - { os: macos-latest , target: x86_64-apple-darwin , features: feat_os_macos }
- { os: windows-latest , target: i686-pc-windows-msvc , features: feat_os_windows } - { os: windows-latest , target: i686-pc-windows-msvc , features: feat_os_windows }
- { os: windows-latest , target: x86_64-pc-windows-gnu , features: feat_os_windows } ## note: requires rust >= 1.43.0 to link correctly - { os: windows-latest , target: x86_64-pc-windows-gnu , features: feat_os_windows }
- { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows } - { os: windows-latest , target: x86_64-pc-windows-msvc , features: feat_os_windows }
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -575,7 +576,7 @@ jobs:
- uses: taiki-e/install-action@v2 - uses: taiki-e/install-action@v2
if: steps.vars.outputs.CARGO_CMD == 'cross' if: steps.vars.outputs.CARGO_CMD == 'cross'
with: with:
tool: cross@0.2.1 tool: cross@0.2.5
- name: Create all needed build/work directories - name: Create all needed build/work directories
shell: bash shell: bash
run: | run: |
@ -650,6 +651,7 @@ jobs:
${{ steps.vars.outputs.CARGO_CMD }} +${{ env.RUST_MIN_SRV }} build --release \ ${{ steps.vars.outputs.CARGO_CMD }} +${{ env.RUST_MIN_SRV }} build --release \
--target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }} --target=${{ matrix.job.target }} ${{ matrix.job.cargo-options }} ${{ steps.vars.outputs.CARGO_FEATURES_OPTION }}
- name: Test - name: Test
if: matrix.job.skip-tests != true
shell: bash shell: bash
run: | run: |
## Test ## Test
@ -658,6 +660,7 @@ jobs:
env: env:
RUST_BACKTRACE: "1" RUST_BACKTRACE: "1"
- name: Test individual utilities - name: Test individual utilities
if: matrix.job.skip-tests != true
shell: bash shell: bash
run: | run: |
## Test individual utilities ## Test individual utilities

View file

@ -18,7 +18,7 @@ jobs:
github.event.workflow_run.event == 'pull_request' github.event.workflow_run.event == 'pull_request'
steps: steps:
- name: 'Download artifact' - name: 'Download artifact'
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
script: | script: |
// List all artifacts from GnuTests // List all artifacts from GnuTests
@ -43,7 +43,7 @@ jobs:
- run: unzip comment.zip - run: unzip comment.zip
- name: 'Comment on PR' - name: 'Comment on PR'
uses: actions/github-script@v6 uses: actions/github-script@v7
with: with:
github-token: ${{ secrets.GITHUB_TOKEN }} github-token: ${{ secrets.GITHUB_TOKEN }}
script: | script: |

View file

@ -117,7 +117,7 @@ jobs:
run: | run: |
## `cargo clippy` lint testing ## `cargo clippy` lint testing
unset fault unset fault
CLIPPY_FLAGS="-W clippy::default_trait_access -W clippy::manual_string_new -W clippy::cognitive_complexity" CLIPPY_FLAGS="-W clippy::default_trait_access -W clippy::manual_string_new -W clippy::cognitive_complexity -W clippy::implicit_clone"
fault_type="${{ steps.vars.outputs.FAULT_TYPE }}" fault_type="${{ steps.vars.outputs.FAULT_TYPE }}"
fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]') fault_prefix=$(echo "$fault_type" | tr '[:lower:]' '[:upper:]')
# * convert any warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message> # * convert any warnings to GHA UI annotations; ref: <https://help.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-a-warning-message>

View file

@ -13,52 +13,62 @@ concurrency:
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
jobs: jobs:
fuzz: fuzz-build:
name: Run the fuzzers name: Build the fuzzers
runs-on: ubuntu-latest runs-on: ubuntu-latest
env:
RUN_FOR: 60
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly - uses: dtolnay/rust-toolchain@nightly
- name: Install `cargo-fuzz` - name: Install `cargo-fuzz`
run: cargo install cargo-fuzz run: cargo install cargo-fuzz
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
with:
shared-key: "cargo-fuzz-cache-key"
cache-directories: "fuzz/target"
- name: Run `cargo-fuzz build`
run: cargo +nightly fuzz build
fuzz-run:
needs: fuzz-build
name: Run the fuzzers
runs-on: ubuntu-latest
env:
RUN_FOR: 60
strategy:
matrix:
test-target:
[
fuzz_date,
fuzz_test,
fuzz_expr,
fuzz_parse_glob,
fuzz_parse_size,
fuzz_parse_time,
# adding more fuzz tests here.
# e.g. fuzz_test_a,
]
steps:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@nightly
- name: Install `cargo-fuzz`
run: cargo install cargo-fuzz
- uses: Swatinem/rust-cache@v2
with:
shared-key: "cargo-fuzz-cache-key"
cache-directories: "fuzz/target"
- name: Restore Cached Corpus - name: Restore Cached Corpus
uses: actions/cache/restore@v3 uses: actions/cache/restore@v3
with: with:
key: corpus-cache key: corpus-cache-${{ matrix.test-target }}
path: | path: |
fuzz/corpus fuzz/corpus/${{ matrix.test-target }}
- name: Run fuzz_date for XX seconds - name: Run ${{ matrix.test-target }} for XX seconds
continue-on-error: true
shell: bash shell: bash
run: | run: |
cargo +nightly fuzz run fuzz_date -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0 cargo +nightly fuzz run ${{ matrix.test-target }} -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_test for XX seconds
shell: bash
run: |
cargo +nightly fuzz run fuzz_test -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_expr for XX seconds
continue-on-error: true
shell: bash
run: |
cargo +nightly fuzz run fuzz_expr -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_glob for XX seconds
shell: bash
run: |
cargo +nightly fuzz run fuzz_parse_glob -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_size for XX seconds
shell: bash
run: |
cargo +nightly fuzz run fuzz_parse_size -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Run fuzz_parse_time for XX seconds
shell: bash
run: |
cargo +nightly fuzz run fuzz_parse_time -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
- name: Save Corpus Cache - name: Save Corpus Cache
uses: actions/cache/save@v3 uses: actions/cache/save@v3
with: with:
key: corpus-cache key: corpus-cache-${{ matrix.test-target }}
path: | path: |
fuzz/corpus fuzz/corpus/${{ matrix.test-target }}

View file

@ -59,6 +59,7 @@ clippy
rustc rustc
rustfmt rustfmt
rustup rustup
rustdoc
# #
bitor # BitOr trait function bitor # BitOr trait function
bitxor # BitXor trait function bitxor # BitXor trait function

View file

@ -1,52 +1,270 @@
<!-- spell-checker:ignore reimplementing toybox RUNTEST CARGOFLAGS nextest --> <!-- spell-checker:ignore reimplementing toybox RUNTEST CARGOFLAGS nextest embeddable Rustonomicon rustdoc's -->
# Contributing to coreutils # Contributing to coreutils
Contributions are very welcome via Pull Requests. If you don't know where to Hi! Welcome to uutils/coreutils!
start, take a look at the
[`good-first-issues`](https://github.com/uutils/coreutils/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).
If you have any questions, feel free to ask them in the issues or on
[Discord](https://discord.gg/wQVJbvJ).
## Best practices Thanks for wanting to contribute to this project! This document explains
everything you need to know to contribute. Before you start make sure to also
check out these documents:
1. Follow what GNU is doing in terms of options and behavior. It is recommended - Our community's [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
to look at the GNU Coreutils manual ([on the - [DEVELOPMENT.md](./DEVELOPMENT.md) for setting up your development
web](https://www.gnu.org/software/coreutils/manual/html_node/index.html), or environment.
locally using `info <utility>`). It is more in depth than the man pages and
provides a good description of available features and their implementation Now follows a very important warning:
details.
1. If possible, look at the GNU test suite execution in the CI and make the test > [!WARNING]
work if failing. > uutils is original code and cannot contain any code from GNU or
1. Use clap for argument management. > other implementations. This means that **we cannot accept any changes based on
1. Make sure that the code coverage is covering all of the cases, including > the GNU source code**. To make sure that cannot happen, **you cannot link to
errors. > the GNU source code** either.
1. The code must be clippy-warning-free and rustfmt-compliant.
1. Don't hesitate to move common functions into uucore if they can be reused by Finally, feel free to join our [Discord](https://discord.gg/wQVJbvJ)!
other binaries.
1. Unsafe code should be documented with Safety comments. ## Getting Oriented
1. uutils is original code. It cannot contain code from existing GNU or Unix-like
utilities, nor should it link to or reference GNU libraries. uutils is a big project consisting of many parts. Here are the most important
parts for getting started:
- [`src/uu`](./src/uu/): The code for all utilities
- [`src/uucore`](./src/uucore/): Crate containing all the shared code between
the utilities.
- [`tests/by-util`](./tests/by-util/): The tests for all utilities.
- [`src/bin/coreutils.rs`](./src/bin/coreutils.rs): Code for the multicall
binary.
- [`docs`](./docs/src): the documentation for the website
Each utility is defined as a separate crate. The structure of each of these
crates is as follows:
- `Cargo.toml`
- `src/main.rs`: contains only a single macro call
- `src/<util name>.rs`: the actual code for the utility
- `<util name>.md`: the documentation for the utility
We have separated repositories for crates that we maintain but also publish for
use by others:
- [uutils-term-grid](https://github.com/uutils/uutils-term-grid)
- [parse_datetime](https://github.com/uutils/parse_datetime)
## Design Goals
We have the following goals with our development:
- **Compatible**: The utilities should be a drop-in replacement for the GNU
coreutils.
- **Cross-platform**: All utilities should run on as many of the supported
platforms as possible.
- **Reliable**: The utilities should never unexpectedly fail.
- **Performant**: Our utilities should be written in fast idiomatic Rust. We aim
to match or exceed the performance of the GNU utilities.
- **Well-tested**: We should have a lot of tests to be able to guarantee
reliability and compatibility.
## How to Help
There are several ways to help and writing code is just one of them. Reporting
issues and writing documentation are just as important as writing code.
### Reporting Issues
We can't fix bugs we don't know about, so good issues are super helpful! Here
are some tips for writing good issues:
- If you find a bug, make sure it's still a problem on the `main` branch.
- Search through the existing issues to see whether it has already been
reported.
- Make sure to include all relevant information, such as:
- Which version of uutils did you check?
- Which version of GNU coreutils are you comparing with?
- What platform are you on?
- Provide a way to reliably reproduce the issue.
- Be as specific as possible!
### Writing Documentation
There's never enough documentation. If you come across any documentation that
could be improved, feel free to submit a PR for it!
### Writing Code
If you want to submit a PR, make sure that you've discussed the solution with
the maintainers beforehand. We want to avoid situations where you put a lot of
work into a fix that we can't merge! If there's no issue for what you're trying
to fix yet, make one _before_ you start working on the PR.
Generally, we try to follow what GNU is doing in terms of options and behavior.
It is recommended to look at the GNU coreutils manual
([on the web](https://www.gnu.org/software/coreutils/manual/html_node/index.html),
or locally using `info <utility>`). It is more in depth than the man pages and
provides a good description of available features and their implementation
details. But remember, you cannot look at the GNU source code!
Also remember that we can only merge PRs which pass our test suite, follow
rustfmt, and do not have any warnings from clippy. See
[DEVELOPMENT.md](./DEVELOPMENT.md) for more information. Be sure to also read
about our [Rust style](#our-rust-style).
## Our Rust Style
We want uutils to be written in idiomatic Rust, so here are some guidelines to
follow. Some of these are aspirational, meaning that we don't do them correctly
everywhere in the code. If you find violations of the advice below, feel free to
submit a patch!
### Don't `panic!`
The coreutils should be very reliable. This means that we should never `panic!`.
Therefore, you should avoid using `.unwrap()` and `panic!`. Sometimes the use of
`unreachable!` can be justified with a comment explaining why that code is
unreachable.
### Don't `exit`
We want uutils to be embeddable in other programs. This means that no function
in uutils should exit the program. Doing so would also lead to code with more
confusing control flow. Avoid therefore `std::process::exit` and similar
functions which exit the program early.
### `unsafe`
uutils cannot be entirely safe, because we have to call out to `libc` and do
syscalls. However, we still want to limit our use of `unsafe`. We generally only
accept `unsafe` for FFI, with very few exceptions. Note that performance is very
rarely a valid argument for using `unsafe`.
If you still need to write code with `unsafe`, make sure to read the
[Rustonomicon](https://doc.rust-lang.org/nomicon/intro.html) and annotate the
calls with `// SAFETY:` comments explaining why the use of `unsafe` is sound.
### Macros
Macros can be a great tool, but they are also usually hard to understand. They
should be used sparingly. Make sure to explore simpler options before you reach
for a solution involving macros.
### `str`, `OsStr` & `Path`
Rust has many string-like types, and sometimes it's hard to choose the right
one. It's tempting to use `str` (and `String`) for everything, but that is not
always the right choice for uutils, because we need to support invalid UTF-8,
just like the GNU coreutils. For example, paths on Linux might not be valid
UTF-8! Whenever we are dealing with paths, we should therefore stick with
`OsStr` and `Path`. Make sure that you only convert to `str`/`String` if you
know that something is always valid UTF-8. If you need more operations on
`OsStr`, you can use the [`bstr`](https://docs.rs/bstr/latest/bstr/) crate.
### Doc-comments
We use rustdoc for our documentation, so it's best to follow
[rustdoc's guidelines](https://doc.rust-lang.org/rustdoc/how-to-write-documentation.html#documenting-components).
Make sure that your documentation is not just repeating the name of the
function, but actually giving more useful information. Rustdoc recommends the
following structure:
```
[short sentence explaining what it is]
[more detailed explanation]
[at least one code example that users can copy/paste to try it]
[even more advanced explanations if necessary]
```
### Other comments
Comments should be written to _explain_ the code, not to _describe_ the code.
Try to focus on explaining _why_ the code is the way it is. If you feel like you
have to describe the code, that's usually a sign that you could improve the
naming of variables and functions.
If you edit a piece of code, make sure to update any comments that need to
change as a result. The only thing worse than having no comments is having
outdated comments!
## Git Etiquette
To ensure easy collaboration, we have guidelines for using Git and GitHub.
### Commits
- Make small and atomic commits.
- Keep a clean history of commits.
- Write informative commit messages.
- Annotate your commit message with the component you're editing. For example:
`cp: do not overwrite on with -i` or `uucore: add support for FreeBSD`.
- Do not unnecessarily move items around in the code. This makes the changes
much harder to review. If you do need to move things around, do that in a
separate commit.
### Commit messages
You can read this section in the Git book to learn how to write good commit
messages: https://git-scm.com/book/ch5-2.html.
In addition, here are a few examples for a summary line when committing to
uutils:
- commit for a single utility
```
nohup: cleanup and refactor
```
- commit for a utility's tests
```
tests/rm: test new feature
```
Beyond changes to an individual utility or its tests, other summary lines for
non-utility modules include:
```
README: add help
uucore: add new modules
uutils: add new utility
gitignore: add temporary files
```
### PRs
- Make the titles of PRs descriptive.
- This means describing the problem you solve. For example, do not write
`Fix #1234`, but `ls: fix version sort order`.
- You can prefix the title with the utility the PR concerns.
- Keep PRs small and self-contained. A set of small PRs is much more likely to
get merged quickly than one large PR.
- Make sure the CI passes (up to intermittently failing tests).
- You know your code best, that's why it's best if you can solve merge conflicts
on your branch yourself.
- It's up to you whether you want to use `git merge main` or
`git rebase main`.
- Feel free to ask for help with merge conflicts.
- You do not need to ping maintainers to request a review, but it's fine to do
so if you don't get a response within a few days.
## Platforms ## Platforms
We take pride in supporting many operating systems and architectures. Any code We take pride in supporting many operating systems and architectures. Any code
you contribute must at least compile without warnings for all platforms in the you contribute must at least compile without warnings for all platforms in the
CI. However, you can use `#[cfg(...)]` attributes to create platform dependent features. CI. However, you can use `#[cfg(...)]` attributes to create platform dependent
features.
**Tip:** For Windows, Microsoft provides some images (VMWare, Hyper-V, **Tip:** For Windows, Microsoft provides some images (VMWare, Hyper-V,
VirtualBox and Parallels) for development: VirtualBox and Parallels) for development:
<https://developer.microsoft.com/windows/downloads/virtual-machines/> <https://developer.microsoft.com/windows/downloads/virtual-machines/>
## Setting up your development environment
To setup your local development environment for this project please follow [DEVELOPMENT.md guide](DEVELOPMENT.md)
It covers [installation of necessary tools and prerequisites](DEVELOPMENT.md#tools) as well as using those tools to [test your code changes locally](DEVELOPMENT.md#testing)
## Improving the GNU compatibility ## Improving the GNU compatibility
Please make sure you have installed [GNU utils and prerequisites](DEVELOPMENT.md#gnu-utils-and-prerequisites) and can execute commands described in [Comparing with GNU](DEVELOPMENT.md#comparing-with-gnu) section of [DEVELOPMENT.md](DEVELOPMENT.md) Please make sure you have installed
[GNU utils and prerequisites](DEVELOPMENT.md#gnu-utils-and-prerequisites) and
can execute commands described in
[Comparing with GNU](DEVELOPMENT.md#comparing-with-gnu) section of
[DEVELOPMENT.md](DEVELOPMENT.md)
The Python script `./util/remaining-gnu-error.py` shows the list of failing The Python script `./util/remaining-gnu-error.py` shows the list of failing
tests in the CI. tests in the CI.
@ -70,89 +288,28 @@ To improve the GNU compatibility, the following process is recommended:
1. Start to modify the Rust implementation to match the expected behavior 1. Start to modify the Rust implementation to match the expected behavior
1. Add a test to make sure that we don't regress (our test suite is super quick) 1. Add a test to make sure that we don't regress (our test suite is super quick)
## Commit messages
To help the project maintainers review pull requests from contributors across
numerous utilities, the team has settled on conventions for commit messages.
From <https://git-scm.com/book/ch5-2.html>:
```
Capitalized, short (50 chars or less) summary
More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of an email and the rest of the text as the body. The blank
line separating the summary from the body is critical (unless you omit
the body entirely); tools like rebase will confuse you if you run the
two together.
Write your commit message in the imperative: "Fix bug" and not "Fixed bug"
or "Fixes bug." This convention matches up with commit messages generated
by commands like git merge and git revert.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, followed by a
single space, with blank lines in between, but conventions vary here
- Use a hanging indent
```
Furthermore, here are a few examples for a summary line:
* commit for a single utility
```
nohup: cleanup and refactor
```
* commit for a utility's tests
```
tests/rm: test new feature
```
Beyond changes to an individual utility or its tests, other summary
lines for non-utility modules include:
```
README: add help
```
```
uucore: add new modules
```
```
uutils: add new utility
```
```
gitignore: add temporary files
```
## Code coverage ## Code coverage
To generate code coverage report locally please follow [Code coverage report](DEVELOPMENT.md#code-coverage-report) section of [DEVELOPMENT.md](DEVELOPMENT.md) To generate code coverage report locally please follow
[Code coverage report](DEVELOPMENT.md#code-coverage-report) section of
[DEVELOPMENT.md](DEVELOPMENT.md)
## Other implementations ## Other implementations
The Coreutils have different implementations, with different levels of completions: The Coreutils have different implementations, with different levels of
completions:
* [GNU's](https://git.savannah.gnu.org/gitweb/?p=coreutils.git) - [GNU's](https://git.savannah.gnu.org/gitweb/?p=coreutils.git)
* [OpenBSD](https://github.com/openbsd/src/tree/master/bin) - [OpenBSD](https://github.com/openbsd/src/tree/master/bin)
* [Busybox](https://github.com/mirror/busybox/tree/master/coreutils) - [Busybox](https://github.com/mirror/busybox/tree/master/coreutils)
* [Toybox (Android)](https://github.com/landley/toybox/tree/master/toys/posix) - [Toybox (Android)](https://github.com/landley/toybox/tree/master/toys/posix)
* [V lang](https://github.com/vlang/coreutils) - [V lang](https://github.com/vlang/coreutils)
* [SerenityOS](https://github.com/SerenityOS/serenity/tree/master/Userland/Utilities) - [SerenityOS](https://github.com/SerenityOS/serenity/tree/master/Userland/Utilities)
* [Initial Unix](https://github.com/dspinellis/unix-history-repo) - [Initial Unix](https://github.com/dspinellis/unix-history-repo)
* [Perl Power Tools](https://metacpan.org/pod/PerlPowerTools) - [Perl Power Tools](https://metacpan.org/pod/PerlPowerTools)
However, when reimplementing the tools/options in Rust, don't read their source codes However, when reimplementing the tools/options in Rust, don't read their source
when they are using reciprocal licenses (ex: GNU GPL, GNU LGPL, etc). codes when they are using reciprocal licenses (ex: GNU GPL, GNU LGPL, etc).
## Licensing ## Licensing
@ -167,17 +324,17 @@ If you wish to add or change dependencies as part of a contribution to the
project, a tool like `cargo-license` can be used to show their license details. project, a tool like `cargo-license` can be used to show their license details.
The following types of license are acceptable: The following types of license are acceptable:
* MIT License - MIT License
* Dual- or tri-license with an MIT License option ("Apache-2.0 or MIT" is a - Dual- or tri-license with an MIT License option ("Apache-2.0 or MIT" is a
popular combination) popular combination)
* "MIT equivalent" license (2-clause BSD, 3-clause BSD, ISC) - "MIT equivalent" license (2-clause BSD, 3-clause BSD, ISC)
* License less restrictive than the MIT License (CC0 1.0 Universal) - License less restrictive than the MIT License (CC0 1.0 Universal)
* Apache License version 2.0 - Apache License version 2.0
Licenses we will not use: Licenses we will not use:
* An ambiguous license, or no license - An ambiguous license, or no license
* Strongly reciprocal licenses (GNU GPL, GNU LGPL) - Strongly reciprocal licenses (GNU GPL, GNU LGPL)
If you wish to add a reference but it doesn't meet these requirements, please If you wish to add a reference but it doesn't meet these requirements, please
raise an issue to describe the dependency. raise an issue to describe the dependency.

270
Cargo.lock generated
View file

@ -188,9 +188,9 @@ dependencies = [
[[package]] [[package]]
name = "bstr" name = "bstr"
version = "1.7.0" version = "1.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019" checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
dependencies = [ dependencies = [
"memchr", "memchr",
"regex-automata", "regex-automata",
@ -374,7 +374,7 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]] [[package]]
name = "coreutils" name = "coreutils"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -1122,9 +1122,9 @@ dependencies = [
[[package]] [[package]]
name = "itertools" name = "itertools"
version = "0.11.0" version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
dependencies = [ dependencies = [
"either", "either",
] ]
@ -1187,9 +1187,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.149" version = "0.2.150"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
[[package]] [[package]]
name = "libloading" name = "libloading"
@ -1207,12 +1207,6 @@ version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]]
name = "linux-raw-sys"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.3.8" version = "0.3.8"
@ -1598,15 +1592,25 @@ dependencies = [
[[package]] [[package]]
name = "procfs" name = "procfs"
version = "0.15.1" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "943ca7f9f29bab5844ecd8fdb3992c5969b6622bb9609b9502fef9b4310e3f1f" checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4"
dependencies = [ dependencies = [
"bitflags 1.3.2", "bitflags 2.4.0",
"byteorder",
"hex", "hex",
"lazy_static", "lazy_static",
"rustix 0.36.16", "procfs-core",
"rustix 0.38.21",
]
[[package]]
name = "procfs-core"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29"
dependencies = [
"bitflags 2.4.0",
"hex",
] ]
[[package]] [[package]]
@ -1822,20 +1826,6 @@ dependencies = [
"semver", "semver",
] ]
[[package]]
name = "rustix"
version = "0.36.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6da3636faa25820d8648e0e31c5d519bbb01f72fdf57131f0f5f7da5fed36eab"
dependencies = [
"bitflags 1.3.2",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys 0.1.4",
"windows-sys 0.45.0",
]
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.37.26" version = "0.37.26"
@ -1880,9 +1870,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]] [[package]]
name = "self_cell" name = "self_cell"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6" checksum = "e388332cd64eb80cd595a00941baf513caffae8dce9cfd0467fc9c66397dade6"
[[package]] [[package]]
name = "selinux" name = "selinux"
@ -2217,7 +2207,7 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "uu_arch" name = "uu_arch"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"platform-info", "platform-info",
@ -2226,7 +2216,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_base32" name = "uu_base32"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2234,7 +2224,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_base64" name = "uu_base64"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"uu_base32", "uu_base32",
"uucore", "uucore",
@ -2242,7 +2232,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_basename" name = "uu_basename"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2250,7 +2240,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_basenc" name = "uu_basenc"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uu_base32", "uu_base32",
@ -2259,7 +2249,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_cat" name = "uu_cat"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
@ -2269,7 +2259,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chcon" name = "uu_chcon"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"fts-sys", "fts-sys",
@ -2281,7 +2271,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chgrp" name = "uu_chgrp"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2289,7 +2279,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chmod" name = "uu_chmod"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2298,7 +2288,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chown" name = "uu_chown"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2306,7 +2296,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_chroot" name = "uu_chroot"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2314,7 +2304,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_cksum" name = "uu_cksum"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"hex", "hex",
@ -2323,7 +2313,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_comm" name = "uu_comm"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2331,7 +2321,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_cp" name = "uu_cp"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"exacl", "exacl",
@ -2347,7 +2337,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_csplit" name = "uu_csplit"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"regex", "regex",
@ -2357,7 +2347,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_cut" name = "uu_cut"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"bstr", "bstr",
"clap", "clap",
@ -2367,7 +2357,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_date" name = "uu_date"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -2379,7 +2369,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_dd" name = "uu_dd"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"gcd", "gcd",
@ -2391,7 +2381,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_df" name = "uu_df"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"tempfile", "tempfile",
@ -2401,7 +2391,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_dir" name = "uu_dir"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uu_ls", "uu_ls",
@ -2410,7 +2400,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_dircolors" name = "uu_dircolors"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2418,7 +2408,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_dirname" name = "uu_dirname"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2426,7 +2416,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_du" name = "uu_du"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -2437,7 +2427,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_echo" name = "uu_echo"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2445,7 +2435,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_env" name = "uu_env"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
@ -2455,7 +2445,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_expand" name = "uu_expand"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"unicode-width", "unicode-width",
@ -2464,7 +2454,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_expr" name = "uu_expr"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"num-bigint", "num-bigint",
@ -2475,7 +2465,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_factor" name = "uu_factor"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"coz", "coz",
@ -2488,7 +2478,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_false" name = "uu_false"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2496,7 +2486,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_fmt" name = "uu_fmt"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"unicode-width", "unicode-width",
@ -2505,7 +2495,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_fold" name = "uu_fold"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2513,7 +2503,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_groups" name = "uu_groups"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2521,7 +2511,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_hashsum" name = "uu_hashsum"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"hex", "hex",
@ -2532,7 +2522,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_head" name = "uu_head"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -2541,7 +2531,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_hostid" name = "uu_hostid"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2550,7 +2540,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_hostname" name = "uu_hostname"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"hostname", "hostname",
@ -2560,7 +2550,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_id" name = "uu_id"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"selinux", "selinux",
@ -2569,7 +2559,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_install" name = "uu_install"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"file_diff", "file_diff",
@ -2580,7 +2570,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_join" name = "uu_join"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -2589,7 +2579,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_kill" name = "uu_kill"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
@ -2598,7 +2588,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_link" name = "uu_link"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2606,7 +2596,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_ln" name = "uu_ln"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2614,7 +2604,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_logname" name = "uu_logname"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2623,7 +2613,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_ls" name = "uu_ls"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -2640,7 +2630,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mkdir" name = "uu_mkdir"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2648,7 +2638,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mkfifo" name = "uu_mkfifo"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2657,7 +2647,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mknod" name = "uu_mknod"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2666,7 +2656,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mktemp" name = "uu_mktemp"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"rand", "rand",
@ -2676,7 +2666,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_more" name = "uu_more"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"crossterm", "crossterm",
@ -2688,7 +2678,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_mv" name = "uu_mv"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"fs_extra", "fs_extra",
@ -2698,7 +2688,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_nice" name = "uu_nice"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2708,7 +2698,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_nl" name = "uu_nl"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"regex", "regex",
@ -2717,7 +2707,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_nohup" name = "uu_nohup"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2726,7 +2716,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_nproc" name = "uu_nproc"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2735,7 +2725,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_numfmt" name = "uu_numfmt"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2743,7 +2733,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_od" name = "uu_od"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"clap", "clap",
@ -2753,7 +2743,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_paste" name = "uu_paste"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2761,7 +2751,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_pathchk" name = "uu_pathchk"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2770,7 +2760,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_pinky" name = "uu_pinky"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2778,7 +2768,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_pr" name = "uu_pr"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -2790,7 +2780,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_printenv" name = "uu_printenv"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2798,7 +2788,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_printf" name = "uu_printf"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2806,7 +2796,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_ptx" name = "uu_ptx"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"regex", "regex",
@ -2815,7 +2805,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_pwd" name = "uu_pwd"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2823,7 +2813,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_readlink" name = "uu_readlink"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2831,7 +2821,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_realpath" name = "uu_realpath"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2839,7 +2829,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_rm" name = "uu_rm"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2850,7 +2840,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_rmdir" name = "uu_rmdir"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2859,7 +2849,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_runcon" name = "uu_runcon"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2870,7 +2860,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_seq" name = "uu_seq"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"bigdecimal", "bigdecimal",
"clap", "clap",
@ -2881,7 +2871,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_shred" name = "uu_shred"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2891,7 +2881,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_shuf" name = "uu_shuf"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -2902,7 +2892,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_sleep" name = "uu_sleep"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"fundu", "fundu",
@ -2911,7 +2901,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_sort" name = "uu_sort"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"binary-heap-plus", "binary-heap-plus",
"clap", "clap",
@ -2930,7 +2920,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_split" name = "uu_split"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -2939,7 +2929,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_stat" name = "uu_stat"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2947,7 +2937,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_stdbuf" name = "uu_stdbuf"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"tempfile", "tempfile",
@ -2957,7 +2947,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_stdbuf_libstdbuf" name = "uu_stdbuf_libstdbuf"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"cpp", "cpp",
"cpp_build", "cpp_build",
@ -2967,7 +2957,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_stty" name = "uu_stty"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
@ -2976,7 +2966,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_sum" name = "uu_sum"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -2984,7 +2974,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_sync" name = "uu_sync"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -2995,7 +2985,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tac" name = "uu_tac"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
@ -3006,7 +2996,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tail" name = "uu_tail"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"fundu", "fundu",
@ -3022,7 +3012,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tee" name = "uu_tee"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3031,7 +3021,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_test" name = "uu_test"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3041,7 +3031,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_timeout" name = "uu_timeout"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3051,7 +3041,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_touch" name = "uu_touch"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -3063,7 +3053,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tr" name = "uu_tr"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"nom", "nom",
@ -3072,7 +3062,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_true" name = "uu_true"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3080,7 +3070,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_truncate" name = "uu_truncate"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3088,7 +3078,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tsort" name = "uu_tsort"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3096,7 +3086,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_tty" name = "uu_tty"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"nix", "nix",
@ -3105,7 +3095,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_uname" name = "uu_uname"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"platform-info", "platform-info",
@ -3114,7 +3104,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_unexpand" name = "uu_unexpand"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"unicode-width", "unicode-width",
@ -3123,7 +3113,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_uniq" name = "uu_uniq"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3131,7 +3121,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_unlink" name = "uu_unlink"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3139,7 +3129,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_uptime" name = "uu_uptime"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"chrono", "chrono",
"clap", "clap",
@ -3148,7 +3138,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_users" name = "uu_users"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3156,7 +3146,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_vdir" name = "uu_vdir"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uu_ls", "uu_ls",
@ -3165,7 +3155,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_wc" name = "uu_wc"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"bytecount", "bytecount",
"clap", "clap",
@ -3178,7 +3168,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_who" name = "uu_who"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"uucore", "uucore",
@ -3186,7 +3176,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_whoami" name = "uu_whoami"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"libc", "libc",
@ -3196,7 +3186,7 @@ dependencies = [
[[package]] [[package]]
name = "uu_yes" name = "uu_yes"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"clap", "clap",
"itertools", "itertools",
@ -3206,7 +3196,7 @@ dependencies = [
[[package]] [[package]]
name = "uucore" name = "uucore"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"blake2b_simd", "blake2b_simd",
"blake3", "blake3",
@ -3242,7 +3232,7 @@ dependencies = [
[[package]] [[package]]
name = "uucore_procs" name = "uucore_procs"
version = "0.0.22" version = "0.0.23"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3251,7 +3241,7 @@ dependencies = [
[[package]] [[package]]
name = "uuhelp_parser" name = "uuhelp_parser"
version = "0.0.22" version = "0.0.23"
[[package]] [[package]]
name = "uuid" name = "uuid"

View file

@ -5,7 +5,7 @@
[package] [package]
name = "coreutils" name = "coreutils"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust" description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust"
@ -259,7 +259,7 @@ test = ["uu_test"]
[workspace.dependencies] [workspace.dependencies]
bigdecimal = "0.4" bigdecimal = "0.4"
binary-heap-plus = "0.5.0" binary-heap-plus = "0.5.0"
bstr = "1.7" bstr = "1.8"
bytecount = "0.6.7" bytecount = "0.6.7"
byteorder = "1.5.0" byteorder = "1.5.0"
chrono = { version = "^0.4.31", default-features = false, features = [ chrono = { version = "^0.4.31", default-features = false, features = [
@ -285,8 +285,8 @@ gcd = "2.3"
glob = "0.3.1" glob = "0.3.1"
half = "2.3" half = "2.3"
indicatif = "0.17" indicatif = "0.17"
itertools = "0.11.0" itertools = "0.12.0"
libc = "0.2.149" libc = "0.2.150"
lscolors = { version = "0.15.0", default-features = false, features = [ lscolors = { version = "0.15.0", default-features = false, features = [
"nu-ansi-term", "nu-ansi-term",
] } ] }
@ -313,7 +313,7 @@ regex = "1.10.2"
rstest = "0.18.2" rstest = "0.18.2"
rust-ini = "0.19.0" rust-ini = "0.19.0"
same-file = "1.0.6" same-file = "1.0.6"
self_cell = "1.0.1" self_cell = "1.0.2"
selinux = "0.4" selinux = "0.4"
signal-hook = "0.3.17" signal-hook = "0.3.17"
smallvec = { version = "1.11", features = ["union"] } smallvec = { version = "1.11", features = ["union"] }
@ -361,109 +361,109 @@ zip = { workspace = true, optional = true }
uuhelp_parser = { optional = true, version = ">=0.0.19", path = "src/uuhelp_parser" } uuhelp_parser = { optional = true, version = ">=0.0.19", path = "src/uuhelp_parser" }
# * uutils # * uutils
uu_test = { optional = true, version = "0.0.22", package = "uu_test", path = "src/uu/test" } uu_test = { optional = true, version = "0.0.23", package = "uu_test", path = "src/uu/test" }
# #
arch = { optional = true, version = "0.0.22", package = "uu_arch", path = "src/uu/arch" } arch = { optional = true, version = "0.0.23", package = "uu_arch", path = "src/uu/arch" }
base32 = { optional = true, version = "0.0.22", package = "uu_base32", path = "src/uu/base32" } base32 = { optional = true, version = "0.0.23", package = "uu_base32", path = "src/uu/base32" }
base64 = { optional = true, version = "0.0.22", package = "uu_base64", path = "src/uu/base64" } base64 = { optional = true, version = "0.0.23", package = "uu_base64", path = "src/uu/base64" }
basename = { optional = true, version = "0.0.22", package = "uu_basename", path = "src/uu/basename" } basename = { optional = true, version = "0.0.23", package = "uu_basename", path = "src/uu/basename" }
basenc = { optional = true, version = "0.0.22", package = "uu_basenc", path = "src/uu/basenc" } basenc = { optional = true, version = "0.0.23", package = "uu_basenc", path = "src/uu/basenc" }
cat = { optional = true, version = "0.0.22", package = "uu_cat", path = "src/uu/cat" } cat = { optional = true, version = "0.0.23", package = "uu_cat", path = "src/uu/cat" }
chcon = { optional = true, version = "0.0.22", package = "uu_chcon", path = "src/uu/chcon" } chcon = { optional = true, version = "0.0.23", package = "uu_chcon", path = "src/uu/chcon" }
chgrp = { optional = true, version = "0.0.22", package = "uu_chgrp", path = "src/uu/chgrp" } chgrp = { optional = true, version = "0.0.23", package = "uu_chgrp", path = "src/uu/chgrp" }
chmod = { optional = true, version = "0.0.22", package = "uu_chmod", path = "src/uu/chmod" } chmod = { optional = true, version = "0.0.23", package = "uu_chmod", path = "src/uu/chmod" }
chown = { optional = true, version = "0.0.22", package = "uu_chown", path = "src/uu/chown" } chown = { optional = true, version = "0.0.23", package = "uu_chown", path = "src/uu/chown" }
chroot = { optional = true, version = "0.0.22", package = "uu_chroot", path = "src/uu/chroot" } chroot = { optional = true, version = "0.0.23", package = "uu_chroot", path = "src/uu/chroot" }
cksum = { optional = true, version = "0.0.22", package = "uu_cksum", path = "src/uu/cksum" } cksum = { optional = true, version = "0.0.23", package = "uu_cksum", path = "src/uu/cksum" }
comm = { optional = true, version = "0.0.22", package = "uu_comm", path = "src/uu/comm" } comm = { optional = true, version = "0.0.23", package = "uu_comm", path = "src/uu/comm" }
cp = { optional = true, version = "0.0.22", package = "uu_cp", path = "src/uu/cp" } cp = { optional = true, version = "0.0.23", package = "uu_cp", path = "src/uu/cp" }
csplit = { optional = true, version = "0.0.22", package = "uu_csplit", path = "src/uu/csplit" } csplit = { optional = true, version = "0.0.23", package = "uu_csplit", path = "src/uu/csplit" }
cut = { optional = true, version = "0.0.22", package = "uu_cut", path = "src/uu/cut" } cut = { optional = true, version = "0.0.23", package = "uu_cut", path = "src/uu/cut" }
date = { optional = true, version = "0.0.22", package = "uu_date", path = "src/uu/date" } date = { optional = true, version = "0.0.23", package = "uu_date", path = "src/uu/date" }
dd = { optional = true, version = "0.0.22", package = "uu_dd", path = "src/uu/dd" } dd = { optional = true, version = "0.0.23", package = "uu_dd", path = "src/uu/dd" }
df = { optional = true, version = "0.0.22", package = "uu_df", path = "src/uu/df" } df = { optional = true, version = "0.0.23", package = "uu_df", path = "src/uu/df" }
dir = { optional = true, version = "0.0.22", package = "uu_dir", path = "src/uu/dir" } dir = { optional = true, version = "0.0.23", package = "uu_dir", path = "src/uu/dir" }
dircolors = { optional = true, version = "0.0.22", package = "uu_dircolors", path = "src/uu/dircolors" } dircolors = { optional = true, version = "0.0.23", package = "uu_dircolors", path = "src/uu/dircolors" }
dirname = { optional = true, version = "0.0.22", package = "uu_dirname", path = "src/uu/dirname" } dirname = { optional = true, version = "0.0.23", package = "uu_dirname", path = "src/uu/dirname" }
du = { optional = true, version = "0.0.22", package = "uu_du", path = "src/uu/du" } du = { optional = true, version = "0.0.23", package = "uu_du", path = "src/uu/du" }
echo = { optional = true, version = "0.0.22", package = "uu_echo", path = "src/uu/echo" } echo = { optional = true, version = "0.0.23", package = "uu_echo", path = "src/uu/echo" }
env = { optional = true, version = "0.0.22", package = "uu_env", path = "src/uu/env" } env = { optional = true, version = "0.0.23", package = "uu_env", path = "src/uu/env" }
expand = { optional = true, version = "0.0.22", package = "uu_expand", path = "src/uu/expand" } expand = { optional = true, version = "0.0.23", package = "uu_expand", path = "src/uu/expand" }
expr = { optional = true, version = "0.0.22", package = "uu_expr", path = "src/uu/expr" } expr = { optional = true, version = "0.0.23", package = "uu_expr", path = "src/uu/expr" }
factor = { optional = true, version = "0.0.22", package = "uu_factor", path = "src/uu/factor" } factor = { optional = true, version = "0.0.23", package = "uu_factor", path = "src/uu/factor" }
false = { optional = true, version = "0.0.22", package = "uu_false", path = "src/uu/false" } false = { optional = true, version = "0.0.23", package = "uu_false", path = "src/uu/false" }
fmt = { optional = true, version = "0.0.22", package = "uu_fmt", path = "src/uu/fmt" } fmt = { optional = true, version = "0.0.23", package = "uu_fmt", path = "src/uu/fmt" }
fold = { optional = true, version = "0.0.22", package = "uu_fold", path = "src/uu/fold" } fold = { optional = true, version = "0.0.23", package = "uu_fold", path = "src/uu/fold" }
groups = { optional = true, version = "0.0.22", package = "uu_groups", path = "src/uu/groups" } groups = { optional = true, version = "0.0.23", package = "uu_groups", path = "src/uu/groups" }
hashsum = { optional = true, version = "0.0.22", package = "uu_hashsum", path = "src/uu/hashsum" } hashsum = { optional = true, version = "0.0.23", package = "uu_hashsum", path = "src/uu/hashsum" }
head = { optional = true, version = "0.0.22", package = "uu_head", path = "src/uu/head" } head = { optional = true, version = "0.0.23", package = "uu_head", path = "src/uu/head" }
hostid = { optional = true, version = "0.0.22", package = "uu_hostid", path = "src/uu/hostid" } hostid = { optional = true, version = "0.0.23", package = "uu_hostid", path = "src/uu/hostid" }
hostname = { optional = true, version = "0.0.22", package = "uu_hostname", path = "src/uu/hostname" } hostname = { optional = true, version = "0.0.23", package = "uu_hostname", path = "src/uu/hostname" }
id = { optional = true, version = "0.0.22", package = "uu_id", path = "src/uu/id" } id = { optional = true, version = "0.0.23", package = "uu_id", path = "src/uu/id" }
install = { optional = true, version = "0.0.22", package = "uu_install", path = "src/uu/install" } install = { optional = true, version = "0.0.23", package = "uu_install", path = "src/uu/install" }
join = { optional = true, version = "0.0.22", package = "uu_join", path = "src/uu/join" } join = { optional = true, version = "0.0.23", package = "uu_join", path = "src/uu/join" }
kill = { optional = true, version = "0.0.22", package = "uu_kill", path = "src/uu/kill" } kill = { optional = true, version = "0.0.23", package = "uu_kill", path = "src/uu/kill" }
link = { optional = true, version = "0.0.22", package = "uu_link", path = "src/uu/link" } link = { optional = true, version = "0.0.23", package = "uu_link", path = "src/uu/link" }
ln = { optional = true, version = "0.0.22", package = "uu_ln", path = "src/uu/ln" } ln = { optional = true, version = "0.0.23", package = "uu_ln", path = "src/uu/ln" }
ls = { optional = true, version = "0.0.22", package = "uu_ls", path = "src/uu/ls" } ls = { optional = true, version = "0.0.23", package = "uu_ls", path = "src/uu/ls" }
logname = { optional = true, version = "0.0.22", package = "uu_logname", path = "src/uu/logname" } logname = { optional = true, version = "0.0.23", package = "uu_logname", path = "src/uu/logname" }
mkdir = { optional = true, version = "0.0.22", package = "uu_mkdir", path = "src/uu/mkdir" } mkdir = { optional = true, version = "0.0.23", package = "uu_mkdir", path = "src/uu/mkdir" }
mkfifo = { optional = true, version = "0.0.22", package = "uu_mkfifo", path = "src/uu/mkfifo" } mkfifo = { optional = true, version = "0.0.23", package = "uu_mkfifo", path = "src/uu/mkfifo" }
mknod = { optional = true, version = "0.0.22", package = "uu_mknod", path = "src/uu/mknod" } mknod = { optional = true, version = "0.0.23", package = "uu_mknod", path = "src/uu/mknod" }
mktemp = { optional = true, version = "0.0.22", package = "uu_mktemp", path = "src/uu/mktemp" } mktemp = { optional = true, version = "0.0.23", package = "uu_mktemp", path = "src/uu/mktemp" }
more = { optional = true, version = "0.0.22", package = "uu_more", path = "src/uu/more" } more = { optional = true, version = "0.0.23", package = "uu_more", path = "src/uu/more" }
mv = { optional = true, version = "0.0.22", package = "uu_mv", path = "src/uu/mv" } mv = { optional = true, version = "0.0.23", package = "uu_mv", path = "src/uu/mv" }
nice = { optional = true, version = "0.0.22", package = "uu_nice", path = "src/uu/nice" } nice = { optional = true, version = "0.0.23", package = "uu_nice", path = "src/uu/nice" }
nl = { optional = true, version = "0.0.22", package = "uu_nl", path = "src/uu/nl" } nl = { optional = true, version = "0.0.23", package = "uu_nl", path = "src/uu/nl" }
nohup = { optional = true, version = "0.0.22", package = "uu_nohup", path = "src/uu/nohup" } nohup = { optional = true, version = "0.0.23", package = "uu_nohup", path = "src/uu/nohup" }
nproc = { optional = true, version = "0.0.22", package = "uu_nproc", path = "src/uu/nproc" } nproc = { optional = true, version = "0.0.23", package = "uu_nproc", path = "src/uu/nproc" }
numfmt = { optional = true, version = "0.0.22", package = "uu_numfmt", path = "src/uu/numfmt" } numfmt = { optional = true, version = "0.0.23", package = "uu_numfmt", path = "src/uu/numfmt" }
od = { optional = true, version = "0.0.22", package = "uu_od", path = "src/uu/od" } od = { optional = true, version = "0.0.23", package = "uu_od", path = "src/uu/od" }
paste = { optional = true, version = "0.0.22", package = "uu_paste", path = "src/uu/paste" } paste = { optional = true, version = "0.0.23", package = "uu_paste", path = "src/uu/paste" }
pathchk = { optional = true, version = "0.0.22", package = "uu_pathchk", path = "src/uu/pathchk" } pathchk = { optional = true, version = "0.0.23", package = "uu_pathchk", path = "src/uu/pathchk" }
pinky = { optional = true, version = "0.0.22", package = "uu_pinky", path = "src/uu/pinky" } pinky = { optional = true, version = "0.0.23", package = "uu_pinky", path = "src/uu/pinky" }
pr = { optional = true, version = "0.0.22", package = "uu_pr", path = "src/uu/pr" } pr = { optional = true, version = "0.0.23", package = "uu_pr", path = "src/uu/pr" }
printenv = { optional = true, version = "0.0.22", package = "uu_printenv", path = "src/uu/printenv" } printenv = { optional = true, version = "0.0.23", package = "uu_printenv", path = "src/uu/printenv" }
printf = { optional = true, version = "0.0.22", package = "uu_printf", path = "src/uu/printf" } printf = { optional = true, version = "0.0.23", package = "uu_printf", path = "src/uu/printf" }
ptx = { optional = true, version = "0.0.22", package = "uu_ptx", path = "src/uu/ptx" } ptx = { optional = true, version = "0.0.23", package = "uu_ptx", path = "src/uu/ptx" }
pwd = { optional = true, version = "0.0.22", package = "uu_pwd", path = "src/uu/pwd" } pwd = { optional = true, version = "0.0.23", package = "uu_pwd", path = "src/uu/pwd" }
readlink = { optional = true, version = "0.0.22", package = "uu_readlink", path = "src/uu/readlink" } readlink = { optional = true, version = "0.0.23", package = "uu_readlink", path = "src/uu/readlink" }
realpath = { optional = true, version = "0.0.22", package = "uu_realpath", path = "src/uu/realpath" } realpath = { optional = true, version = "0.0.23", package = "uu_realpath", path = "src/uu/realpath" }
rm = { optional = true, version = "0.0.22", package = "uu_rm", path = "src/uu/rm" } rm = { optional = true, version = "0.0.23", package = "uu_rm", path = "src/uu/rm" }
rmdir = { optional = true, version = "0.0.22", package = "uu_rmdir", path = "src/uu/rmdir" } rmdir = { optional = true, version = "0.0.23", package = "uu_rmdir", path = "src/uu/rmdir" }
runcon = { optional = true, version = "0.0.22", package = "uu_runcon", path = "src/uu/runcon" } runcon = { optional = true, version = "0.0.23", package = "uu_runcon", path = "src/uu/runcon" }
seq = { optional = true, version = "0.0.22", package = "uu_seq", path = "src/uu/seq" } seq = { optional = true, version = "0.0.23", package = "uu_seq", path = "src/uu/seq" }
shred = { optional = true, version = "0.0.22", package = "uu_shred", path = "src/uu/shred" } shred = { optional = true, version = "0.0.23", package = "uu_shred", path = "src/uu/shred" }
shuf = { optional = true, version = "0.0.22", package = "uu_shuf", path = "src/uu/shuf" } shuf = { optional = true, version = "0.0.23", package = "uu_shuf", path = "src/uu/shuf" }
sleep = { optional = true, version = "0.0.22", package = "uu_sleep", path = "src/uu/sleep" } sleep = { optional = true, version = "0.0.23", package = "uu_sleep", path = "src/uu/sleep" }
sort = { optional = true, version = "0.0.22", package = "uu_sort", path = "src/uu/sort" } sort = { optional = true, version = "0.0.23", package = "uu_sort", path = "src/uu/sort" }
split = { optional = true, version = "0.0.22", package = "uu_split", path = "src/uu/split" } split = { optional = true, version = "0.0.23", package = "uu_split", path = "src/uu/split" }
stat = { optional = true, version = "0.0.22", package = "uu_stat", path = "src/uu/stat" } stat = { optional = true, version = "0.0.23", package = "uu_stat", path = "src/uu/stat" }
stdbuf = { optional = true, version = "0.0.22", package = "uu_stdbuf", path = "src/uu/stdbuf" } stdbuf = { optional = true, version = "0.0.23", package = "uu_stdbuf", path = "src/uu/stdbuf" }
stty = { optional = true, version = "0.0.22", package = "uu_stty", path = "src/uu/stty" } stty = { optional = true, version = "0.0.23", package = "uu_stty", path = "src/uu/stty" }
sum = { optional = true, version = "0.0.22", package = "uu_sum", path = "src/uu/sum" } sum = { optional = true, version = "0.0.23", package = "uu_sum", path = "src/uu/sum" }
sync = { optional = true, version = "0.0.22", package = "uu_sync", path = "src/uu/sync" } sync = { optional = true, version = "0.0.23", package = "uu_sync", path = "src/uu/sync" }
tac = { optional = true, version = "0.0.22", package = "uu_tac", path = "src/uu/tac" } tac = { optional = true, version = "0.0.23", package = "uu_tac", path = "src/uu/tac" }
tail = { optional = true, version = "0.0.22", package = "uu_tail", path = "src/uu/tail" } tail = { optional = true, version = "0.0.23", package = "uu_tail", path = "src/uu/tail" }
tee = { optional = true, version = "0.0.22", package = "uu_tee", path = "src/uu/tee" } tee = { optional = true, version = "0.0.23", package = "uu_tee", path = "src/uu/tee" }
timeout = { optional = true, version = "0.0.22", package = "uu_timeout", path = "src/uu/timeout" } timeout = { optional = true, version = "0.0.23", package = "uu_timeout", path = "src/uu/timeout" }
touch = { optional = true, version = "0.0.22", package = "uu_touch", path = "src/uu/touch" } touch = { optional = true, version = "0.0.23", package = "uu_touch", path = "src/uu/touch" }
tr = { optional = true, version = "0.0.22", package = "uu_tr", path = "src/uu/tr" } tr = { optional = true, version = "0.0.23", package = "uu_tr", path = "src/uu/tr" }
true = { optional = true, version = "0.0.22", package = "uu_true", path = "src/uu/true" } true = { optional = true, version = "0.0.23", package = "uu_true", path = "src/uu/true" }
truncate = { optional = true, version = "0.0.22", package = "uu_truncate", path = "src/uu/truncate" } truncate = { optional = true, version = "0.0.23", package = "uu_truncate", path = "src/uu/truncate" }
tsort = { optional = true, version = "0.0.22", package = "uu_tsort", path = "src/uu/tsort" } tsort = { optional = true, version = "0.0.23", package = "uu_tsort", path = "src/uu/tsort" }
tty = { optional = true, version = "0.0.22", package = "uu_tty", path = "src/uu/tty" } tty = { optional = true, version = "0.0.23", package = "uu_tty", path = "src/uu/tty" }
uname = { optional = true, version = "0.0.22", package = "uu_uname", path = "src/uu/uname" } uname = { optional = true, version = "0.0.23", package = "uu_uname", path = "src/uu/uname" }
unexpand = { optional = true, version = "0.0.22", package = "uu_unexpand", path = "src/uu/unexpand" } unexpand = { optional = true, version = "0.0.23", package = "uu_unexpand", path = "src/uu/unexpand" }
uniq = { optional = true, version = "0.0.22", package = "uu_uniq", path = "src/uu/uniq" } uniq = { optional = true, version = "0.0.23", package = "uu_uniq", path = "src/uu/uniq" }
unlink = { optional = true, version = "0.0.22", package = "uu_unlink", path = "src/uu/unlink" } unlink = { optional = true, version = "0.0.23", package = "uu_unlink", path = "src/uu/unlink" }
uptime = { optional = true, version = "0.0.22", package = "uu_uptime", path = "src/uu/uptime" } uptime = { optional = true, version = "0.0.23", package = "uu_uptime", path = "src/uu/uptime" }
users = { optional = true, version = "0.0.22", package = "uu_users", path = "src/uu/users" } users = { optional = true, version = "0.0.23", package = "uu_users", path = "src/uu/users" }
vdir = { optional = true, version = "0.0.22", package = "uu_vdir", path = "src/uu/vdir" } vdir = { optional = true, version = "0.0.23", package = "uu_vdir", path = "src/uu/vdir" }
wc = { optional = true, version = "0.0.22", package = "uu_wc", path = "src/uu/wc" } wc = { optional = true, version = "0.0.23", package = "uu_wc", path = "src/uu/wc" }
who = { optional = true, version = "0.0.22", package = "uu_who", path = "src/uu/who" } who = { optional = true, version = "0.0.23", package = "uu_who", path = "src/uu/who" }
whoami = { optional = true, version = "0.0.22", package = "uu_whoami", path = "src/uu/whoami" } whoami = { optional = true, version = "0.0.23", package = "uu_whoami", path = "src/uu/whoami" }
yes = { optional = true, version = "0.0.22", package = "uu_yes", path = "src/uu/yes" } yes = { optional = true, version = "0.0.23", package = "uu_yes", path = "src/uu/yes" }
# this breaks clippy linting with: "tests/by-util/test_factor_benches.rs: No such file or directory (os error 2)" # this breaks clippy linting with: "tests/by-util/test_factor_benches.rs: No such file or directory (os error 2)"
# factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" } # factor_benches = { optional = true, version = "0.0.0", package = "uu_factor_benches", path = "tests/benches/factor" }
@ -492,7 +492,7 @@ hex-literal = "0.4.1"
rstest = { workspace = true } rstest = { workspace = true }
[target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies] [target.'cfg(any(target_os = "linux", target_os = "android"))'.dev-dependencies]
procfs = { version = "0.15", default-features = false } procfs = { version = "0.16", default-features = false }
rlimit = "0.10.1" rlimit = "0.10.1"
[target.'cfg(unix)'.dev-dependencies] [target.'cfg(unix)'.dev-dependencies]

View file

@ -1,4 +1,4 @@
Copyright (c) Jordi Boggiano and many others Copyright (c) uutils developers
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 this software and associated documentation files (the "Software"), to deal in

View file

@ -58,10 +58,7 @@ highlight = "all"
# introduces it. # introduces it.
# spell-checker: disable # spell-checker: disable
skip = [ skip = [
# procfs
{ name = "rustix", version = "0.36.16" },
# rustix # rustix
{ name = "linux-raw-sys", version = "0.1.4" },
{ name = "linux-raw-sys", version = "0.3.8" }, { name = "linux-raw-sys", version = "0.3.8" },
# terminal_size # terminal_size
{ name = "rustix", version = "0.37.26" }, { name = "rustix", version = "0.37.26" },

View file

@ -6,7 +6,7 @@ This is a list of uutils packages in various distributions and package managers.
Note that these are packaged by third-parties and the packages might contain Note that these are packaged by third-parties and the packages might contain
patches. patches.
You can also [build uutils from source](/build.md). You can also [build uutils from source](build.md).
<!-- toc --> <!-- toc -->

View file

@ -3,13 +3,30 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // file that was distributed with this source code.
use libc::{dup, dup2, STDOUT_FILENO}; use libc::{close, dup, dup2, pipe, STDERR_FILENO, STDOUT_FILENO};
use rand::prelude::SliceRandom;
use rand::Rng;
use std::ffi::OsString; use std::ffi::OsString;
use std::io; use std::io;
use std::io::Write;
use std::os::fd::RawFd;
use std::process::Command; use std::process::Command;
use std::sync::atomic::Ordering; use std::sync::atomic::Ordering;
use std::sync::{atomic::AtomicBool, Once}; use std::sync::{atomic::AtomicBool, Once};
/// Represents the result of running a command, including its standard output,
/// standard error, and exit code.
pub struct CommandResult {
/// The standard output (stdout) of the command as a string.
pub stdout: String,
/// The standard error (stderr) of the command as a string.
pub stderr: String,
/// The exit code of the command.
pub exit_code: i32,
}
static CHECK_GNU: Once = Once::new(); static CHECK_GNU: Once = Once::new();
static IS_GNU: AtomicBool = AtomicBool::new(false); static IS_GNU: AtomicBool = AtomicBool::new(false);
@ -32,58 +49,135 @@ pub fn is_gnu_cmd(cmd_path: &str) -> Result<(), std::io::Error> {
} }
} }
pub fn generate_and_run_uumain<F>(args: &[OsString], uumain_function: F) -> (String, i32) pub fn generate_and_run_uumain<F>(args: &[OsString], uumain_function: F) -> CommandResult
where where
F: FnOnce(std::vec::IntoIter<OsString>) -> i32, F: FnOnce(std::vec::IntoIter<OsString>) -> i32,
{ {
let uumain_exit_status; // Duplicate the stdout and stderr file descriptors
let original_stdout_fd = unsafe { dup(STDOUT_FILENO) }; let original_stdout_fd = unsafe { dup(STDOUT_FILENO) };
println!("Running test {:?}", &args[1..]); let original_stderr_fd = unsafe { dup(STDERR_FILENO) };
let mut pipe_fds = [-1; 2]; if original_stdout_fd == -1 || original_stderr_fd == -1 {
unsafe { libc::pipe(pipe_fds.as_mut_ptr()) }; return CommandResult {
stdout: "Failed to duplicate STDOUT_FILENO or STDERR_FILENO".to_string(),
{ stderr: "".to_string(),
unsafe { dup2(pipe_fds[1], STDOUT_FILENO) }; exit_code: -1,
uumain_exit_status = uumain_function(args.to_owned().into_iter()); };
unsafe { dup2(original_stdout_fd, STDOUT_FILENO) };
unsafe { libc::close(original_stdout_fd) };
} }
unsafe { libc::close(pipe_fds[1]) }; println!("Running test {:?}", &args[0..]);
let mut pipe_stdout_fds = [-1; 2];
let mut pipe_stderr_fds = [-1; 2];
// Create pipes for stdout and stderr
if unsafe { pipe(pipe_stdout_fds.as_mut_ptr()) } == -1
|| unsafe { pipe(pipe_stderr_fds.as_mut_ptr()) } == -1
{
return CommandResult {
stdout: "Failed to create pipes".to_string(),
stderr: "".to_string(),
exit_code: -1,
};
}
// Redirect stdout and stderr to their respective pipes
if unsafe { dup2(pipe_stdout_fds[1], STDOUT_FILENO) } == -1
|| unsafe { dup2(pipe_stderr_fds[1], STDERR_FILENO) } == -1
{
unsafe {
close(pipe_stdout_fds[0]);
close(pipe_stdout_fds[1]);
close(pipe_stderr_fds[0]);
close(pipe_stderr_fds[1]);
}
return CommandResult {
stdout: "Failed to redirect STDOUT_FILENO or STDERR_FILENO".to_string(),
stderr: "".to_string(),
exit_code: -1,
};
}
let uumain_exit_status = uumain_function(args.to_owned().into_iter());
io::stdout().flush().unwrap();
io::stderr().flush().unwrap();
// Restore the original stdout and stderr
if unsafe { dup2(original_stdout_fd, STDOUT_FILENO) } == -1
|| unsafe { dup2(original_stderr_fd, STDERR_FILENO) } == -1
{
return CommandResult {
stdout: "Failed to restore the original STDOUT_FILENO or STDERR_FILENO".to_string(),
stderr: "".to_string(),
exit_code: -1,
};
}
unsafe {
close(original_stdout_fd);
close(original_stderr_fd);
close(pipe_stdout_fds[1]);
close(pipe_stderr_fds[1]);
}
let captured_stdout = read_from_fd(pipe_stdout_fds[0]).trim().to_string();
let captured_stderr = read_from_fd(pipe_stderr_fds[0]).to_string();
let captured_stderr = captured_stderr
.split_once(':')
.map(|x| x.1)
.unwrap_or("")
.trim()
.to_string();
CommandResult {
stdout: captured_stdout,
stderr: captured_stderr,
exit_code: uumain_exit_status,
}
}
fn read_from_fd(fd: RawFd) -> String {
let mut captured_output = Vec::new(); let mut captured_output = Vec::new();
let mut read_buffer = [0; 1024]; let mut read_buffer = [0; 1024];
loop { loop {
let bytes_read = unsafe { let bytes_read = unsafe {
libc::read( libc::read(
pipe_fds[0], fd,
read_buffer.as_mut_ptr() as *mut libc::c_void, read_buffer.as_mut_ptr() as *mut libc::c_void,
read_buffer.len(), read_buffer.len(),
) )
}; };
if bytes_read <= 0 {
if bytes_read == -1 {
eprintln!("Failed to read from the pipe");
break;
}
if bytes_read == 0 {
break; break;
} }
captured_output.extend_from_slice(&read_buffer[..bytes_read as usize]); captured_output.extend_from_slice(&read_buffer[..bytes_read as usize]);
} }
unsafe { libc::close(pipe_fds[0]) }; unsafe { libc::close(fd) };
let my_output = String::from_utf8_lossy(&captured_output) String::from_utf8_lossy(&captured_output).into_owned()
.to_string()
.trim()
.to_owned();
(my_output, uumain_exit_status)
} }
pub fn run_gnu_cmd( pub fn run_gnu_cmd(
cmd_path: &str, cmd_path: &str,
args: &[OsString], args: &[OsString],
check_gnu: bool, check_gnu: bool,
) -> Result<(String, i32), io::Error> { ) -> Result<CommandResult, CommandResult> {
if check_gnu { if check_gnu {
is_gnu_cmd(cmd_path)?; // Check if it's a GNU implementation match is_gnu_cmd(cmd_path) {
Ok(_) => {} // if the check passes, do nothing
Err(e) => {
// Convert the io::Error into the function's error type
return Err(CommandResult {
stdout: String::new(),
stderr: e.to_string(),
exit_code: -1,
});
}
}
} }
let mut command = Command::new(cmd_path); let mut command = Command::new(cmd_path);
@ -91,17 +185,115 @@ pub fn run_gnu_cmd(
command.arg(arg); command.arg(arg);
} }
let output = command.output()?; let output = match command.output() {
Ok(output) => output,
Err(e) => {
return Err(CommandResult {
stdout: String::new(),
stderr: e.to_string(),
exit_code: -1,
});
}
};
let exit_code = output.status.code().unwrap_or(-1); let exit_code = output.status.code().unwrap_or(-1);
// Here we get stdout and stderr as Strings
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
let stderr = String::from_utf8_lossy(&output.stderr).to_string();
let stderr = stderr
.split_once(':')
.map(|x| x.1)
.unwrap_or("")
.trim()
.to_string();
if output.status.success() || !check_gnu { if output.status.success() || !check_gnu {
Ok(( Ok(CommandResult {
String::from_utf8_lossy(&output.stdout).to_string(), stdout,
stderr,
exit_code, exit_code,
)) })
} else { } else {
Err(io::Error::new( Err(CommandResult {
io::ErrorKind::Other, stdout,
format!("GNU command execution failed with exit code {}", exit_code), stderr,
)) exit_code,
})
} }
} }
pub fn compare_result(
test_type: &str,
input: &str,
rust_stdout: &str,
gnu_stdout: &str,
rust_stderr: &str,
gnu_stderr: &str,
rust_exit_code: i32,
gnu_exit_code: i32,
fail_on_stderr_diff: bool,
) {
println!("Test Type: {}", test_type);
println!("Input: {}", input);
let mut discrepancies = Vec::new();
let mut should_panic = false;
if rust_stdout.trim() != gnu_stdout.trim() {
discrepancies.push("stdout differs");
println!("Rust stdout: {}", rust_stdout);
println!("GNU stdout: {}", gnu_stdout);
should_panic = true;
}
if rust_stderr.trim() != gnu_stderr.trim() {
discrepancies.push("stderr differs");
println!("Rust stderr: {}", rust_stderr);
println!("GNU stderr: {}", gnu_stderr);
if fail_on_stderr_diff {
should_panic = true;
}
}
if rust_exit_code != gnu_exit_code {
discrepancies.push("exit code differs");
println!("Rust exit code: {}", rust_exit_code);
println!("GNU exit code: {}", gnu_exit_code);
should_panic = true;
}
if discrepancies.is_empty() {
println!("All outputs and exit codes matched.");
} else {
println!("Discrepancy detected: {}", discrepancies.join(", "));
if should_panic {
panic!("Test failed for {}: {}", test_type, input);
} else {
println!(
"Test completed with discrepancies for {}: {}",
test_type, input
);
}
}
}
pub fn generate_random_string(max_length: usize) -> String {
let mut rng = rand::thread_rng();
let valid_utf8: Vec<char> = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
.chars()
.collect();
let invalid_utf8 = [0xC3, 0x28]; // Invalid UTF-8 sequence
let mut result = String::new();
for _ in 0..rng.gen_range(1..=max_length) {
if rng.gen_bool(0.9) {
let ch = valid_utf8.choose(&mut rng).unwrap();
result.push(*ch);
} else {
let ch = invalid_utf8.choose(&mut rng).unwrap();
if let Some(c) = char::from_u32(*ch as u32) {
result.push(c);
}
}
}
result
}

View file

@ -13,33 +13,12 @@ use rand::Rng;
use std::{env, ffi::OsString}; use std::{env, ffi::OsString};
mod fuzz_common; mod fuzz_common;
use crate::fuzz_common::{generate_and_run_uumain, run_gnu_cmd}; use crate::fuzz_common::CommandResult;
use crate::fuzz_common::{
compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd,
};
static CMD_PATH: &str = "expr"; static CMD_PATH: &str = "expr";
fn generate_random_string(max_length: usize) -> String {
let mut rng = rand::thread_rng();
let valid_utf8: Vec<char> = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
.chars()
.collect();
let invalid_utf8 = [0xC3, 0x28]; // Invalid UTF-8 sequence
let mut result = String::new();
for _ in 0..rng.gen_range(1..=max_length) {
if rng.gen_bool(0.9) {
let ch = valid_utf8.choose(&mut rng).unwrap();
result.push(*ch);
} else {
let ch = invalid_utf8.choose(&mut rng).unwrap();
if let Some(c) = char::from_u32(*ch as u32) {
result.push(c);
}
}
}
result
}
fn generate_expr(max_depth: u32) -> String { fn generate_expr(max_depth: u32) -> String {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let ops = ["+", "-", "*", "/", "%", "<", ">", "=", "&", "|"]; let ops = ["+", "-", "*", "/", "%", "<", ">", "=", "&", "|"];
@ -84,37 +63,35 @@ fuzz_target!(|_data: &[u8]| {
let mut args = vec![OsString::from("expr")]; let mut args = vec![OsString::from("expr")];
args.extend(expr.split_whitespace().map(OsString::from)); args.extend(expr.split_whitespace().map(OsString::from));
let (rust_output, uumain_exit_code) = generate_and_run_uumain(&args, uumain);
// Use C locale to avoid false positives, like in https://github.com/uutils/coreutils/issues/5378, // Use C locale to avoid false positives, like in https://github.com/uutils/coreutils/issues/5378,
// because uutils expr doesn't support localization yet // because uutils expr doesn't support localization yet
// TODO remove once uutils expr supports localization // TODO remove once uutils expr supports localization
env::set_var("LC_COLLATE", "C"); env::set_var("LC_COLLATE", "C");
let rust_result = generate_and_run_uumain(&args, uumain);
// Run GNU expr with the provided arguments and compare the output let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false) {
match run_gnu_cmd(CMD_PATH, &args[1..], true) { Ok(result) => result,
Ok((gnu_output, gnu_exit_code)) => { Err(error_result) => {
let gnu_output = gnu_output.trim().to_owned(); eprintln!("Failed to run GNU command:");
if uumain_exit_code != gnu_exit_code { eprintln!("Stderr: {}", error_result.stderr);
println!("Expression: {}", expr); eprintln!("Exit Code: {}", error_result.exit_code);
println!("Rust code: {}", uumain_exit_code); CommandResult {
println!("GNU code: {}", gnu_exit_code); stdout: String::new(),
panic!("Different error codes"); stderr: error_result.stderr,
} exit_code: error_result.exit_code,
if rust_output == gnu_output {
println!(
"Outputs matched for expression: {} => Result: {}",
expr, rust_output
);
} else {
println!("Expression: {}", expr);
println!("Rust output: {}", rust_output);
println!("GNU output: {}", gnu_output);
panic!("Different output between Rust & GNU");
} }
} }
Err(_) => { };
println!("GNU expr execution failed for expression: {}", expr);
} compare_result(
} "expr",
&format!("{:?}", &args[1..]),
&rust_result.stdout,
&gnu_result.stdout,
&rust_result.stderr,
&gnu_result.stderr,
rust_result.exit_code,
gnu_result.exit_code,
false, // Set to true if you want to fail on stderr diff
);
}); });

View file

@ -1,10 +1,10 @@
#![no_main] #![no_main]
use libfuzzer_sys::fuzz_target; use libfuzzer_sys::fuzz_target;
use uucore::parse_size::parse_size; use uucore::parse_size::parse_size_u64;
fuzz_target!(|data: &[u8]| { fuzz_target!(|data: &[u8]| {
if let Ok(s) = std::str::from_utf8(data) { if let Ok(s) = std::str::from_utf8(data) {
_ = parse_size(s); _ = parse_size_u64(s);
} }
}); });

View file

@ -13,7 +13,10 @@ use rand::Rng;
use std::ffi::OsString; use std::ffi::OsString;
mod fuzz_common; mod fuzz_common;
use crate::fuzz_common::{generate_and_run_uumain, run_gnu_cmd}; use crate::fuzz_common::CommandResult;
use crate::fuzz_common::{
compare_result, generate_and_run_uumain, generate_random_string, run_gnu_cmd,
};
#[derive(PartialEq, Debug, Clone)] #[derive(PartialEq, Debug, Clone)]
enum ArgType { enum ArgType {
@ -28,29 +31,6 @@ enum ArgType {
static CMD_PATH: &str = "test"; static CMD_PATH: &str = "test";
fn generate_random_string(max_length: usize) -> String {
let mut rng = rand::thread_rng();
let valid_utf8: Vec<char> = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
.chars()
.collect();
let invalid_utf8 = [0xC3, 0x28]; // Invalid UTF-8 sequence
let mut result = String::new();
for _ in 0..rng.gen_range(1..=max_length) {
if rng.gen_bool(0.9) {
let ch = valid_utf8.choose(&mut rng).unwrap();
result.push(*ch);
} else {
let ch = invalid_utf8.choose(&mut rng).unwrap();
if let Some(c) = char::from_u32(*ch as u32) {
result.push(c);
}
}
}
result
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
struct TestArg { struct TestArg {
arg: String, arg: String,
@ -204,31 +184,31 @@ fuzz_target!(|_data: &[u8]| {
args.push(OsString::from(generate_test_arg())); args.push(OsString::from(generate_test_arg()));
} }
let (rust_output, uumain_exit_status) = generate_and_run_uumain(&args, uumain); let rust_result = generate_and_run_uumain(&args, uumain);
// Run GNU test with the provided arguments and compare the output let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false) {
match run_gnu_cmd(CMD_PATH, &args[1..], false) { Ok(result) => result,
Ok((gnu_output, gnu_exit_status)) => { Err(error_result) => {
let gnu_output = gnu_output.trim().to_owned(); eprintln!("Failed to run GNU command:");
println!("gnu_exit_status {}", gnu_exit_status); eprintln!("Stderr: {}", error_result.stderr);
println!("uumain_exit_status {}", uumain_exit_status); eprintln!("Exit Code: {}", error_result.exit_code);
if rust_output != gnu_output || uumain_exit_status != gnu_exit_status { CommandResult {
println!("Discrepancy detected!"); stdout: String::new(),
println!("Test: {:?}", &args[1..]); stderr: error_result.stderr,
println!("My output: {}", rust_output); exit_code: error_result.exit_code,
println!("GNU output: {}", gnu_output);
println!("My exit status: {}", uumain_exit_status);
println!("GNU exit status: {}", gnu_exit_status);
panic!();
} else {
println!(
"Outputs and exit statuses matched for expression {:?}",
&args[1..]
);
} }
} }
Err(_) => { };
println!("GNU test execution failed for expression {:?}", &args[1..]);
} compare_result(
} "test",
&format!("{:?}", &args[1..]),
&rust_result.stdout,
&gnu_result.stdout,
&rust_result.stderr,
&gnu_result.stderr,
rust_result.exit_code,
gnu_result.exit_code,
false, // Set to true if you want to fail on stderr diff
);
}); });

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_arch" name = "uu_arch"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "arch ~ (uutils) display machine architecture" description = "arch ~ (uutils) display machine architecture"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_base32" name = "uu_base32"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "base32 ~ (uutils) decode/encode input (base32-encoding)" description = "base32 ~ (uutils) decode/encode input (base32-encoding)"

View file

@ -54,7 +54,7 @@ impl Config {
format!("{}: No such file or directory", name.maybe_quote()), format!("{}: No such file or directory", name.maybe_quote()),
)); ));
} }
Some(name.to_owned()) Some(name.clone())
} }
} }
None => None, None => None,

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_base64" name = "uu_base64"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "base64 ~ (uutils) decode/encode input (base64-encoding)" description = "base64 ~ (uutils) decode/encode input (base64-encoding)"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_basename" name = "uu_basename"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "basename ~ (uutils) display PATHNAME with leading directory components removed" description = "basename ~ (uutils) display PATHNAME with leading directory components removed"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_basenc" name = "uu_basenc"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "basenc ~ (uutils) decode/encode input" description = "basenc ~ (uutils) decode/encode input"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_cat" name = "uu_cat"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "cat ~ (uutils) concatenate and display input" description = "cat ~ (uutils) concatenate and display input"

View file

@ -3,9 +3,7 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // file that was distributed with this source code.
// spell-checker:ignore (ToDO) nonprint nonblank nonprinting // spell-checker:ignore (ToDO) nonprint nonblank nonprinting ELOOP
// last synced with: cat (GNU coreutils) 8.13
use clap::{crate_version, Arg, ArgAction, Command}; use clap::{crate_version, Arg, ArgAction, Command};
use std::fs::{metadata, File}; use std::fs::{metadata, File};
use std::io::{self, IsTerminal, Read, Write}; use std::io::{self, IsTerminal, Read, Write};
@ -52,6 +50,8 @@ enum CatError {
IsDirectory, IsDirectory,
#[error("input file is output file")] #[error("input file is output file")]
OutputIsInput, OutputIsInput,
#[error("Too many levels of symbolic links")]
TooManySymlinks,
} }
type CatResult<T> = Result<T, CatError>; type CatResult<T> = Result<T, CatError>;
@ -213,7 +213,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let squeeze_blank = matches.get_flag(options::SQUEEZE_BLANK); let squeeze_blank = matches.get_flag(options::SQUEEZE_BLANK);
let files: Vec<String> = match matches.get_many::<String>(options::FILE) { let files: Vec<String> = match matches.get_many::<String>(options::FILE) {
Some(v) => v.clone().map(|v| v.to_owned()).collect(), Some(v) => v.cloned().collect(),
None => vec!["-".to_owned()], None => vec!["-".to_owned()],
}; };
@ -403,7 +403,23 @@ fn get_input_type(path: &str) -> CatResult<InputType> {
return Ok(InputType::StdIn); return Ok(InputType::StdIn);
} }
let ft = metadata(path)?.file_type(); let ft = match metadata(path) {
Ok(md) => md.file_type(),
Err(e) => {
if let Some(raw_error) = e.raw_os_error() {
// On Unix-like systems, the error code for "Too many levels of symbolic links" is 40 (ELOOP).
// we want to provide a proper error message in this case.
#[cfg(not(any(target_os = "macos", target_os = "freebsd")))]
let too_many_symlink_code = 40;
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
let too_many_symlink_code = 62;
if raw_error == too_many_symlink_code {
return Err(CatError::TooManySymlinks);
}
}
return Err(CatError::Io(e));
}
};
match ft { match ft {
#[cfg(unix)] #[cfg(unix)]
ft if ft.is_block_device() => Ok(InputType::BlockDevice), ft if ft.is_block_device() => Ok(InputType::BlockDevice),

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chcon" name = "uu_chcon"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chcon ~ (uutils) change file security context" description = "chcon ~ (uutils) change file security context"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chgrp" name = "uu_chgrp"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chgrp ~ (uutils) change the group ownership of FILE" description = "chgrp ~ (uutils) change the group ownership of FILE"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chmod" name = "uu_chmod"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chmod ~ (uutils) change mode of FILE" description = "chmod ~ (uutils) change mode of FILE"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chown" name = "uu_chown"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chown ~ (uutils) change the ownership of FILE" description = "chown ~ (uutils) change the ownership of FILE"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_chroot" name = "uu_chroot"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "chroot ~ (uutils) run COMMAND under a new root directory" description = "chroot ~ (uutils) run COMMAND under a new root directory"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_cksum" name = "uu_cksum"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "cksum ~ (uutils) display CRC and size of input" description = "cksum ~ (uutils) display CRC and size of input"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_comm" name = "uu_comm"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "comm ~ (uutils) compare sorted inputs" description = "comm ~ (uutils) compare sorted inputs"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_cp" name = "uu_cp"
version = "0.0.22" version = "0.0.23"
authors = [ authors = [
"Jordy Dickinson <jordy.dickinson@gmail.com>", "Jordy Dickinson <jordy.dickinson@gmail.com>",
"Joshua S. Miller <jsmiller@uchicago.edu>", "Joshua S. Miller <jsmiller@uchicago.edu>",

View file

@ -87,6 +87,9 @@ struct Context<'a> {
/// The target path to which the directory will be copied. /// The target path to which the directory will be copied.
target: &'a Path, target: &'a Path,
/// The source path from which the directory will be copied.
root: &'a Path,
} }
impl<'a> Context<'a> { impl<'a> Context<'a> {
@ -102,6 +105,7 @@ impl<'a> Context<'a> {
current_dir, current_dir,
root_parent, root_parent,
target, target,
root,
}) })
} }
} }
@ -156,11 +160,19 @@ struct Entry {
} }
impl Entry { impl Entry {
fn new(context: &Context, direntry: &DirEntry) -> Result<Self, StripPrefixError> { fn new(
context: &Context,
direntry: &DirEntry,
no_target_dir: bool,
) -> Result<Self, StripPrefixError> {
let source_relative = direntry.path().to_path_buf(); let source_relative = direntry.path().to_path_buf();
let source_absolute = context.current_dir.join(&source_relative); let source_absolute = context.current_dir.join(&source_relative);
let descendant = let mut descendant =
get_local_to_root_parent(&source_absolute, context.root_parent.as_deref())?; get_local_to_root_parent(&source_absolute, context.root_parent.as_deref())?;
if no_target_dir {
descendant = descendant.strip_prefix(context.root)?.to_path_buf();
}
let local_to_target = context.target.join(descendant); let local_to_target = context.target.join(descendant);
let target_is_file = context.target.is_file(); let target_is_file = context.target.is_file();
Ok(Self { Ok(Self {
@ -389,7 +401,7 @@ pub(crate) fn copy_directory(
{ {
match direntry_result { match direntry_result {
Ok(direntry) => { Ok(direntry) => {
let entry = Entry::new(&context, &direntry)?; let entry = Entry::new(&context, &direntry, options.no_target_dir)?;
copy_direntry( copy_direntry(
progress_bar, progress_bar,
entry, entry,

View file

@ -7,7 +7,6 @@
#![allow(clippy::extra_unused_lifetimes)] #![allow(clippy::extra_unused_lifetimes)]
use quick_error::quick_error; use quick_error::quick_error;
use std::borrow::Cow;
use std::cmp::Ordering; use std::cmp::Ordering;
use std::collections::{HashMap, HashSet}; use std::collections::{HashMap, HashSet};
use std::env; use std::env;
@ -41,8 +40,8 @@ use uucore::{backup_control, update_control};
// requires these enum. // requires these enum.
pub use uucore::{backup_control::BackupMode, update_control::UpdateMode}; pub use uucore::{backup_control::BackupMode, update_control::UpdateMode};
use uucore::{ use uucore::{
crash, format_usage, help_about, help_section, help_usage, prompt_yes, show_error, format_usage, help_about, help_section, help_usage, prompt_yes, show_error, show_warning,
show_warning, util_name, util_name,
}; };
use crate::copydir::copy_directory; use crate::copydir::copy_directory;
@ -144,6 +143,7 @@ pub enum SparseMode {
} }
/// The expected file type of copy target /// The expected file type of copy target
#[derive(Copy, Clone)]
pub enum TargetType { pub enum TargetType {
Directory, Directory,
File, File,
@ -1195,7 +1195,7 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult
&progress_bar, &progress_bar,
source, source,
target, target,
&target_type, target_type,
options, options,
&mut symlinked_files, &mut symlinked_files,
&mut copied_files, &mut copied_files,
@ -1220,7 +1220,7 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult
fn construct_dest_path( fn construct_dest_path(
source_path: &Path, source_path: &Path,
target: &Path, target: &Path,
target_type: &TargetType, target_type: TargetType,
options: &Options, options: &Options,
) -> CopyResult<PathBuf> { ) -> CopyResult<PathBuf> {
if options.no_target_dir && target.is_dir() { if options.no_target_dir && target.is_dir() {
@ -1235,7 +1235,7 @@ fn construct_dest_path(
return Err("with --parents, the destination must be a directory".into()); return Err("with --parents, the destination must be a directory".into());
} }
Ok(match *target_type { Ok(match target_type {
TargetType::Directory => { TargetType::Directory => {
let root = if options.parents { let root = if options.parents {
Path::new("") Path::new("")
@ -1252,7 +1252,7 @@ fn copy_source(
progress_bar: &Option<ProgressBar>, progress_bar: &Option<ProgressBar>,
source: &Path, source: &Path,
target: &Path, target: &Path,
target_type: &TargetType, target_type: TargetType,
options: &Options, options: &Options,
symlinked_files: &mut HashSet<FileInformation>, symlinked_files: &mut HashSet<FileInformation>,
copied_files: &mut HashMap<FileInformation, PathBuf>, copied_files: &mut HashMap<FileInformation, PathBuf>,
@ -1995,24 +1995,12 @@ fn copy_link(
) -> CopyResult<()> { ) -> CopyResult<()> {
// Here, we will copy the symlink itself (actually, just recreate it) // Here, we will copy the symlink itself (actually, just recreate it)
let link = fs::read_link(source)?; let link = fs::read_link(source)?;
let dest: Cow<'_, Path> = if dest.is_dir() { // we always need to remove the file to be able to create a symlink,
match source.file_name() { // even if it is writeable.
Some(name) => dest.join(name).into(), if dest.is_symlink() || dest.is_file() {
None => crash!( fs::remove_file(dest)?;
EXIT_ERR, }
"cannot stat {}: No such file or directory", symlink_file(&link, dest, &context_for(&link, dest), symlinked_files)
source.quote()
),
}
} else {
// we always need to remove the file to be able to create a symlink,
// even if it is writeable.
if dest.is_symlink() || dest.is_file() {
fs::remove_file(dest)?;
}
dest.into()
};
symlink_file(&link, &dest, &context_for(&link, &dest), symlinked_files)
} }
/// Generate an error message if `target` is not the correct `target_type` /// Generate an error message if `target` is not the correct `target_type`

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_csplit" name = "uu_csplit"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "csplit ~ (uutils) Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output" description = "csplit ~ (uutils) Output pieces of FILE separated by PATTERN(s) to files 'xx00', 'xx01', ..., and output byte counts of each piece to standard output"

View file

@ -62,15 +62,9 @@ impl CsplitOptions {
split_name: crash_if_err!( split_name: crash_if_err!(
1, 1,
SplitName::new( SplitName::new(
matches matches.get_one::<String>(options::PREFIX).cloned(),
.get_one::<String>(options::PREFIX) matches.get_one::<String>(options::SUFFIX_FORMAT).cloned(),
.map(|s| s.to_owned()), matches.get_one::<String>(options::DIGITS).cloned()
matches
.get_one::<String>(options::SUFFIX_FORMAT)
.map(|s| s.to_owned()),
matches
.get_one::<String>(options::DIGITS)
.map(|s| s.to_owned())
) )
), ),
keep_files, keep_files,

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_cut" name = "uu_cut"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "cut ~ (uutils) display byte/field columns of input lines" description = "cut ~ (uutils) display byte/field columns of input lines"

View file

@ -400,7 +400,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
if s.is_empty() { if s.is_empty() {
Some("\0".to_owned()) Some("\0".to_owned())
} else { } else {
Some(s.to_owned()) Some(s.clone())
} }
} }
None => None, None => None,
@ -491,7 +491,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let files: Vec<String> = matches let files: Vec<String> = matches
.get_many::<String>(options::FILE) .get_many::<String>(options::FILE)
.unwrap_or_default() .unwrap_or_default()
.map(|s| s.to_owned()) .cloned()
.collect(); .collect();
match mode_parse { match mode_parse {

View file

@ -1,7 +1,7 @@
# spell-checker:ignore datetime # spell-checker:ignore datetime
[package] [package]
name = "uu_date" name = "uu_date"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "date ~ (uutils) display or set the current time" description = "date ~ (uutils) display or set the current time"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_dd" name = "uu_dd"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "dd ~ (uutils) copy and convert files" description = "dd ~ (uutils) copy and convert files"
@ -18,7 +18,7 @@ path = "src/dd.rs"
clap = { workspace = true } clap = { workspace = true }
gcd = { workspace = true } gcd = { workspace = true }
libc = { workspace = true } libc = { workspace = true }
uucore = { workspace = true, features = ["format"] } uucore = { workspace = true, features = ["format", "quoting-style"] }
[target.'cfg(any(target_os = "linux"))'.dependencies] [target.'cfg(any(target_os = "linux"))'.dependencies]
nix = { workspace = true, features = ["fs"] } nix = { workspace = true, features = ["fs"] }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_df" name = "uu_df"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "df ~ (uutils) display file system information" description = "df ~ (uutils) display file system information"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_dir" name = "uu_dir"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "shortcut to ls -C -b" description = "shortcut to ls -C -b"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_dircolors" name = "uu_dircolors"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "dircolors ~ (uutils) display commands to set LS_COLORS" description = "dircolors ~ (uutils) display commands to set LS_COLORS"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_dirname" name = "uu_dirname"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "dirname ~ (uutils) display parent directory of PATHNAME" description = "dirname ~ (uutils) display parent directory of PATHNAME"

View file

@ -30,7 +30,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let dirnames: Vec<String> = matches let dirnames: Vec<String> = matches
.get_many::<String>(options::DIR) .get_many::<String>(options::DIR)
.unwrap_or_default() .unwrap_or_default()
.map(|s| s.to_owned()) .cloned()
.collect(); .collect();
if dirnames.is_empty() { if dirnames.is_empty() {

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_du" name = "uu_du"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "du ~ (uutils) display disk usage" description = "du ~ (uutils) display disk usage"

View file

@ -31,13 +31,11 @@ use std::time::{Duration, UNIX_EPOCH};
use std::{error::Error, fmt::Display}; use std::{error::Error, fmt::Display};
use uucore::display::{print_verbatim, Quotable}; use uucore::display::{print_verbatim, Quotable};
use uucore::error::FromIo; use uucore::error::FromIo;
use uucore::error::{set_exit_code, UError, UResult}; use uucore::error::{set_exit_code, UError, UResult, USimpleError};
use uucore::line_ending::LineEnding; use uucore::line_ending::LineEnding;
use uucore::parse_glob; use uucore::parse_glob;
use uucore::parse_size::{parse_size_u64, ParseSizeError}; use uucore::parse_size::{parse_size_u64, ParseSizeError};
use uucore::{ use uucore::{format_usage, help_about, help_section, help_usage, show, show_error, show_warning};
crash, format_usage, help_about, help_section, help_usage, show, show_error, show_warning,
};
#[cfg(windows)] #[cfg(windows)]
use windows_sys::Win32::Foundation::HANDLE; use windows_sys::Win32::Foundation::HANDLE;
#[cfg(windows)] #[cfg(windows)]
@ -68,6 +66,7 @@ mod options {
pub const ONE_FILE_SYSTEM: &str = "one-file-system"; pub const ONE_FILE_SYSTEM: &str = "one-file-system";
pub const DEREFERENCE: &str = "dereference"; pub const DEREFERENCE: &str = "dereference";
pub const DEREFERENCE_ARGS: &str = "dereference-args"; pub const DEREFERENCE_ARGS: &str = "dereference-args";
pub const NO_DEREFERENCE: &str = "no-dereference";
pub const INODES: &str = "inodes"; pub const INODES: &str = "inodes";
pub const EXCLUDE: &str = "exclude"; pub const EXCLUDE: &str = "exclude";
pub const EXCLUDE_FROM: &str = "exclude-from"; pub const EXCLUDE_FROM: &str = "exclude-from";
@ -89,6 +88,7 @@ struct Options {
separate_dirs: bool, separate_dirs: bool,
one_file_system: bool, one_file_system: bool,
dereference: Deref, dereference: Deref,
count_links: bool,
inodes: bool, inodes: bool,
verbose: bool, verbose: bool,
} }
@ -136,39 +136,42 @@ impl Stat {
}?; }?;
#[cfg(not(windows))] #[cfg(not(windows))]
let file_info = FileInfo { {
file_id: metadata.ino() as u128, let file_info = FileInfo {
dev_id: metadata.dev(), file_id: metadata.ino() as u128,
}; dev_id: metadata.dev(),
#[cfg(not(windows))] };
return Ok(Self {
path: path.to_path_buf(), Ok(Self {
is_dir: metadata.is_dir(), path: path.to_path_buf(),
size: if path.is_dir() { 0 } else { metadata.len() }, is_dir: metadata.is_dir(),
blocks: metadata.blocks(), size: if path.is_dir() { 0 } else { metadata.len() },
inodes: 1, blocks: metadata.blocks(),
inode: Some(file_info), inodes: 1,
created: birth_u64(&metadata), inode: Some(file_info),
accessed: metadata.atime() as u64, created: birth_u64(&metadata),
modified: metadata.mtime() as u64, accessed: metadata.atime() as u64,
}); modified: metadata.mtime() as u64,
})
}
#[cfg(windows)] #[cfg(windows)]
let size_on_disk = get_size_on_disk(path); {
#[cfg(windows)] let size_on_disk = get_size_on_disk(path);
let file_info = get_file_info(path); let file_info = get_file_info(path);
#[cfg(windows)]
Ok(Self { Ok(Self {
path: path.to_path_buf(), path: path.to_path_buf(),
is_dir: metadata.is_dir(), is_dir: metadata.is_dir(),
size: if path.is_dir() { 0 } else { metadata.len() }, size: if path.is_dir() { 0 } else { metadata.len() },
blocks: size_on_disk / 1024 * 2, blocks: size_on_disk / 1024 * 2,
inode: file_info, inodes: 1,
inodes: 1, inode: file_info,
created: windows_creation_time_to_unix_time(metadata.creation_time()), created: windows_creation_time_to_unix_time(metadata.creation_time()),
accessed: windows_time_to_unix_time(metadata.last_access_time()), accessed: windows_time_to_unix_time(metadata.last_access_time()),
modified: windows_time_to_unix_time(metadata.last_write_time()), modified: windows_time_to_unix_time(metadata.last_write_time()),
}) })
}
} }
} }
@ -254,22 +257,22 @@ fn get_file_info(path: &Path) -> Option<FileInfo> {
result result
} }
fn read_block_size(s: Option<&str>) -> u64 { fn read_block_size(s: Option<&str>) -> UResult<u64> {
if let Some(s) = s { if let Some(s) = s {
parse_size_u64(s) parse_size_u64(s)
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::BLOCK_SIZE))) .map_err(|e| USimpleError::new(1, format_error_message(&e, s, options::BLOCK_SIZE)))
} else { } else {
for env_var in ["DU_BLOCK_SIZE", "BLOCK_SIZE", "BLOCKSIZE"] { for env_var in ["DU_BLOCK_SIZE", "BLOCK_SIZE", "BLOCKSIZE"] {
if let Ok(env_size) = env::var(env_var) { if let Ok(env_size) = env::var(env_var) {
if let Ok(v) = parse_size_u64(&env_size) { if let Ok(v) = parse_size_u64(&env_size) {
return v; return Ok(v);
} }
} }
} }
if env::var("POSIXLY_CORRECT").is_ok() { if env::var("POSIXLY_CORRECT").is_ok() {
512 Ok(512)
} else { } else {
1024 Ok(1024)
} }
} }
} }
@ -293,7 +296,7 @@ fn du(
mut my_stat: Stat, mut my_stat: Stat,
options: &Options, options: &Options,
depth: usize, depth: usize,
inodes: &mut HashSet<FileInfo>, seen_inodes: &mut HashSet<FileInfo>,
exclude: &[Pattern], exclude: &[Pattern],
) -> Box<dyn DoubleEndedIterator<Item = Stat>> { ) -> Box<dyn DoubleEndedIterator<Item = Stat>> {
let mut stats = vec![]; let mut stats = vec![];
@ -333,10 +336,13 @@ fn du(
} }
if let Some(inode) = this_stat.inode { if let Some(inode) = this_stat.inode {
if inodes.contains(&inode) { if seen_inodes.contains(&inode) {
if options.count_links {
my_stat.inodes += 1;
}
continue; continue;
} }
inodes.insert(inode); seen_inodes.insert(inode);
} }
if this_stat.is_dir { if this_stat.is_dir {
if options.one_file_system { if options.one_file_system {
@ -348,7 +354,13 @@ fn du(
} }
} }
} }
futures.push(du(this_stat, options, depth + 1, inodes, exclude)); futures.push(du(
this_stat,
options,
depth + 1,
seen_inodes,
exclude,
));
} else { } else {
my_stat.size += this_stat.size; my_stat.size += this_stat.size;
my_stat.blocks += this_stat.blocks; my_stat.blocks += this_stat.blocks;
@ -505,7 +517,7 @@ fn build_exclude_patterns(matches: &ArgMatches) -> UResult<Vec<Pattern>> {
let excludes_iterator = matches let excludes_iterator = matches
.get_many::<String>(options::EXCLUDE) .get_many::<String>(options::EXCLUDE)
.unwrap_or_default() .unwrap_or_default()
.map(|v| v.to_owned()); .cloned();
let mut exclude_patterns = Vec::new(); let mut exclude_patterns = Vec::new();
for f in excludes_iterator.chain(exclude_from_iterator) { for f in excludes_iterator.chain(exclude_from_iterator) {
@ -559,6 +571,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} else { } else {
Deref::None Deref::None
}, },
count_links: matches.get_flag(options::COUNT_LINKS),
inodes: matches.get_flag(options::INODES), inodes: matches.get_flag(options::INODES),
verbose: matches.get_flag(options::VERBOSE), verbose: matches.get_flag(options::VERBOSE),
}; };
@ -573,12 +586,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
matches matches
.get_one::<String>(options::BLOCK_SIZE) .get_one::<String>(options::BLOCK_SIZE)
.map(|s| s.as_str()), .map(|s| s.as_str()),
); )?;
let threshold = matches.get_one::<String>(options::THRESHOLD).map(|s| { let threshold = match matches.get_one::<String>(options::THRESHOLD) {
Threshold::from_str(s) Some(s) => match Threshold::from_str(s) {
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::THRESHOLD))) Ok(t) => Some(t),
}); Err(e) => {
return Err(USimpleError::new(
1,
format_error_message(&e, s, options::THRESHOLD),
))
}
},
None => None,
};
let multiplier: u64 = if matches.get_flag(options::SI) { let multiplier: u64 = if matches.get_flag(options::SI) {
1000 1000
@ -622,11 +643,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
// Check existence of path provided in argument // Check existence of path provided in argument
if let Ok(stat) = Stat::new(&path, &options) { if let Ok(stat) = Stat::new(&path, &options) {
// Kick off the computation of disk usage from the initial path // Kick off the computation of disk usage from the initial path
let mut inodes: HashSet<FileInfo> = HashSet::new(); let mut seen_inodes: HashSet<FileInfo> = HashSet::new();
if let Some(inode) = stat.inode { if let Some(inode) = stat.inode {
inodes.insert(inode); seen_inodes.insert(inode);
} }
let iter = du(stat, &options, 0, &mut inodes, &excludes); let iter = du(stat, &options, 0, &mut seen_inodes, &excludes);
// Sum up all the returned `Stat`s and display results // Sum up all the returned `Stat`s and display results
let (_, len) = iter.size_hint(); let (_, len) = iter.size_hint();
@ -820,17 +841,19 @@ pub fn uu_app() -> Command {
.arg( .arg(
Arg::new(options::DEREFERENCE_ARGS) Arg::new(options::DEREFERENCE_ARGS)
.short('D') .short('D')
.visible_short_alias('H')
.long(options::DEREFERENCE_ARGS) .long(options::DEREFERENCE_ARGS)
.help("follow only symlinks that are listed on the command line") .help("follow only symlinks that are listed on the command line")
.action(ArgAction::SetTrue) .action(ArgAction::SetTrue)
) )
// .arg( .arg(
// Arg::new("no-dereference") Arg::new(options::NO_DEREFERENCE)
// .short('P') .short('P')
// .long("no-dereference") .long(options::NO_DEREFERENCE)
// .help("don't follow any symbolic links (this is the default)") .help("don't follow any symbolic links (this is the default)")
// .action(ArgAction::SetTrue), .overrides_with(options::DEREFERENCE)
// ) .action(ArgAction::SetTrue),
)
.arg( .arg(
Arg::new(options::BLOCK_SIZE_1M) Arg::new(options::BLOCK_SIZE_1M)
.short('m') .short('m')
@ -989,13 +1012,9 @@ mod test_du {
#[test] #[test]
fn test_read_block_size() { fn test_read_block_size() {
let test_data = [ let test_data = [Some("1024".to_string()), Some("K".to_string()), None];
(Some("1024".to_string()), 1024),
(Some("K".to_string()), 1024),
(None, 1024),
];
for it in &test_data { for it in &test_data {
assert_eq!(read_block_size(it.0.as_deref()), it.1); assert!(matches!(read_block_size(it.as_deref()), Ok(1024)));
} }
} }
} }

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_echo" name = "uu_echo"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "echo ~ (uutils) display TEXT" description = "echo ~ (uutils) display TEXT"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_env" name = "uu_env"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND" description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND"

View file

@ -3,8 +3,6 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // file that was distributed with this source code.
/* last synced with: env (GNU coreutils) 8.13 */
// spell-checker:ignore (ToDO) chdir execvp progname subcommand subcommands unsets setenv putenv spawnp SIGSEGV SIGBUS sigaction // spell-checker:ignore (ToDO) chdir execvp progname subcommand subcommands unsets setenv putenv spawnp SIGSEGV SIGBUS sigaction
use clap::{crate_name, crate_version, Arg, ArgAction, Command}; use clap::{crate_name, crate_version, Arg, ArgAction, Command};

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_expand" name = "uu_expand"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "expand ~ (uutils) convert input tabs to spaces" description = "expand ~ (uutils) convert input tabs to spaces"

View file

@ -15,7 +15,7 @@ use std::str::from_utf8;
use unicode_width::UnicodeWidthChar; use unicode_width::UnicodeWidthChar;
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{FromIo, UError, UResult}; use uucore::error::{FromIo, UError, UResult};
use uucore::{crash, format_usage, help_about, help_usage}; use uucore::{format_usage, help_about, help_usage};
const ABOUT: &str = help_about!("expand.md"); const ABOUT: &str = help_about!("expand.md");
const USAGE: &str = help_usage!("expand.md"); const USAGE: &str = help_usage!("expand.md");
@ -265,7 +265,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let matches = uu_app().try_get_matches_from(expand_shortcuts(&args))?; let matches = uu_app().try_get_matches_from(expand_shortcuts(&args))?;
expand(&Options::new(&matches)?).map_err_context(|| "failed to write output".to_string()) expand(&Options::new(&matches)?)
} }
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
@ -308,16 +308,13 @@ pub fn uu_app() -> Command {
) )
} }
fn open(path: &str) -> BufReader<Box<dyn Read + 'static>> { fn open(path: &str) -> UResult<BufReader<Box<dyn Read + 'static>>> {
let file_buf; let file_buf;
if path == "-" { if path == "-" {
BufReader::new(Box::new(stdin()) as Box<dyn Read>) Ok(BufReader::new(Box::new(stdin()) as Box<dyn Read>))
} else { } else {
file_buf = match File::open(path) { file_buf = File::open(path).map_err_context(|| path.to_string())?;
Ok(a) => a, Ok(BufReader::new(Box::new(file_buf) as Box<dyn Read>))
Err(e) => crash!(1, "{}: {}\n", path.maybe_quote(), e),
};
BufReader::new(Box::new(file_buf) as Box<dyn Read>)
} }
} }
@ -370,99 +367,111 @@ enum CharType {
} }
#[allow(clippy::cognitive_complexity)] #[allow(clippy::cognitive_complexity)]
fn expand(options: &Options) -> std::io::Result<()> { fn expand_line(
buf: &mut Vec<u8>,
output: &mut BufWriter<std::io::Stdout>,
tabstops: &[usize],
options: &Options,
) -> std::io::Result<()> {
use self::CharType::*; use self::CharType::*;
let mut col = 0;
let mut byte = 0;
let mut init = true;
while byte < buf.len() {
let (ctype, cwidth, nbytes) = if options.uflag {
let nbytes = char::from(buf[byte]).len_utf8();
if byte + nbytes > buf.len() {
// don't overrun buffer because of invalid UTF-8
(Other, 1, 1)
} else if let Ok(t) = from_utf8(&buf[byte..byte + nbytes]) {
match t.chars().next() {
Some('\t') => (Tab, 0, nbytes),
Some('\x08') => (Backspace, 0, nbytes),
Some(c) => (Other, UnicodeWidthChar::width(c).unwrap_or(0), nbytes),
None => {
// no valid char at start of t, so take 1 byte
(Other, 1, 1)
}
}
} else {
(Other, 1, 1) // implicit assumption: non-UTF-8 char is 1 col wide
}
} else {
(
match buf[byte] {
// always take exactly 1 byte in strict ASCII mode
0x09 => Tab,
0x08 => Backspace,
_ => Other,
},
1,
1,
)
};
// figure out how many columns this char takes up
match ctype {
Tab => {
// figure out how many spaces to the next tabstop
let nts = next_tabstop(tabstops, col, &options.remaining_mode);
col += nts;
// now dump out either spaces if we're expanding, or a literal tab if we're not
if init || !options.iflag {
if nts <= options.tspaces.len() {
output.write_all(options.tspaces[..nts].as_bytes())?;
} else {
output.write_all(" ".repeat(nts).as_bytes())?;
};
} else {
output.write_all(&buf[byte..byte + nbytes])?;
}
}
_ => {
col = if ctype == Other {
col + cwidth
} else if col > 0 {
col - 1
} else {
0
};
// if we're writing anything other than a space, then we're
// done with the line's leading spaces
if buf[byte] != 0x20 {
init = false;
}
output.write_all(&buf[byte..byte + nbytes])?;
}
}
byte += nbytes; // advance the pointer
}
output.flush()?;
buf.truncate(0); // clear the buffer
Ok(())
}
fn expand(options: &Options) -> UResult<()> {
let mut output = BufWriter::new(stdout()); let mut output = BufWriter::new(stdout());
let ts = options.tabstops.as_ref(); let ts = options.tabstops.as_ref();
let mut buf = Vec::new(); let mut buf = Vec::new();
for file in &options.files { for file in &options.files {
let mut fh = open(file); let mut fh = open(file)?;
while match fh.read_until(b'\n', &mut buf) { while match fh.read_until(b'\n', &mut buf) {
Ok(s) => s > 0, Ok(s) => s > 0,
Err(_) => buf.is_empty(), Err(_) => buf.is_empty(),
} { } {
let mut col = 0; expand_line(&mut buf, &mut output, ts, options)
let mut byte = 0; .map_err_context(|| "failed to write output".to_string())?;
let mut init = true;
while byte < buf.len() {
let (ctype, cwidth, nbytes) = if options.uflag {
let nbytes = char::from(buf[byte]).len_utf8();
if byte + nbytes > buf.len() {
// don't overrun buffer because of invalid UTF-8
(Other, 1, 1)
} else if let Ok(t) = from_utf8(&buf[byte..byte + nbytes]) {
match t.chars().next() {
Some('\t') => (Tab, 0, nbytes),
Some('\x08') => (Backspace, 0, nbytes),
Some(c) => (Other, UnicodeWidthChar::width(c).unwrap_or(0), nbytes),
None => {
// no valid char at start of t, so take 1 byte
(Other, 1, 1)
}
}
} else {
(Other, 1, 1) // implicit assumption: non-UTF-8 char is 1 col wide
}
} else {
(
match buf[byte] {
// always take exactly 1 byte in strict ASCII mode
0x09 => Tab,
0x08 => Backspace,
_ => Other,
},
1,
1,
)
};
// figure out how many columns this char takes up
match ctype {
Tab => {
// figure out how many spaces to the next tabstop
let nts = next_tabstop(ts, col, &options.remaining_mode);
col += nts;
// now dump out either spaces if we're expanding, or a literal tab if we're not
if init || !options.iflag {
if nts <= options.tspaces.len() {
output.write_all(options.tspaces[..nts].as_bytes())?;
} else {
output.write_all(" ".repeat(nts).as_bytes())?;
};
} else {
output.write_all(&buf[byte..byte + nbytes])?;
}
}
_ => {
col = if ctype == Other {
col + cwidth
} else if col > 0 {
col - 1
} else {
0
};
// if we're writing anything other than a space, then we're
// done with the line's leading spaces
if buf[byte] != 0x20 {
init = false;
}
output.write_all(&buf[byte..byte + nbytes])?;
}
}
byte += nbytes; // advance the pointer
}
output.flush()?;
buf.truncate(0); // clear the buffer
} }
} }
Ok(()) Ok(())

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_expr" name = "uu_expr"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "expr ~ (uutils) display the value of EXPRESSION" description = "expr ~ (uutils) display the value of EXPRESSION"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_factor" name = "uu_factor"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "factor ~ (uutils) display the prime factors of each NUMBER" description = "factor ~ (uutils) display the prime factors of each NUMBER"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_false" name = "uu_false"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "false ~ (uutils) do nothing and fail" description = "false ~ (uutils) do nothing and fail"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_fmt" name = "uu_fmt"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "fmt ~ (uutils) reformat each paragraph of input" description = "fmt ~ (uutils) reformat each paragraph of input"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_fold" name = "uu_fold"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "fold ~ (uutils) wrap each line of input" description = "fold ~ (uutils) wrap each line of input"

View file

@ -35,7 +35,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let bytes = matches.get_flag(options::BYTES); let bytes = matches.get_flag(options::BYTES);
let spaces = matches.get_flag(options::SPACES); let spaces = matches.get_flag(options::SPACES);
let poss_width = match matches.get_one::<String>(options::WIDTH) { let poss_width = match matches.get_one::<String>(options::WIDTH) {
Some(v) => Some(v.to_owned()), Some(v) => Some(v.clone()),
None => obs_width, None => obs_width,
}; };
@ -50,7 +50,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}; };
let files = match matches.get_many::<String>(options::FILE) { let files = match matches.get_many::<String>(options::FILE) {
Some(v) => v.map(|v| v.to_owned()).collect(), Some(v) => v.cloned().collect(),
None => vec!["-".to_owned()], None => vec!["-".to_owned()],
}; };

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_groups" name = "uu_groups"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "groups ~ (uutils) display group memberships for USERNAME" description = "groups ~ (uutils) display group memberships for USERNAME"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_hashsum" name = "uu_hashsum"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "hashsum ~ (uutils) display or check input digests" description = "hashsum ~ (uutils) display or check input digests"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_head" name = "uu_head"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "head ~ (uutils) display the first lines of input" description = "head ~ (uutils) display the first lines of input"

View file

@ -205,7 +205,7 @@ impl HeadOptions {
options.mode = Mode::from(matches)?; options.mode = Mode::from(matches)?;
options.files = match matches.get_many::<String>(options::FILES_NAME) { options.files = match matches.get_many::<String>(options::FILES_NAME) {
Some(v) => v.map(|s| s.to_owned()).collect(), Some(v) => v.cloned().collect(),
None => vec!["-".to_owned()], None => vec!["-".to_owned()],
}; };
//println!("{:#?}", options); //println!("{:#?}", options);

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_hostid" name = "uu_hostid"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "hostid ~ (uutils) display the numeric identifier of the current host" description = "hostid ~ (uutils) display the numeric identifier of the current host"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_hostname" name = "uu_hostname"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "hostname ~ (uutils) display or set the host name of the current host" description = "hostname ~ (uutils) display or set the host name of the current host"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_id" name = "uu_id"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "id ~ (uutils) display user and group information for USER" description = "id ~ (uutils) display user and group information for USER"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_install" name = "uu_install"
version = "0.0.22" version = "0.0.23"
authors = ["Ben Eills <ben@beneills.com>", "uutils developers"] authors = ["Ben Eills <ben@beneills.com>", "uutils developers"]
license = "MIT" license = "MIT"
description = "install ~ (uutils) copy files from SOURCE to DESTINATION (with specified attributes)" description = "install ~ (uutils) copy files from SOURCE to DESTINATION (with specified attributes)"

View file

@ -375,9 +375,7 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
}; };
let backup_mode = backup_control::determine_backup_mode(matches)?; let backup_mode = backup_control::determine_backup_mode(matches)?;
let target_dir = matches let target_dir = matches.get_one::<String>(OPT_TARGET_DIRECTORY).cloned();
.get_one::<String>(OPT_TARGET_DIRECTORY)
.map(|d| d.to_owned());
let preserve_timestamps = matches.get_flag(OPT_PRESERVE_TIMESTAMPS); let preserve_timestamps = matches.get_flag(OPT_PRESERVE_TIMESTAMPS);
let compare = matches.get_flag(OPT_COMPARE); let compare = matches.get_flag(OPT_COMPARE);
@ -593,7 +591,7 @@ fn standard(mut paths: Vec<String>, b: &Behavior) -> UResult<()> {
let source = sources.first().unwrap(); let source = sources.first().unwrap();
if source.is_dir() { if source.is_dir() {
return Err(InstallError::OmittingDirectory(source.to_path_buf()).into()); return Err(InstallError::OmittingDirectory(source.clone()).into());
} }
if target.is_file() || is_new_file_path(&target) { if target.is_file() || is_new_file_path(&target) {
@ -628,7 +626,7 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
} }
if sourcepath.is_dir() { if sourcepath.is_dir() {
let err = InstallError::OmittingDirectory(sourcepath.to_path_buf()); let err = InstallError::OmittingDirectory(sourcepath.clone());
show!(err); show!(err);
continue; continue;
} }
@ -701,12 +699,9 @@ fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
if let Some(ref backup_path) = backup_path { if let Some(ref backup_path) = backup_path {
// TODO!! // TODO!!
if let Err(err) = fs::rename(to, backup_path) { if let Err(err) = fs::rename(to, backup_path) {
return Err(InstallError::BackupFailed( return Err(
to.to_path_buf(), InstallError::BackupFailed(to.to_path_buf(), backup_path.clone(), err).into(),
backup_path.to_path_buf(), );
err,
)
.into());
} }
} }
Ok(backup_path) Ok(backup_path)

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_join" name = "uu_join"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "join ~ (uutils) merge lines from inputs with matching join fields" description = "join ~ (uutils) merge lines from inputs with matching join fields"

View file

@ -19,9 +19,9 @@ use std::num::IntErrorKind;
#[cfg(unix)] #[cfg(unix)]
use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStrExt;
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{set_exit_code, UError, UResult, USimpleError}; use uucore::error::{set_exit_code, FromIo, UError, UResult, USimpleError};
use uucore::line_ending::LineEnding; use uucore::line_ending::LineEnding;
use uucore::{crash, crash_if_err, format_usage, help_about, help_usage}; use uucore::{crash_if_err, format_usage, help_about, help_usage};
const ABOUT: &str = help_about!("join.md"); const ABOUT: &str = help_about!("join.md");
const USAGE: &str = help_usage!("join.md"); const USAGE: &str = help_usage!("join.md");
@ -334,37 +334,30 @@ impl<'a> State<'a> {
key: usize, key: usize,
line_ending: LineEnding, line_ending: LineEnding,
print_unpaired: bool, print_unpaired: bool,
) -> State<'a> { ) -> UResult<State<'a>> {
let f = if name == "-" { let file_buf = if name == "-" {
Box::new(stdin.lock()) as Box<dyn BufRead> Box::new(stdin.lock()) as Box<dyn BufRead>
} else { } else {
match File::open(name) { let file = File::open(name).map_err_context(|| format!("{}", name.maybe_quote()))?;
Ok(file) => Box::new(BufReader::new(file)) as Box<dyn BufRead>, Box::new(BufReader::new(file)) as Box<dyn BufRead>
Err(err) => crash!(1, "{}: {}", name.maybe_quote(), err),
}
}; };
State { Ok(State {
key, key,
file_name: name, file_name: name,
file_num, file_num,
print_unpaired, print_unpaired,
lines: f.split(line_ending as u8), lines: file_buf.split(line_ending as u8),
max_len: 1, max_len: 1,
seq: Vec::new(), seq: Vec::new(),
line_num: 0, line_num: 0,
has_failed: false, has_failed: false,
has_unpaired: false, has_unpaired: false,
} })
} }
/// Skip the current unpaired line. /// Skip the current unpaired line.
fn skip_line( fn skip_line(&mut self, writer: &mut impl Write, input: &Input, repr: &Repr) -> UResult<()> {
&mut self,
writer: &mut impl Write,
input: &Input,
repr: &Repr,
) -> Result<(), JoinError> {
if self.print_unpaired { if self.print_unpaired {
self.print_first_line(writer, repr)?; self.print_first_line(writer, repr)?;
} }
@ -375,7 +368,7 @@ impl<'a> State<'a> {
/// Keep reading line sequence until the key does not change, return /// Keep reading line sequence until the key does not change, return
/// the first line whose key differs. /// the first line whose key differs.
fn extend(&mut self, input: &Input) -> Result<Option<Line>, JoinError> { fn extend(&mut self, input: &Input) -> UResult<Option<Line>> {
while let Some(line) = self.next_line(input)? { while let Some(line) = self.next_line(input)? {
let diff = input.compare(self.get_current_key(), line.get_field(self.key)); let diff = input.compare(self.get_current_key(), line.get_field(self.key));
@ -484,12 +477,7 @@ impl<'a> State<'a> {
0 0
} }
fn finalize( fn finalize(&mut self, writer: &mut impl Write, input: &Input, repr: &Repr) -> UResult<()> {
&mut self,
writer: &mut impl Write,
input: &Input,
repr: &Repr,
) -> Result<(), JoinError> {
if self.has_line() { if self.has_line() {
if self.print_unpaired { if self.print_unpaired {
self.print_first_line(writer, repr)?; self.print_first_line(writer, repr)?;
@ -713,10 +701,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
return Err(USimpleError::new(1, "both files cannot be standard input")); return Err(USimpleError::new(1, "both files cannot be standard input"));
} }
match exec(file1, file2, settings) { exec(file1, file2, settings)
Ok(_) => Ok(()),
Err(e) => Err(USimpleError::new(1, format!("{e}"))),
}
} }
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
@ -837,7 +822,7 @@ FILENUM is 1 or 2, corresponding to FILE1 or FILE2",
) )
} }
fn exec(file1: &str, file2: &str, settings: Settings) -> Result<(), JoinError> { fn exec(file1: &str, file2: &str, settings: Settings) -> UResult<()> {
let stdin = stdin(); let stdin = stdin();
let mut state1 = State::new( let mut state1 = State::new(
@ -847,7 +832,7 @@ fn exec(file1: &str, file2: &str, settings: Settings) -> Result<(), JoinError> {
settings.key1, settings.key1,
settings.line_ending, settings.line_ending,
settings.print_unpaired1, settings.print_unpaired1,
); )?;
let mut state2 = State::new( let mut state2 = State::new(
FileNum::File2, FileNum::File2,
@ -856,7 +841,7 @@ fn exec(file1: &str, file2: &str, settings: Settings) -> Result<(), JoinError> {
settings.key2, settings.key2,
settings.line_ending, settings.line_ending,
settings.print_unpaired2, settings.print_unpaired2,
); )?;
let input = Input::new( let input = Input::new(
settings.separator, settings.separator,

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_kill" name = "uu_kill"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "kill ~ (uutils) send a signal to a process" description = "kill ~ (uutils) send a signal to a process"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_link" name = "uu_link"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "link ~ (uutils) create a hard (file system) link to FILE" description = "link ~ (uutils) create a hard (file system) link to FILE"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_ln" name = "uu_ln"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "ln ~ (uutils) create a (file system) link to TARGET" description = "ln ~ (uutils) create a (file system) link to TARGET"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_logname" name = "uu_logname"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "logname ~ (uutils) display the login name of the current user" description = "logname ~ (uutils) display the login name of the current user"

View file

@ -3,8 +3,6 @@
// For the full copyright and license information, please view the LICENSE // For the full copyright and license information, please view the LICENSE
// file that was distributed with this source code. // file that was distributed with this source code.
/* last synced with: logname (GNU coreutils) 8.22 */
// spell-checker:ignore (ToDO) getlogin userlogin // spell-checker:ignore (ToDO) getlogin userlogin
use clap::{crate_version, Command}; use clap::{crate_version, Command};

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_ls" name = "uu_ls"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "ls ~ (uutils) display directory contents" description = "ls ~ (uutils) display directory contents"

View file

@ -577,9 +577,7 @@ fn extract_color(options: &clap::ArgMatches) -> bool {
/// ///
/// A QuotingStyle variant representing the quoting style to use. /// A QuotingStyle variant representing the quoting style to use.
fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> QuotingStyle { fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> QuotingStyle {
let opt_quoting_style = options let opt_quoting_style = options.get_one::<String>(options::QUOTING_STYLE).cloned();
.get_one::<String>(options::QUOTING_STYLE)
.map(|cmd_line_qs| cmd_line_qs.to_owned());
if let Some(style) = opt_quoting_style { if let Some(style) = opt_quoting_style {
match style.as_str() { match style.as_str() {
@ -788,9 +786,7 @@ impl Config {
match parse_size_u64(&raw_bs.to_string_lossy()) { match parse_size_u64(&raw_bs.to_string_lossy()) {
Ok(size) => Some(size), Ok(size) => Some(size),
Err(_) => { Err(_) => {
show!(LsError::BlockSizeParseError( show!(LsError::BlockSizeParseError(cmd_line_bs.unwrap().clone()));
cmd_line_bs.unwrap().to_owned()
));
None None
} }
} }
@ -3056,7 +3052,7 @@ fn display_file_name(
target_data.must_dereference, target_data.must_dereference,
) { ) {
Ok(md) => md, Ok(md) => md,
Err(_) => path.md(out).unwrap().to_owned(), Err(_) => path.md(out).unwrap().clone(),
}; };
name.push_str(&color_name( name.push_str(&color_name(
@ -3073,11 +3069,7 @@ fn display_file_name(
} }
} }
Err(err) => { Err(err) => {
show!(LsError::IOErrorContext( show!(LsError::IOErrorContext(err, path.p_buf.clone(), false));
err,
path.p_buf.to_path_buf(),
false
));
} }
} }
} }
@ -3087,7 +3079,7 @@ fn display_file_name(
if config.context { if config.context {
if let Some(pad_count) = prefix_context { if let Some(pad_count) = prefix_context {
let security_context = if matches!(config.format, Format::Commas) { let security_context = if matches!(config.format, Format::Commas) {
path.security_context.to_owned() path.security_context.clone()
} else { } else {
pad_left(&path.security_context, pad_count) pad_left(&path.security_context, pad_count)
}; };

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_mkdir" name = "uu_mkdir"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "mkdir ~ (uutils) create DIRECTORY" description = "mkdir ~ (uutils) create DIRECTORY"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_mkfifo" name = "uu_mkfifo"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "mkfifo ~ (uutils) create FIFOs (named pipes)" description = "mkfifo ~ (uutils) create FIFOs (named pipes)"

View file

@ -42,7 +42,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
}; };
let fifos: Vec<String> = match matches.get_many::<String>(options::FIFO) { let fifos: Vec<String> = match matches.get_many::<String>(options::FIFO) {
Some(v) => v.clone().map(|s| s.to_owned()).collect(), Some(v) => v.cloned().collect(),
None => return Err(USimpleError::new(1, "missing operand")), None => return Err(USimpleError::new(1, "missing operand")),
}; };

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_mknod" name = "uu_mknod"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "mknod ~ (uutils) create special file NAME of TYPE" description = "mknod ~ (uutils) create special file NAME of TYPE"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_mktemp" name = "uu_mktemp"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "mktemp ~ (uutils) create and display a temporary file or directory from TEMPLATE" description = "mktemp ~ (uutils) create and display a temporary file or directory from TEMPLATE"

View file

@ -115,29 +115,30 @@ impl Display for MkTempError {
/// This provides a layer of indirection between the application logic /// This provides a layer of indirection between the application logic
/// and the argument parsing library `clap`, allowing each to vary /// and the argument parsing library `clap`, allowing each to vary
/// independently. /// independently.
struct Options { #[derive(Clone)]
pub struct Options {
/// Whether to create a temporary directory instead of a file. /// Whether to create a temporary directory instead of a file.
directory: bool, pub directory: bool,
/// Whether to just print the name of a file that would have been created. /// Whether to just print the name of a file that would have been created.
dry_run: bool, pub dry_run: bool,
/// Whether to suppress file creation error messages. /// Whether to suppress file creation error messages.
quiet: bool, pub quiet: bool,
/// The directory in which to create the temporary file. /// The directory in which to create the temporary file.
/// ///
/// If `None`, the file will be created in the current directory. /// If `None`, the file will be created in the current directory.
tmpdir: Option<PathBuf>, pub tmpdir: Option<PathBuf>,
/// The suffix to append to the temporary file, if any. /// The suffix to append to the temporary file, if any.
suffix: Option<String>, pub suffix: Option<String>,
/// Whether to treat the template argument as a single file path component. /// Whether to treat the template argument as a single file path component.
treat_as_template: bool, pub treat_as_template: bool,
/// The template to use for the name of the temporary file. /// The template to use for the name of the temporary file.
template: String, pub template: String,
} }
impl Options { impl Options {
@ -192,7 +193,7 @@ impl Options {
/// `num_rand_chars`. /// `num_rand_chars`.
struct Params { struct Params {
/// The directory that will contain the temporary file. /// The directory that will contain the temporary file.
directory: String, directory: PathBuf,
/// The (non-random) prefix of the temporary file. /// The (non-random) prefix of the temporary file.
prefix: String, prefix: String,
@ -297,7 +298,7 @@ impl Params {
let num_rand_chars = j - i; let num_rand_chars = j - i;
Ok(Self { Ok(Self {
directory, directory: directory.into(),
prefix, prefix,
num_rand_chars, num_rand_chars,
suffix, suffix,
@ -357,12 +358,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
exec(&tmpdir, &prefix, rand, &suffix, make_dir) exec(&tmpdir, &prefix, rand, &suffix, make_dir)
}; };
if suppress_file_err { let res = if suppress_file_err {
// Mapping all UErrors to ExitCodes prevents the errors from being printed // Mapping all UErrors to ExitCodes prevents the errors from being printed
res.map_err(|e| e.code().into()) res.map_err(|e| e.code().into())
} else { } else {
res res
} };
println_verbatim(res?).map_err_context(|| "failed to print directory name".to_owned())
} }
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
@ -441,7 +443,7 @@ pub fn uu_app() -> Command {
.arg(Arg::new(ARG_TEMPLATE).num_args(..=1)) .arg(Arg::new(ARG_TEMPLATE).num_args(..=1))
} }
pub fn dry_exec(tmpdir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<()> { fn dry_exec(tmpdir: &Path, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
let len = prefix.len() + suffix.len() + rand; let len = prefix.len() + suffix.len() + rand;
let mut buf = Vec::with_capacity(len); let mut buf = Vec::with_capacity(len);
buf.extend(prefix.as_bytes()); buf.extend(prefix.as_bytes());
@ -462,7 +464,7 @@ pub fn dry_exec(tmpdir: &str, prefix: &str, rand: usize, suffix: &str) -> UResul
// We guarantee utf8. // We guarantee utf8.
let buf = String::from_utf8(buf).unwrap(); let buf = String::from_utf8(buf).unwrap();
let tmpdir = Path::new(tmpdir).join(buf); let tmpdir = Path::new(tmpdir).join(buf);
println_verbatim(tmpdir).map_err_context(|| "failed to print directory name".to_owned()) Ok(tmpdir)
} }
/// Create a temporary directory with the given parameters. /// Create a temporary directory with the given parameters.
@ -476,7 +478,7 @@ pub fn dry_exec(tmpdir: &str, prefix: &str, rand: usize, suffix: &str) -> UResul
/// ///
/// If the temporary directory could not be written to disk or if the /// If the temporary directory could not be written to disk or if the
/// given directory `dir` does not exist. /// given directory `dir` does not exist.
fn make_temp_dir(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> { fn make_temp_dir(dir: &Path, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
let mut builder = Builder::new(); let mut builder = Builder::new();
builder.prefix(prefix).rand_bytes(rand).suffix(suffix); builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
match builder.tempdir_in(dir) { match builder.tempdir_in(dir) {
@ -508,7 +510,7 @@ fn make_temp_dir(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<
/// ///
/// If the file could not be written to disk or if the directory does /// If the file could not be written to disk or if the directory does
/// not exist. /// not exist.
fn make_temp_file(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> { fn make_temp_file(dir: &Path, prefix: &str, rand: usize, suffix: &str) -> UResult<PathBuf> {
let mut builder = Builder::new(); let mut builder = Builder::new();
builder.prefix(prefix).rand_bytes(rand).suffix(suffix); builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
match builder.tempfile_in(dir) { match builder.tempfile_in(dir) {
@ -527,7 +529,7 @@ fn make_temp_file(dir: &str, prefix: &str, rand: usize, suffix: &str) -> UResult
} }
} }
fn exec(dir: &str, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<()> { fn exec(dir: &Path, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> UResult<PathBuf> {
let path = if make_dir { let path = if make_dir {
make_temp_dir(dir, prefix, rand, suffix)? make_temp_dir(dir, prefix, rand, suffix)?
} else { } else {
@ -546,7 +548,27 @@ fn exec(dir: &str, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> U
// relative path. // relative path.
let path = Path::new(dir).join(filename); let path = Path::new(dir).join(filename);
println_verbatim(path).map_err_context(|| "failed to print directory name".to_owned()) Ok(path)
}
/// Create a temporary file or directory
///
/// Behavior is determined by the `options` parameter, see [`Options`] for details.
pub fn mktemp(options: &Options) -> UResult<PathBuf> {
// Parse file path parameters from the command-line options.
let Params {
directory: tmpdir,
prefix,
num_rand_chars: rand,
suffix,
} = Params::from(options.clone())?;
// Create the temporary file or directory, or simulate creating it.
if options.dry_run {
dry_exec(&tmpdir, &prefix, rand, &suffix)
} else {
exec(&tmpdir, &prefix, rand, &suffix, options.directory)
}
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_more" name = "uu_more"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "more ~ (uutils) input perusal filter" description = "more ~ (uutils) input perusal filter"

View file

@ -88,7 +88,7 @@ impl Options {
#[uucore::main] #[uucore::main]
pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let args = args.collect_lossy(); let args = args.collect_lossy();
let matches = match uu_app().try_get_matches_from(&args) { let matches = match uu_app().try_get_matches_from(args) {
Ok(m) => m, Ok(m) => m,
Err(e) => return Err(e.into()), Err(e) => return Err(e.into()),
}; };

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_mv" name = "uu_mv"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "mv ~ (uutils) move (rename) SOURCE to DESTINATION" description = "mv ~ (uutils) move (rename) SOURCE to DESTINATION"

View file

@ -146,7 +146,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let files: Vec<OsString> = matches let files: Vec<OsString> = matches
.get_many::<OsString>(ARG_FILES) .get_many::<OsString>(ARG_FILES)
.unwrap_or_default() .unwrap_or_default()
.map(|v| v.to_os_string()) .cloned()
.collect(); .collect();
let overwrite_mode = determine_overwrite_mode(&matches); let overwrite_mode = determine_overwrite_mode(&matches);

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_nice" name = "uu_nice"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "nice ~ (uutils) run PROGRAM with modified scheduling priority" description = "nice ~ (uutils) run PROGRAM with modified scheduling priority"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_nl" name = "uu_nl"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "nl ~ (uutils) display input with added line numbers" description = "nl ~ (uutils) display input with added line numbers"

View file

@ -19,11 +19,11 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) ->
settings.section_delimiter = if delimiter.len() == 1 { settings.section_delimiter = if delimiter.len() == 1 {
format!("{delimiter}:") format!("{delimiter}:")
} else { } else {
delimiter.to_owned() delimiter.clone()
}; };
} }
if let Some(val) = opts.get_one::<String>(options::NUMBER_SEPARATOR) { if let Some(val) = opts.get_one::<String>(options::NUMBER_SEPARATOR) {
settings.number_separator = val.to_owned(); settings.number_separator = val.clone();
} }
settings.number_format = opts settings.number_format = opts
.get_one::<String>(options::NUMBER_FORMAT) .get_one::<String>(options::NUMBER_FORMAT)

View file

@ -195,7 +195,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
} }
let files: Vec<String> = match matches.get_many::<String>(options::FILE) { let files: Vec<String> = match matches.get_many::<String>(options::FILE) {
Some(v) => v.clone().map(|v| v.to_owned()).collect(), Some(v) => v.cloned().collect(),
None => vec!["-".to_owned()], None => vec!["-".to_owned()],
}; };

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_nohup" name = "uu_nohup"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "nohup ~ (uutils) run COMMAND, ignoring hangup signals" description = "nohup ~ (uutils) run COMMAND, ignoring hangup signals"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_nproc" name = "uu_nproc"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "nproc ~ (uutils) display the number of processing units available" description = "nproc ~ (uutils) display the number of processing units available"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_numfmt" name = "uu_numfmt"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "numfmt ~ (uutils) reformat NUMBER" description = "numfmt ~ (uutils) reformat NUMBER"

View file

@ -211,9 +211,7 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
_ => unreachable!("Should be restricted by clap"), _ => unreachable!("Should be restricted by clap"),
}; };
let suffix = args let suffix = args.get_one::<String>(options::SUFFIX).cloned();
.get_one::<String>(options::SUFFIX)
.map(|s| s.to_owned());
let invalid = let invalid =
InvalidModes::from_str(args.get_one::<String>(options::INVALID).unwrap()).unwrap(); InvalidModes::from_str(args.get_one::<String>(options::INVALID).unwrap()).unwrap();

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_od" name = "uu_od"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "od ~ (uutils) display formatted representation of input" description = "od ~ (uutils) display formatted representation of input"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_paste" name = "uu_paste"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "paste ~ (uutils) merge lines from inputs" description = "paste ~ (uutils) merge lines from inputs"

View file

@ -44,7 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let files = matches let files = matches
.get_many::<String>(options::FILE) .get_many::<String>(options::FILE)
.unwrap() .unwrap()
.map(|s| s.to_owned()) .cloned()
.collect(); .collect();
let line_ending = LineEnding::from_zero_flag(matches.get_flag(options::ZERO_TERMINATED)); let line_ending = LineEnding::from_zero_flag(matches.get_flag(options::ZERO_TERMINATED));

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_pathchk" name = "uu_pathchk"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "pathchk ~ (uutils) diagnose invalid or non-portable PATHNAME" description = "pathchk ~ (uutils) diagnose invalid or non-portable PATHNAME"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_pinky" name = "uu_pinky"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "pinky ~ (uutils) display user information" description = "pinky ~ (uutils) display user information"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_pr" name = "uu_pr"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "pr ~ (uutils) convert text files for printing" description = "pr ~ (uutils) convert text files for printing"

View file

@ -1,6 +1,6 @@
[package] [package]
name = "uu_printenv" name = "uu_printenv"
version = "0.0.22" version = "0.0.23"
authors = ["uutils developers"] authors = ["uutils developers"]
license = "MIT" license = "MIT"
description = "printenv ~ (uutils) display value of environment VAR" description = "printenv ~ (uutils) display value of environment VAR"

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