This commit is contained in:
sylvestre
2023-03-16 02:48:54 +00:00
parent 1919aa0803
commit dd7124ce90
5 changed files with 390 additions and 114 deletions
+28 -27
View File
@@ -176,11 +176,11 @@
<li>GNU Make (optional)</li>
</ul>
<h3 id="rust-version"><a class="header" href="#rust-version">Rust Version</a></h3>
<p>uutils follows Rust's release channels and is tested against stable, beta and nightly.
The current Minimum Supported Rust Version (MSRV) is <code>1.64.0</code>.</p>
<p>uutils follows Rust's release channels and is tested against stable, beta and
nightly. The current Minimum Supported Rust Version (MSRV) is <code>1.64.0</code>.</p>
<h2 id="building"><a class="header" href="#building">Building</a></h2>
<p>There are currently two methods to build the uutils binaries: either Cargo
or GNU Make.</p>
<p>There are currently two methods to build the uutils binaries: either Cargo or
GNU Make.</p>
<blockquote>
<p>Building the full package, including all documentation, requires both Cargo
and Gnu Make on a Unix platform.</p>
@@ -190,15 +190,15 @@ and Gnu Make on a Unix platform.</p>
cd coreutils
</code></pre>
<h3 id="cargo"><a class="header" href="#cargo">Cargo</a></h3>
<p>Building uutils using Cargo is easy because the process is the same as for
every other Rust program:</p>
<p>Building uutils using Cargo is easy because the process is the same as for every
other Rust program:</p>
<pre><code class="language-shell">cargo build --release
</code></pre>
<p>This command builds the most portable common core set of uutils into a multicall
(BusyBox-type) binary, named 'coreutils', on most Rust-supported platforms.</p>
<p>Additional platform-specific uutils are often available. Building these
expanded sets of uutils for a platform (on that platform) is as simple as
specifying it as a feature:</p>
<p>Additional platform-specific uutils are often available. Building these expanded
sets of uutils for a platform (on that platform) is as simple as specifying it
as a feature:</p>
<pre><code class="language-shell">cargo build --release --features macos
# or ...
cargo build --release --features windows
@@ -206,15 +206,15 @@ cargo build --release --features windows
cargo build --release --features unix
</code></pre>
<p>If you don't want to build every utility available on your platform into the
final binary, you can also specify which ones you want to build manually.
For example:</p>
final binary, you can also specify which ones you want to build manually. For
example:</p>
<pre><code class="language-shell">cargo build --features &quot;base32 cat echo rm&quot; --no-default-features
</code></pre>
<p>If you don't want to build the multicall binary and would prefer to build
the utilities as individual binaries, that is also possible. Each utility
is contained in its own package within the main repository, named
&quot;uu_UTILNAME&quot;. To build individual utilities, use cargo to build just the
specific packages (using the <code>--package</code> [aka <code>-p</code>] option). For example:</p>
<p>If you don't want to build the multicall binary and would prefer to build the
utilities as individual binaries, that is also possible. Each utility is
contained in its own package within the main repository, named &quot;uu_UTILNAME&quot;. To
build individual utilities, use cargo to build just the specific packages (using
the <code>--package</code> [aka <code>-p</code>] option). For example:</p>
<pre><code class="language-shell">cargo build -p uu_base32 -p uu_cat -p uu_echo -p uu_rm
</code></pre>
<h3 id="gnu-make"><a class="header" href="#gnu-make">GNU Make</a></h3>
@@ -236,9 +236,11 @@ specific packages (using the <code>--package</code> [aka <code>-p</code>] option
<p>Likewise, installing can simply be done using:</p>
<pre><code class="language-shell">cargo install --path . --locked
</code></pre>
<p>This command will install uutils into Cargo's <em>bin</em> folder (<em>e.g.</em> <code>$HOME/.cargo/bin</code>).</p>
<p>This does not install files necessary for shell completion or manpages.
For manpages or shell completion to work, use <code>GNU Make</code> or see <code>Manually install shell completions</code>/<code>Manually install manpages</code>.</p>
<p>This command will install uutils into Cargo's <em>bin</em> folder (<em>e.g.</em>
<code>$HOME/.cargo/bin</code>).</p>
<p>This does not install files necessary for shell completion or manpages. For
manpages or shell completion to work, use <code>GNU Make</code> or see
<code>Manually install shell completions</code>/<code>Manually install manpages</code>.</p>
<h3 id="install-with-gnu-make"><a class="header" href="#install-with-gnu-make">Install with GNU Make</a></h3>
<p>To install all available utilities:</p>
<pre><code class="language-shell">make install
@@ -266,26 +268,25 @@ make PREFIX=/my/path install
for <code>bash</code>, <code>fish</code> and <code>zsh</code>. Completions for <code>elvish</code> and <code>powershell</code> can also
be generated; See <code>Manually install shell completions</code>.</p>
<h3 id="manually-install-shell-completions"><a class="header" href="#manually-install-shell-completions">Manually install shell completions</a></h3>
<p>The <code>coreutils</code> binary can generate completions for the <code>bash</code>, <code>elvish</code>, <code>fish</code>, <code>powershell</code>
and <code>zsh</code> shells. It prints the result to stdout.</p>
<p>The <code>coreutils</code> binary can generate completions for the <code>bash</code>, <code>elvish</code>,
<code>fish</code>, <code>powershell</code> and <code>zsh</code> shells. It prints the result to stdout.</p>
<p>The syntax is:</p>
<pre><code class="language-shell">cargo run completion &lt;utility&gt; &lt;shell&gt;
</code></pre>
<p>So, to install completions for <code>ls</code> on <code>bash</code> to <code>/usr/local/share/bash-completion/completions/ls</code>,
run:</p>
<p>So, to install completions for <code>ls</code> on <code>bash</code> to
<code>/usr/local/share/bash-completion/completions/ls</code>, run:</p>
<pre><code class="language-shell">cargo run completion ls bash &gt; /usr/local/share/bash-completion/completions/ls
</code></pre>
<h3 id="manually-install-manpages"><a class="header" href="#manually-install-manpages">Manually install manpages</a></h3>
<p>To generate manpages, the syntax is:</p>
<pre><code class="language-bash">cargo run manpage &lt;utility&gt;
</code></pre>
<p>So, to install the manpage for <code>ls</code> to <code>/usr/local/share/man/man1/ls.1</code>
run:</p>
<p>So, to install the manpage for <code>ls</code> to <code>/usr/local/share/man/man1/ls.1</code> run:</p>
<pre><code class="language-bash">cargo run manpage ls &gt; /usr/local/share/man/man1/ls.1
</code></pre>
<h2 id="un-installation"><a class="header" href="#un-installation">Un-installation</a></h2>
<p>Un-installation differs depending on how you have installed uutils. If you used
Cargo to install, use Cargo to uninstall. If you used GNU Make to install, use
<p>Un-installation differs depending on how you have installed uutils. If you used
Cargo to install, use Cargo to uninstall. If you used GNU Make to install, use
Make to uninstall.</p>
<h3 id="uninstall-with-cargo"><a class="header" href="#uninstall-with-cargo">Uninstall with Cargo</a></h3>
<p>To uninstall uutils:</p>
+166 -29
View File
@@ -170,23 +170,13 @@
<div id="content" class="content">
<main>
<!-- markdownlint-disable MD041 -->
<!-- spell-checker:ignore reimplementing toybox -->
<!-- spell-checker:ignore reimplementing toybox RUNTEST -->
<h1 id="contributing-to-coreutils"><a class="header" href="#contributing-to-coreutils">Contributing to coreutils</a></h1>
<p>Contributions are very welcome, and should target Rust's main branch until the
standard libraries are stabilized. You may <em>claim</em> an item on the to-do list by
following these steps:</p>
<ol>
<li>Open an issue named &quot;Implement [the utility of your choice]&quot;, e.g. &quot;Implement
ls&quot;.</li>
<li>State that you are working on this utility.</li>
<li>Develop the utility.</li>
<li>Add integration tests.</li>
<li>Add the reference to your utility into Cargo.toml and Makefile.</li>
<li>Remove utility from the to-do list in the README.</li>
<li>Submit a pull request and close the issue.</li>
</ol>
<p>The steps above imply that, before starting to work on a utility, you should
search the issues to make sure no one else is working on it.</p>
<p>Contributions are very welcome via Pull Requests. If you don't know where to
start, take a look at the
<a href="https://github.com/uutils/coreutils/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22"><code>good-first-issues</code></a>.
If you have any questions, feel free to ask them in the issues or on
<a href="https://discord.gg/wQVJbvJ">Discord</a>.</p>
<h2 id="best-practices"><a class="header" href="#best-practices">Best practices</a></h2>
<ol>
<li>Follow what GNU is doing in terms of options and behavior. It is recommended
@@ -208,30 +198,166 @@ other binaries.</li>
utilities, nor should it link to or reference GNU libraries.</li>
</ol>
<h2 id="platforms"><a class="header" href="#platforms">Platforms</a></h2>
<p>We take pride in supporting many operating systems and architectures.</p>
<p><strong>Tip:</strong>
For Windows, Microsoft provides some images (VMWare, Hyper-V, VirtualBox and Parallels)
for development:
<p>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 <code>#[cfg(...)]</code> attributes to create platform dependent features.</p>
<p><strong>Tip:</strong> For Windows, Microsoft provides some images (VMWare, Hyper-V,
VirtualBox and Parallels) for development:
<a href="https://developer.microsoft.com/windows/downloads/virtual-machines/">https://developer.microsoft.com/windows/downloads/virtual-machines/</a></p>
<h2 id="tools"><a class="header" href="#tools">Tools</a></h2>
<p>We have an extensive CI that will check your code before it can be merged. This
section explains how to run those checks locally to avoid waiting for the CI.</p>
<h3 id="pre-commit-hooks"><a class="header" href="#pre-commit-hooks">pre-commit hooks</a></h3>
<p>A configuration for <code>pre-commit</code> is provided in the repository. It allows
automatically checking every git commit you make to ensure it compiles, and
passes <code>clippy</code> and <code>rustfmt</code> without warnings.</p>
<p>To use the provided hook:</p>
<ol>
<li><a href="https://pre-commit.com/#install">Install <code>pre-commit</code></a></li>
<li>Run <code>pre-commit install</code> while in the repository directory</li>
</ol>
<p>Your git commits will then automatically be checked. If a check fails, an error
message will explain why, and your commit will be canceled. You can then make
the suggested changes, and run <code>git commit ...</code> again.</p>
<h3 id="clippy"><a class="header" href="#clippy">clippy</a></h3>
<pre><code class="language-shell">cargo clippy --all-targets --all-features
</code></pre>
<p>The <code>msrv</code> key in the clippy configuration file <code>clippy.toml</code> is used to disable
lints pertaining to newer features by specifying the minimum supported Rust
version (MSRV).</p>
<h3 id="rustfmt"><a class="header" href="#rustfmt">rustfmt</a></h3>
<pre><code class="language-shell">cargo fmt --all
</code></pre>
<h3 id="cargo-deny"><a class="header" href="#cargo-deny">cargo-deny</a></h3>
<p>This project uses <a href="https://github.com/EmbarkStudios/cargo-deny/">cargo-deny</a> to
detect duplicate dependencies, checks licenses, etc. To run it locally, first
install it and then run with:</p>
<pre><code>cargo deny --all-features check all
</code></pre>
<h3 id="markdown-linter"><a class="header" href="#markdown-linter">Markdown linter</a></h3>
<p>We use <a href="https://github.com/DavidAnson/markdownlint">markdownlint</a> to lint the
Markdown files in the repository.</p>
<h3 id="spell-checker"><a class="header" href="#spell-checker">Spell checker</a></h3>
<p>We use <code>cspell</code> as spell checker for all files in the project. If you are using
VS Code, you can install the
<a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker">code spell checker</a>
extension to enable spell checking within your editor. Otherwise, you can
install <a href="https://cspell.org/">cspell</a> separately.</p>
<p>If you want to make the spell checker ignore a word, you can add</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// spell-checker:ignore word_to_ignore
<span class="boring">}</span></code></pre></pre>
<p>at the top of the file.</p>
<h2 id="testing"><a class="header" href="#testing">Testing</a></h2>
<p>Testing can be done using either Cargo or <code>make</code>.</p>
<h3 id="testing-with-cargo"><a class="header" href="#testing-with-cargo">Testing with Cargo</a></h3>
<p>Just like with building, we follow the standard procedure for testing using
Cargo:</p>
<pre><code class="language-shell">cargo test
</code></pre>
<p>By default, <code>cargo test</code> only runs the common programs. To run also platform
specific tests, run:</p>
<pre><code class="language-shell">cargo test --features unix
</code></pre>
<p>If you would prefer to test a select few utilities:</p>
<pre><code class="language-shell">cargo test --features &quot;chmod mv tail&quot; --no-default-features
</code></pre>
<p>If you also want to test the core utilities:</p>
<pre><code class="language-shell">cargo test -p uucore -p coreutils
</code></pre>
<p>To debug:</p>
<pre><code class="language-shell">gdb --args target/debug/coreutils ls
(gdb) b ls.rs:79
(gdb) run
</code></pre>
<h3 id="testing-with-gnu-make"><a class="header" href="#testing-with-gnu-make">Testing with GNU Make</a></h3>
<p>To simply test all available utilities:</p>
<pre><code class="language-shell">make test
</code></pre>
<p>To test all but a few of the available utilities:</p>
<pre><code class="language-shell">make SKIP_UTILS='UTILITY_1 UTILITY_2' test
</code></pre>
<p>To test only a few of the available utilities:</p>
<pre><code class="language-shell">make UTILS='UTILITY_1 UTILITY_2' test
</code></pre>
<p>To include tests for unimplemented behavior:</p>
<pre><code class="language-shell">make UTILS='UTILITY_1 UTILITY_2' SPEC=y test
</code></pre>
<h3 id="run-busybox-tests"><a class="header" href="#run-busybox-tests">Run Busybox Tests</a></h3>
<p>This testing functionality is only available on *nix operating systems and
requires <code>make</code>.</p>
<p>To run busybox tests for all utilities for which busybox has tests</p>
<pre><code class="language-shell">make busytest
</code></pre>
<p>To run busybox tests for a few of the available utilities</p>
<pre><code class="language-shell">make UTILS='UTILITY_1 UTILITY_2' busytest
</code></pre>
<p>To pass an argument like &quot;-v&quot; to the busybox test runtime</p>
<pre><code class="language-shell">make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest
</code></pre>
<h3 id="comparing-with-gnu"><a class="header" href="#comparing-with-gnu">Comparing with GNU</a></h3>
<p>To run uutils against the GNU test suite locally, run the following commands:</p>
<pre><code class="language-shell">bash util/build-gnu.sh
bash util/run-gnu-test.sh
# To run a single test:
bash util/run-gnu-test.sh tests/touch/not-owner.sh # for example
# To run several tests:
bash util/run-gnu-test.sh tests/touch/not-owner.sh tests/rm/no-give-up.sh # for example
# If this is a perl (.pl) test, to run in debug:
DEBUG=1 bash util/run-gnu-test.sh tests/misc/sm3sum.pl
</code></pre>
<p>Note that it relies on individual utilities (not the multicall binary).</p>
<h3 id="improving-the-gnu-compatibility"><a class="header" href="#improving-the-gnu-compatibility">Improving the GNU compatibility</a></h3>
<p>The Python script <code>./util/remaining-gnu-error.py</code> shows the list of failing
tests in the CI.</p>
<p>To improve the GNU compatibility, the following process is recommended:</p>
<ol>
<li>Identify a test (the smaller, the better) on a program that you understand or
is easy to understand. You can use the <code>./util/remaining-gnu-error.py</code> script
to help with this decision.</li>
<li>Build both the GNU and Rust coreutils using: <code>bash util/build-gnu.sh</code></li>
<li>Run the test with <code>bash util/run-gnu-test.sh &lt;your test&gt;</code></li>
<li>Start to modify <code>&lt;your test&gt;</code> to understand what is wrong. Examples:
<ol>
<li>Add <code>set -v</code> to have the bash verbose mode</li>
<li>Add <code>echo $?</code> where needed</li>
<li>When the variable <code>fail</code> is used in the test, <code>echo $fail</code> to see when the
test started to fail</li>
<li>Bump the content of the output (ex: <code>cat err</code>)</li>
<li>...</li>
</ol>
</li>
<li>Or, if the test is simple, extract the relevant information to create a new
test case running both GNU &amp; Rust implementation</li>
<li>Start to modify the Rust implementation to match the expected behavior</li>
<li>Add a test to make sure that we don't regress (our test suite is super quick)</li>
</ol>
<h2 id="commit-messages"><a class="header" href="#commit-messages">Commit messages</a></h2>
<p>To help the project maintainers review pull requests from contributors across
numerous utilities, the team has settled on conventions for commit messages.</p>
<p>From <a href="http://git-scm.com/book/ch5-2.html">http://git-scm.com/book/ch5-2.html</a>:</p>
<pre><code>Short (50 chars or less) summary of changes
<p>From <a href="https://git-scm.com/book/ch5-2.html">https://git-scm.com/book/ch5-2.html</a>:</p>
<pre><code>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 can get confused if you run the
the body entirely); tools like rebase will confuse you if you run the
two together.
Write your commit message in the imperative: &quot;Fix bug&quot; and not &quot;Fixed bug&quot;
or &quot;Fixes bug.&quot; 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, preceded by a
- 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
</code></pre>
<p>Furthermore, here are a few examples for a summary line:</p>
<ul>
@@ -254,12 +380,23 @@ lines for non-utility modules include:</p>
</code></pre>
<pre><code>gitignore: add temporary files
</code></pre>
<h2 id="cargo-deny"><a class="header" href="#cargo-deny">cargo-deny</a></h2>
<p>This project uses <a href="https://github.com/EmbarkStudios/cargo-deny/">cargo-deny</a> to
detect duplicate dependencies, checks licenses, etc. To run it locally, first
install it and then run with:</p>
<pre><code>cargo deny --all-features check all
<h2 id="code-coverage"><a class="header" href="#code-coverage">Code coverage</a></h2>
<!-- spell-checker:ignore (flags) Ccodegen Coverflow Cpanic Zinstrument Zpanic -->
<p>Code coverage report can be generated using <a href="https://github.com/mozilla/grcov">grcov</a>.</p>
<h3 id="using-nightly-rust"><a class="header" href="#using-nightly-rust">Using Nightly Rust</a></h3>
<p>To generate <a href="https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project">gcov-based</a> coverage report</p>
<pre><code class="language-shell">export CARGO_INCREMENTAL=0
export RUSTFLAGS=&quot;-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort&quot;
export RUSTDOCFLAGS=&quot;-Cpanic=abort&quot;
cargo build &lt;options...&gt; # e.g., --features feat_os_unix
cargo test &lt;options...&gt; # e.g., --features feat_os_unix test_pathchk
grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing --ignore build.rs --excl-br-line &quot;^\s*((debug_)?assert(_eq|_ne)?\#\[derive\()&quot; -o ./target/debug/coverage/
# open target/debug/coverage/index.html in browser
</code></pre>
<p>if changes are not reflected in the report then run <code>cargo clean</code> and run the above commands.</p>
<h3 id="using-stable-rust"><a class="header" href="#using-stable-rust">Using Stable Rust</a></h3>
<p>If you are using stable version of Rust that doesn't enable code coverage instrumentation by default
then add <code>-Z-Zinstrument-coverage</code> flag to <code>RUSTFLAGS</code> env variable specified above.</p>
<h2 id="other-implementations"><a class="header" href="#other-implementations">Other implementations</a></h2>
<p>The Coreutils have different implementations, with different levels of completions:</p>
<ul>
+194 -56
View File
@@ -405,11 +405,11 @@ unfinished or buggy.</p>
<li>GNU Make (optional)</li>
</ul>
<h3 id="rust-version"><a class="header" href="#rust-version">Rust Version</a></h3>
<p>uutils follows Rust's release channels and is tested against stable, beta and nightly.
The current Minimum Supported Rust Version (MSRV) is <code>1.64.0</code>.</p>
<p>uutils follows Rust's release channels and is tested against stable, beta and
nightly. The current Minimum Supported Rust Version (MSRV) is <code>1.64.0</code>.</p>
<h2 id="building"><a class="header" href="#building">Building</a></h2>
<p>There are currently two methods to build the uutils binaries: either Cargo
or GNU Make.</p>
<p>There are currently two methods to build the uutils binaries: either Cargo or
GNU Make.</p>
<blockquote>
<p>Building the full package, including all documentation, requires both Cargo
and Gnu Make on a Unix platform.</p>
@@ -419,15 +419,15 @@ and Gnu Make on a Unix platform.</p>
cd coreutils
</code></pre>
<h3 id="cargo-1"><a class="header" href="#cargo-1">Cargo</a></h3>
<p>Building uutils using Cargo is easy because the process is the same as for
every other Rust program:</p>
<p>Building uutils using Cargo is easy because the process is the same as for every
other Rust program:</p>
<pre><code class="language-shell">cargo build --release
</code></pre>
<p>This command builds the most portable common core set of uutils into a multicall
(BusyBox-type) binary, named 'coreutils', on most Rust-supported platforms.</p>
<p>Additional platform-specific uutils are often available. Building these
expanded sets of uutils for a platform (on that platform) is as simple as
specifying it as a feature:</p>
<p>Additional platform-specific uutils are often available. Building these expanded
sets of uutils for a platform (on that platform) is as simple as specifying it
as a feature:</p>
<pre><code class="language-shell">cargo build --release --features macos
# or ...
cargo build --release --features windows
@@ -435,15 +435,15 @@ cargo build --release --features windows
cargo build --release --features unix
</code></pre>
<p>If you don't want to build every utility available on your platform into the
final binary, you can also specify which ones you want to build manually.
For example:</p>
final binary, you can also specify which ones you want to build manually. For
example:</p>
<pre><code class="language-shell">cargo build --features &quot;base32 cat echo rm&quot; --no-default-features
</code></pre>
<p>If you don't want to build the multicall binary and would prefer to build
the utilities as individual binaries, that is also possible. Each utility
is contained in its own package within the main repository, named
&quot;uu_UTILNAME&quot;. To build individual utilities, use cargo to build just the
specific packages (using the <code>--package</code> [aka <code>-p</code>] option). For example:</p>
<p>If you don't want to build the multicall binary and would prefer to build the
utilities as individual binaries, that is also possible. Each utility is
contained in its own package within the main repository, named &quot;uu_UTILNAME&quot;. To
build individual utilities, use cargo to build just the specific packages (using
the <code>--package</code> [aka <code>-p</code>] option). For example:</p>
<pre><code class="language-shell">cargo build -p uu_base32 -p uu_cat -p uu_echo -p uu_rm
</code></pre>
<h3 id="gnu-make"><a class="header" href="#gnu-make">GNU Make</a></h3>
@@ -465,9 +465,11 @@ specific packages (using the <code>--package</code> [aka <code>-p</code>] option
<p>Likewise, installing can simply be done using:</p>
<pre><code class="language-shell">cargo install --path . --locked
</code></pre>
<p>This command will install uutils into Cargo's <em>bin</em> folder (<em>e.g.</em> <code>$HOME/.cargo/bin</code>).</p>
<p>This does not install files necessary for shell completion or manpages.
For manpages or shell completion to work, use <code>GNU Make</code> or see <code>Manually install shell completions</code>/<code>Manually install manpages</code>.</p>
<p>This command will install uutils into Cargo's <em>bin</em> folder (<em>e.g.</em>
<code>$HOME/.cargo/bin</code>).</p>
<p>This does not install files necessary for shell completion or manpages. For
manpages or shell completion to work, use <code>GNU Make</code> or see
<code>Manually install shell completions</code>/<code>Manually install manpages</code>.</p>
<h3 id="install-with-gnu-make"><a class="header" href="#install-with-gnu-make">Install with GNU Make</a></h3>
<p>To install all available utilities:</p>
<pre><code class="language-shell">make install
@@ -495,26 +497,25 @@ make PREFIX=/my/path install
for <code>bash</code>, <code>fish</code> and <code>zsh</code>. Completions for <code>elvish</code> and <code>powershell</code> can also
be generated; See <code>Manually install shell completions</code>.</p>
<h3 id="manually-install-shell-completions"><a class="header" href="#manually-install-shell-completions">Manually install shell completions</a></h3>
<p>The <code>coreutils</code> binary can generate completions for the <code>bash</code>, <code>elvish</code>, <code>fish</code>, <code>powershell</code>
and <code>zsh</code> shells. It prints the result to stdout.</p>
<p>The <code>coreutils</code> binary can generate completions for the <code>bash</code>, <code>elvish</code>,
<code>fish</code>, <code>powershell</code> and <code>zsh</code> shells. It prints the result to stdout.</p>
<p>The syntax is:</p>
<pre><code class="language-shell">cargo run completion &lt;utility&gt; &lt;shell&gt;
</code></pre>
<p>So, to install completions for <code>ls</code> on <code>bash</code> to <code>/usr/local/share/bash-completion/completions/ls</code>,
run:</p>
<p>So, to install completions for <code>ls</code> on <code>bash</code> to
<code>/usr/local/share/bash-completion/completions/ls</code>, run:</p>
<pre><code class="language-shell">cargo run completion ls bash &gt; /usr/local/share/bash-completion/completions/ls
</code></pre>
<h3 id="manually-install-manpages"><a class="header" href="#manually-install-manpages">Manually install manpages</a></h3>
<p>To generate manpages, the syntax is:</p>
<pre><code class="language-bash">cargo run manpage &lt;utility&gt;
</code></pre>
<p>So, to install the manpage for <code>ls</code> to <code>/usr/local/share/man/man1/ls.1</code>
run:</p>
<p>So, to install the manpage for <code>ls</code> to <code>/usr/local/share/man/man1/ls.1</code> run:</p>
<pre><code class="language-bash">cargo run manpage ls &gt; /usr/local/share/man/man1/ls.1
</code></pre>
<h2 id="un-installation"><a class="header" href="#un-installation">Un-installation</a></h2>
<p>Un-installation differs depending on how you have installed uutils. If you used
Cargo to install, use Cargo to uninstall. If you used GNU Make to install, use
<p>Un-installation differs depending on how you have installed uutils. If you used
Cargo to install, use Cargo to uninstall. If you used GNU Make to install, use
Make to uninstall.</p>
<h3 id="uninstall-with-cargo"><a class="header" href="#uninstall-with-cargo">Uninstall with Cargo</a></h3>
<p>To uninstall uutils:</p>
@@ -535,23 +536,13 @@ Make to uninstall.</p>
make PREFIX=/my/path uninstall
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><!-- markdownlint-disable MD041 -->
<!-- spell-checker:ignore reimplementing toybox -->
<!-- spell-checker:ignore reimplementing toybox RUNTEST -->
<h1 id="contributing-to-coreutils"><a class="header" href="#contributing-to-coreutils">Contributing to coreutils</a></h1>
<p>Contributions are very welcome, and should target Rust's main branch until the
standard libraries are stabilized. You may <em>claim</em> an item on the to-do list by
following these steps:</p>
<ol>
<li>Open an issue named &quot;Implement [the utility of your choice]&quot;, e.g. &quot;Implement
ls&quot;.</li>
<li>State that you are working on this utility.</li>
<li>Develop the utility.</li>
<li>Add integration tests.</li>
<li>Add the reference to your utility into Cargo.toml and Makefile.</li>
<li>Remove utility from the to-do list in the README.</li>
<li>Submit a pull request and close the issue.</li>
</ol>
<p>The steps above imply that, before starting to work on a utility, you should
search the issues to make sure no one else is working on it.</p>
<p>Contributions are very welcome via Pull Requests. If you don't know where to
start, take a look at the
<a href="https://github.com/uutils/coreutils/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22"><code>good-first-issues</code></a>.
If you have any questions, feel free to ask them in the issues or on
<a href="https://discord.gg/wQVJbvJ">Discord</a>.</p>
<h2 id="best-practices"><a class="header" href="#best-practices">Best practices</a></h2>
<ol>
<li>Follow what GNU is doing in terms of options and behavior. It is recommended
@@ -573,30 +564,166 @@ other binaries.</li>
utilities, nor should it link to or reference GNU libraries.</li>
</ol>
<h2 id="platforms"><a class="header" href="#platforms">Platforms</a></h2>
<p>We take pride in supporting many operating systems and architectures.</p>
<p><strong>Tip:</strong>
For Windows, Microsoft provides some images (VMWare, Hyper-V, VirtualBox and Parallels)
for development:
<p>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 <code>#[cfg(...)]</code> attributes to create platform dependent features.</p>
<p><strong>Tip:</strong> For Windows, Microsoft provides some images (VMWare, Hyper-V,
VirtualBox and Parallels) for development:
<a href="https://developer.microsoft.com/windows/downloads/virtual-machines/">https://developer.microsoft.com/windows/downloads/virtual-machines/</a></p>
<h2 id="tools"><a class="header" href="#tools">Tools</a></h2>
<p>We have an extensive CI that will check your code before it can be merged. This
section explains how to run those checks locally to avoid waiting for the CI.</p>
<h3 id="pre-commit-hooks"><a class="header" href="#pre-commit-hooks">pre-commit hooks</a></h3>
<p>A configuration for <code>pre-commit</code> is provided in the repository. It allows
automatically checking every git commit you make to ensure it compiles, and
passes <code>clippy</code> and <code>rustfmt</code> without warnings.</p>
<p>To use the provided hook:</p>
<ol>
<li><a href="https://pre-commit.com/#install">Install <code>pre-commit</code></a></li>
<li>Run <code>pre-commit install</code> while in the repository directory</li>
</ol>
<p>Your git commits will then automatically be checked. If a check fails, an error
message will explain why, and your commit will be canceled. You can then make
the suggested changes, and run <code>git commit ...</code> again.</p>
<h3 id="clippy"><a class="header" href="#clippy">clippy</a></h3>
<pre><code class="language-shell">cargo clippy --all-targets --all-features
</code></pre>
<p>The <code>msrv</code> key in the clippy configuration file <code>clippy.toml</code> is used to disable
lints pertaining to newer features by specifying the minimum supported Rust
version (MSRV).</p>
<h3 id="rustfmt"><a class="header" href="#rustfmt">rustfmt</a></h3>
<pre><code class="language-shell">cargo fmt --all
</code></pre>
<h3 id="cargo-deny"><a class="header" href="#cargo-deny">cargo-deny</a></h3>
<p>This project uses <a href="https://github.com/EmbarkStudios/cargo-deny/">cargo-deny</a> to
detect duplicate dependencies, checks licenses, etc. To run it locally, first
install it and then run with:</p>
<pre><code>cargo deny --all-features check all
</code></pre>
<h3 id="markdown-linter"><a class="header" href="#markdown-linter">Markdown linter</a></h3>
<p>We use <a href="https://github.com/DavidAnson/markdownlint">markdownlint</a> to lint the
Markdown files in the repository.</p>
<h3 id="spell-checker"><a class="header" href="#spell-checker">Spell checker</a></h3>
<p>We use <code>cspell</code> as spell checker for all files in the project. If you are using
VS Code, you can install the
<a href="https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker">code spell checker</a>
extension to enable spell checking within your editor. Otherwise, you can
install <a href="https://cspell.org/">cspell</a> separately.</p>
<p>If you want to make the spell checker ignore a word, you can add</p>
<pre><pre class="playground"><code class="language-rust"><span class="boring">#![allow(unused)]
</span><span class="boring">fn main() {
</span>// spell-checker:ignore word_to_ignore
<span class="boring">}</span></code></pre></pre>
<p>at the top of the file.</p>
<h2 id="testing"><a class="header" href="#testing">Testing</a></h2>
<p>Testing can be done using either Cargo or <code>make</code>.</p>
<h3 id="testing-with-cargo"><a class="header" href="#testing-with-cargo">Testing with Cargo</a></h3>
<p>Just like with building, we follow the standard procedure for testing using
Cargo:</p>
<pre><code class="language-shell">cargo test
</code></pre>
<p>By default, <code>cargo test</code> only runs the common programs. To run also platform
specific tests, run:</p>
<pre><code class="language-shell">cargo test --features unix
</code></pre>
<p>If you would prefer to test a select few utilities:</p>
<pre><code class="language-shell">cargo test --features &quot;chmod mv tail&quot; --no-default-features
</code></pre>
<p>If you also want to test the core utilities:</p>
<pre><code class="language-shell">cargo test -p uucore -p coreutils
</code></pre>
<p>To debug:</p>
<pre><code class="language-shell">gdb --args target/debug/coreutils ls
(gdb) b ls.rs:79
(gdb) run
</code></pre>
<h3 id="testing-with-gnu-make"><a class="header" href="#testing-with-gnu-make">Testing with GNU Make</a></h3>
<p>To simply test all available utilities:</p>
<pre><code class="language-shell">make test
</code></pre>
<p>To test all but a few of the available utilities:</p>
<pre><code class="language-shell">make SKIP_UTILS='UTILITY_1 UTILITY_2' test
</code></pre>
<p>To test only a few of the available utilities:</p>
<pre><code class="language-shell">make UTILS='UTILITY_1 UTILITY_2' test
</code></pre>
<p>To include tests for unimplemented behavior:</p>
<pre><code class="language-shell">make UTILS='UTILITY_1 UTILITY_2' SPEC=y test
</code></pre>
<h3 id="run-busybox-tests"><a class="header" href="#run-busybox-tests">Run Busybox Tests</a></h3>
<p>This testing functionality is only available on *nix operating systems and
requires <code>make</code>.</p>
<p>To run busybox tests for all utilities for which busybox has tests</p>
<pre><code class="language-shell">make busytest
</code></pre>
<p>To run busybox tests for a few of the available utilities</p>
<pre><code class="language-shell">make UTILS='UTILITY_1 UTILITY_2' busytest
</code></pre>
<p>To pass an argument like &quot;-v&quot; to the busybox test runtime</p>
<pre><code class="language-shell">make UTILS='UTILITY_1 UTILITY_2' RUNTEST_ARGS='-v' busytest
</code></pre>
<h3 id="comparing-with-gnu"><a class="header" href="#comparing-with-gnu">Comparing with GNU</a></h3>
<p>To run uutils against the GNU test suite locally, run the following commands:</p>
<pre><code class="language-shell">bash util/build-gnu.sh
bash util/run-gnu-test.sh
# To run a single test:
bash util/run-gnu-test.sh tests/touch/not-owner.sh # for example
# To run several tests:
bash util/run-gnu-test.sh tests/touch/not-owner.sh tests/rm/no-give-up.sh # for example
# If this is a perl (.pl) test, to run in debug:
DEBUG=1 bash util/run-gnu-test.sh tests/misc/sm3sum.pl
</code></pre>
<p>Note that it relies on individual utilities (not the multicall binary).</p>
<h3 id="improving-the-gnu-compatibility"><a class="header" href="#improving-the-gnu-compatibility">Improving the GNU compatibility</a></h3>
<p>The Python script <code>./util/remaining-gnu-error.py</code> shows the list of failing
tests in the CI.</p>
<p>To improve the GNU compatibility, the following process is recommended:</p>
<ol>
<li>Identify a test (the smaller, the better) on a program that you understand or
is easy to understand. You can use the <code>./util/remaining-gnu-error.py</code> script
to help with this decision.</li>
<li>Build both the GNU and Rust coreutils using: <code>bash util/build-gnu.sh</code></li>
<li>Run the test with <code>bash util/run-gnu-test.sh &lt;your test&gt;</code></li>
<li>Start to modify <code>&lt;your test&gt;</code> to understand what is wrong. Examples:
<ol>
<li>Add <code>set -v</code> to have the bash verbose mode</li>
<li>Add <code>echo $?</code> where needed</li>
<li>When the variable <code>fail</code> is used in the test, <code>echo $fail</code> to see when the
test started to fail</li>
<li>Bump the content of the output (ex: <code>cat err</code>)</li>
<li>...</li>
</ol>
</li>
<li>Or, if the test is simple, extract the relevant information to create a new
test case running both GNU &amp; Rust implementation</li>
<li>Start to modify the Rust implementation to match the expected behavior</li>
<li>Add a test to make sure that we don't regress (our test suite is super quick)</li>
</ol>
<h2 id="commit-messages"><a class="header" href="#commit-messages">Commit messages</a></h2>
<p>To help the project maintainers review pull requests from contributors across
numerous utilities, the team has settled on conventions for commit messages.</p>
<p>From <a href="http://git-scm.com/book/ch5-2.html">http://git-scm.com/book/ch5-2.html</a>:</p>
<pre><code>Short (50 chars or less) summary of changes
<p>From <a href="https://git-scm.com/book/ch5-2.html">https://git-scm.com/book/ch5-2.html</a>:</p>
<pre><code>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 can get confused if you run the
the body entirely); tools like rebase will confuse you if you run the
two together.
Write your commit message in the imperative: &quot;Fix bug&quot; and not &quot;Fixed bug&quot;
or &quot;Fixes bug.&quot; 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, preceded by a
- 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
</code></pre>
<p>Furthermore, here are a few examples for a summary line:</p>
<ul>
@@ -619,12 +746,23 @@ lines for non-utility modules include:</p>
</code></pre>
<pre><code>gitignore: add temporary files
</code></pre>
<h2 id="cargo-deny"><a class="header" href="#cargo-deny">cargo-deny</a></h2>
<p>This project uses <a href="https://github.com/EmbarkStudios/cargo-deny/">cargo-deny</a> to
detect duplicate dependencies, checks licenses, etc. To run it locally, first
install it and then run with:</p>
<pre><code>cargo deny --all-features check all
<h2 id="code-coverage"><a class="header" href="#code-coverage">Code coverage</a></h2>
<!-- spell-checker:ignore (flags) Ccodegen Coverflow Cpanic Zinstrument Zpanic -->
<p>Code coverage report can be generated using <a href="https://github.com/mozilla/grcov">grcov</a>.</p>
<h3 id="using-nightly-rust"><a class="header" href="#using-nightly-rust">Using Nightly Rust</a></h3>
<p>To generate <a href="https://github.com/mozilla/grcov#example-how-to-generate-gcda-files-for-a-rust-project">gcov-based</a> coverage report</p>
<pre><code class="language-shell">export CARGO_INCREMENTAL=0
export RUSTFLAGS=&quot;-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort&quot;
export RUSTDOCFLAGS=&quot;-Cpanic=abort&quot;
cargo build &lt;options...&gt; # e.g., --features feat_os_unix
cargo test &lt;options...&gt; # e.g., --features feat_os_unix test_pathchk
grcov . -s . --binary-path ./target/debug/ -t html --branch --ignore-not-existing --ignore build.rs --excl-br-line &quot;^\s*((debug_)?assert(_eq|_ne)?\#\[derive\()&quot; -o ./target/debug/coverage/
# open target/debug/coverage/index.html in browser
</code></pre>
<p>if changes are not reflected in the report then run <code>cargo clean</code> and run the above commands.</p>
<h3 id="using-stable-rust"><a class="header" href="#using-stable-rust">Using Stable Rust</a></h3>
<p>If you are using stable version of Rust that doesn't enable code coverage instrumentation by default
then add <code>-Z-Zinstrument-coverage</code> flag to <code>RUSTFLAGS</code> env variable specified above.</p>
<h2 id="other-implementations"><a class="header" href="#other-implementations">Other implementations</a></h2>
<p>The Coreutils have different implementations, with different levels of completions:</p>
<ul>
+1 -1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long