mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-29 03:57:44 +00:00
ls: adapt to standardized error handling
This commit is contained in:
parent
60e4621c3b
commit
e4eac825fb
1 changed files with 50 additions and 31 deletions
|
@ -26,10 +26,11 @@ use quoting_style::{escape_name, QuotingStyle};
|
|||
use std::os::windows::fs::MetadataExt;
|
||||
use std::{
|
||||
cmp::Reverse,
|
||||
error::Error,
|
||||
fmt::Display,
|
||||
fs::{self, DirEntry, FileType, Metadata},
|
||||
io::{stdout, BufWriter, Stdout, Write},
|
||||
path::{Path, PathBuf},
|
||||
process::exit,
|
||||
time::{SystemTime, UNIX_EPOCH},
|
||||
};
|
||||
#[cfg(unix)]
|
||||
|
@ -38,8 +39,8 @@ use std::{
|
|||
os::unix::fs::{FileTypeExt, MetadataExt},
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use term_grid::{Cell, Direction, Filling, Grid, GridOptions};
|
||||
use uucore::error::{set_exit_code, FromIo, UCustomError, UResult};
|
||||
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
#[cfg(unix)]
|
||||
|
@ -125,6 +126,32 @@ pub mod options {
|
|||
pub static IGNORE: &str = "ignore";
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum LsError {
|
||||
InvalidLineWidth(String),
|
||||
NoMetadata(PathBuf),
|
||||
}
|
||||
|
||||
impl UCustomError for LsError {
|
||||
fn code(&self) -> i32 {
|
||||
match self {
|
||||
LsError::InvalidLineWidth(_) => 2,
|
||||
LsError::NoMetadata(_) => 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Error for LsError {}
|
||||
|
||||
impl Display for LsError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
LsError::InvalidLineWidth(s) => write!(f, "invalid line width: '{}'", s),
|
||||
LsError::NoMetadata(p) => write!(f, "could not open file: '{}'", p.display()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
enum Format {
|
||||
Columns,
|
||||
|
@ -218,7 +245,7 @@ struct LongFormat {
|
|||
|
||||
impl Config {
|
||||
#[allow(clippy::cognitive_complexity)]
|
||||
fn from(options: clap::ArgMatches) -> Config {
|
||||
fn from(options: clap::ArgMatches) -> UResult<Config> {
|
||||
let (mut format, opt) = if let Some(format_) = options.value_of(options::FORMAT) {
|
||||
(
|
||||
match format_ {
|
||||
|
@ -369,15 +396,13 @@ impl Config {
|
|||
}
|
||||
};
|
||||
|
||||
let width = options
|
||||
.value_of(options::WIDTH)
|
||||
.map(|x| {
|
||||
x.parse::<u16>().unwrap_or_else(|_e| {
|
||||
show_error!("invalid line width: '{}'", x);
|
||||
exit(2);
|
||||
})
|
||||
})
|
||||
.or_else(|| termsize::get().map(|s| s.cols));
|
||||
let width = match options.value_of(options::WIDTH) {
|
||||
Some(x) => match x.parse::<u16>() {
|
||||
Ok(u) => Some(u),
|
||||
Err(_) => return Err(LsError::InvalidLineWidth(x.into()).into()),
|
||||
},
|
||||
None => termsize::get().map(|s| s.cols),
|
||||
};
|
||||
|
||||
#[allow(clippy::needless_bool)]
|
||||
let show_control = if options.is_present(options::HIDE_CONTROL_CHARS) {
|
||||
|
@ -528,7 +553,7 @@ impl Config {
|
|||
Dereference::DirArgs
|
||||
};
|
||||
|
||||
Config {
|
||||
Ok(Config {
|
||||
format,
|
||||
files,
|
||||
sort,
|
||||
|
@ -547,11 +572,12 @@ impl Config {
|
|||
quoting_style,
|
||||
indicator_style,
|
||||
time_style,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn uumain(args: impl uucore::Args) -> i32 {
|
||||
#[uucore_procs::gen_uumain]
|
||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||
let args = args
|
||||
.collect_str(InvalidEncodingHandling::Ignore)
|
||||
.accept_any();
|
||||
|
@ -567,7 +593,7 @@ pub fn uumain(args: impl uucore::Args) -> i32 {
|
|||
.map(|v| v.map(ToString::to_string).collect())
|
||||
.unwrap_or_else(|| vec![String::from(".")]);
|
||||
|
||||
list(locs, Config::from(matches))
|
||||
list(locs, Config::from(matches)?)
|
||||
}
|
||||
|
||||
pub fn uu_app() -> App<'static, 'static> {
|
||||
|
@ -1190,10 +1216,9 @@ impl PathData {
|
|||
}
|
||||
}
|
||||
|
||||
fn list(locs: Vec<String>, config: Config) -> i32 {
|
||||
fn list(locs: Vec<String>, config: Config) -> UResult<()> {
|
||||
let mut files = Vec::<PathData>::new();
|
||||
let mut dirs = Vec::<PathData>::new();
|
||||
let mut has_failed = false;
|
||||
|
||||
let mut out = BufWriter::new(stdout());
|
||||
|
||||
|
@ -1202,19 +1227,16 @@ fn list(locs: Vec<String>, config: Config) -> i32 {
|
|||
let path_data = PathData::new(p, None, None, &config, true);
|
||||
|
||||
if path_data.md().is_none() {
|
||||
show_error!("'{}': {}", &loc, "No such file or directory");
|
||||
/*
|
||||
We found an error, the return code of ls should not be 0
|
||||
And no need to continue the execution
|
||||
*/
|
||||
has_failed = true;
|
||||
show!(std::io::ErrorKind::NotFound
|
||||
.map_err_context(|| format!("cannot access '{}'", path_data.p_buf.display())));
|
||||
// We found an error, no need to continue the execution
|
||||
continue;
|
||||
}
|
||||
|
||||
let show_dir_contents = match path_data.file_type() {
|
||||
Some(ft) => !config.directory && ft.is_dir(),
|
||||
None => {
|
||||
has_failed = true;
|
||||
set_exit_code(1);
|
||||
false
|
||||
}
|
||||
};
|
||||
|
@ -1235,11 +1257,8 @@ fn list(locs: Vec<String>, config: Config) -> i32 {
|
|||
}
|
||||
enter_directory(&dir, &config, &mut out);
|
||||
}
|
||||
if has_failed {
|
||||
1
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sort_entries(entries: &mut Vec<PathData>, config: &Config) {
|
||||
|
@ -1478,7 +1497,7 @@ fn display_item_long(
|
|||
) {
|
||||
let md = match item.md() {
|
||||
None => {
|
||||
show_error!("could not show file: {}", &item.p_buf.display());
|
||||
show!(LsError::NoMetadata(item.p_buf.clone()));
|
||||
return;
|
||||
}
|
||||
Some(md) => md,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue