diff --git a/src/uu/uname/locales/en-US.ftl b/src/uu/uname/locales/en-US.ftl index b985518427d..608d49145c4 100644 --- a/src/uu/uname/locales/en-US.ftl +++ b/src/uu/uname/locales/en-US.ftl @@ -18,3 +18,14 @@ uname-help-machine = print the machine hardware name. uname-help-os = print the operating system name. uname-help-processor = print the processor type (non-portable) uname-help-hardware-platform = print the hardware platform (non-portable) +uname-help-all-labeled = like -a, print all information but one item per line, labeled. + +# Labels for --all-labeled +uname-label-kernel-name = Kernel name +uname-label-nodename = Node name +uname-label-kernel-release = Kernel release +uname-label-kernel-version = Kernel version +uname-label-machine = Machine +uname-label-processor = Processor +uname-label-hardware-platform = Hardware platform +uname-label-os = Operating system diff --git a/src/uu/uname/locales/fr-FR.ftl b/src/uu/uname/locales/fr-FR.ftl index fc48f3f8ba6..36b12f450f8 100644 --- a/src/uu/uname/locales/fr-FR.ftl +++ b/src/uu/uname/locales/fr-FR.ftl @@ -18,3 +18,14 @@ uname-help-machine = affiche le nom du matériel de la machine. uname-help-os = affiche le nom du système d'exploitation. uname-help-processor = affiche le type de processeur (non portable) uname-help-hardware-platform = affiche la plateforme matérielle (non portable) +uname-help-all-labeled = comme -a, affiche toutes les informations mais une par ligne, avec étiquette. + +# Étiquettes pour --all-labeled +uname-label-kernel-name = Nom du noyau +uname-label-nodename = Nom du nœud +uname-label-kernel-release = Version du noyau +uname-label-kernel-version = Version détaillée du noyau +uname-label-machine = Machine +uname-label-processor = Processeur +uname-label-hardware-platform = Plateforme matérielle +uname-label-os = Système d'exploitation diff --git a/src/uu/uname/src/uname.rs b/src/uu/uname/src/uname.rs index 1439bd6f7f2..ce04829b77d 100644 --- a/src/uu/uname/src/uname.rs +++ b/src/uu/uname/src/uname.rs @@ -3,13 +3,13 @@ // For the full copyright and license information, please view the LICENSE // file that was distributed with this source code. -// spell-checker:ignore (API) nodename osname sysname (options) mnrsv mnrsvo +// spell-checker:ignore (API) nodename osname sysname (options) mnrsv mnrsvo mnrsvoA use std::ffi::{OsStr, OsString}; use clap::{Arg, ArgAction, Command}; use platform_info::{PlatformInfo, PlatformInfoAPI, UNameAPI}; -use uucore::display::println_verbatim; +use uucore::display::{print_verbatim, println_verbatim}; use uucore::translate; use uucore::{ error::{UResult, USimpleError}, @@ -18,6 +18,7 @@ use uucore::{ pub mod options { pub static ALL: &str = "all"; + pub static ALL_LABELED: &str = "all-labeled"; pub static KERNEL_NAME: &str = "kernel-name"; pub static NODENAME: &str = "nodename"; pub static KERNEL_VERSION: &str = "kernel-version"; @@ -58,10 +59,35 @@ impl UNameOutput { .join(OsStr::new(" ")) } + fn display_labeled(&self) -> OsString { + let mut out = OsString::new(); + for (label, value) in [ + ("uname-label-kernel-name", self.kernel_name.as_ref()), + ("uname-label-nodename", self.nodename.as_ref()), + ("uname-label-kernel-release", self.kernel_release.as_ref()), + ("uname-label-kernel-version", self.kernel_version.as_ref()), + ("uname-label-machine", self.machine.as_ref()), + ("uname-label-processor", self.processor.as_ref()), + ( + "uname-label-hardware-platform", + self.hardware_platform.as_ref(), + ), + ("uname-label-os", self.os.as_ref()), + ] { + let Some(value) = value else { continue }; + out.push(translate!(label)); + out.push(": "); + out.push(value); + out.push("\n"); + } + out + } + pub fn new(opts: &Options) -> UResult { let uname = PlatformInfo::new() .map_err(|_e| USimpleError::new(1, translate!("uname-error-cannot-get-system-name")))?; let none = !(opts.all + || opts.all_labeled || opts.kernel_name || opts.nodename || opts.kernel_release @@ -71,21 +97,28 @@ impl UNameOutput { || opts.processor || opts.hardware_platform); - let kernel_name = - (opts.kernel_name || opts.all || none).then(|| uname.sysname().to_owned()); + let kernel_name = (opts.kernel_name || opts.all || opts.all_labeled || none) + .then(|| uname.sysname().to_owned()); - let nodename = (opts.nodename || opts.all).then(|| uname.nodename().to_owned()); + let nodename = + (opts.nodename || opts.all || opts.all_labeled).then(|| uname.nodename().to_owned()); - let kernel_release = (opts.kernel_release || opts.all).then(|| uname.release().to_owned()); + let kernel_release = (opts.kernel_release || opts.all || opts.all_labeled) + .then(|| uname.release().to_owned()); - let kernel_version = (opts.kernel_version || opts.all).then(|| uname.version().to_owned()); + let kernel_version = (opts.kernel_version || opts.all || opts.all_labeled) + .then(|| uname.version().to_owned()); - let machine = (opts.machine || opts.all).then(|| uname.machine().to_owned()); + let machine = + (opts.machine || opts.all || opts.all_labeled).then(|| uname.machine().to_owned()); - let os = (opts.os || opts.all).then(|| uname.osname().to_owned()); + let os = (opts.os || opts.all || opts.all_labeled).then(|| uname.osname().to_owned()); // This option is unsupported on modern Linux systems // See: https://lists.gnu.org/archive/html/bug-coreutils/2005-09/msg00063.html + // + // -a and -A omit an unknown processor or hardware platform, and since we never + // determine either one, they only ever show up when explicitly requested. let processor = opts.processor.then(|| translate!("uname-unknown").into()); // This option is unsupported on modern Linux systems @@ -109,6 +142,7 @@ impl UNameOutput { pub struct Options { pub all: bool, + pub all_labeled: bool, pub kernel_name: bool, pub nodename: bool, pub kernel_version: bool, @@ -125,6 +159,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { let options = Options { all: matches.get_flag(options::ALL), + all_labeled: matches.get_flag(options::ALL_LABELED), kernel_name: matches.get_flag(options::KERNEL_NAME), nodename: matches.get_flag(options::NODENAME), kernel_release: matches.get_flag(options::KERNEL_RELEASE), @@ -135,8 +170,13 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { os: matches.get_flag(options::OS), }; let output = UNameOutput::new(&options)?; - println_verbatim(output.display().as_os_str()) - .map_err(|e| USimpleError::new(1, e.to_string()))?; + if options.all_labeled { + print_verbatim(output.display_labeled().as_os_str()) + .map_err(|e| USimpleError::new(1, e.to_string()))?; + } else { + println_verbatim(output.display().as_os_str()) + .map_err(|e| USimpleError::new(1, e.to_string()))?; + } Ok(()) } @@ -154,6 +194,13 @@ pub fn uu_app() -> Command { .help(translate!("uname-help-all")) .action(ArgAction::SetTrue), ) + .arg( + Arg::new(options::ALL_LABELED) + .short('A') + .long(options::ALL_LABELED) + .help(translate!("uname-help-all-labeled")) + .action(ArgAction::SetTrue), + ) .arg( Arg::new(options::KERNEL_NAME) .short('s') diff --git a/tests/by-util/test_uname.rs b/tests/by-util/test_uname.rs index 25485f5c120..5eb58a7787b 100644 --- a/tests/by-util/test_uname.rs +++ b/tests/by-util/test_uname.rs @@ -134,3 +134,33 @@ fn test_uname_output_for_invisible_chars() { let result = new_ucmd!().arg("--all").succeeds(); assert_eq!(re.find(result.stdout_str().trim_end()), None); } + +#[test] +fn test_uname_all_labeled() { + let result = new_ucmd!().arg("-A").succeeds(); + let stdout = result.stdout_str(); + // One labeled "Label: value" line per item. Like GNU, an unknown processor or + // hardware platform is omitted, and we never determine either one. + assert_eq!(stdout.lines().count(), 6); + for label in [ + "Kernel name: ", + "Node name: ", + "Kernel release: ", + "Kernel version: ", + "Machine: ", + "Operating system: ", + ] { + assert!(stdout.contains(label), "missing {label:?}"); + } + assert!(!stdout.contains("Processor:")); + assert!(!stdout.contains("Hardware platform:")); +} + +#[test] +fn test_uname_all_labeled_long_flag() { + let short = new_ucmd!().arg("-A").succeeds(); + new_ucmd!() + .arg("--all-labeled") + .succeeds() + .stdout_is(short.stdout_str()); +} diff --git a/util/fetch-gnu.sh b/util/fetch-gnu.sh index fd7203228fd..e9b89e64f8b 100755 --- a/util/fetch-gnu.sh +++ b/util/fetch-gnu.sh @@ -6,8 +6,20 @@ curl -L "${repo}/releases/download/v${ver}/coreutils-${ver}.tar.xz" | tar --stri # TODO stop backporting tests from master at GNU coreutils > $ver backport=( cat/splice.sh # split tests + misc/uname-labeled.sh # uname -A/--all-labeled, added after $ver nproc/nproc-quota.sh # remove LD_PRELOAD ) for f in "${backport[@]}" do curl -L ${repo}/raw/refs/heads/master/tests/$f > tests/$f done + +# A test that does not exist in $ver at all is absent from its test list, so +# `make check` would silently never run it. Register those in both the automake +# input and the generated Makefile.in: configure derives Makefile from the +# latter, and build-gnu.sh deliberately keeps automake from re-running. +for f in "${backport[@]}"; do + grep -qF "tests/$f" tests/local.mk || + sed -i "s|^all_tests =.*|&\n tests/$f\t\t\t\t\\\\|" tests/local.mk + grep -qF "tests/$f" Makefile.in || + sed -i "s|^all_tests =.*|&\n tests/$f\t\t\t\t\\\\|" Makefile.in +done