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