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:
parent
5837bc4fc9
commit
1e37c29b1f
3 changed files with 99 additions and 88 deletions
2
Cargo.lock
generated
2
Cargo.lock
generated
|
@ -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)",
|
||||||
|
|
|
@ -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" }
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue