who: update to clap 4

This commit is contained in:
Terts Diepraam 2022-10-01 12:22:59 +02:00
parent 92c4b32eeb
commit 53567deb0f
3 changed files with 49 additions and 44 deletions

View file

@ -15,7 +15,7 @@ edition = "2021"
path = "src/who.rs" path = "src/who.rs"
[dependencies] [dependencies]
clap = { version = "3.2", features = ["wrap_help", "cargo"] } clap = { version = "4.0", features = ["wrap_help", "cargo"] }
uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["utmpx"] } uucore = { version=">=0.0.16", package="uucore", path="../../uucore", features=["utmpx"] }
[[bin]] [[bin]]

View file

@ -12,7 +12,7 @@ use uucore::error::{FromIo, UResult};
use uucore::libc::{ttyname, STDIN_FILENO, S_IWGRP}; use uucore::libc::{ttyname, STDIN_FILENO, S_IWGRP};
use uucore::utmpx::{self, time, Utmpx}; use uucore::utmpx::{self, time, Utmpx};
use clap::{crate_version, Arg, Command}; use clap::{crate_version, Arg, ArgAction, Command};
use std::borrow::Cow; use std::borrow::Cow;
use std::ffi::CStr; use std::ffi::CStr;
use std::fmt::Write; use std::fmt::Write;
@ -58,10 +58,8 @@ fn get_long_usage() -> String {
pub fn uumain(args: impl uucore::Args) -> UResult<()> { pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let args = args.collect_ignore(); let args = args.collect_ignore();
let after_help = get_long_usage();
let matches = uu_app() let matches = uu_app()
.after_help(&after_help[..]) .after_help(get_long_usage())
.try_get_matches_from(args)?; .try_get_matches_from(args)?;
let files: Vec<String> = matches let files: Vec<String> = matches
@ -70,39 +68,39 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
.unwrap_or_default(); .unwrap_or_default();
// If true, attempt to canonicalize hostnames via a DNS lookup. // If true, attempt to canonicalize hostnames via a DNS lookup.
let do_lookup = matches.contains_id(options::LOOKUP); let do_lookup = matches.get_flag(options::LOOKUP);
// If true, display only a list of usernames and count of // If true, display only a list of usernames and count of
// the users logged on. // the users logged on.
// Ignored for 'who am i'. // Ignored for 'who am i'.
let short_list = matches.contains_id(options::COUNT); let short_list = matches.get_flag(options::COUNT);
let all = matches.contains_id(options::ALL); let all = matches.get_flag(options::ALL);
// If true, display a line at the top describing each field. // If true, display a line at the top describing each field.
let include_heading = matches.contains_id(options::HEADING); let include_heading = matches.get_flag(options::HEADING);
// If true, display a '+' for each user if mesg y, a '-' if mesg n, // If true, display a '+' for each user if mesg y, a '-' if mesg n,
// or a '?' if their tty cannot be statted. // or a '?' if their tty cannot be statted.
let include_mesg = all || matches.contains_id(options::MESG) || matches.contains_id("w"); let include_mesg = all || matches.get_flag(options::MESG);
// If true, display the last boot time. // If true, display the last boot time.
let need_boottime = all || matches.contains_id(options::BOOT); let need_boottime = all || matches.get_flag(options::BOOT);
// If true, display dead processes. // If true, display dead processes.
let need_deadprocs = all || matches.contains_id(options::DEAD); let need_deadprocs = all || matches.get_flag(options::DEAD);
// If true, display processes waiting for user login. // If true, display processes waiting for user login.
let need_login = all || matches.contains_id(options::LOGIN); let need_login = all || matches.get_flag(options::LOGIN);
// If true, display processes started by init. // If true, display processes started by init.
let need_initspawn = all || matches.contains_id(options::PROCESS); let need_initspawn = all || matches.get_flag(options::PROCESS);
// If true, display the last clock change. // If true, display the last clock change.
let need_clockchange = all || matches.contains_id(options::TIME); let need_clockchange = all || matches.get_flag(options::TIME);
// If true, display the current runlevel. // If true, display the current runlevel.
let need_runlevel = all || matches.contains_id(options::RUNLEVEL); let need_runlevel = all || matches.get_flag(options::RUNLEVEL);
let use_defaults = !(all let use_defaults = !(all
|| need_boottime || need_boottime
@ -111,10 +109,10 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|| need_initspawn || need_initspawn
|| need_runlevel || need_runlevel
|| need_clockchange || need_clockchange
|| matches.contains_id(options::USERS)); || matches.get_flag(options::USERS));
// If true, display user processes. // If true, display user processes.
let need_users = all || matches.contains_id(options::USERS) || use_defaults; let need_users = all || matches.get_flag(options::USERS) || use_defaults;
// If true, display the hours:minutes since each user has touched // If true, display the hours:minutes since each user has touched
// the keyboard, or "." if within the last minute, or "old" if // the keyboard, or "." if within the last minute, or "old" if
@ -128,7 +126,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let short_output = !include_exit && use_defaults; let short_output = !include_exit && use_defaults;
// If true, display info only for the controlling tty. // If true, display info only for the controlling tty.
let my_line_only = matches.contains_id(options::ONLY_HOSTNAME_USER) || files.len() == 2; let my_line_only = matches.get_flag(options::ONLY_HOSTNAME_USER) || files.len() == 2;
let mut who = Who { let mut who = Who {
do_lookup, do_lookup,
@ -152,7 +150,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
who.exec() who.exec()
} }
pub fn uu_app<'a>() -> Command<'a> { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.version(crate_version!()) .version(crate_version!())
.about(ABOUT) .about(ABOUT)
@ -162,96 +160,103 @@ pub fn uu_app<'a>() -> Command<'a> {
Arg::new(options::ALL) Arg::new(options::ALL)
.long(options::ALL) .long(options::ALL)
.short('a') .short('a')
.help("same as -b -d --login -p -r -t -T -u"), .help("same as -b -d --login -p -r -t -T -u")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::BOOT) Arg::new(options::BOOT)
.long(options::BOOT) .long(options::BOOT)
.short('b') .short('b')
.help("time of last system boot"), .help("time of last system boot")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::DEAD) Arg::new(options::DEAD)
.long(options::DEAD) .long(options::DEAD)
.short('d') .short('d')
.help("print dead processes"), .help("print dead processes")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::HEADING) Arg::new(options::HEADING)
.long(options::HEADING) .long(options::HEADING)
.short('H') .short('H')
.help("print line of column headings"), .help("print line of column headings")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::LOGIN) Arg::new(options::LOGIN)
.long(options::LOGIN) .long(options::LOGIN)
.short('l') .short('l')
.help("print system login processes"), .help("print system login processes")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::LOOKUP) Arg::new(options::LOOKUP)
.long(options::LOOKUP) .long(options::LOOKUP)
.help("attempt to canonicalize hostnames via DNS"), .help("attempt to canonicalize hostnames via DNS")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::ONLY_HOSTNAME_USER) Arg::new(options::ONLY_HOSTNAME_USER)
.short('m') .short('m')
.help("only hostname and user associated with stdin"), .help("only hostname and user associated with stdin")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::PROCESS) Arg::new(options::PROCESS)
.long(options::PROCESS) .long(options::PROCESS)
.short('p') .short('p')
.help("print active processes spawned by init"), .help("print active processes spawned by init")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::COUNT) Arg::new(options::COUNT)
.long(options::COUNT) .long(options::COUNT)
.short('q') .short('q')
.help("all login names and number of users logged on"), .help("all login names and number of users logged on")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::RUNLEVEL) Arg::new(options::RUNLEVEL)
.long(options::RUNLEVEL) .long(options::RUNLEVEL)
.short('r') .short('r')
.help(RUNLEVEL_HELP), .help(RUNLEVEL_HELP)
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::SHORT) Arg::new(options::SHORT)
.long(options::SHORT) .long(options::SHORT)
.short('s') .short('s')
.help("print only name, line, and time (default)"), .help("print only name, line, and time (default)")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::TIME) Arg::new(options::TIME)
.long(options::TIME) .long(options::TIME)
.short('t') .short('t')
.help("print last system clock change"), .help("print last system clock change")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::USERS) Arg::new(options::USERS)
.long(options::USERS) .long(options::USERS)
.short('u') .short('u')
.help("list users logged in"), .help("list users logged in")
.action(ArgAction::SetTrue),
) )
.arg( .arg(
Arg::new(options::MESG) Arg::new(options::MESG)
.long(options::MESG) .long(options::MESG)
.short('T') .short('T')
// .visible_short_alias('w') // TODO: requires clap "3.0.0-beta.2" .visible_short_alias('w')
.visible_aliases(&["message", "writable"]) .visible_aliases(&["message", "writable"])
.help("add user's message status as +, - or ?"), .help("add user's message status as +, - or ?")
) .action(ArgAction::SetTrue),
.arg(
Arg::new("w") // work around for `Arg::visible_short_alias`
.short('w')
.help("same as -T"),
) )
.arg( .arg(
Arg::new(options::FILE) Arg::new(options::FILE)
.takes_value(true) .num_args(1..=2)
.min_values(1)
.max_values(2)
.value_hint(clap::ValueHint::FilePath), .value_hint(clap::ValueHint::FilePath),
) )
} }

View file

@ -151,7 +151,7 @@ fn test_arg1_arg2() {
#[test] #[test]
fn test_too_many_args() { fn test_too_many_args() {
const EXPECTED: &str = const EXPECTED: &str =
"error: The value 'u' was provided to '<FILE>...' but it wasn't expecting any more values"; "error: The value 'u' was provided to '[FILE]...' but it wasn't expecting any more values";
let args = ["am", "i", "u"]; let args = ["am", "i", "u"];
new_ucmd!().args(&args).fails().stderr_contains(EXPECTED); new_ucmd!().args(&args).fails().stderr_contains(EXPECTED);