1
Fork 0
mirror of https://github.com/RGBCube/uutils-coreutils synced 2025-07-28 19:47:45 +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 = [
"clap",
"memchr",
"thiserror 2.0.9",
"uucore",
]

View file

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

View file

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