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

head: refactor to use specific error enums

This commit is contained in:
Daringcuteseal 2025-01-04 11:30:57 +07:00
parent 2cdf30938d
commit 5fe6706c51
No known key found for this signature in database
GPG key ID: 173F4A541C0E39D7
3 changed files with 53 additions and 24 deletions

1
Cargo.lock generated
View file

@ -2770,6 +2770,7 @@ version = "0.0.28"
dependencies = [ dependencies = [
"clap", "clap",
"memchr", "memchr",
"thiserror 2.0.9",
"uucore", "uucore",
] ]

View file

@ -19,6 +19,7 @@ path = "src/head.rs"
[dependencies] [dependencies]
clap = { workspace = true } clap = { workspace = true }
memchr = { workspace = true } memchr = { workspace = true }
thiserror = { workspace = true }
uucore = { workspace = true, features = ["ringbuffer", "lines", "fs"] } uucore = { workspace = true, features = ["ringbuffer", "lines", "fs"] }
[[bin]] [[bin]]

View file

@ -8,8 +8,10 @@
use clap::{crate_version, Arg, ArgAction, ArgMatches, Command}; use clap::{crate_version, Arg, ArgAction, ArgMatches, Command};
use std::ffi::OsString; use std::ffi::OsString;
use std::io::{self, BufWriter, ErrorKind, Read, Seek, SeekFrom, Write}; use std::io::{self, BufWriter, ErrorKind, Read, Seek, SeekFrom, Write};
use std::num::TryFromIntError;
use thiserror::Error;
use uucore::display::Quotable; use uucore::display::Quotable;
use uucore::error::{FromIo, UResult, USimpleError}; use uucore::error::{FromIo, UError, UResult};
use uucore::line_ending::LineEnding; use uucore::line_ending::LineEnding;
use uucore::lines::lines; use uucore::lines::lines;
use uucore::{format_usage, help_about, help_usage, show}; use uucore::{format_usage, help_about, help_usage, show};
@ -37,6 +39,36 @@ mod take;
use take::take_all_but; use take::take_all_but;
use take::take_lines; use take::take_lines;
#[derive(Error, Debug)]
enum HeadError {
/// Wrapper around `io::Error`
#[error("error reading {name}: {err}")]
Io { name: String, err: io::Error },
#[error("parse error: {0}")]
ParseError(String),
#[error("bad argument encoding")]
BadEncoding,
#[error("{0}: number of -bytes or -lines is too large")]
NumTooLarge(#[from] TryFromIntError),
#[error("clap error: {0}")]
Clap(#[from] clap::Error),
#[error("{0}")]
MatchOption(String),
}
impl UError for HeadError {
fn code(&self) -> i32 {
1
}
}
type HeadResult<T> = Result<T, HeadError>;
pub fn uu_app() -> Command { pub fn uu_app() -> Command {
Command::new(uucore::util_name()) Command::new(uucore::util_name())
.version(crate_version!()) .version(crate_version!())
@ -152,7 +184,7 @@ impl Mode {
fn arg_iterate<'a>( fn arg_iterate<'a>(
mut args: impl uucore::Args + 'a, mut args: impl uucore::Args + 'a,
) -> UResult<Box<dyn Iterator<Item = OsString> + 'a>> { ) -> HeadResult<Box<dyn Iterator<Item = OsString> + 'a>> {
// argv[0] is always present // argv[0] is always present
let first = args.next().unwrap(); let first = args.next().unwrap();
if let Some(second) = args.next() { if let Some(second) = args.next() {
@ -160,22 +192,19 @@ fn arg_iterate<'a>(
match parse::parse_obsolete(s) { match parse::parse_obsolete(s) {
Some(Ok(iter)) => Ok(Box::new(vec![first].into_iter().chain(iter).chain(args))), Some(Ok(iter)) => Ok(Box::new(vec![first].into_iter().chain(iter).chain(args))),
Some(Err(e)) => match e { Some(Err(e)) => match e {
parse::ParseError::Syntax => Err(USimpleError::new( parse::ParseError::Syntax => Err(HeadError::ParseError(format!(
1, "bad argument format: {}",
format!("bad argument format: {}", s.quote()), s.quote()
)), ))),
parse::ParseError::Overflow => Err(USimpleError::new( parse::ParseError::Overflow => Err(HeadError::ParseError(format!(
1, "invalid argument: {} Value too large for defined datatype",
format!( s.quote()
"invalid argument: {} Value too large for defined datatype", ))),
s.quote()
),
)),
}, },
None => Ok(Box::new(vec![first, second].into_iter().chain(args))), None => Ok(Box::new(vec![first, second].into_iter().chain(args))),
} }
} else { } else {
Err(USimpleError::new(1, "bad argument encoding".to_owned())) Err(HeadError::BadEncoding)
} }
} else { } else {
Ok(Box::new(vec![first].into_iter())) Ok(Box::new(vec![first].into_iter()))
@ -247,10 +276,7 @@ fn catch_too_large_numbers_in_backwards_bytes_or_lines(n: u64) -> Option<usize>
match usize::try_from(n) { match usize::try_from(n) {
Ok(value) => Some(value), Ok(value) => Some(value),
Err(e) => { Err(e) => {
show!(USimpleError::new( show!(HeadError::NumTooLarge(e));
1,
format!("{e}: number of -bytes or -lines is too large")
));
None None
} }
} }
@ -511,16 +537,17 @@ fn uu_head(options: &HeadOptions) -> UResult<()> {
head_file(&mut file, options) head_file(&mut file, options)
} }
}; };
if res.is_err() { if let Err(e) = res {
let name = if file.as_str() == "-" { let name = if file.as_str() == "-" {
"standard input" "standard input"
} else { } else {
file file
}; };
show!(USimpleError::new( return Err(HeadError::Io {
1, name: name.to_string(),
format!("error reading {name}: Input/output error") err: e,
)); }
.into());
} }
first = false; first = false;
} }
@ -537,7 +564,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
let args = match HeadOptions::get_from(&matches) { let args = match HeadOptions::get_from(&matches) {
Ok(o) => o, Ok(o) => o,
Err(s) => { Err(s) => {
return Err(USimpleError::new(1, s)); return Err(HeadError::MatchOption(s).into());
} }
}; };
uu_head(&args) uu_head(&args)