mirror of
https://github.com/uutils/coreutils
synced 2024-11-17 02:08:09 +00:00
Merge pull request #2148 from jhscheer/pinky2clap
pinky: move from getopts to clap (#2123)
This commit is contained in:
commit
bffcb431b5
3 changed files with 132 additions and 63 deletions
|
@ -17,6 +17,7 @@ path = "src/pinky.rs"
|
|||
[dependencies]
|
||||
uucore = { version=">=0.0.8", package="uucore", path="../../uucore", features=["utmpx", "entries"] }
|
||||
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }
|
||||
clap = "2.33.3"
|
||||
|
||||
[[bin]]
|
||||
name = "pinky"
|
||||
|
|
|
@ -19,67 +19,110 @@ use std::io::BufReader;
|
|||
use std::fs::File;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use std::path::PathBuf;
|
||||
use uucore::InvalidEncodingHandling;
|
||||
|
||||
static SYNTAX: &str = "[OPTION]... [USER]...";
|
||||
static SUMMARY: &str = "A lightweight 'finger' program; print user information.";
|
||||
|
||||
const BUFSIZE: usize = 1024;
|
||||
|
||||
static VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
static ABOUT: &str = "pinky - lightweight finger";
|
||||
|
||||
mod options {
|
||||
pub const LONG_FORMAT: &str = "long_format";
|
||||
pub const OMIT_HOME_DIR: &str = "omit_home_dir";
|
||||
pub const OMIT_PROJECT_FILE: &str = "omit_project_file";
|
||||
pub const OMIT_PLAN_FILE: &str = "omit_plan_file";
|
||||
pub const SHORT_FORMAT: &str = "short_format";
|
||||
pub const OMIT_HEADINGS: &str = "omit_headings";
|
||||
pub const OMIT_NAME: &str = "omit_name";
|
||||
pub const OMIT_NAME_HOST: &str = "omit_name_host";
|
||||
pub const OMIT_NAME_HOST_TIME: &str = "omit_name_host_time";
|
||||
pub const USER: &str = "user";
|
||||
}
|
||||
|
||||
fn get_usage() -> String {
|
||||
format!("{0} [OPTION]... [USER]...", executable!())
|
||||
}
|
||||
|
||||
fn get_long_usage() -> String {
|
||||
format!(
|
||||
"A lightweight 'finger' program; print user information.\n\
|
||||
The utmp file will be {}.",
|
||||
utmpx::DEFAULT_FILE
|
||||
)
|
||||
}
|
||||
|
||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||
let args = args
|
||||
.collect_str(InvalidEncodingHandling::Ignore)
|
||||
.accept_any();
|
||||
|
||||
let long_help = &format!(
|
||||
"
|
||||
-l produce long format output for the specified USERs
|
||||
-b omit the user's home directory and shell in long format
|
||||
-h omit the user's project file in long format
|
||||
-p omit the user's plan file in long format
|
||||
-s do short format output, this is the default
|
||||
-f omit the line of column headings in short format
|
||||
-w omit the user's full name in short format
|
||||
-i omit the user's full name and remote host in short format
|
||||
-q omit the user's full name, remote host and idle time
|
||||
in short format
|
||||
--help display this help and exit
|
||||
--version output version information and exit
|
||||
let usage = get_usage();
|
||||
let after_help = get_long_usage();
|
||||
|
||||
The utmp file will be {}",
|
||||
utmpx::DEFAULT_FILE
|
||||
);
|
||||
let mut opts = app!(SYNTAX, SUMMARY, &long_help);
|
||||
opts.optflag(
|
||||
"l",
|
||||
"",
|
||||
"produce long format output for the specified USERs",
|
||||
);
|
||||
opts.optflag(
|
||||
"b",
|
||||
"",
|
||||
"omit the user's home directory and shell in long format",
|
||||
);
|
||||
opts.optflag("h", "", "omit the user's project file in long format");
|
||||
opts.optflag("p", "", "omit the user's plan file in long format");
|
||||
opts.optflag("s", "", "do short format output, this is the default");
|
||||
opts.optflag("f", "", "omit the line of column headings in short format");
|
||||
opts.optflag("w", "", "omit the user's full name in short format");
|
||||
opts.optflag(
|
||||
"i",
|
||||
"",
|
||||
"omit the user's full name and remote host in short format",
|
||||
);
|
||||
opts.optflag(
|
||||
"q",
|
||||
"",
|
||||
"omit the user's full name, remote host and idle time in short format",
|
||||
);
|
||||
opts.optflag("", "help", "display this help and exit");
|
||||
opts.optflag("", "version", "output version information and exit");
|
||||
let matches = App::new(executable!())
|
||||
.version(VERSION)
|
||||
.about(ABOUT)
|
||||
.usage(&usage[..])
|
||||
.after_help(&after_help[..])
|
||||
.arg(
|
||||
Arg::with_name(options::LONG_FORMAT)
|
||||
.short("l")
|
||||
.requires(options::USER)
|
||||
.help("produce long format output for the specified USERs"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::OMIT_HOME_DIR)
|
||||
.short("b")
|
||||
.help("omit the user's home directory and shell in long format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::OMIT_PROJECT_FILE)
|
||||
.short("h")
|
||||
.help("omit the user's project file in long format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::OMIT_PLAN_FILE)
|
||||
.short("p")
|
||||
.help("omit the user's plan file in long format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::SHORT_FORMAT)
|
||||
.short("s")
|
||||
.help("do short format output, this is the default"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::OMIT_HEADINGS)
|
||||
.short("f")
|
||||
.help("omit the line of column headings in short format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::OMIT_NAME)
|
||||
.short("w")
|
||||
.help("omit the user's full name in short format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::OMIT_NAME_HOST)
|
||||
.short("i")
|
||||
.help("omit the user's full name and remote host in short format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::OMIT_NAME_HOST_TIME)
|
||||
.short("q")
|
||||
.help("omit the user's full name, remote host and idle time in short format"),
|
||||
)
|
||||
.arg(
|
||||
Arg::with_name(options::USER)
|
||||
.takes_value(true)
|
||||
.multiple(true),
|
||||
)
|
||||
.get_matches_from(args);
|
||||
|
||||
let matches = opts.parse(args);
|
||||
let users: Vec<String> = matches
|
||||
.values_of(options::USER)
|
||||
.map(|v| v.map(ToString::to_string).collect())
|
||||
.unwrap_or_default();
|
||||
|
||||
// If true, display the hours:minutes since each user has touched
|
||||
// the keyboard, or blank if within the last minute, or days followed
|
||||
|
@ -87,45 +130,40 @@ The utmp file will be {}",
|
|||
let mut include_idle = true;
|
||||
|
||||
// If true, display a line at the top describing each field.
|
||||
let include_heading = !matches.opt_present("f");
|
||||
let include_heading = !matches.is_present(options::OMIT_HEADINGS);
|
||||
|
||||
// if true, display the user's full name from pw_gecos.
|
||||
let mut include_fullname = true;
|
||||
|
||||
// if true, display the user's ~/.project file when doing long format.
|
||||
let include_project = !matches.opt_present("h");
|
||||
let include_project = !matches.is_present(options::OMIT_PROJECT_FILE);
|
||||
|
||||
// if true, display the user's ~/.plan file when doing long format.
|
||||
let include_plan = !matches.opt_present("p");
|
||||
let include_plan = !matches.is_present(options::OMIT_PLAN_FILE);
|
||||
|
||||
// if true, display the user's home directory and shell
|
||||
// when doing long format.
|
||||
let include_home_and_shell = !matches.opt_present("b");
|
||||
let include_home_and_shell = !matches.is_present(options::OMIT_HOME_DIR);
|
||||
|
||||
// if true, use the "short" output format.
|
||||
let do_short_format = !matches.opt_present("l");
|
||||
let do_short_format = !matches.is_present(options::LONG_FORMAT);
|
||||
|
||||
/* if true, display the ut_host field. */
|
||||
let mut include_where = true;
|
||||
|
||||
if matches.opt_present("w") {
|
||||
if matches.is_present(options::OMIT_NAME) {
|
||||
include_fullname = false;
|
||||
}
|
||||
if matches.opt_present("i") {
|
||||
if matches.is_present(options::OMIT_NAME_HOST) {
|
||||
include_fullname = false;
|
||||
include_where = false;
|
||||
}
|
||||
if matches.opt_present("q") {
|
||||
if matches.is_present(options::OMIT_NAME_HOST_TIME) {
|
||||
include_fullname = false;
|
||||
include_idle = false;
|
||||
include_where = false;
|
||||
}
|
||||
|
||||
if !do_short_format && matches.free.is_empty() {
|
||||
show_usage_error!("no username specified; at least one must be specified when using -l");
|
||||
return 1;
|
||||
}
|
||||
|
||||
let pk = Pinky {
|
||||
include_idle,
|
||||
include_heading,
|
||||
|
@ -134,7 +172,7 @@ The utmp file will be {}",
|
|||
include_plan,
|
||||
include_home_and_shell,
|
||||
include_where,
|
||||
names: matches.free,
|
||||
names: users,
|
||||
};
|
||||
|
||||
if do_short_format {
|
||||
|
|
|
@ -34,6 +34,36 @@ fn test_long_format() {
|
|||
));
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_long_format_multiple_users() {
|
||||
let scene = TestScenario::new(util_name!());
|
||||
|
||||
let expected = scene
|
||||
.cmd_keepenv(util_name!())
|
||||
.env("LANGUAGE", "C")
|
||||
.arg("-l")
|
||||
.arg("root")
|
||||
.arg("root")
|
||||
.arg("root")
|
||||
.succeeds();
|
||||
|
||||
scene
|
||||
.ucmd()
|
||||
.arg("-l")
|
||||
.arg("root")
|
||||
.arg("root")
|
||||
.arg("root")
|
||||
.succeeds()
|
||||
.stdout_is(expected.stdout_str());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_long_format_wo_user() {
|
||||
// "no username specified; at least one must be specified when using -l"
|
||||
new_ucmd!().arg("-l").fails().code_is(1);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[test]
|
||||
fn test_short_format_i() {
|
||||
|
|
Loading…
Reference in a new issue