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

tee: move from getopts to clap (#1814)

This commit is contained in:
Jan Scheer 2021-03-19 22:58:50 +01:00 committed by GitHub
parent e76ce1e908
commit 0e217e202a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 50 additions and 70 deletions

View file

@ -15,7 +15,7 @@ edition = "2018"
path = "src/tee.rs" path = "src/tee.rs"
[dependencies] [dependencies]
getopts = "0.2.18" clap = "2.33.3"
libc = "0.2.42" libc = "0.2.42"
uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["libc"] } uucore = { version=">=0.0.7", package="uucore", path="../../uucore", features=["libc"] }
uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" } uucore_procs = { version=">=0.0.5", package="uucore_procs", path="../../uucore_procs" }

View file

@ -5,6 +5,10 @@
// * For the full copyright and license information, please view the LICENSE // * For the full copyright and license information, please view the LICENSE
// * file that was distributed with this source code. // * file that was distributed with this source code.
#[macro_use]
extern crate uucore;
use clap::{App, Arg};
use std::fs::OpenOptions; use std::fs::OpenOptions;
use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write}; use std::io::{copy, sink, stdin, stdout, Error, ErrorKind, Read, Result, Write};
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
@ -12,80 +16,61 @@ use std::path::{Path, PathBuf};
#[cfg(unix)] #[cfg(unix)]
use uucore::libc; use uucore::libc;
static NAME: &str = "tee";
static VERSION: &str = env!("CARGO_PKG_VERSION"); static VERSION: &str = env!("CARGO_PKG_VERSION");
static ABOUT: &str = "Copy standard input to each FILE, and also to standard output.";
pub fn uumain(args: impl uucore::Args) -> i32 { mod options {
let args = args.collect_str(); pub const APPEND: &str = "append";
pub const IGNORE_INTERRUPTS: &str = "ignore-interrupts";
match options(&args).and_then(exec) { pub const FILE: &str = "file";
Ok(_) => 0,
Err(_) => 1,
}
} }
#[allow(dead_code)] #[allow(dead_code)]
struct Options { struct Options {
program: String,
append: bool, append: bool,
ignore_interrupts: bool, ignore_interrupts: bool,
print_and_exit: Option<String>,
files: Vec<String>, files: Vec<String>,
} }
fn options(args: &[String]) -> Result<Options> { fn get_usage() -> String {
let mut opts = getopts::Options::new(); format!("{0} [OPTION]... [FILE]...", executable!())
opts.optflag("a", "append", "append to the given FILEs, do not overwrite");
opts.optflag(
"i",
"ignore-interrupts",
"ignore interrupt signals (ignored on non-Unix platforms)",
);
opts.optflag("h", "help", "display this help and exit");
opts.optflag("V", "version", "output version information and exit");
opts.parse(&args[1..])
.map_err(|e| Error::new(ErrorKind::Other, format!("{}", e)))
.map(|m| {
let version = format!("{} {}", NAME, VERSION);
let arguments = "[OPTION]... [FILE]...";
let brief = "Copy standard input to each FILE, and also to standard output.";
let comment = "If a FILE is -, it refers to a file named - .";
let help = format!(
"{}\n\nUsage:\n {} {}\n\n{}\n{}",
version,
NAME,
arguments,
opts.usage(brief),
comment
);
let names: Vec<String> = m.free.clone().into_iter().collect();
let to_print = if m.opt_present("help") {
Some(help)
} else if m.opt_present("version") {
Some(version)
} else {
None
};
Options {
program: NAME.to_owned(),
append: m.opt_present("append"),
ignore_interrupts: m.opt_present("ignore-interrupts"),
print_and_exit: to_print,
files: names,
}
})
.map_err(|message| warn(format!("{}", message).as_ref()))
} }
fn exec(options: Options) -> Result<()> { pub fn uumain(args: impl uucore::Args) -> i32 {
match options.print_and_exit { let usage = get_usage();
Some(text) => {
println!("{}", text); let matches = App::new(executable!())
Ok(()) .version(VERSION)
} .about(ABOUT)
None => tee(options), .usage(&usage[..])
.after_help("If a FILE is -, it refers to a file named - .")
.arg(
Arg::with_name(options::APPEND)
.long(options::APPEND)
.short("a")
.help("append to the given FILEs, do not overwrite"),
)
.arg(
Arg::with_name(options::IGNORE_INTERRUPTS)
.long(options::IGNORE_INTERRUPTS)
.short("i")
.help("ignore interrupt signals (ignored on non-Unix platforms)"),
)
.arg(Arg::with_name(options::FILE).multiple(true))
.get_matches_from(args);
let options = Options {
append: matches.is_present(options::APPEND),
ignore_interrupts: matches.is_present(options::IGNORE_INTERRUPTS),
files: matches
.values_of(options::FILE)
.map(|v| v.map(ToString::to_string).collect())
.unwrap_or_default(),
};
match tee(options) {
Ok(_) => 0,
Err(_) => 1,
} }
} }
@ -173,7 +158,7 @@ impl Write for NamedWriter {
match self.inner.write(buf) { match self.inner.write(buf) {
Err(f) => { Err(f) => {
self.inner = Box::new(sink()) as Box<dyn Write>; self.inner = Box::new(sink()) as Box<dyn Write>;
warn(format!("{}: {}", self.path.display(), f.to_string()).as_ref()); show_warning!("{}: {}", self.path.display(), f.to_string());
Err(f) Err(f)
} }
okay => okay, okay => okay,
@ -184,7 +169,7 @@ impl Write for NamedWriter {
match self.inner.flush() { match self.inner.flush() {
Err(f) => { Err(f) => {
self.inner = Box::new(sink()) as Box<dyn Write>; self.inner = Box::new(sink()) as Box<dyn Write>;
warn(format!("{}: {}", self.path.display(), f.to_string()).as_ref()); show_warning!("{}: {}", self.path.display(), f.to_string());
Err(f) Err(f)
} }
okay => okay, okay => okay,
@ -200,15 +185,10 @@ impl Read for NamedReader {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> { fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
match self.inner.read(buf) { match self.inner.read(buf) {
Err(f) => { Err(f) => {
warn(format!("{}: {}", Path::new("stdin").display(), f.to_string()).as_ref()); show_warning!("{}: {}", Path::new("stdin").display(), f.to_string());
Err(f) Err(f)
} }
okay => okay, okay => okay,
} }
} }
} }
fn warn(message: &str) -> Error {
eprintln!("{}: {}", NAME, message);
Error::new(ErrorKind::Other, format!("{}: {}", NAME, message))
}