mirror of
https://github.com/uutils/coreutils
synced 2024-12-13 23:02:38 +00:00
Merge branch 'main' into printf-rewrite
This commit is contained in:
commit
6d2698b802
179 changed files with 2883 additions and 2016 deletions
17
.github/workflows/CICD.yml
vendored
17
.github/workflows/CICD.yml
vendored
|
@ -461,17 +461,18 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
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: 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: 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: 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: 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: 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: 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: 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 }
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
@ -575,7 +576,7 @@ jobs:
|
|||
- uses: taiki-e/install-action@v2
|
||||
if: steps.vars.outputs.CARGO_CMD == 'cross'
|
||||
with:
|
||||
tool: cross@0.2.1
|
||||
tool: cross@0.2.5
|
||||
- name: Create all needed build/work directories
|
||||
shell: bash
|
||||
run: |
|
||||
|
@ -650,6 +651,7 @@ jobs:
|
|||
${{ 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 }}
|
||||
- name: Test
|
||||
if: matrix.job.skip-tests != true
|
||||
shell: bash
|
||||
run: |
|
||||
## Test
|
||||
|
@ -658,6 +660,7 @@ jobs:
|
|||
env:
|
||||
RUST_BACKTRACE: "1"
|
||||
- name: Test individual utilities
|
||||
if: matrix.job.skip-tests != true
|
||||
shell: bash
|
||||
run: |
|
||||
## Test individual utilities
|
||||
|
|
4
.github/workflows/GnuComment.yml
vendored
4
.github/workflows/GnuComment.yml
vendored
|
@ -18,7 +18,7 @@ jobs:
|
|||
github.event.workflow_run.event == 'pull_request'
|
||||
steps:
|
||||
- name: 'Download artifact'
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
// List all artifacts from GnuTests
|
||||
|
@ -43,7 +43,7 @@ jobs:
|
|||
- run: unzip comment.zip
|
||||
|
||||
- name: 'Comment on PR'
|
||||
uses: actions/github-script@v6
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
script: |
|
||||
|
|
2
.github/workflows/code-quality.yml
vendored
2
.github/workflows/code-quality.yml
vendored
|
@ -117,7 +117,7 @@ jobs:
|
|||
run: |
|
||||
## `cargo clippy` lint testing
|
||||
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_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>
|
||||
|
|
74
.github/workflows/fuzzing.yml
vendored
74
.github/workflows/fuzzing.yml
vendored
|
@ -13,52 +13,62 @@ concurrency:
|
|||
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
|
||||
|
||||
jobs:
|
||||
fuzz:
|
||||
name: Run the fuzzers
|
||||
fuzz-build:
|
||||
name: Build the fuzzers
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
RUN_FOR: 60
|
||||
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: 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
|
||||
uses: actions/cache/restore@v3
|
||||
with:
|
||||
key: corpus-cache
|
||||
key: corpus-cache-${{ matrix.test-target }}
|
||||
path: |
|
||||
fuzz/corpus
|
||||
- name: Run fuzz_date for XX seconds
|
||||
continue-on-error: true
|
||||
fuzz/corpus/${{ matrix.test-target }}
|
||||
- name: Run ${{ matrix.test-target }} for XX seconds
|
||||
shell: bash
|
||||
run: |
|
||||
cargo +nightly fuzz run fuzz_date -- -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
|
||||
cargo +nightly fuzz run ${{ matrix.test-target }} -- -max_total_time=${{ env.RUN_FOR }} -detect_leaks=0
|
||||
- name: Save Corpus Cache
|
||||
uses: actions/cache/save@v3
|
||||
with:
|
||||
key: corpus-cache
|
||||
key: corpus-cache-${{ matrix.test-target }}
|
||||
path: |
|
||||
fuzz/corpus
|
||||
fuzz/corpus/${{ matrix.test-target }}
|
||||
|
|
|
@ -59,6 +59,7 @@ clippy
|
|||
rustc
|
||||
rustfmt
|
||||
rustup
|
||||
rustdoc
|
||||
#
|
||||
bitor # BitOr trait function
|
||||
bitxor # BitXor trait function
|
||||
|
|
387
CONTRIBUTING.md
387
CONTRIBUTING.md
|
@ -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
|
||||
|
||||
Contributions are very welcome via Pull Requests. If you don't know where to
|
||||
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).
|
||||
Hi! Welcome to uutils/coreutils!
|
||||
|
||||
## 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
|
||||
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.
|
||||
1. If possible, look at the GNU test suite execution in the CI and make the test
|
||||
work if failing.
|
||||
1. Use clap for argument management.
|
||||
1. Make sure that the code coverage is covering all of the cases, including
|
||||
errors.
|
||||
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
|
||||
other binaries.
|
||||
1. Unsafe code should be documented with Safety comments.
|
||||
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.
|
||||
- Our community's [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md).
|
||||
- [DEVELOPMENT.md](./DEVELOPMENT.md) for setting up your development
|
||||
environment.
|
||||
|
||||
Now follows a very important warning:
|
||||
|
||||
> [!WARNING]
|
||||
> uutils is original code and cannot contain any code from GNU or
|
||||
> other implementations. This means that **we cannot accept any changes based on
|
||||
> the GNU source code**. To make sure that cannot happen, **you cannot link to
|
||||
> the GNU source code** either.
|
||||
|
||||
Finally, feel free to join our [Discord](https://discord.gg/wQVJbvJ)!
|
||||
|
||||
## Getting Oriented
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
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,
|
||||
VirtualBox and Parallels) for development:
|
||||
<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
|
||||
|
||||
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
|
||||
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. 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
|
||||
|
||||
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
|
||||
|
||||
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)
|
||||
* [OpenBSD](https://github.com/openbsd/src/tree/master/bin)
|
||||
* [Busybox](https://github.com/mirror/busybox/tree/master/coreutils)
|
||||
* [Toybox (Android)](https://github.com/landley/toybox/tree/master/toys/posix)
|
||||
* [V lang](https://github.com/vlang/coreutils)
|
||||
* [SerenityOS](https://github.com/SerenityOS/serenity/tree/master/Userland/Utilities)
|
||||
* [Initial Unix](https://github.com/dspinellis/unix-history-repo)
|
||||
* [Perl Power Tools](https://metacpan.org/pod/PerlPowerTools)
|
||||
- [GNU's](https://git.savannah.gnu.org/gitweb/?p=coreutils.git)
|
||||
- [OpenBSD](https://github.com/openbsd/src/tree/master/bin)
|
||||
- [Busybox](https://github.com/mirror/busybox/tree/master/coreutils)
|
||||
- [Toybox (Android)](https://github.com/landley/toybox/tree/master/toys/posix)
|
||||
- [V lang](https://github.com/vlang/coreutils)
|
||||
- [SerenityOS](https://github.com/SerenityOS/serenity/tree/master/Userland/Utilities)
|
||||
- [Initial Unix](https://github.com/dspinellis/unix-history-repo)
|
||||
- [Perl Power Tools](https://metacpan.org/pod/PerlPowerTools)
|
||||
|
||||
However, when reimplementing the tools/options in Rust, don't read their source codes
|
||||
when they are using reciprocal licenses (ex: GNU GPL, GNU LGPL, etc).
|
||||
However, when reimplementing the tools/options in Rust, don't read their source
|
||||
codes when they are using reciprocal licenses (ex: GNU GPL, GNU LGPL, etc).
|
||||
|
||||
## 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.
|
||||
The following types of license are acceptable:
|
||||
|
||||
* MIT License
|
||||
* Dual- or tri-license with an MIT License option ("Apache-2.0 or MIT" is a
|
||||
- MIT License
|
||||
- Dual- or tri-license with an MIT License option ("Apache-2.0 or MIT" is a
|
||||
popular combination)
|
||||
* "MIT equivalent" license (2-clause BSD, 3-clause BSD, ISC)
|
||||
* License less restrictive than the MIT License (CC0 1.0 Universal)
|
||||
* Apache License version 2.0
|
||||
- "MIT equivalent" license (2-clause BSD, 3-clause BSD, ISC)
|
||||
- License less restrictive than the MIT License (CC0 1.0 Universal)
|
||||
- Apache License version 2.0
|
||||
|
||||
Licenses we will not use:
|
||||
|
||||
* An ambiguous license, or no license
|
||||
* Strongly reciprocal licenses (GNU GPL, GNU LGPL)
|
||||
- An ambiguous license, or no license
|
||||
- Strongly reciprocal licenses (GNU GPL, GNU LGPL)
|
||||
|
||||
If you wish to add a reference but it doesn't meet these requirements, please
|
||||
raise an issue to describe the dependency.
|
||||
|
|
270
Cargo.lock
generated
270
Cargo.lock
generated
|
@ -188,9 +188,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "bstr"
|
||||
version = "1.7.0"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019"
|
||||
checksum = "542f33a8835a0884b006a0c3df3dadd99c0c3f296ed26c2fdc8028e01ad6230c"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"regex-automata",
|
||||
|
@ -374,7 +374,7 @@ checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
|||
|
||||
[[package]]
|
||||
name = "coreutils"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -1122,9 +1122,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.11.0"
|
||||
version = "0.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
|
||||
checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
@ -1187,9 +1187,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.149"
|
||||
version = "0.2.150"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
|
||||
checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
|
@ -1207,12 +1207,6 @@ version = "0.2.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
|
@ -1598,15 +1592,25 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "procfs"
|
||||
version = "0.15.1"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "943ca7f9f29bab5844ecd8fdb3992c5969b6622bb9609b9502fef9b4310e3f1f"
|
||||
checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"byteorder",
|
||||
"bitflags 2.4.0",
|
||||
"hex",
|
||||
"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]]
|
||||
|
@ -1822,20 +1826,6 @@ dependencies = [
|
|||
"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]]
|
||||
name = "rustix"
|
||||
version = "0.37.26"
|
||||
|
@ -1880,9 +1870,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
|||
|
||||
[[package]]
|
||||
name = "self_cell"
|
||||
version = "1.0.1"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c309e515543e67811222dbc9e3dd7e1056279b782e1dacffe4242b718734fb6"
|
||||
checksum = "e388332cd64eb80cd595a00941baf513caffae8dce9cfd0467fc9c66397dade6"
|
||||
|
||||
[[package]]
|
||||
name = "selinux"
|
||||
|
@ -2217,7 +2207,7 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
|
|||
|
||||
[[package]]
|
||||
name = "uu_arch"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"platform-info",
|
||||
|
@ -2226,7 +2216,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_base32"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2234,7 +2224,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_base64"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"uu_base32",
|
||||
"uucore",
|
||||
|
@ -2242,7 +2232,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_basename"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2250,7 +2240,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_basenc"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uu_base32",
|
||||
|
@ -2259,7 +2249,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_cat"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"nix",
|
||||
|
@ -2269,7 +2259,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_chcon"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fts-sys",
|
||||
|
@ -2281,7 +2271,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_chgrp"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2289,7 +2279,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_chmod"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2298,7 +2288,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_chown"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2306,7 +2296,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_chroot"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2314,7 +2304,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_cksum"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"hex",
|
||||
|
@ -2323,7 +2313,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_comm"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2331,7 +2321,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_cp"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"exacl",
|
||||
|
@ -2347,7 +2337,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_csplit"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"regex",
|
||||
|
@ -2357,7 +2347,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_cut"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"bstr",
|
||||
"clap",
|
||||
|
@ -2367,7 +2357,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_date"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -2379,7 +2369,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_dd"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"gcd",
|
||||
|
@ -2391,7 +2381,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_df"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"tempfile",
|
||||
|
@ -2401,7 +2391,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_dir"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uu_ls",
|
||||
|
@ -2410,7 +2400,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_dircolors"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2418,7 +2408,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_dirname"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2426,7 +2416,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_du"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -2437,7 +2427,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_echo"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2445,7 +2435,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_env"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"nix",
|
||||
|
@ -2455,7 +2445,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_expand"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"unicode-width",
|
||||
|
@ -2464,7 +2454,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_expr"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"num-bigint",
|
||||
|
@ -2475,7 +2465,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_factor"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"coz",
|
||||
|
@ -2488,7 +2478,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_false"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2496,7 +2486,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_fmt"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"unicode-width",
|
||||
|
@ -2505,7 +2495,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_fold"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2513,7 +2503,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_groups"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2521,7 +2511,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_hashsum"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"hex",
|
||||
|
@ -2532,7 +2522,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_head"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"memchr",
|
||||
|
@ -2541,7 +2531,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_hostid"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2550,7 +2540,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_hostname"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"hostname",
|
||||
|
@ -2560,7 +2550,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_id"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"selinux",
|
||||
|
@ -2569,7 +2559,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_install"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"file_diff",
|
||||
|
@ -2580,7 +2570,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_join"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"memchr",
|
||||
|
@ -2589,7 +2579,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_kill"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"nix",
|
||||
|
@ -2598,7 +2588,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_link"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2606,7 +2596,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_ln"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2614,7 +2604,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_logname"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2623,7 +2613,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_ls"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -2640,7 +2630,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_mkdir"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2648,7 +2638,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_mkfifo"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2657,7 +2647,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_mknod"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2666,7 +2656,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_mktemp"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"rand",
|
||||
|
@ -2676,7 +2666,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_more"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"crossterm",
|
||||
|
@ -2688,7 +2678,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_mv"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fs_extra",
|
||||
|
@ -2698,7 +2688,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_nice"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2708,7 +2698,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_nl"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"regex",
|
||||
|
@ -2717,7 +2707,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_nohup"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2726,7 +2716,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_nproc"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2735,7 +2725,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_numfmt"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2743,7 +2733,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_od"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"clap",
|
||||
|
@ -2753,7 +2743,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_paste"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2761,7 +2751,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_pathchk"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2770,7 +2760,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_pinky"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2778,7 +2768,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_pr"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -2790,7 +2780,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_printenv"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2798,7 +2788,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_printf"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2806,7 +2796,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_ptx"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"regex",
|
||||
|
@ -2815,7 +2805,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_pwd"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2823,7 +2813,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_readlink"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2831,7 +2821,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_realpath"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2839,7 +2829,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_rm"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2850,7 +2840,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_rmdir"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2859,7 +2849,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_runcon"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2870,7 +2860,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_seq"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"bigdecimal",
|
||||
"clap",
|
||||
|
@ -2881,7 +2871,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_shred"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2891,7 +2881,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_shuf"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"memchr",
|
||||
|
@ -2902,7 +2892,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_sleep"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fundu",
|
||||
|
@ -2911,7 +2901,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_sort"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"binary-heap-plus",
|
||||
"clap",
|
||||
|
@ -2930,7 +2920,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_split"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"memchr",
|
||||
|
@ -2939,7 +2929,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_stat"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2947,7 +2937,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_stdbuf"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"tempfile",
|
||||
|
@ -2957,7 +2947,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_stdbuf_libstdbuf"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"cpp",
|
||||
"cpp_build",
|
||||
|
@ -2967,7 +2957,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_stty"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"nix",
|
||||
|
@ -2976,7 +2966,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_sum"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -2984,7 +2974,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_sync"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -2995,7 +2985,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_tac"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"memchr",
|
||||
|
@ -3006,7 +2996,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_tail"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"fundu",
|
||||
|
@ -3022,7 +3012,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_tee"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -3031,7 +3021,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_test"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -3041,7 +3031,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_timeout"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -3051,7 +3041,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_touch"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -3063,7 +3053,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_tr"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"nom",
|
||||
|
@ -3072,7 +3062,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_true"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -3080,7 +3070,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_truncate"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -3088,7 +3078,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_tsort"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -3096,7 +3086,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_tty"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"nix",
|
||||
|
@ -3105,7 +3095,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_uname"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"platform-info",
|
||||
|
@ -3114,7 +3104,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_unexpand"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"unicode-width",
|
||||
|
@ -3123,7 +3113,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_uniq"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -3131,7 +3121,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_unlink"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -3139,7 +3129,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_uptime"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"clap",
|
||||
|
@ -3148,7 +3138,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_users"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -3156,7 +3146,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_vdir"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uu_ls",
|
||||
|
@ -3165,7 +3155,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_wc"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"bytecount",
|
||||
"clap",
|
||||
|
@ -3178,7 +3168,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_who"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"uucore",
|
||||
|
@ -3186,7 +3176,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_whoami"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"libc",
|
||||
|
@ -3196,7 +3186,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uu_yes"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"itertools",
|
||||
|
@ -3206,7 +3196,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uucore"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"blake2b_simd",
|
||||
"blake3",
|
||||
|
@ -3242,7 +3232,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uucore_procs"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -3251,7 +3241,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "uuhelp_parser"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
|
|
216
Cargo.toml
216
Cargo.toml
|
@ -5,7 +5,7 @@
|
|||
|
||||
[package]
|
||||
name = "coreutils"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "coreutils ~ GNU coreutils (updated); implemented as universal (cross-platform) utils, written in Rust"
|
||||
|
@ -259,7 +259,7 @@ test = ["uu_test"]
|
|||
[workspace.dependencies]
|
||||
bigdecimal = "0.4"
|
||||
binary-heap-plus = "0.5.0"
|
||||
bstr = "1.7"
|
||||
bstr = "1.8"
|
||||
bytecount = "0.6.7"
|
||||
byteorder = "1.5.0"
|
||||
chrono = { version = "^0.4.31", default-features = false, features = [
|
||||
|
@ -285,8 +285,8 @@ gcd = "2.3"
|
|||
glob = "0.3.1"
|
||||
half = "2.3"
|
||||
indicatif = "0.17"
|
||||
itertools = "0.11.0"
|
||||
libc = "0.2.149"
|
||||
itertools = "0.12.0"
|
||||
libc = "0.2.150"
|
||||
lscolors = { version = "0.15.0", default-features = false, features = [
|
||||
"nu-ansi-term",
|
||||
] }
|
||||
|
@ -313,7 +313,7 @@ regex = "1.10.2"
|
|||
rstest = "0.18.2"
|
||||
rust-ini = "0.19.0"
|
||||
same-file = "1.0.6"
|
||||
self_cell = "1.0.1"
|
||||
self_cell = "1.0.2"
|
||||
selinux = "0.4"
|
||||
signal-hook = "0.3.17"
|
||||
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" }
|
||||
|
||||
# * 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" }
|
||||
base32 = { optional = true, version = "0.0.22", package = "uu_base32", path = "src/uu/base32" }
|
||||
base64 = { optional = true, version = "0.0.22", package = "uu_base64", path = "src/uu/base64" }
|
||||
basename = { optional = true, version = "0.0.22", package = "uu_basename", path = "src/uu/basename" }
|
||||
basenc = { optional = true, version = "0.0.22", package = "uu_basenc", path = "src/uu/basenc" }
|
||||
cat = { optional = true, version = "0.0.22", package = "uu_cat", path = "src/uu/cat" }
|
||||
chcon = { optional = true, version = "0.0.22", package = "uu_chcon", path = "src/uu/chcon" }
|
||||
chgrp = { optional = true, version = "0.0.22", package = "uu_chgrp", path = "src/uu/chgrp" }
|
||||
chmod = { optional = true, version = "0.0.22", package = "uu_chmod", path = "src/uu/chmod" }
|
||||
chown = { optional = true, version = "0.0.22", package = "uu_chown", path = "src/uu/chown" }
|
||||
chroot = { optional = true, version = "0.0.22", package = "uu_chroot", path = "src/uu/chroot" }
|
||||
cksum = { optional = true, version = "0.0.22", package = "uu_cksum", path = "src/uu/cksum" }
|
||||
comm = { optional = true, version = "0.0.22", package = "uu_comm", path = "src/uu/comm" }
|
||||
cp = { optional = true, version = "0.0.22", package = "uu_cp", path = "src/uu/cp" }
|
||||
csplit = { optional = true, version = "0.0.22", package = "uu_csplit", path = "src/uu/csplit" }
|
||||
cut = { optional = true, version = "0.0.22", package = "uu_cut", path = "src/uu/cut" }
|
||||
date = { optional = true, version = "0.0.22", package = "uu_date", path = "src/uu/date" }
|
||||
dd = { optional = true, version = "0.0.22", package = "uu_dd", path = "src/uu/dd" }
|
||||
df = { optional = true, version = "0.0.22", package = "uu_df", path = "src/uu/df" }
|
||||
dir = { optional = true, version = "0.0.22", package = "uu_dir", path = "src/uu/dir" }
|
||||
dircolors = { optional = true, version = "0.0.22", package = "uu_dircolors", path = "src/uu/dircolors" }
|
||||
dirname = { optional = true, version = "0.0.22", package = "uu_dirname", path = "src/uu/dirname" }
|
||||
du = { optional = true, version = "0.0.22", package = "uu_du", path = "src/uu/du" }
|
||||
echo = { optional = true, version = "0.0.22", package = "uu_echo", path = "src/uu/echo" }
|
||||
env = { optional = true, version = "0.0.22", package = "uu_env", path = "src/uu/env" }
|
||||
expand = { optional = true, version = "0.0.22", package = "uu_expand", path = "src/uu/expand" }
|
||||
expr = { optional = true, version = "0.0.22", package = "uu_expr", path = "src/uu/expr" }
|
||||
factor = { optional = true, version = "0.0.22", package = "uu_factor", path = "src/uu/factor" }
|
||||
false = { optional = true, version = "0.0.22", package = "uu_false", path = "src/uu/false" }
|
||||
fmt = { optional = true, version = "0.0.22", package = "uu_fmt", path = "src/uu/fmt" }
|
||||
fold = { optional = true, version = "0.0.22", package = "uu_fold", path = "src/uu/fold" }
|
||||
groups = { optional = true, version = "0.0.22", package = "uu_groups", path = "src/uu/groups" }
|
||||
hashsum = { optional = true, version = "0.0.22", package = "uu_hashsum", path = "src/uu/hashsum" }
|
||||
head = { optional = true, version = "0.0.22", package = "uu_head", path = "src/uu/head" }
|
||||
hostid = { optional = true, version = "0.0.22", package = "uu_hostid", path = "src/uu/hostid" }
|
||||
hostname = { optional = true, version = "0.0.22", package = "uu_hostname", path = "src/uu/hostname" }
|
||||
id = { optional = true, version = "0.0.22", package = "uu_id", path = "src/uu/id" }
|
||||
install = { optional = true, version = "0.0.22", package = "uu_install", path = "src/uu/install" }
|
||||
join = { optional = true, version = "0.0.22", package = "uu_join", path = "src/uu/join" }
|
||||
kill = { optional = true, version = "0.0.22", package = "uu_kill", path = "src/uu/kill" }
|
||||
link = { optional = true, version = "0.0.22", package = "uu_link", path = "src/uu/link" }
|
||||
ln = { optional = true, version = "0.0.22", package = "uu_ln", path = "src/uu/ln" }
|
||||
ls = { optional = true, version = "0.0.22", package = "uu_ls", path = "src/uu/ls" }
|
||||
logname = { optional = true, version = "0.0.22", package = "uu_logname", path = "src/uu/logname" }
|
||||
mkdir = { optional = true, version = "0.0.22", package = "uu_mkdir", path = "src/uu/mkdir" }
|
||||
mkfifo = { optional = true, version = "0.0.22", package = "uu_mkfifo", path = "src/uu/mkfifo" }
|
||||
mknod = { optional = true, version = "0.0.22", package = "uu_mknod", path = "src/uu/mknod" }
|
||||
mktemp = { optional = true, version = "0.0.22", package = "uu_mktemp", path = "src/uu/mktemp" }
|
||||
more = { optional = true, version = "0.0.22", package = "uu_more", path = "src/uu/more" }
|
||||
mv = { optional = true, version = "0.0.22", package = "uu_mv", path = "src/uu/mv" }
|
||||
nice = { optional = true, version = "0.0.22", package = "uu_nice", path = "src/uu/nice" }
|
||||
nl = { optional = true, version = "0.0.22", package = "uu_nl", path = "src/uu/nl" }
|
||||
nohup = { optional = true, version = "0.0.22", package = "uu_nohup", path = "src/uu/nohup" }
|
||||
nproc = { optional = true, version = "0.0.22", package = "uu_nproc", path = "src/uu/nproc" }
|
||||
numfmt = { optional = true, version = "0.0.22", package = "uu_numfmt", path = "src/uu/numfmt" }
|
||||
od = { optional = true, version = "0.0.22", package = "uu_od", path = "src/uu/od" }
|
||||
paste = { optional = true, version = "0.0.22", package = "uu_paste", path = "src/uu/paste" }
|
||||
pathchk = { optional = true, version = "0.0.22", package = "uu_pathchk", path = "src/uu/pathchk" }
|
||||
pinky = { optional = true, version = "0.0.22", package = "uu_pinky", path = "src/uu/pinky" }
|
||||
pr = { optional = true, version = "0.0.22", package = "uu_pr", path = "src/uu/pr" }
|
||||
printenv = { optional = true, version = "0.0.22", package = "uu_printenv", path = "src/uu/printenv" }
|
||||
printf = { optional = true, version = "0.0.22", package = "uu_printf", path = "src/uu/printf" }
|
||||
ptx = { optional = true, version = "0.0.22", package = "uu_ptx", path = "src/uu/ptx" }
|
||||
pwd = { optional = true, version = "0.0.22", package = "uu_pwd", path = "src/uu/pwd" }
|
||||
readlink = { optional = true, version = "0.0.22", package = "uu_readlink", path = "src/uu/readlink" }
|
||||
realpath = { optional = true, version = "0.0.22", package = "uu_realpath", path = "src/uu/realpath" }
|
||||
rm = { optional = true, version = "0.0.22", package = "uu_rm", path = "src/uu/rm" }
|
||||
rmdir = { optional = true, version = "0.0.22", package = "uu_rmdir", path = "src/uu/rmdir" }
|
||||
runcon = { optional = true, version = "0.0.22", package = "uu_runcon", path = "src/uu/runcon" }
|
||||
seq = { optional = true, version = "0.0.22", package = "uu_seq", path = "src/uu/seq" }
|
||||
shred = { optional = true, version = "0.0.22", package = "uu_shred", path = "src/uu/shred" }
|
||||
shuf = { optional = true, version = "0.0.22", package = "uu_shuf", path = "src/uu/shuf" }
|
||||
sleep = { optional = true, version = "0.0.22", package = "uu_sleep", path = "src/uu/sleep" }
|
||||
sort = { optional = true, version = "0.0.22", package = "uu_sort", path = "src/uu/sort" }
|
||||
split = { optional = true, version = "0.0.22", package = "uu_split", path = "src/uu/split" }
|
||||
stat = { optional = true, version = "0.0.22", package = "uu_stat", path = "src/uu/stat" }
|
||||
stdbuf = { optional = true, version = "0.0.22", package = "uu_stdbuf", path = "src/uu/stdbuf" }
|
||||
stty = { optional = true, version = "0.0.22", package = "uu_stty", path = "src/uu/stty" }
|
||||
sum = { optional = true, version = "0.0.22", package = "uu_sum", path = "src/uu/sum" }
|
||||
sync = { optional = true, version = "0.0.22", package = "uu_sync", path = "src/uu/sync" }
|
||||
tac = { optional = true, version = "0.0.22", package = "uu_tac", path = "src/uu/tac" }
|
||||
tail = { optional = true, version = "0.0.22", package = "uu_tail", path = "src/uu/tail" }
|
||||
tee = { optional = true, version = "0.0.22", package = "uu_tee", path = "src/uu/tee" }
|
||||
timeout = { optional = true, version = "0.0.22", package = "uu_timeout", path = "src/uu/timeout" }
|
||||
touch = { optional = true, version = "0.0.22", package = "uu_touch", path = "src/uu/touch" }
|
||||
tr = { optional = true, version = "0.0.22", package = "uu_tr", path = "src/uu/tr" }
|
||||
true = { optional = true, version = "0.0.22", package = "uu_true", path = "src/uu/true" }
|
||||
truncate = { optional = true, version = "0.0.22", package = "uu_truncate", path = "src/uu/truncate" }
|
||||
tsort = { optional = true, version = "0.0.22", package = "uu_tsort", path = "src/uu/tsort" }
|
||||
tty = { optional = true, version = "0.0.22", package = "uu_tty", path = "src/uu/tty" }
|
||||
uname = { optional = true, version = "0.0.22", package = "uu_uname", path = "src/uu/uname" }
|
||||
unexpand = { optional = true, version = "0.0.22", package = "uu_unexpand", path = "src/uu/unexpand" }
|
||||
uniq = { optional = true, version = "0.0.22", package = "uu_uniq", path = "src/uu/uniq" }
|
||||
unlink = { optional = true, version = "0.0.22", package = "uu_unlink", path = "src/uu/unlink" }
|
||||
uptime = { optional = true, version = "0.0.22", package = "uu_uptime", path = "src/uu/uptime" }
|
||||
users = { optional = true, version = "0.0.22", package = "uu_users", path = "src/uu/users" }
|
||||
vdir = { optional = true, version = "0.0.22", package = "uu_vdir", path = "src/uu/vdir" }
|
||||
wc = { optional = true, version = "0.0.22", package = "uu_wc", path = "src/uu/wc" }
|
||||
who = { optional = true, version = "0.0.22", package = "uu_who", path = "src/uu/who" }
|
||||
whoami = { optional = true, version = "0.0.22", package = "uu_whoami", path = "src/uu/whoami" }
|
||||
yes = { optional = true, version = "0.0.22", package = "uu_yes", path = "src/uu/yes" }
|
||||
arch = { optional = true, version = "0.0.23", package = "uu_arch", path = "src/uu/arch" }
|
||||
base32 = { optional = true, version = "0.0.23", package = "uu_base32", path = "src/uu/base32" }
|
||||
base64 = { optional = true, version = "0.0.23", package = "uu_base64", path = "src/uu/base64" }
|
||||
basename = { optional = true, version = "0.0.23", package = "uu_basename", path = "src/uu/basename" }
|
||||
basenc = { optional = true, version = "0.0.23", package = "uu_basenc", path = "src/uu/basenc" }
|
||||
cat = { optional = true, version = "0.0.23", package = "uu_cat", path = "src/uu/cat" }
|
||||
chcon = { optional = true, version = "0.0.23", package = "uu_chcon", path = "src/uu/chcon" }
|
||||
chgrp = { optional = true, version = "0.0.23", package = "uu_chgrp", path = "src/uu/chgrp" }
|
||||
chmod = { optional = true, version = "0.0.23", package = "uu_chmod", path = "src/uu/chmod" }
|
||||
chown = { optional = true, version = "0.0.23", package = "uu_chown", path = "src/uu/chown" }
|
||||
chroot = { optional = true, version = "0.0.23", package = "uu_chroot", path = "src/uu/chroot" }
|
||||
cksum = { optional = true, version = "0.0.23", package = "uu_cksum", path = "src/uu/cksum" }
|
||||
comm = { optional = true, version = "0.0.23", package = "uu_comm", path = "src/uu/comm" }
|
||||
cp = { optional = true, version = "0.0.23", package = "uu_cp", path = "src/uu/cp" }
|
||||
csplit = { optional = true, version = "0.0.23", package = "uu_csplit", path = "src/uu/csplit" }
|
||||
cut = { optional = true, version = "0.0.23", package = "uu_cut", path = "src/uu/cut" }
|
||||
date = { optional = true, version = "0.0.23", package = "uu_date", path = "src/uu/date" }
|
||||
dd = { optional = true, version = "0.0.23", package = "uu_dd", path = "src/uu/dd" }
|
||||
df = { optional = true, version = "0.0.23", package = "uu_df", path = "src/uu/df" }
|
||||
dir = { optional = true, version = "0.0.23", package = "uu_dir", path = "src/uu/dir" }
|
||||
dircolors = { optional = true, version = "0.0.23", package = "uu_dircolors", path = "src/uu/dircolors" }
|
||||
dirname = { optional = true, version = "0.0.23", package = "uu_dirname", path = "src/uu/dirname" }
|
||||
du = { optional = true, version = "0.0.23", package = "uu_du", path = "src/uu/du" }
|
||||
echo = { optional = true, version = "0.0.23", package = "uu_echo", path = "src/uu/echo" }
|
||||
env = { optional = true, version = "0.0.23", package = "uu_env", path = "src/uu/env" }
|
||||
expand = { optional = true, version = "0.0.23", package = "uu_expand", path = "src/uu/expand" }
|
||||
expr = { optional = true, version = "0.0.23", package = "uu_expr", path = "src/uu/expr" }
|
||||
factor = { optional = true, version = "0.0.23", package = "uu_factor", path = "src/uu/factor" }
|
||||
false = { optional = true, version = "0.0.23", package = "uu_false", path = "src/uu/false" }
|
||||
fmt = { optional = true, version = "0.0.23", package = "uu_fmt", path = "src/uu/fmt" }
|
||||
fold = { optional = true, version = "0.0.23", package = "uu_fold", path = "src/uu/fold" }
|
||||
groups = { optional = true, version = "0.0.23", package = "uu_groups", path = "src/uu/groups" }
|
||||
hashsum = { optional = true, version = "0.0.23", package = "uu_hashsum", path = "src/uu/hashsum" }
|
||||
head = { optional = true, version = "0.0.23", package = "uu_head", path = "src/uu/head" }
|
||||
hostid = { optional = true, version = "0.0.23", package = "uu_hostid", path = "src/uu/hostid" }
|
||||
hostname = { optional = true, version = "0.0.23", package = "uu_hostname", path = "src/uu/hostname" }
|
||||
id = { optional = true, version = "0.0.23", package = "uu_id", path = "src/uu/id" }
|
||||
install = { optional = true, version = "0.0.23", package = "uu_install", path = "src/uu/install" }
|
||||
join = { optional = true, version = "0.0.23", package = "uu_join", path = "src/uu/join" }
|
||||
kill = { optional = true, version = "0.0.23", package = "uu_kill", path = "src/uu/kill" }
|
||||
link = { optional = true, version = "0.0.23", package = "uu_link", path = "src/uu/link" }
|
||||
ln = { optional = true, version = "0.0.23", package = "uu_ln", path = "src/uu/ln" }
|
||||
ls = { optional = true, version = "0.0.23", package = "uu_ls", path = "src/uu/ls" }
|
||||
logname = { optional = true, version = "0.0.23", package = "uu_logname", path = "src/uu/logname" }
|
||||
mkdir = { optional = true, version = "0.0.23", package = "uu_mkdir", path = "src/uu/mkdir" }
|
||||
mkfifo = { optional = true, version = "0.0.23", package = "uu_mkfifo", path = "src/uu/mkfifo" }
|
||||
mknod = { optional = true, version = "0.0.23", package = "uu_mknod", path = "src/uu/mknod" }
|
||||
mktemp = { optional = true, version = "0.0.23", package = "uu_mktemp", path = "src/uu/mktemp" }
|
||||
more = { optional = true, version = "0.0.23", package = "uu_more", path = "src/uu/more" }
|
||||
mv = { optional = true, version = "0.0.23", package = "uu_mv", path = "src/uu/mv" }
|
||||
nice = { optional = true, version = "0.0.23", package = "uu_nice", path = "src/uu/nice" }
|
||||
nl = { optional = true, version = "0.0.23", package = "uu_nl", path = "src/uu/nl" }
|
||||
nohup = { optional = true, version = "0.0.23", package = "uu_nohup", path = "src/uu/nohup" }
|
||||
nproc = { optional = true, version = "0.0.23", package = "uu_nproc", path = "src/uu/nproc" }
|
||||
numfmt = { optional = true, version = "0.0.23", package = "uu_numfmt", path = "src/uu/numfmt" }
|
||||
od = { optional = true, version = "0.0.23", package = "uu_od", path = "src/uu/od" }
|
||||
paste = { optional = true, version = "0.0.23", package = "uu_paste", path = "src/uu/paste" }
|
||||
pathchk = { optional = true, version = "0.0.23", package = "uu_pathchk", path = "src/uu/pathchk" }
|
||||
pinky = { optional = true, version = "0.0.23", package = "uu_pinky", path = "src/uu/pinky" }
|
||||
pr = { optional = true, version = "0.0.23", package = "uu_pr", path = "src/uu/pr" }
|
||||
printenv = { optional = true, version = "0.0.23", package = "uu_printenv", path = "src/uu/printenv" }
|
||||
printf = { optional = true, version = "0.0.23", package = "uu_printf", path = "src/uu/printf" }
|
||||
ptx = { optional = true, version = "0.0.23", package = "uu_ptx", path = "src/uu/ptx" }
|
||||
pwd = { optional = true, version = "0.0.23", package = "uu_pwd", path = "src/uu/pwd" }
|
||||
readlink = { optional = true, version = "0.0.23", package = "uu_readlink", path = "src/uu/readlink" }
|
||||
realpath = { optional = true, version = "0.0.23", package = "uu_realpath", path = "src/uu/realpath" }
|
||||
rm = { optional = true, version = "0.0.23", package = "uu_rm", path = "src/uu/rm" }
|
||||
rmdir = { optional = true, version = "0.0.23", package = "uu_rmdir", path = "src/uu/rmdir" }
|
||||
runcon = { optional = true, version = "0.0.23", package = "uu_runcon", path = "src/uu/runcon" }
|
||||
seq = { optional = true, version = "0.0.23", package = "uu_seq", path = "src/uu/seq" }
|
||||
shred = { optional = true, version = "0.0.23", package = "uu_shred", path = "src/uu/shred" }
|
||||
shuf = { optional = true, version = "0.0.23", package = "uu_shuf", path = "src/uu/shuf" }
|
||||
sleep = { optional = true, version = "0.0.23", package = "uu_sleep", path = "src/uu/sleep" }
|
||||
sort = { optional = true, version = "0.0.23", package = "uu_sort", path = "src/uu/sort" }
|
||||
split = { optional = true, version = "0.0.23", package = "uu_split", path = "src/uu/split" }
|
||||
stat = { optional = true, version = "0.0.23", package = "uu_stat", path = "src/uu/stat" }
|
||||
stdbuf = { optional = true, version = "0.0.23", package = "uu_stdbuf", path = "src/uu/stdbuf" }
|
||||
stty = { optional = true, version = "0.0.23", package = "uu_stty", path = "src/uu/stty" }
|
||||
sum = { optional = true, version = "0.0.23", package = "uu_sum", path = "src/uu/sum" }
|
||||
sync = { optional = true, version = "0.0.23", package = "uu_sync", path = "src/uu/sync" }
|
||||
tac = { optional = true, version = "0.0.23", package = "uu_tac", path = "src/uu/tac" }
|
||||
tail = { optional = true, version = "0.0.23", package = "uu_tail", path = "src/uu/tail" }
|
||||
tee = { optional = true, version = "0.0.23", package = "uu_tee", path = "src/uu/tee" }
|
||||
timeout = { optional = true, version = "0.0.23", package = "uu_timeout", path = "src/uu/timeout" }
|
||||
touch = { optional = true, version = "0.0.23", package = "uu_touch", path = "src/uu/touch" }
|
||||
tr = { optional = true, version = "0.0.23", package = "uu_tr", path = "src/uu/tr" }
|
||||
true = { optional = true, version = "0.0.23", package = "uu_true", path = "src/uu/true" }
|
||||
truncate = { optional = true, version = "0.0.23", package = "uu_truncate", path = "src/uu/truncate" }
|
||||
tsort = { optional = true, version = "0.0.23", package = "uu_tsort", path = "src/uu/tsort" }
|
||||
tty = { optional = true, version = "0.0.23", package = "uu_tty", path = "src/uu/tty" }
|
||||
uname = { optional = true, version = "0.0.23", package = "uu_uname", path = "src/uu/uname" }
|
||||
unexpand = { optional = true, version = "0.0.23", package = "uu_unexpand", path = "src/uu/unexpand" }
|
||||
uniq = { optional = true, version = "0.0.23", package = "uu_uniq", path = "src/uu/uniq" }
|
||||
unlink = { optional = true, version = "0.0.23", package = "uu_unlink", path = "src/uu/unlink" }
|
||||
uptime = { optional = true, version = "0.0.23", package = "uu_uptime", path = "src/uu/uptime" }
|
||||
users = { optional = true, version = "0.0.23", package = "uu_users", path = "src/uu/users" }
|
||||
vdir = { optional = true, version = "0.0.23", package = "uu_vdir", path = "src/uu/vdir" }
|
||||
wc = { optional = true, version = "0.0.23", package = "uu_wc", path = "src/uu/wc" }
|
||||
who = { optional = true, version = "0.0.23", package = "uu_who", path = "src/uu/who" }
|
||||
whoami = { optional = true, version = "0.0.23", package = "uu_whoami", path = "src/uu/whoami" }
|
||||
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)"
|
||||
# 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 }
|
||||
|
||||
[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"
|
||||
|
||||
[target.'cfg(unix)'.dev-dependencies]
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -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
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
|
|
|
@ -58,10 +58,7 @@ highlight = "all"
|
|||
# introduces it.
|
||||
# spell-checker: disable
|
||||
skip = [
|
||||
# procfs
|
||||
{ name = "rustix", version = "0.36.16" },
|
||||
# rustix
|
||||
{ name = "linux-raw-sys", version = "0.1.4" },
|
||||
{ name = "linux-raw-sys", version = "0.3.8" },
|
||||
# terminal_size
|
||||
{ name = "rustix", version = "0.37.26" },
|
||||
|
|
|
@ -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
|
||||
patches.
|
||||
|
||||
You can also [build uutils from source](/build.md).
|
||||
You can also [build uutils from source](build.md).
|
||||
|
||||
<!-- toc -->
|
||||
|
||||
|
|
|
@ -3,13 +3,30 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// 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::io;
|
||||
use std::io::Write;
|
||||
use std::os::fd::RawFd;
|
||||
use std::process::Command;
|
||||
use std::sync::atomic::Ordering;
|
||||
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 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
|
||||
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) };
|
||||
println!("Running test {:?}", &args[1..]);
|
||||
let mut pipe_fds = [-1; 2];
|
||||
unsafe { libc::pipe(pipe_fds.as_mut_ptr()) };
|
||||
|
||||
{
|
||||
unsafe { dup2(pipe_fds[1], STDOUT_FILENO) };
|
||||
uumain_exit_status = uumain_function(args.to_owned().into_iter());
|
||||
unsafe { dup2(original_stdout_fd, STDOUT_FILENO) };
|
||||
unsafe { libc::close(original_stdout_fd) };
|
||||
let original_stderr_fd = unsafe { dup(STDERR_FILENO) };
|
||||
if original_stdout_fd == -1 || original_stderr_fd == -1 {
|
||||
return CommandResult {
|
||||
stdout: "Failed to duplicate STDOUT_FILENO or STDERR_FILENO".to_string(),
|
||||
stderr: "".to_string(),
|
||||
exit_code: -1,
|
||||
};
|
||||
}
|
||||
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 read_buffer = [0; 1024];
|
||||
loop {
|
||||
let bytes_read = unsafe {
|
||||
libc::read(
|
||||
pipe_fds[0],
|
||||
fd,
|
||||
read_buffer.as_mut_ptr() as *mut libc::c_void,
|
||||
read_buffer.len(),
|
||||
)
|
||||
};
|
||||
if bytes_read <= 0 {
|
||||
|
||||
if bytes_read == -1 {
|
||||
eprintln!("Failed to read from the pipe");
|
||||
break;
|
||||
}
|
||||
if bytes_read == 0 {
|
||||
break;
|
||||
}
|
||||
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)
|
||||
.to_string()
|
||||
.trim()
|
||||
.to_owned();
|
||||
|
||||
(my_output, uumain_exit_status)
|
||||
String::from_utf8_lossy(&captured_output).into_owned()
|
||||
}
|
||||
|
||||
pub fn run_gnu_cmd(
|
||||
cmd_path: &str,
|
||||
args: &[OsString],
|
||||
check_gnu: bool,
|
||||
) -> Result<(String, i32), io::Error> {
|
||||
) -> Result<CommandResult, CommandResult> {
|
||||
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);
|
||||
|
@ -91,17 +185,115 @@ pub fn run_gnu_cmd(
|
|||
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);
|
||||
|
||||
// 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 {
|
||||
Ok((
|
||||
String::from_utf8_lossy(&output.stdout).to_string(),
|
||||
Ok(CommandResult {
|
||||
stdout,
|
||||
stderr,
|
||||
exit_code,
|
||||
))
|
||||
})
|
||||
} else {
|
||||
Err(io::Error::new(
|
||||
io::ErrorKind::Other,
|
||||
format!("GNU command execution failed with exit code {}", exit_code),
|
||||
))
|
||||
Err(CommandResult {
|
||||
stdout,
|
||||
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
|
||||
}
|
||||
|
|
|
@ -13,33 +13,12 @@ use rand::Rng;
|
|||
use std::{env, ffi::OsString};
|
||||
|
||||
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";
|
||||
|
||||
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 {
|
||||
let mut rng = rand::thread_rng();
|
||||
let ops = ["+", "-", "*", "/", "%", "<", ">", "=", "&", "|"];
|
||||
|
@ -84,37 +63,35 @@ fuzz_target!(|_data: &[u8]| {
|
|||
let mut args = vec![OsString::from("expr")];
|
||||
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,
|
||||
// because uutils expr doesn't support localization yet
|
||||
// TODO remove once uutils expr supports localization
|
||||
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
|
||||
match run_gnu_cmd(CMD_PATH, &args[1..], true) {
|
||||
Ok((gnu_output, gnu_exit_code)) => {
|
||||
let gnu_output = gnu_output.trim().to_owned();
|
||||
if uumain_exit_code != gnu_exit_code {
|
||||
println!("Expression: {}", expr);
|
||||
println!("Rust code: {}", uumain_exit_code);
|
||||
println!("GNU code: {}", gnu_exit_code);
|
||||
panic!("Different error codes");
|
||||
}
|
||||
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");
|
||||
let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false) {
|
||||
Ok(result) => result,
|
||||
Err(error_result) => {
|
||||
eprintln!("Failed to run GNU command:");
|
||||
eprintln!("Stderr: {}", error_result.stderr);
|
||||
eprintln!("Exit Code: {}", error_result.exit_code);
|
||||
CommandResult {
|
||||
stdout: String::new(),
|
||||
stderr: error_result.stderr,
|
||||
exit_code: error_result.exit_code,
|
||||
}
|
||||
}
|
||||
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
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#![no_main]
|
||||
|
||||
use libfuzzer_sys::fuzz_target;
|
||||
use uucore::parse_size::parse_size;
|
||||
use uucore::parse_size::parse_size_u64;
|
||||
|
||||
fuzz_target!(|data: &[u8]| {
|
||||
if let Ok(s) = std::str::from_utf8(data) {
|
||||
_ = parse_size(s);
|
||||
_ = parse_size_u64(s);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -13,7 +13,10 @@ use rand::Rng;
|
|||
use std::ffi::OsString;
|
||||
|
||||
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)]
|
||||
enum ArgType {
|
||||
|
@ -28,29 +31,6 @@ enum ArgType {
|
|||
|
||||
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)]
|
||||
struct TestArg {
|
||||
arg: String,
|
||||
|
@ -204,31 +184,31 @@ fuzz_target!(|_data: &[u8]| {
|
|||
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
|
||||
match run_gnu_cmd(CMD_PATH, &args[1..], false) {
|
||||
Ok((gnu_output, gnu_exit_status)) => {
|
||||
let gnu_output = gnu_output.trim().to_owned();
|
||||
println!("gnu_exit_status {}", gnu_exit_status);
|
||||
println!("uumain_exit_status {}", uumain_exit_status);
|
||||
if rust_output != gnu_output || uumain_exit_status != gnu_exit_status {
|
||||
println!("Discrepancy detected!");
|
||||
println!("Test: {:?}", &args[1..]);
|
||||
println!("My output: {}", rust_output);
|
||||
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..]
|
||||
);
|
||||
let gnu_result = match run_gnu_cmd(CMD_PATH, &args[1..], false) {
|
||||
Ok(result) => result,
|
||||
Err(error_result) => {
|
||||
eprintln!("Failed to run GNU command:");
|
||||
eprintln!("Stderr: {}", error_result.stderr);
|
||||
eprintln!("Exit Code: {}", error_result.exit_code);
|
||||
CommandResult {
|
||||
stdout: String::new(),
|
||||
stderr: error_result.stderr,
|
||||
exit_code: error_result.exit_code,
|
||||
}
|
||||
}
|
||||
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
|
||||
);
|
||||
});
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_arch"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "arch ~ (uutils) display machine architecture"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_base32"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "base32 ~ (uutils) decode/encode input (base32-encoding)"
|
||||
|
|
|
@ -54,7 +54,7 @@ impl Config {
|
|||
format!("{}: No such file or directory", name.maybe_quote()),
|
||||
));
|
||||
}
|
||||
Some(name.to_owned())
|
||||
Some(name.clone())
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_base64"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "base64 ~ (uutils) decode/encode input (base64-encoding)"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_basename"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "basename ~ (uutils) display PATHNAME with leading directory components removed"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_basenc"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "basenc ~ (uutils) decode/encode input"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_cat"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "cat ~ (uutils) concatenate and display input"
|
||||
|
|
|
@ -3,9 +3,7 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
// spell-checker:ignore (ToDO) nonprint nonblank nonprinting
|
||||
|
||||
// last synced with: cat (GNU coreutils) 8.13
|
||||
// spell-checker:ignore (ToDO) nonprint nonblank nonprinting ELOOP
|
||||
use clap::{crate_version, Arg, ArgAction, Command};
|
||||
use std::fs::{metadata, File};
|
||||
use std::io::{self, IsTerminal, Read, Write};
|
||||
|
@ -52,6 +50,8 @@ enum CatError {
|
|||
IsDirectory,
|
||||
#[error("input file is output file")]
|
||||
OutputIsInput,
|
||||
#[error("Too many levels of symbolic links")]
|
||||
TooManySymlinks,
|
||||
}
|
||||
|
||||
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 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()],
|
||||
};
|
||||
|
||||
|
@ -403,7 +403,23 @@ fn get_input_type(path: &str) -> CatResult<InputType> {
|
|||
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 {
|
||||
#[cfg(unix)]
|
||||
ft if ft.is_block_device() => Ok(InputType::BlockDevice),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chcon"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chcon ~ (uutils) change file security context"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chgrp"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chgrp ~ (uutils) change the group ownership of FILE"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chmod"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chmod ~ (uutils) change mode of FILE"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chown"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chown ~ (uutils) change the ownership of FILE"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_chroot"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "chroot ~ (uutils) run COMMAND under a new root directory"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_cksum"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "cksum ~ (uutils) display CRC and size of input"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_comm"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "comm ~ (uutils) compare sorted inputs"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_cp"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = [
|
||||
"Jordy Dickinson <jordy.dickinson@gmail.com>",
|
||||
"Joshua S. Miller <jsmiller@uchicago.edu>",
|
||||
|
|
|
@ -87,6 +87,9 @@ struct Context<'a> {
|
|||
|
||||
/// The target path to which the directory will be copied.
|
||||
target: &'a Path,
|
||||
|
||||
/// The source path from which the directory will be copied.
|
||||
root: &'a Path,
|
||||
}
|
||||
|
||||
impl<'a> Context<'a> {
|
||||
|
@ -102,6 +105,7 @@ impl<'a> Context<'a> {
|
|||
current_dir,
|
||||
root_parent,
|
||||
target,
|
||||
root,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -156,11 +160,19 @@ struct 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_absolute = context.current_dir.join(&source_relative);
|
||||
let descendant =
|
||||
let mut descendant =
|
||||
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 target_is_file = context.target.is_file();
|
||||
Ok(Self {
|
||||
|
@ -389,7 +401,7 @@ pub(crate) fn copy_directory(
|
|||
{
|
||||
match direntry_result {
|
||||
Ok(direntry) => {
|
||||
let entry = Entry::new(&context, &direntry)?;
|
||||
let entry = Entry::new(&context, &direntry, options.no_target_dir)?;
|
||||
copy_direntry(
|
||||
progress_bar,
|
||||
entry,
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#![allow(clippy::extra_unused_lifetimes)]
|
||||
|
||||
use quick_error::quick_error;
|
||||
use std::borrow::Cow;
|
||||
use std::cmp::Ordering;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::env;
|
||||
|
@ -41,8 +40,8 @@ use uucore::{backup_control, update_control};
|
|||
// requires these enum.
|
||||
pub use uucore::{backup_control::BackupMode, update_control::UpdateMode};
|
||||
use uucore::{
|
||||
crash, format_usage, help_about, help_section, help_usage, prompt_yes, show_error,
|
||||
show_warning, util_name,
|
||||
format_usage, help_about, help_section, help_usage, prompt_yes, show_error, show_warning,
|
||||
util_name,
|
||||
};
|
||||
|
||||
use crate::copydir::copy_directory;
|
||||
|
@ -144,6 +143,7 @@ pub enum SparseMode {
|
|||
}
|
||||
|
||||
/// The expected file type of copy target
|
||||
#[derive(Copy, Clone)]
|
||||
pub enum TargetType {
|
||||
Directory,
|
||||
File,
|
||||
|
@ -1195,7 +1195,7 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult
|
|||
&progress_bar,
|
||||
source,
|
||||
target,
|
||||
&target_type,
|
||||
target_type,
|
||||
options,
|
||||
&mut symlinked_files,
|
||||
&mut copied_files,
|
||||
|
@ -1220,7 +1220,7 @@ pub fn copy(sources: &[PathBuf], target: &Path, options: &Options) -> CopyResult
|
|||
fn construct_dest_path(
|
||||
source_path: &Path,
|
||||
target: &Path,
|
||||
target_type: &TargetType,
|
||||
target_type: TargetType,
|
||||
options: &Options,
|
||||
) -> CopyResult<PathBuf> {
|
||||
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());
|
||||
}
|
||||
|
||||
Ok(match *target_type {
|
||||
Ok(match target_type {
|
||||
TargetType::Directory => {
|
||||
let root = if options.parents {
|
||||
Path::new("")
|
||||
|
@ -1252,7 +1252,7 @@ fn copy_source(
|
|||
progress_bar: &Option<ProgressBar>,
|
||||
source: &Path,
|
||||
target: &Path,
|
||||
target_type: &TargetType,
|
||||
target_type: TargetType,
|
||||
options: &Options,
|
||||
symlinked_files: &mut HashSet<FileInformation>,
|
||||
copied_files: &mut HashMap<FileInformation, PathBuf>,
|
||||
|
@ -1995,24 +1995,12 @@ fn copy_link(
|
|||
) -> CopyResult<()> {
|
||||
// Here, we will copy the symlink itself (actually, just recreate it)
|
||||
let link = fs::read_link(source)?;
|
||||
let dest: Cow<'_, Path> = if dest.is_dir() {
|
||||
match source.file_name() {
|
||||
Some(name) => dest.join(name).into(),
|
||||
None => crash!(
|
||||
EXIT_ERR,
|
||||
"cannot stat {}: No such file or directory",
|
||||
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)
|
||||
// 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)?;
|
||||
}
|
||||
symlink_file(&link, dest, &context_for(&link, dest), symlinked_files)
|
||||
}
|
||||
|
||||
/// Generate an error message if `target` is not the correct `target_type`
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_csplit"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
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"
|
||||
|
|
|
@ -62,15 +62,9 @@ impl CsplitOptions {
|
|||
split_name: crash_if_err!(
|
||||
1,
|
||||
SplitName::new(
|
||||
matches
|
||||
.get_one::<String>(options::PREFIX)
|
||||
.map(|s| s.to_owned()),
|
||||
matches
|
||||
.get_one::<String>(options::SUFFIX_FORMAT)
|
||||
.map(|s| s.to_owned()),
|
||||
matches
|
||||
.get_one::<String>(options::DIGITS)
|
||||
.map(|s| s.to_owned())
|
||||
matches.get_one::<String>(options::PREFIX).cloned(),
|
||||
matches.get_one::<String>(options::SUFFIX_FORMAT).cloned(),
|
||||
matches.get_one::<String>(options::DIGITS).cloned()
|
||||
)
|
||||
),
|
||||
keep_files,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_cut"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "cut ~ (uutils) display byte/field columns of input lines"
|
||||
|
|
|
@ -400,7 +400,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
if s.is_empty() {
|
||||
Some("\0".to_owned())
|
||||
} else {
|
||||
Some(s.to_owned())
|
||||
Some(s.clone())
|
||||
}
|
||||
}
|
||||
None => None,
|
||||
|
@ -491,7 +491,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let files: Vec<String> = matches
|
||||
.get_many::<String>(options::FILE)
|
||||
.unwrap_or_default()
|
||||
.map(|s| s.to_owned())
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
match mode_parse {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# spell-checker:ignore datetime
|
||||
[package]
|
||||
name = "uu_date"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "date ~ (uutils) display or set the current time"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_dd"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "dd ~ (uutils) copy and convert files"
|
||||
|
@ -18,7 +18,7 @@ path = "src/dd.rs"
|
|||
clap = { workspace = true }
|
||||
gcd = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
uucore = { workspace = true, features = ["format"] }
|
||||
uucore = { workspace = true, features = ["format", "quoting-style"] }
|
||||
|
||||
[target.'cfg(any(target_os = "linux"))'.dependencies]
|
||||
nix = { workspace = true, features = ["fs"] }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_df"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "df ~ (uutils) display file system information"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_dir"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "shortcut to ls -C -b"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_dircolors"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "dircolors ~ (uutils) display commands to set LS_COLORS"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_dirname"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "dirname ~ (uutils) display parent directory of PATHNAME"
|
||||
|
|
|
@ -30,7 +30,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let dirnames: Vec<String> = matches
|
||||
.get_many::<String>(options::DIR)
|
||||
.unwrap_or_default()
|
||||
.map(|s| s.to_owned())
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
if dirnames.is_empty() {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_du"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "du ~ (uutils) display disk usage"
|
||||
|
|
|
@ -31,13 +31,11 @@ use std::time::{Duration, UNIX_EPOCH};
|
|||
use std::{error::Error, fmt::Display};
|
||||
use uucore::display::{print_verbatim, Quotable};
|
||||
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::parse_glob;
|
||||
use uucore::parse_size::{parse_size_u64, ParseSizeError};
|
||||
use uucore::{
|
||||
crash, format_usage, help_about, help_section, help_usage, show, show_error, show_warning,
|
||||
};
|
||||
use uucore::{format_usage, help_about, help_section, help_usage, show, show_error, show_warning};
|
||||
#[cfg(windows)]
|
||||
use windows_sys::Win32::Foundation::HANDLE;
|
||||
#[cfg(windows)]
|
||||
|
@ -68,6 +66,7 @@ mod options {
|
|||
pub const ONE_FILE_SYSTEM: &str = "one-file-system";
|
||||
pub const DEREFERENCE: &str = "dereference";
|
||||
pub const DEREFERENCE_ARGS: &str = "dereference-args";
|
||||
pub const NO_DEREFERENCE: &str = "no-dereference";
|
||||
pub const INODES: &str = "inodes";
|
||||
pub const EXCLUDE: &str = "exclude";
|
||||
pub const EXCLUDE_FROM: &str = "exclude-from";
|
||||
|
@ -89,6 +88,7 @@ struct Options {
|
|||
separate_dirs: bool,
|
||||
one_file_system: bool,
|
||||
dereference: Deref,
|
||||
count_links: bool,
|
||||
inodes: bool,
|
||||
verbose: bool,
|
||||
}
|
||||
|
@ -136,39 +136,42 @@ impl Stat {
|
|||
}?;
|
||||
|
||||
#[cfg(not(windows))]
|
||||
let file_info = FileInfo {
|
||||
file_id: metadata.ino() as u128,
|
||||
dev_id: metadata.dev(),
|
||||
};
|
||||
#[cfg(not(windows))]
|
||||
return Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
is_dir: metadata.is_dir(),
|
||||
size: if path.is_dir() { 0 } else { metadata.len() },
|
||||
blocks: metadata.blocks(),
|
||||
inodes: 1,
|
||||
inode: Some(file_info),
|
||||
created: birth_u64(&metadata),
|
||||
accessed: metadata.atime() as u64,
|
||||
modified: metadata.mtime() as u64,
|
||||
});
|
||||
{
|
||||
let file_info = FileInfo {
|
||||
file_id: metadata.ino() as u128,
|
||||
dev_id: metadata.dev(),
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
is_dir: metadata.is_dir(),
|
||||
size: if path.is_dir() { 0 } else { metadata.len() },
|
||||
blocks: metadata.blocks(),
|
||||
inodes: 1,
|
||||
inode: Some(file_info),
|
||||
created: birth_u64(&metadata),
|
||||
accessed: metadata.atime() as u64,
|
||||
modified: metadata.mtime() as u64,
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
let size_on_disk = get_size_on_disk(path);
|
||||
#[cfg(windows)]
|
||||
let file_info = get_file_info(path);
|
||||
#[cfg(windows)]
|
||||
Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
is_dir: metadata.is_dir(),
|
||||
size: if path.is_dir() { 0 } else { metadata.len() },
|
||||
blocks: size_on_disk / 1024 * 2,
|
||||
inode: file_info,
|
||||
inodes: 1,
|
||||
created: windows_creation_time_to_unix_time(metadata.creation_time()),
|
||||
accessed: windows_time_to_unix_time(metadata.last_access_time()),
|
||||
modified: windows_time_to_unix_time(metadata.last_write_time()),
|
||||
})
|
||||
{
|
||||
let size_on_disk = get_size_on_disk(path);
|
||||
let file_info = get_file_info(path);
|
||||
|
||||
Ok(Self {
|
||||
path: path.to_path_buf(),
|
||||
is_dir: metadata.is_dir(),
|
||||
size: if path.is_dir() { 0 } else { metadata.len() },
|
||||
blocks: size_on_disk / 1024 * 2,
|
||||
inodes: 1,
|
||||
inode: file_info,
|
||||
created: windows_creation_time_to_unix_time(metadata.creation_time()),
|
||||
accessed: windows_time_to_unix_time(metadata.last_access_time()),
|
||||
modified: windows_time_to_unix_time(metadata.last_write_time()),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -254,22 +257,22 @@ fn get_file_info(path: &Path) -> Option<FileInfo> {
|
|||
result
|
||||
}
|
||||
|
||||
fn read_block_size(s: Option<&str>) -> u64 {
|
||||
fn read_block_size(s: Option<&str>) -> UResult<u64> {
|
||||
if let Some(s) = 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 {
|
||||
for env_var in ["DU_BLOCK_SIZE", "BLOCK_SIZE", "BLOCKSIZE"] {
|
||||
if let Ok(env_size) = env::var(env_var) {
|
||||
if let Ok(v) = parse_size_u64(&env_size) {
|
||||
return v;
|
||||
return Ok(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
if env::var("POSIXLY_CORRECT").is_ok() {
|
||||
512
|
||||
Ok(512)
|
||||
} else {
|
||||
1024
|
||||
Ok(1024)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -293,7 +296,7 @@ fn du(
|
|||
mut my_stat: Stat,
|
||||
options: &Options,
|
||||
depth: usize,
|
||||
inodes: &mut HashSet<FileInfo>,
|
||||
seen_inodes: &mut HashSet<FileInfo>,
|
||||
exclude: &[Pattern],
|
||||
) -> Box<dyn DoubleEndedIterator<Item = Stat>> {
|
||||
let mut stats = vec![];
|
||||
|
@ -333,10 +336,13 @@ fn du(
|
|||
}
|
||||
|
||||
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;
|
||||
}
|
||||
inodes.insert(inode);
|
||||
seen_inodes.insert(inode);
|
||||
}
|
||||
if this_stat.is_dir {
|
||||
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 {
|
||||
my_stat.size += this_stat.size;
|
||||
my_stat.blocks += this_stat.blocks;
|
||||
|
@ -505,7 +517,7 @@ fn build_exclude_patterns(matches: &ArgMatches) -> UResult<Vec<Pattern>> {
|
|||
let excludes_iterator = matches
|
||||
.get_many::<String>(options::EXCLUDE)
|
||||
.unwrap_or_default()
|
||||
.map(|v| v.to_owned());
|
||||
.cloned();
|
||||
|
||||
let mut exclude_patterns = Vec::new();
|
||||
for f in excludes_iterator.chain(exclude_from_iterator) {
|
||||
|
@ -559,6 +571,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
} else {
|
||||
Deref::None
|
||||
},
|
||||
count_links: matches.get_flag(options::COUNT_LINKS),
|
||||
inodes: matches.get_flag(options::INODES),
|
||||
verbose: matches.get_flag(options::VERBOSE),
|
||||
};
|
||||
|
@ -573,12 +586,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
matches
|
||||
.get_one::<String>(options::BLOCK_SIZE)
|
||||
.map(|s| s.as_str()),
|
||||
);
|
||||
)?;
|
||||
|
||||
let threshold = matches.get_one::<String>(options::THRESHOLD).map(|s| {
|
||||
Threshold::from_str(s)
|
||||
.unwrap_or_else(|e| crash!(1, "{}", format_error_message(&e, s, options::THRESHOLD)))
|
||||
});
|
||||
let threshold = match matches.get_one::<String>(options::THRESHOLD) {
|
||||
Some(s) => match Threshold::from_str(s) {
|
||||
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) {
|
||||
1000
|
||||
|
@ -622,11 +643,11 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
// Check existence of path provided in argument
|
||||
if let Ok(stat) = Stat::new(&path, &options) {
|
||||
// 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 {
|
||||
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
|
||||
let (_, len) = iter.size_hint();
|
||||
|
@ -820,17 +841,19 @@ pub fn uu_app() -> Command {
|
|||
.arg(
|
||||
Arg::new(options::DEREFERENCE_ARGS)
|
||||
.short('D')
|
||||
.visible_short_alias('H')
|
||||
.long(options::DEREFERENCE_ARGS)
|
||||
.help("follow only symlinks that are listed on the command line")
|
||||
.action(ArgAction::SetTrue)
|
||||
)
|
||||
// .arg(
|
||||
// Arg::new("no-dereference")
|
||||
// .short('P')
|
||||
// .long("no-dereference")
|
||||
// .help("don't follow any symbolic links (this is the default)")
|
||||
// .action(ArgAction::SetTrue),
|
||||
// )
|
||||
.arg(
|
||||
Arg::new(options::NO_DEREFERENCE)
|
||||
.short('P')
|
||||
.long(options::NO_DEREFERENCE)
|
||||
.help("don't follow any symbolic links (this is the default)")
|
||||
.overrides_with(options::DEREFERENCE)
|
||||
.action(ArgAction::SetTrue),
|
||||
)
|
||||
.arg(
|
||||
Arg::new(options::BLOCK_SIZE_1M)
|
||||
.short('m')
|
||||
|
@ -989,13 +1012,9 @@ mod test_du {
|
|||
|
||||
#[test]
|
||||
fn test_read_block_size() {
|
||||
let test_data = [
|
||||
(Some("1024".to_string()), 1024),
|
||||
(Some("K".to_string()), 1024),
|
||||
(None, 1024),
|
||||
];
|
||||
let test_data = [Some("1024".to_string()), Some("K".to_string()), None];
|
||||
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)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_echo"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "echo ~ (uutils) display TEXT"
|
||||
|
|
2
src/uu/env/Cargo.toml
vendored
2
src/uu/env/Cargo.toml
vendored
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_env"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "env ~ (uutils) set each NAME to VALUE in the environment and run COMMAND"
|
||||
|
|
2
src/uu/env/src/env.rs
vendored
2
src/uu/env/src/env.rs
vendored
|
@ -3,8 +3,6 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// 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
|
||||
|
||||
use clap::{crate_name, crate_version, Arg, ArgAction, Command};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_expand"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "expand ~ (uutils) convert input tabs to spaces"
|
||||
|
|
|
@ -15,7 +15,7 @@ use std::str::from_utf8;
|
|||
use unicode_width::UnicodeWidthChar;
|
||||
use uucore::display::Quotable;
|
||||
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 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))?;
|
||||
|
||||
expand(&Options::new(&matches)?).map_err_context(|| "failed to write output".to_string())
|
||||
expand(&Options::new(&matches)?)
|
||||
}
|
||||
|
||||
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;
|
||||
if path == "-" {
|
||||
BufReader::new(Box::new(stdin()) as Box<dyn Read>)
|
||||
Ok(BufReader::new(Box::new(stdin()) as Box<dyn Read>))
|
||||
} else {
|
||||
file_buf = match File::open(path) {
|
||||
Ok(a) => a,
|
||||
Err(e) => crash!(1, "{}: {}\n", path.maybe_quote(), e),
|
||||
};
|
||||
BufReader::new(Box::new(file_buf) as Box<dyn Read>)
|
||||
file_buf = File::open(path).map_err_context(|| path.to_string())?;
|
||||
Ok(BufReader::new(Box::new(file_buf) as Box<dyn Read>))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -370,99 +367,111 @@ enum CharType {
|
|||
}
|
||||
|
||||
#[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::*;
|
||||
|
||||
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 ts = options.tabstops.as_ref();
|
||||
let mut buf = Vec::new();
|
||||
|
||||
for file in &options.files {
|
||||
let mut fh = open(file);
|
||||
let mut fh = open(file)?;
|
||||
|
||||
while match fh.read_until(b'\n', &mut buf) {
|
||||
Ok(s) => s > 0,
|
||||
Err(_) => buf.is_empty(),
|
||||
} {
|
||||
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(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
|
||||
expand_line(&mut buf, &mut output, ts, options)
|
||||
.map_err_context(|| "failed to write output".to_string())?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_expr"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "expr ~ (uutils) display the value of EXPRESSION"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_factor"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "factor ~ (uutils) display the prime factors of each NUMBER"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_false"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "false ~ (uutils) do nothing and fail"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_fmt"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "fmt ~ (uutils) reformat each paragraph of input"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_fold"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "fold ~ (uutils) wrap each line of input"
|
||||
|
|
|
@ -35,7 +35,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let bytes = matches.get_flag(options::BYTES);
|
||||
let spaces = matches.get_flag(options::SPACES);
|
||||
let poss_width = match matches.get_one::<String>(options::WIDTH) {
|
||||
Some(v) => Some(v.to_owned()),
|
||||
Some(v) => Some(v.clone()),
|
||||
None => obs_width,
|
||||
};
|
||||
|
||||
|
@ -50,7 +50,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
};
|
||||
|
||||
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()],
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_groups"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "groups ~ (uutils) display group memberships for USERNAME"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_hashsum"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "hashsum ~ (uutils) display or check input digests"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_head"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "head ~ (uutils) display the first lines of input"
|
||||
|
|
|
@ -205,7 +205,7 @@ impl HeadOptions {
|
|||
options.mode = Mode::from(matches)?;
|
||||
|
||||
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()],
|
||||
};
|
||||
//println!("{:#?}", options);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_hostid"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "hostid ~ (uutils) display the numeric identifier of the current host"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_hostname"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "hostname ~ (uutils) display or set the host name of the current host"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_id"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "id ~ (uutils) display user and group information for USER"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_install"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["Ben Eills <ben@beneills.com>", "uutils developers"]
|
||||
license = "MIT"
|
||||
description = "install ~ (uutils) copy files from SOURCE to DESTINATION (with specified attributes)"
|
||||
|
|
|
@ -375,9 +375,7 @@ fn behavior(matches: &ArgMatches) -> UResult<Behavior> {
|
|||
};
|
||||
|
||||
let backup_mode = backup_control::determine_backup_mode(matches)?;
|
||||
let target_dir = matches
|
||||
.get_one::<String>(OPT_TARGET_DIRECTORY)
|
||||
.map(|d| d.to_owned());
|
||||
let target_dir = matches.get_one::<String>(OPT_TARGET_DIRECTORY).cloned();
|
||||
|
||||
let preserve_timestamps = matches.get_flag(OPT_PRESERVE_TIMESTAMPS);
|
||||
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();
|
||||
|
||||
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) {
|
||||
|
@ -628,7 +626,7 @@ fn copy_files_into_dir(files: &[PathBuf], target_dir: &Path, b: &Behavior) -> UR
|
|||
}
|
||||
|
||||
if sourcepath.is_dir() {
|
||||
let err = InstallError::OmittingDirectory(sourcepath.to_path_buf());
|
||||
let err = InstallError::OmittingDirectory(sourcepath.clone());
|
||||
show!(err);
|
||||
continue;
|
||||
}
|
||||
|
@ -701,12 +699,9 @@ fn perform_backup(to: &Path, b: &Behavior) -> UResult<Option<PathBuf>> {
|
|||
if let Some(ref backup_path) = backup_path {
|
||||
// TODO!!
|
||||
if let Err(err) = fs::rename(to, backup_path) {
|
||||
return Err(InstallError::BackupFailed(
|
||||
to.to_path_buf(),
|
||||
backup_path.to_path_buf(),
|
||||
err,
|
||||
)
|
||||
.into());
|
||||
return Err(
|
||||
InstallError::BackupFailed(to.to_path_buf(), backup_path.clone(), err).into(),
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(backup_path)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_join"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "join ~ (uutils) merge lines from inputs with matching join fields"
|
||||
|
|
|
@ -19,9 +19,9 @@ use std::num::IntErrorKind;
|
|||
#[cfg(unix)]
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
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::{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 USAGE: &str = help_usage!("join.md");
|
||||
|
@ -334,37 +334,30 @@ impl<'a> State<'a> {
|
|||
key: usize,
|
||||
line_ending: LineEnding,
|
||||
print_unpaired: bool,
|
||||
) -> State<'a> {
|
||||
let f = if name == "-" {
|
||||
) -> UResult<State<'a>> {
|
||||
let file_buf = if name == "-" {
|
||||
Box::new(stdin.lock()) as Box<dyn BufRead>
|
||||
} else {
|
||||
match File::open(name) {
|
||||
Ok(file) => Box::new(BufReader::new(file)) as Box<dyn BufRead>,
|
||||
Err(err) => crash!(1, "{}: {}", name.maybe_quote(), err),
|
||||
}
|
||||
let file = File::open(name).map_err_context(|| format!("{}", name.maybe_quote()))?;
|
||||
Box::new(BufReader::new(file)) as Box<dyn BufRead>
|
||||
};
|
||||
|
||||
State {
|
||||
Ok(State {
|
||||
key,
|
||||
file_name: name,
|
||||
file_num,
|
||||
print_unpaired,
|
||||
lines: f.split(line_ending as u8),
|
||||
lines: file_buf.split(line_ending as u8),
|
||||
max_len: 1,
|
||||
seq: Vec::new(),
|
||||
line_num: 0,
|
||||
has_failed: false,
|
||||
has_unpaired: false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Skip the current unpaired line.
|
||||
fn skip_line(
|
||||
&mut self,
|
||||
writer: &mut impl Write,
|
||||
input: &Input,
|
||||
repr: &Repr,
|
||||
) -> Result<(), JoinError> {
|
||||
fn skip_line(&mut self, writer: &mut impl Write, input: &Input, repr: &Repr) -> UResult<()> {
|
||||
if self.print_unpaired {
|
||||
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
|
||||
/// 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)? {
|
||||
let diff = input.compare(self.get_current_key(), line.get_field(self.key));
|
||||
|
||||
|
@ -484,12 +477,7 @@ impl<'a> State<'a> {
|
|||
0
|
||||
}
|
||||
|
||||
fn finalize(
|
||||
&mut self,
|
||||
writer: &mut impl Write,
|
||||
input: &Input,
|
||||
repr: &Repr,
|
||||
) -> Result<(), JoinError> {
|
||||
fn finalize(&mut self, writer: &mut impl Write, input: &Input, repr: &Repr) -> UResult<()> {
|
||||
if self.has_line() {
|
||||
if self.print_unpaired {
|
||||
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"));
|
||||
}
|
||||
|
||||
match exec(file1, file2, settings) {
|
||||
Ok(_) => Ok(()),
|
||||
Err(e) => Err(USimpleError::new(1, format!("{e}"))),
|
||||
}
|
||||
exec(file1, file2, settings)
|
||||
}
|
||||
|
||||
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 mut state1 = State::new(
|
||||
|
@ -847,7 +832,7 @@ fn exec(file1: &str, file2: &str, settings: Settings) -> Result<(), JoinError> {
|
|||
settings.key1,
|
||||
settings.line_ending,
|
||||
settings.print_unpaired1,
|
||||
);
|
||||
)?;
|
||||
|
||||
let mut state2 = State::new(
|
||||
FileNum::File2,
|
||||
|
@ -856,7 +841,7 @@ fn exec(file1: &str, file2: &str, settings: Settings) -> Result<(), JoinError> {
|
|||
settings.key2,
|
||||
settings.line_ending,
|
||||
settings.print_unpaired2,
|
||||
);
|
||||
)?;
|
||||
|
||||
let input = Input::new(
|
||||
settings.separator,
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_kill"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "kill ~ (uutils) send a signal to a process"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_link"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "link ~ (uutils) create a hard (file system) link to FILE"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_ln"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "ln ~ (uutils) create a (file system) link to TARGET"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_logname"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "logname ~ (uutils) display the login name of the current user"
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
/* last synced with: logname (GNU coreutils) 8.22 */
|
||||
|
||||
// spell-checker:ignore (ToDO) getlogin userlogin
|
||||
|
||||
use clap::{crate_version, Command};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_ls"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "ls ~ (uutils) display directory contents"
|
||||
|
|
|
@ -577,9 +577,7 @@ fn extract_color(options: &clap::ArgMatches) -> bool {
|
|||
///
|
||||
/// A QuotingStyle variant representing the quoting style to use.
|
||||
fn extract_quoting_style(options: &clap::ArgMatches, show_control: bool) -> QuotingStyle {
|
||||
let opt_quoting_style = options
|
||||
.get_one::<String>(options::QUOTING_STYLE)
|
||||
.map(|cmd_line_qs| cmd_line_qs.to_owned());
|
||||
let opt_quoting_style = options.get_one::<String>(options::QUOTING_STYLE).cloned();
|
||||
|
||||
if let Some(style) = opt_quoting_style {
|
||||
match style.as_str() {
|
||||
|
@ -788,9 +786,7 @@ impl Config {
|
|||
match parse_size_u64(&raw_bs.to_string_lossy()) {
|
||||
Ok(size) => Some(size),
|
||||
Err(_) => {
|
||||
show!(LsError::BlockSizeParseError(
|
||||
cmd_line_bs.unwrap().to_owned()
|
||||
));
|
||||
show!(LsError::BlockSizeParseError(cmd_line_bs.unwrap().clone()));
|
||||
None
|
||||
}
|
||||
}
|
||||
|
@ -3056,7 +3052,7 @@ fn display_file_name(
|
|||
target_data.must_dereference,
|
||||
) {
|
||||
Ok(md) => md,
|
||||
Err(_) => path.md(out).unwrap().to_owned(),
|
||||
Err(_) => path.md(out).unwrap().clone(),
|
||||
};
|
||||
|
||||
name.push_str(&color_name(
|
||||
|
@ -3073,11 +3069,7 @@ fn display_file_name(
|
|||
}
|
||||
}
|
||||
Err(err) => {
|
||||
show!(LsError::IOErrorContext(
|
||||
err,
|
||||
path.p_buf.to_path_buf(),
|
||||
false
|
||||
));
|
||||
show!(LsError::IOErrorContext(err, path.p_buf.clone(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3087,7 +3079,7 @@ fn display_file_name(
|
|||
if config.context {
|
||||
if let Some(pad_count) = prefix_context {
|
||||
let security_context = if matches!(config.format, Format::Commas) {
|
||||
path.security_context.to_owned()
|
||||
path.security_context.clone()
|
||||
} else {
|
||||
pad_left(&path.security_context, pad_count)
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mkdir"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mkdir ~ (uutils) create DIRECTORY"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mkfifo"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mkfifo ~ (uutils) create FIFOs (named pipes)"
|
||||
|
|
|
@ -42,7 +42,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
};
|
||||
|
||||
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")),
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mknod"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mknod ~ (uutils) create special file NAME of TYPE"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mktemp"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mktemp ~ (uutils) create and display a temporary file or directory from TEMPLATE"
|
||||
|
|
|
@ -115,29 +115,30 @@ impl Display for MkTempError {
|
|||
/// This provides a layer of indirection between the application logic
|
||||
/// and the argument parsing library `clap`, allowing each to vary
|
||||
/// independently.
|
||||
struct Options {
|
||||
#[derive(Clone)]
|
||||
pub struct Options {
|
||||
/// 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.
|
||||
dry_run: bool,
|
||||
pub dry_run: bool,
|
||||
|
||||
/// Whether to suppress file creation error messages.
|
||||
quiet: bool,
|
||||
pub quiet: bool,
|
||||
|
||||
/// The directory in which to create the temporary file.
|
||||
///
|
||||
/// 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.
|
||||
suffix: Option<String>,
|
||||
pub suffix: Option<String>,
|
||||
|
||||
/// 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.
|
||||
template: String,
|
||||
pub template: String,
|
||||
}
|
||||
|
||||
impl Options {
|
||||
|
@ -192,7 +193,7 @@ impl Options {
|
|||
/// `num_rand_chars`.
|
||||
struct Params {
|
||||
/// The directory that will contain the temporary file.
|
||||
directory: String,
|
||||
directory: PathBuf,
|
||||
|
||||
/// The (non-random) prefix of the temporary file.
|
||||
prefix: String,
|
||||
|
@ -297,7 +298,7 @@ impl Params {
|
|||
let num_rand_chars = j - i;
|
||||
|
||||
Ok(Self {
|
||||
directory,
|
||||
directory: directory.into(),
|
||||
prefix,
|
||||
num_rand_chars,
|
||||
suffix,
|
||||
|
@ -357,12 +358,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
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
|
||||
res.map_err(|e| e.code().into())
|
||||
} else {
|
||||
res
|
||||
}
|
||||
};
|
||||
println_verbatim(res?).map_err_context(|| "failed to print directory name".to_owned())
|
||||
}
|
||||
|
||||
pub fn uu_app() -> Command {
|
||||
|
@ -441,7 +443,7 @@ pub fn uu_app() -> Command {
|
|||
.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 mut buf = Vec::with_capacity(len);
|
||||
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.
|
||||
let buf = String::from_utf8(buf).unwrap();
|
||||
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.
|
||||
|
@ -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
|
||||
/// 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();
|
||||
builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
|
||||
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
|
||||
/// 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();
|
||||
builder.prefix(prefix).rand_bytes(rand).suffix(suffix);
|
||||
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 {
|
||||
make_temp_dir(dir, prefix, rand, suffix)?
|
||||
} else {
|
||||
|
@ -546,7 +548,27 @@ fn exec(dir: &str, prefix: &str, rand: usize, suffix: &str, make_dir: bool) -> U
|
|||
// relative path.
|
||||
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)]
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_more"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "more ~ (uutils) input perusal filter"
|
||||
|
|
|
@ -88,7 +88,7 @@ impl Options {
|
|||
#[uucore::main]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
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,
|
||||
Err(e) => return Err(e.into()),
|
||||
};
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_mv"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "mv ~ (uutils) move (rename) SOURCE to DESTINATION"
|
||||
|
|
|
@ -146,7 +146,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let files: Vec<OsString> = matches
|
||||
.get_many::<OsString>(ARG_FILES)
|
||||
.unwrap_or_default()
|
||||
.map(|v| v.to_os_string())
|
||||
.cloned()
|
||||
.collect();
|
||||
|
||||
let overwrite_mode = determine_overwrite_mode(&matches);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_nice"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "nice ~ (uutils) run PROGRAM with modified scheduling priority"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_nl"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "nl ~ (uutils) display input with added line numbers"
|
||||
|
|
|
@ -19,11 +19,11 @@ pub fn parse_options(settings: &mut crate::Settings, opts: &clap::ArgMatches) ->
|
|||
settings.section_delimiter = if delimiter.len() == 1 {
|
||||
format!("{delimiter}:")
|
||||
} else {
|
||||
delimiter.to_owned()
|
||||
delimiter.clone()
|
||||
};
|
||||
}
|
||||
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
|
||||
.get_one::<String>(options::NUMBER_FORMAT)
|
||||
|
|
|
@ -195,7 +195,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
}
|
||||
|
||||
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()],
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_nohup"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "nohup ~ (uutils) run COMMAND, ignoring hangup signals"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_nproc"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "nproc ~ (uutils) display the number of processing units available"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_numfmt"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "numfmt ~ (uutils) reformat NUMBER"
|
||||
|
|
|
@ -211,9 +211,7 @@ fn parse_options(args: &ArgMatches) -> Result<NumfmtOptions> {
|
|||
_ => unreachable!("Should be restricted by clap"),
|
||||
};
|
||||
|
||||
let suffix = args
|
||||
.get_one::<String>(options::SUFFIX)
|
||||
.map(|s| s.to_owned());
|
||||
let suffix = args.get_one::<String>(options::SUFFIX).cloned();
|
||||
|
||||
let invalid =
|
||||
InvalidModes::from_str(args.get_one::<String>(options::INVALID).unwrap()).unwrap();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_od"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "od ~ (uutils) display formatted representation of input"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_paste"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "paste ~ (uutils) merge lines from inputs"
|
||||
|
|
|
@ -44,7 +44,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
|||
let files = matches
|
||||
.get_many::<String>(options::FILE)
|
||||
.unwrap()
|
||||
.map(|s| s.to_owned())
|
||||
.cloned()
|
||||
.collect();
|
||||
let line_ending = LineEnding::from_zero_flag(matches.get_flag(options::ZERO_TERMINATED));
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_pathchk"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "pathchk ~ (uutils) diagnose invalid or non-portable PATHNAME"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_pinky"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "pinky ~ (uutils) display user information"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_pr"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "pr ~ (uutils) convert text files for printing"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "uu_printenv"
|
||||
version = "0.0.22"
|
||||
version = "0.0.23"
|
||||
authors = ["uutils developers"]
|
||||
license = "MIT"
|
||||
description = "printenv ~ (uutils) display value of environment VAR"
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue