mirror of
https://github.com/uutils/coreutils.git
synced 2026-10-16 02:48:27 -07:00
diagnostics: let the caret rendering be compiled out
The renderer and its ariadne dependency sit behind the new feat_diagnostics cargo feature, on by default. Without it a no-op stand-in with the same API takes uucore::diagnostics' place, so the utilities need no cfg of their own: enabled() is always false and every caller falls back to its plain one-line message. Each utility keeps a crate-level `diagnostics` feature for standalone builds, the caret snapshot tests compile out with the renderer, and CI gains a Build/No-diagnostics job that runs the suite without the feature and fails if ariadne sneaks back into the dependency tree.
This commit is contained in:
1 parent
3850289841
commit
77741def26
30 files changed
+204
-46
No files matched your search
@@ -901,6 +901,50 @@ jobs:
|
||||
--features "${{ matrix.job.features }},openssl" \
|
||||
-E 'test(/^test_(md5sum|sha1sum|sha224sum|sha256sum|sha384sum|sha512sum|cksum)::/)'
|
||||
|
||||
test_no_diagnostics:
|
||||
name: Build/No-diagnostics
|
||||
needs: [ min_version, deps ]
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
persist-credentials: false
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: taiki-e/install-action@nextest
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Run sccache-cache
|
||||
id: sccache-setup
|
||||
uses: mozilla-actions/sccache-action@v0.0.11
|
||||
continue-on-error: true
|
||||
- name: Export sccache
|
||||
if: steps.sccache-setup.outcome == 'success'
|
||||
run: |
|
||||
echo "RUSTC_WRAPPER=sccache" >> $GITHUB_ENV
|
||||
echo "SCCACHE_GHA_ENABLED=true" >> $GITHUB_ENV
|
||||
# The caret diagnostics (`feat_diagnostics`) are on by default; packagers
|
||||
# who want the smaller dependency tree build with them off, so that build
|
||||
# must stay green. The caret snapshot tests are gated on the feature and
|
||||
# compile out; everything else runs as usual against the plain messages.
|
||||
- name: Test without the diagnostics feature
|
||||
shell: bash
|
||||
env:
|
||||
RUST_BACKTRACE: "1"
|
||||
run: |
|
||||
cargo nextest run --hide-progress-bar --profile ci \
|
||||
--no-default-features --features feat_os_unix
|
||||
# Confirm the feature actually compiles the renderer out. If ariadne is
|
||||
# still in the tree, some crate re-grew a hard dependency on it.
|
||||
# (`cargo tree -i` exits non-zero when the crate is absent from the graph.)
|
||||
- name: Verify ariadne is compiled out
|
||||
shell: bash
|
||||
run: |
|
||||
if cargo tree -p coreutils --no-default-features --features feat_os_unix -e normal -i ariadne 2>/dev/null; then
|
||||
echo "ERROR: ariadne is still in the dependency tree without feat_diagnostics"
|
||||
exit 1
|
||||
fi
|
||||
echo "OK: ariadne is not in the dependency tree"
|
||||
|
||||
test_selinux:
|
||||
name: Build/SELinux
|
||||
needs: [ min_version, deps ]
|
||||
|
||||
@@ -59,6 +59,9 @@ jobs:
|
||||
# Run host-compiled integration tests against the WASI binary.
|
||||
# Tests incompatible with WASI are annotated with
|
||||
# #[cfg_attr(wasi_runner, ignore)] in the test source files.
|
||||
# The binary above is built without default features, so it has no
|
||||
# caret diagnostics; the host test crate does have them, hence the
|
||||
# not(wasi_runner) in the cfg guarding every `mod diagnostics`.
|
||||
# TODO: add integration tests for these tools as WASI support is extended:
|
||||
# arch b2sum cat cksum csplit date dir dircolors fmt join
|
||||
# ls md5sum mkdir mv nproc pathchk pr printenv ptx pwd readlink
|
||||
|
||||
+15
-1
@@ -20,7 +20,7 @@ categories.workspace = true
|
||||
all-features = true
|
||||
|
||||
[features]
|
||||
default = ["feat_common_core"]
|
||||
default = ["feat_common_core", "feat_diagnostics"]
|
||||
## OS feature shortcodes
|
||||
unix = ["feat_os_unix"]
|
||||
windows = ["feat_os_windows"]
|
||||
@@ -62,6 +62,15 @@ uudoc = [
|
||||
"dep:zip",
|
||||
]
|
||||
## features
|
||||
# "feat_diagnostics" == render errors against the argument list with a caret
|
||||
# when stderr is a terminal. On by default; build with `--no-default-features`
|
||||
# (plus a `feat_os_*` selection) to compile the rendering — and its ariadne
|
||||
# dependency — out. Utilities then keep their plain one-line messages.
|
||||
# Enabling `uucore/diagnostics` is enough: cargo unifies features, so every
|
||||
# utility in the build sees it. The matching `diagnostics` feature each `uu_*`
|
||||
# crate declares is there for building that crate on its own, and is
|
||||
# deliberately not listed here.
|
||||
feat_diagnostics = ["uucore/diagnostics"]
|
||||
## Optional feature for stdbuf
|
||||
# "feat_external_libstdbuf" == use an external libstdbuf.so for stdbuf instead of embedding it
|
||||
feat_external_libstdbuf = ["stdbuf/feat_external_libstdbuf"]
|
||||
@@ -396,6 +405,11 @@ version = "0.10.0"
|
||||
|
||||
[workspace.dependencies]
|
||||
ansi-width = "0.1.0"
|
||||
# The diagnostics rewrite ariadne's output by row number, so a release that
|
||||
# changes the shape of a report is a breaking change here even when it is not
|
||||
# one for ariadne. `uucore`'s `the_rendered_report_has_the_row_shape_the_rewriting_assumes`
|
||||
# is what catches it; keep the bound tight enough that only patch releases
|
||||
# arrive without one running.
|
||||
ariadne = "0.6.0"
|
||||
base64-simd = "0.8"
|
||||
bigdecimal = "0.4"
|
||||
|
||||
Generated
-17
@@ -73,16 +73,6 @@ version = "1.4.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d036a3c4ab069c7b410a2ce876bd74808d2d0888a82667669f8e783a898bf1"
|
||||
|
||||
[[package]]
|
||||
name = "ariadne"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8454c8a44ce2cb9cc7e7fae67fc6128465b343b92c6631e94beca3c8d1524ea5"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arrayref"
|
||||
version = "0.3.9"
|
||||
@@ -2057,7 +2047,6 @@ dependencies = [
|
||||
name = "uucore"
|
||||
version = "0.10.0"
|
||||
dependencies = [
|
||||
"ariadne",
|
||||
"base64-simd",
|
||||
"bigdecimal",
|
||||
"blake2b_simd",
|
||||
@@ -2323,12 +2312,6 @@ dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.8.3"
|
||||
|
||||
@@ -18,18 +18,15 @@ doctest = false
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"diagnostics",
|
||||
"entries",
|
||||
"fs",
|
||||
"mode",
|
||||
"perms",
|
||||
] }
|
||||
uucore = { workspace = true, features = ["entries", "fs", "mode", "perms"] }
|
||||
fluent = { workspace = true }
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "redox")))'.dependencies]
|
||||
uucore = { workspace = true, features = ["safe-traversal"] }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ clap = { workspace = true }
|
||||
num-bigint = { workspace = true }
|
||||
num-traits = { workspace = true }
|
||||
onig = { workspace = true }
|
||||
uucore = { workspace = true, features = ["diagnostics", "i18n-collator"] }
|
||||
uucore = { workspace = true, features = ["i18n-collator"] }
|
||||
thiserror = { workspace = true }
|
||||
fluent = { workspace = true }
|
||||
|
||||
@@ -28,6 +28,9 @@ fluent = { workspace = true }
|
||||
divan = { workspace = true }
|
||||
uucore = { workspace = true, features = ["benchmark"] }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@ thiserror = { workspace = true }
|
||||
uucore = { workspace = true, default-features = true, features = [
|
||||
"backup-control",
|
||||
"buf-copy",
|
||||
"diagnostics",
|
||||
"fs",
|
||||
"mode",
|
||||
"perms",
|
||||
@@ -35,6 +34,7 @@ rustix = { workspace = true }
|
||||
selinux = { workspace = true, optional = true }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
selinux = ["dep:selinux", "uucore/selinux"]
|
||||
|
||||
[lints]
|
||||
|
||||
@@ -18,18 +18,14 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"diagnostics",
|
||||
"fs",
|
||||
"fsxattr",
|
||||
"mode",
|
||||
] }
|
||||
uucore = { workspace = true, features = ["fs", "fsxattr", "mode"] }
|
||||
fluent = { workspace = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
rustix = { workspace = true, features = ["process", "fs"] }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
selinux = ["uucore/selinux"]
|
||||
smack = ["uucore/smack"]
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["diagnostics", "fs", "mode"] }
|
||||
uucore = { workspace = true, features = ["fs", "mode"] }
|
||||
fluent = { workspace = true }
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
@@ -28,6 +28,7 @@ rustix = { workspace = true, features = ["fs", "process"] }
|
||||
libc = { workspace = true }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
selinux = ["uucore/selinux"]
|
||||
smack = ["uucore/smack"]
|
||||
|
||||
|
||||
@@ -19,11 +19,12 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["diagnostics", "fs", "mode"] }
|
||||
uucore = { workspace = true, features = ["fs", "mode"] }
|
||||
fluent = { workspace = true }
|
||||
nix = { workspace = true }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
selinux = ["uucore/selinux"]
|
||||
smack = ["uucore/smack"]
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ path = "src/numfmt.rs"
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"diagnostics",
|
||||
"parser",
|
||||
"ranges",
|
||||
"i18n-common",
|
||||
@@ -31,6 +30,9 @@ memchr = { workspace = true }
|
||||
divan = { workspace = true }
|
||||
uucore = { workspace = true, features = ["benchmark"] }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
||||
@@ -18,13 +18,12 @@ doctest = false
|
||||
|
||||
[dependencies]
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"diagnostics",
|
||||
"format",
|
||||
"quoting-style",
|
||||
] }
|
||||
uucore = { workspace = true, features = ["format", "quoting-style"] }
|
||||
fluent = { workspace = true }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ doctest = false
|
||||
|
||||
[features]
|
||||
default = ["i18n-collator"]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
i18n-collator = ["uucore/i18n-collator"]
|
||||
|
||||
[dependencies]
|
||||
@@ -34,7 +35,6 @@ self_cell = { workspace = true }
|
||||
tempfile = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
uucore = { workspace = true, features = [
|
||||
"diagnostics",
|
||||
"fs",
|
||||
"parser-size",
|
||||
"version-cmp",
|
||||
|
||||
@@ -20,7 +20,7 @@ clap = { workspace = true }
|
||||
fluent = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
uucore = { workspace = true, features = ["diagnostics", "process", "wide"] }
|
||||
uucore = { workspace = true, features = ["process", "wide"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
windows-sys = { workspace = true, features = [
|
||||
@@ -33,6 +33,9 @@ windows-sys = { workspace = true, features = [
|
||||
[dev-dependencies]
|
||||
tempfile = { workspace = true }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ doctest = false
|
||||
[dependencies]
|
||||
nom = { workspace = true }
|
||||
clap = { workspace = true }
|
||||
uucore = { workspace = true, features = ["diagnostics", "fs", "signals"] }
|
||||
uucore = { workspace = true, features = ["fs", "signals"] }
|
||||
fluent = { workspace = true }
|
||||
bytecount = { workspace = true, features = ["runtime-dispatch-simd"] }
|
||||
|
||||
@@ -28,6 +28,9 @@ divan = { workspace = true }
|
||||
rustix = { workspace = true, features = ["stdio", "fs"] }
|
||||
uucore = { workspace = true, features = ["benchmark"] }
|
||||
|
||||
[features]
|
||||
diagnostics = ["uucore/diagnostics"]
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
|
||||
@@ -175,7 +175,7 @@ i18n-datetime = [
|
||||
"jiff-icu",
|
||||
"jiff",
|
||||
]
|
||||
mode = ["diagnostics", "libc"]
|
||||
mode = ["libc"]
|
||||
perms = ["entries", "libc", "walkdir"]
|
||||
buf-copy = []
|
||||
parser-num = ["extendedbigdecimal", "num-traits"]
|
||||
|
||||
@@ -19,6 +19,11 @@ pub mod checksum;
|
||||
pub mod colors;
|
||||
#[cfg(feature = "diagnostics")]
|
||||
pub mod diagnostics;
|
||||
// Without the feature, a no-op stand-in keeps the API — and its callers —
|
||||
// compiling; they all fall back to their plain one-line messages.
|
||||
#[cfg(not(feature = "diagnostics"))]
|
||||
#[path = "features/diagnostics_stub.rs"]
|
||||
pub mod diagnostics;
|
||||
#[cfg(feature = "encoding")]
|
||||
pub mod encoding;
|
||||
#[cfg(feature = "extendedbigdecimal")]
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
// This file is part of the uutils coreutils package.
|
||||
//
|
||||
// For the full copyright and license information, please view the LICENSE
|
||||
// file that was distributed with this source code.
|
||||
|
||||
//! No-op stand-in for the `diagnostics` module, compiled when the
|
||||
//! `diagnostics` cargo feature is off.
|
||||
//!
|
||||
//! It mirrors the real API so callers need no `cfg` of their own:
|
||||
//! [`enabled`] is always `false`, the locators find nothing and the render
|
||||
//! methods render nothing, so every caller falls back to the plain one-line
|
||||
//! message it would print anywhere but a terminal.
|
||||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::ops::Range;
|
||||
|
||||
/// Always `false`: rendering is compiled out.
|
||||
pub fn enabled() -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Always `None`: rendering is compiled out.
|
||||
pub fn capture(_args: &[OsString]) -> Option<Vec<OsString>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Always `None`: rendering is compiled out.
|
||||
pub fn operands(_args: &[OsString]) -> Option<Vec<OsString>> {
|
||||
None
|
||||
}
|
||||
|
||||
/// A snapshot of nothing: it finds nothing and renders nothing.
|
||||
///
|
||||
/// Deliberately derives nothing the real `Snapshot` does not, so that what a
|
||||
/// caller may do with one does not depend on whether the feature is on.
|
||||
pub struct Snapshot;
|
||||
|
||||
#[allow(clippy::unused_self)]
|
||||
impl Snapshot {
|
||||
pub fn new<S: AsRef<OsStr>>(_args: &[S]) -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn with_program<S: AsRef<OsStr>>(_args: &[S]) -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn from_bytes<S: AsRef<[u8]>>(_args: &[S]) -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
pub fn index_of(&self, _arg: &OsStr) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn index_of_value(
|
||||
&self,
|
||||
_operand: &str,
|
||||
_short: Option<char>,
|
||||
_long: Option<&str>,
|
||||
) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn index_of_positional(&self, _n: usize) -> Option<usize> {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&self,
|
||||
_index: usize,
|
||||
_message: &str,
|
||||
_label: Option<&str>,
|
||||
_help: Option<&str>,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
pub fn render_inside_at(
|
||||
&self,
|
||||
_index: usize,
|
||||
_operand: &str,
|
||||
_range: Range<usize>,
|
||||
_message: &str,
|
||||
_label: Option<&str>,
|
||||
_help: Option<&str>,
|
||||
) -> bool {
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,6 @@ pub use crate::features::char_width;
|
||||
pub use crate::features::checksum;
|
||||
#[cfg(feature = "colors")]
|
||||
pub use crate::features::colors;
|
||||
#[cfg(feature = "diagnostics")]
|
||||
pub use crate::features::diagnostics;
|
||||
#[cfg(feature = "encoding")]
|
||||
pub use crate::features::encoding;
|
||||
|
||||
@@ -1691,6 +1691,7 @@ fn test_chmod_symlink_two_links_same_dir() {
|
||||
// cSpell:enable
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "feat_diagnostics", not(wasi_runner)))]
|
||||
mod diagnostics {
|
||||
use super::*;
|
||||
#[cfg(unix)]
|
||||
|
||||
Loaded 20 of 30 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user