From 91edf285b21cc0b0ea144b93e206499dc05a8987 Mon Sep 17 00:00:00 2001 From: Ivan-Shaml <72102779+Ivan-Shaml@users.noreply.github.com> Date: Sun, 11 Jan 2026 11:20:46 +0200 Subject: [PATCH] uptime: Add -p, --pretty argument (#10143) * uptime: Add -p, --pretty argument Rebase of PR https://github.com/uutils/coreutils/pull/7910 All credits go to GitHub User: https://github.com/irbeam256 * Add localization for "up" --- docs/src/extensions.md | 4 +- src/uu/uptime/locales/en-US.ftl | 14 ++++++ src/uu/uptime/locales/fr-FR.ftl | 14 ++++++ src/uu/uptime/src/uptime.rs | 23 ++++++++- src/uucore/src/lib/features/uptime.rs | 70 +++++++++++++++++++++++---- tests/by-util/test_uptime.rs | 9 ++++ 6 files changed, 123 insertions(+), 11 deletions(-) diff --git a/docs/src/extensions.md b/docs/src/extensions.md index 80f89e060..458b9c41e 100644 --- a/docs/src/extensions.md +++ b/docs/src/extensions.md @@ -184,7 +184,9 @@ also provides a `-v`/`--verbose` flag. ## `uptime` -Similar to the proc-ps implementation and unlike GNU/Coreutils, `uptime` provides `-s`/`--since` to show since when the system is up. +Similar to the proc-ps implementation and unlike GNU/Coreutils, `uptime` provides: + * `-s`/`--since` to show since when the system is up + * `-p`/`--pretty` to display uptime in a pretty-printed format ## `base32/base64/basenc` diff --git a/src/uu/uptime/locales/en-US.ftl b/src/uu/uptime/locales/en-US.ftl index a9dd66667..84704c951 100644 --- a/src/uu/uptime/locales/en-US.ftl +++ b/src/uu/uptime/locales/en-US.ftl @@ -9,6 +9,7 @@ uptime-about-musl-warning = Warning: When built with musl libc, the `uptime` uti # Help messages uptime-help-since = system up since uptime-help-path = file to search boot time from +uptime-help-pretty = show uptime in pretty format # Error messages uptime-error-io = couldn't get boot time: { $error } @@ -18,6 +19,7 @@ uptime-error-couldnt-get-boot-time = couldn't get boot time # Output messages uptime-output-unknown-uptime = up ???? days ??:??, +uptime-output-up-text = up uptime-user-count = { $count -> [one] 1 user @@ -36,6 +38,18 @@ uptime-format = { $days -> [one] { $days } day, { $time } *[other] { $days } days { $time } } +uptime-format-pretty-min = { $min -> + [one] { $min } minute + *[other] { $min } minutes +} +uptime-format-pretty-hour = { $hour -> + [one] { $hour } hour + *[other] { $hour } hours +} +uptime-format-pretty-day = { $day -> + [one] { $day } day + *[other] { $day } days +} # Load average formatting uptime-lib-format-loadavg = load average: { $avg1 }, { $avg5 }, { $avg15 } diff --git a/src/uu/uptime/locales/fr-FR.ftl b/src/uu/uptime/locales/fr-FR.ftl index 623e3b0d7..895ec0892 100644 --- a/src/uu/uptime/locales/fr-FR.ftl +++ b/src/uu/uptime/locales/fr-FR.ftl @@ -9,6 +9,7 @@ uptime-about-musl-warning = Avertissement : Lorsque compilé avec musl libc, l'u # Messages d'aide uptime-help-since = système actif depuis uptime-help-path = fichier pour rechercher l'heure de démarrage +uptime-help-pretty = afficher le temps de disponibilité dans un format agréable # Messages d'erreur uptime-error-io = impossible d'obtenir l'heure de démarrage : { $error } @@ -18,6 +19,7 @@ uptime-error-couldnt-get-boot-time = impossible d'obtenir l'heure de démarrage # Messages de sortie uptime-output-unknown-uptime = actif ???? jours ??:??, +uptime-output-up-text = actif uptime-user-count = { $count -> [one] 1 utilisateur @@ -36,6 +38,18 @@ uptime-format = { $days -> [one] { $days } jour, { $time } *[other] { $days } jours { $time } } +uptime-format-pretty-min = { $min -> + [one] { $min } minute + *[other] { $min } minutes +} +uptime-format-pretty-hour = { $hour -> + [one] { $hour } heure + *[other] { $hour } heures +} +uptime-format-pretty-day = { $day -> + [one] { $day } jour + *[other] { $day } jours +} # Formatage de la charge moyenne uptime-lib-format-loadavg = charge moyenne : { $avg1 }, { $avg5 }, { $avg15 } diff --git a/src/uu/uptime/src/uptime.rs b/src/uu/uptime/src/uptime.rs index 89dc55d31..d8da60654 100644 --- a/src/uu/uptime/src/uptime.rs +++ b/src/uu/uptime/src/uptime.rs @@ -27,6 +27,7 @@ use uucore::utmpx::*; pub mod options { pub static SINCE: &str = "since"; pub static PATH: &str = "path"; + pub static PRETTY: &str = "pretty"; } #[derive(Debug, Error)] @@ -57,6 +58,8 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> { if matches.get_flag(options::SINCE) { uptime_since() + } else if matches.get_flag(options::PRETTY) { + pretty_print_uptime() } else if let Some(path) = file_path { uptime_with_file(path) } else { @@ -92,6 +95,13 @@ pub fn uu_app() -> Command { .value_parser(ValueParser::os_string()) .value_hint(ValueHint::AnyPath), ) + .arg( + Arg::new(options::PRETTY) + .short('p') + .long(options::PRETTY) + .help(translate!("uptime-help-pretty")) + .action(ArgAction::SetTrue), + ) } #[cfg(unix)] @@ -266,6 +276,17 @@ fn print_time() { } fn print_uptime(boot_time: Option) -> UResult<()> { - print!("up {}, ", get_formatted_uptime(boot_time)?); + let localized_text = translate!("uptime-output-up-text"); + let uptime_message = get_formatted_uptime(boot_time, OutputFormat::HumanReadable)?; + + print!("{localized_text} {uptime_message}, "); + Ok(()) +} + +fn pretty_print_uptime() -> UResult<()> { + let localized_text = translate!("uptime-output-up-text"); + let uptime_message = get_formatted_uptime(None, OutputFormat::PrettyPrint)?; + + println!("{localized_text} {uptime_message}"); Ok(()) } diff --git a/src/uucore/src/lib/features/uptime.rs b/src/uucore/src/lib/features/uptime.rs index 10b073ad5..6b869ef05 100644 --- a/src/uucore/src/lib/features/uptime.rs +++ b/src/uucore/src/lib/features/uptime.rs @@ -205,6 +205,56 @@ pub fn get_uptime(boot_time: Option) -> UResult { Err(UptimeError::SystemUptime)? } +/// The format used to display a FormattedUptime. +pub enum OutputFormat { + /// Typical `uptime` output (e.g. 2 days, 3:04). + HumanReadable, + + /// Pretty printed output (e.g. 2 days, 3 hours, 04 minutes). + PrettyPrint, +} + +struct FormattedUptime { + up_days: i64, + up_hours: i64, + up_mins: i64, +} + +impl FormattedUptime { + fn new(up_secs: i64) -> Self { + let up_days = up_secs / 86400; + let up_hours = (up_secs - (up_days * 86400)) / 3600; + let up_mins = (up_secs - (up_days * 86400) - (up_hours * 3600)) / 60; + + Self { + up_days, + up_hours, + up_mins, + } + } + + fn get_human_readable_uptime(&self) -> String { + translate!( + "uptime-format", + "days" => self.up_days, + "time" => format!("{:02}:{:02}", self.up_hours, self.up_mins)) + } + + fn get_pretty_print_uptime(&self) -> String { + let mut parts = Vec::new(); + if self.up_days > 0 { + parts.push(translate!("uptime-format-pretty-day", "day" => self.up_days)); + } + if self.up_hours > 0 { + parts.push(translate!("uptime-format-pretty-hour", "hour" => self.up_hours)); + } + if self.up_mins > 0 || parts.is_empty() { + parts.push(translate!("uptime-format-pretty-min", "min" => self.up_mins)); + } + parts.join(", ") + } +} + /// Get the system uptime /// /// # Arguments @@ -227,26 +277,28 @@ pub fn get_uptime(_boot_time: Option) -> UResult { /// # Arguments /// /// boot_time: Option - Manually specify the boot time, or None to try to get it from the system. +/// output_format: OutputFormat - Selects the format of the output string. /// /// # Returns /// /// Returns a UResult with the uptime in a human-readable format(e.g. "1 day, 3:45") if successful, otherwise an UptimeError. #[inline] -pub fn get_formatted_uptime(boot_time: Option) -> UResult { +pub fn get_formatted_uptime( + boot_time: Option, + output_format: OutputFormat, +) -> UResult { let up_secs = get_uptime(boot_time)?; if up_secs < 0 { Err(UptimeError::SystemUptime)?; } - let up_days = up_secs / 86400; - let up_hours = (up_secs - (up_days * 86400)) / 3600; - let up_mins = (up_secs - (up_days * 86400) - (up_hours * 3600)) / 60; - Ok(translate!( - "uptime-format", - "days" => up_days, - "time" => format!("{up_hours:02}:{up_mins:02}") - )) + let formatted_uptime = FormattedUptime::new(up_secs); + + match output_format { + OutputFormat::HumanReadable => Ok(formatted_uptime.get_human_readable_uptime()), + OutputFormat::PrettyPrint => Ok(formatted_uptime.get_pretty_print_uptime()), + } } /// Get the number of users currently logged in diff --git a/tests/by-util/test_uptime.rs b/tests/by-util/test_uptime.rs index 5c1d5d15f..e1d813cde 100644 --- a/tests/by-util/test_uptime.rs +++ b/tests/by-util/test_uptime.rs @@ -267,6 +267,15 @@ fn test_uptime_since() { new_ucmd!().arg("--since").succeeds().stdout_matches(&re); } +#[test] +fn test_uptime_pretty_print() { + new_ucmd!() + .arg("-p") + .succeeds() + .stdout_contains("up") + .stdout_contains("minute"); +} + /// Test uptime reliability on macOS with sysctl kern.boottime fallback. /// This addresses intermittent failures from issue #3621 by ensuring /// the command consistently succeeds when utmpx data is unavailable.