1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-29 12:07:46 +00:00

refactor(stat): Move to clap

This commit is contained in:
Sylvestre Ledru 2020-10-26 22:24:58 +01:00
parent 5837bc4fc9
commit 1e37c29b1f
3 changed files with 99 additions and 88 deletions

2
Cargo.lock generated
View file

@ -2116,7 +2116,7 @@ dependencies = [
name = "uu_stat" name = "uu_stat"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
"uucore 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)", "uucore 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)",
"uucore_procs 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)", "uucore_procs 0.0.4 (git+https://github.com/uutils/uucore.git?branch=canary)",

View file

@ -15,7 +15,7 @@ edition = "2018"
path = "src/stat.rs" path = "src/stat.rs"
[dependencies] [dependencies]
getopts = "0.2.18" clap = "2.33"
time = "0.1.40" time = "0.1.40"
uucore = { version="0.0.4", package="uucore", git="https://github.com/uutils/uucore.git", branch="canary", features=["entries", "libc"] } uucore = { version="0.0.4", package="uucore", git="https://github.com/uutils/uucore.git", branch="canary", features=["entries", "libc"] }
uucore_procs = { version="0.0.4", package="uucore_procs", git="https://github.com/uutils/uucore.git", branch="canary" } uucore_procs = { version="0.0.4", package="uucore_procs", git="https://github.com/uutils/uucore.git", branch="canary" }

View file

@ -7,8 +7,7 @@
// spell-checker:ignore (ToDO) mtab fsext showfs otype fmtstr prec ftype blocksize nlink rdev fnodes fsid namelen blksize inodes fstype iosize statfs gnulib NBLOCKSIZE // spell-checker:ignore (ToDO) mtab fsext showfs otype fmtstr prec ftype blocksize nlink rdev fnodes fsid namelen blksize inodes fstype iosize statfs gnulib NBLOCKSIZE
extern crate getopts; extern crate clap;
use getopts::Options;
#[macro_use] #[macro_use]
mod fsext; mod fsext;
@ -18,6 +17,7 @@ pub use crate::fsext::*;
extern crate uucore; extern crate uucore;
use uucore::entries; use uucore::entries;
use clap::{App, Arg, ArgMatches};
use std::borrow::Cow; use std::borrow::Cow;
use std::convert::AsRef; use std::convert::AsRef;
use std::fs::File; use std::fs::File;
@ -86,9 +86,17 @@ macro_rules! print_adjusted {
}; };
} }
static NAME: &str = "stat"; static ABOUT: &str = "Display file or file system status.";
static VERSION: &str = env!("CARGO_PKG_VERSION"); static VERSION: &str = env!("CARGO_PKG_VERSION");
static OPT_DEREFERENCE: &str = "dereference";
static OPT_FILE_SYSTEM: &str = "file-system";
static OPT_FORMAT: &str = "format";
static OPT_PRINTF: &str = "printf";
static OPT_TERSE: &str = "terse";
static ARG_FILES: &str = "files";
const MOUNT_INFO: &str = "/etc/mtab"; const MOUNT_INFO: &str = "/etc/mtab";
pub const F_ALTER: u8 = 1; pub const F_ALTER: u8 = 1;
pub const F_ZERO: u8 = 1 << 1; pub const F_ZERO: u8 = 1 << 1;
@ -332,7 +340,6 @@ impl Stater {
let mut tokens = Vec::new(); let mut tokens = Vec::new();
let bound = fmtstr.len(); let bound = fmtstr.len();
let chars = fmtstr.chars().collect::<Vec<char>>(); let chars = fmtstr.chars().collect::<Vec<char>>();
let mut i = 0_usize; let mut i = 0_usize;
while i < bound { while i < bound {
match chars[i] { match chars[i] {
@ -453,16 +460,21 @@ impl Stater {
Ok(tokens) Ok(tokens)
} }
fn new(matches: getopts::Matches) -> Result<Stater, String> { fn new(matches: ArgMatches) -> Result<Stater, String> {
let fmtstr = if matches.opt_present("printf") { let files: Vec<String> = matches
matches.opt_str("printf").expect("Invalid format string") .values_of(ARG_FILES)
.map(|v| v.map(ToString::to_string).collect())
.unwrap_or_default();
let fmtstr = if matches.is_present(OPT_PRINTF) {
matches.value_of(OPT_PRINTF).expect("Invalid format string")
} else { } else {
matches.opt_str("format").unwrap_or_else(|| "".to_owned()) matches.value_of(OPT_FORMAT).unwrap_or_else(|| "")
}; };
let use_printf = matches.opt_present("printf"); let use_printf = matches.is_present(OPT_PRINTF);
let terse = matches.opt_present("terse"); let terse = matches.is_present(OPT_TERSE);
let showfs = matches.opt_present("file-system"); let showfs = matches.is_present(OPT_FILE_SYSTEM);
let default_tokens = if fmtstr.is_empty() { let default_tokens = if fmtstr.is_empty() {
Stater::generate_tokens(&Stater::default_fmt(showfs, terse, false), use_printf).unwrap() Stater::generate_tokens(&Stater::default_fmt(showfs, terse, false), use_printf).unwrap()
@ -491,10 +503,10 @@ impl Stater {
}; };
Ok(Stater { Ok(Stater {
follow: matches.opt_present("dereference"), follow: matches.is_present(OPT_DEREFERENCE),
showfs, showfs,
from_user: !fmtstr.is_empty(), from_user: !fmtstr.is_empty(),
files: matches.free, files,
default_tokens, default_tokens,
default_dev_tokens, default_dev_tokens,
mount_list, mount_list,
@ -873,76 +885,13 @@ impl Stater {
} }
} }
pub fn uumain(args: impl uucore::Args) -> i32 { fn get_usage() -> String {
let args = args.collect_str(); format!("{0} [OPTION]... FILE...", executable!())
let mut opts = Options::new();
opts.optflag("h", "help", "display this help and exit");
opts.optflag("", "version", "output version information and exit");
opts.optflag("L", "dereference", "follow links");
opts.optflag(
"f",
"file-system",
"display file system status instead of file status",
);
opts.optflag("t", "terse", "print the information in terse form");
// Omit the unused description as they are too long
opts.optopt("c", "format", "", "FORMAT");
opts.optopt("", "printf", "", "FORMAT");
let matches = match opts.parse(&args[1..]) {
Ok(m) => m,
Err(f) => {
show_usage_error!("{}", f);
return 1;
}
};
if matches.opt_present("help") {
return help();
} else if matches.opt_present("version") {
return version();
}
if matches.free.is_empty() {
show_usage_error!("missing operand");
return 1;
}
match Stater::new(matches) {
Ok(stater) => stater.exec(),
Err(e) => {
show_info!("{}", e);
1
}
}
} }
fn version() -> i32 { fn get_long_usage() -> String {
println!("{} {}", NAME, VERSION); String::from(
0 "
}
fn help() -> i32 {
let msg = format!(
r#"Usage: {} [OPTION]... FILE...
Display file or file system status.
Mandatory arguments to long options are mandatory for short options too.
-L, --dereference follow links
-f, --file-system display file system status instead of file status
-c --format=FORMAT use the specified FORMAT instead of the default;
output a newline after each use of FORMAT
--printf=FORMAT like --format, but interpret backslash escapes,
and do not output a mandatory trailing newline;
if you want a newline, include \n in FORMAT
-t, --terse print the information in terse form
--help display this help and exit
--version output version information and exit
The valid format sequences for files (without --file-system): The valid format sequences for files (without --file-system):
%a access rights in octal (note '#' and '0' printf flags) %a access rights in octal (note '#' and '0' printf flags)
@ -993,9 +942,71 @@ Valid format sequences for file systems:
NOTE: your shell may have its own version of stat, which usually supersedes NOTE: your shell may have its own version of stat, which usually supersedes
the version described here. Please refer to your shell's documentation the version described here. Please refer to your shell's documentation
for details about the options it supports."#, for details about the options it supports.
NAME ",
); )
println!("{}", msg); }
0
pub fn uumain(args: impl uucore::Args) -> i32 {
let usage = get_usage();
let long_usage = get_long_usage();
let matches = App::new(executable!())
.version(VERSION)
.about(ABOUT)
.usage(&usage[..])
.after_help(&long_usage[..])
.arg(
Arg::with_name(OPT_DEREFERENCE)
.short("L")
.long(OPT_DEREFERENCE)
.help("follow links"),
)
.arg(
Arg::with_name(OPT_FILE_SYSTEM)
.short("f")
.long(OPT_FILE_SYSTEM)
.help("display file system status instead of file status"),
)
.arg(
Arg::with_name(OPT_TERSE)
.short("t")
.long(OPT_TERSE)
.help("print the information in terse form"),
)
.arg(
Arg::with_name(OPT_FORMAT)
.short("c")
.long(OPT_FORMAT)
.help(
"use the specified FORMAT instead of the default;
output a newline after each use of FORMAT",
)
.value_name("FORMAT"),
)
.arg(
Arg::with_name(OPT_PRINTF)
.long(OPT_PRINTF)
.value_name("FORMAT")
.help(
"like --format, but interpret backslash escapes,
and do not output a mandatory trailing newline;
if you want a newline, include \n in FORMAT",
),
)
.arg(
Arg::with_name(ARG_FILES)
.multiple(true)
.takes_value(true)
.min_values(1),
)
.get_matches_from(args);
match Stater::new(matches) {
Ok(stater) => stater.exec(),
Err(e) => {
show_info!("{}", e);
1
}
}
} }