mirror of
https://github.com/uutils/coreutils
synced 2024-11-17 10:18:11 +00:00
Merge pull request #2562 from tertsdiepraam/uucore/simpler-uerror
`uucore`: simpler `UResult` and `UError`
This commit is contained in:
commit
ea5097e4a0
13 changed files with 98 additions and 271 deletions
|
@ -14,7 +14,7 @@ use uucore::fs::resolve_relative_path;
|
||||||
use uucore::libc::{gid_t, uid_t};
|
use uucore::libc::{gid_t, uid_t};
|
||||||
use uucore::perms::{wrap_chown, Verbosity};
|
use uucore::perms::{wrap_chown, Verbosity};
|
||||||
|
|
||||||
use uucore::error::{FromIo, UError, UResult, USimpleError};
|
use uucore::error::{FromIo, UResult, USimpleError};
|
||||||
|
|
||||||
use clap::{crate_version, App, Arg};
|
use clap::{crate_version, App, Arg};
|
||||||
|
|
||||||
|
@ -107,10 +107,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
if recursive {
|
if recursive {
|
||||||
if bit_flag == FTS_PHYSICAL {
|
if bit_flag == FTS_PHYSICAL {
|
||||||
if derefer == 1 {
|
if derefer == 1 {
|
||||||
return Err(USimpleError::new(
|
return Err(USimpleError::new(1, "-R --dereference requires -H or -L"));
|
||||||
1,
|
|
||||||
"-R --dereference requires -H or -L".to_string(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
derefer = 0;
|
derefer = 0;
|
||||||
}
|
}
|
||||||
|
@ -324,7 +321,7 @@ impl Chowner {
|
||||||
ret |= self.traverse(f);
|
ret |= self.traverse(f);
|
||||||
}
|
}
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
return Err(UError::from(ret));
|
return Err(ret.into());
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
use uucore::error::UCustomError;
|
use uucore::error::UError;
|
||||||
use uucore::error::UResult;
|
use uucore::error::UResult;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use uucore::fsext::statfs_fn;
|
use uucore::fsext::statfs_fn;
|
||||||
|
@ -274,7 +274,7 @@ impl Display for DfError {
|
||||||
|
|
||||||
impl Error for DfError {}
|
impl Error for DfError {}
|
||||||
|
|
||||||
impl UCustomError for DfError {
|
impl UError for DfError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
DfError::InvalidBaseValue(_) => 1,
|
DfError::InvalidBaseValue(_) => 1,
|
||||||
|
|
|
@ -79,7 +79,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
print!("{}", separator);
|
print!("{}", separator);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(UUsageError::new(1, "missing operand".to_string()));
|
return Err(UUsageError::new(1, "missing operand"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -32,7 +32,7 @@ use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::time::{Duration, UNIX_EPOCH};
|
use std::time::{Duration, UNIX_EPOCH};
|
||||||
use std::{error::Error, fmt::Display};
|
use std::{error::Error, fmt::Display};
|
||||||
use uucore::error::{UCustomError, UResult};
|
use uucore::error::{UError, UResult};
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -438,7 +438,7 @@ Try '{} --help' for more information.",
|
||||||
|
|
||||||
impl Error for DuError {}
|
impl Error for DuError {}
|
||||||
|
|
||||||
impl UCustomError for DuError {
|
impl UError for DuError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
Self::InvalidMaxDepthArg(_) => 1,
|
Self::InvalidMaxDepthArg(_) => 1,
|
||||||
|
|
|
@ -9,13 +9,12 @@
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
use clap::App;
|
use clap::App;
|
||||||
use uucore::error::{UError, UResult};
|
use uucore::{error::UResult, executable};
|
||||||
use uucore::executable;
|
|
||||||
|
|
||||||
#[uucore_procs::gen_uumain]
|
#[uucore_procs::gen_uumain]
|
||||||
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
uu_app().get_matches_from(args);
|
uu_app().get_matches_from(args);
|
||||||
Err(UError::from(1))
|
Err(1.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn uu_app() -> App<'static, 'static> {
|
pub fn uu_app() -> App<'static, 'static> {
|
||||||
|
|
|
@ -171,20 +171,20 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
if (state.nflag || state.rflag) && default_format && !state.cflag {
|
if (state.nflag || state.rflag) && default_format && !state.cflag {
|
||||||
return Err(USimpleError::new(
|
return Err(USimpleError::new(
|
||||||
1,
|
1,
|
||||||
"cannot print only names or real IDs in default format".to_string(),
|
"cannot print only names or real IDs in default format",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if state.zflag && default_format && !state.cflag {
|
if state.zflag && default_format && !state.cflag {
|
||||||
// NOTE: GNU test suite "id/zero.sh" needs this stderr output:
|
// NOTE: GNU test suite "id/zero.sh" needs this stderr output:
|
||||||
return Err(USimpleError::new(
|
return Err(USimpleError::new(
|
||||||
1,
|
1,
|
||||||
"option --zero not permitted in default format".to_string(),
|
"option --zero not permitted in default format",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
if state.user_specified && state.cflag {
|
if state.user_specified && state.cflag {
|
||||||
return Err(USimpleError::new(
|
return Err(USimpleError::new(
|
||||||
1,
|
1,
|
||||||
"cannot print security context when user specified".to_string(),
|
"cannot print security context when user specified",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,7 +218,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
} else {
|
} else {
|
||||||
return Err(USimpleError::new(
|
return Err(USimpleError::new(
|
||||||
1,
|
1,
|
||||||
"--context (-Z) works only on an SELinux-enabled kernel".to_string(),
|
"--context (-Z) works only on an SELinux-enabled kernel",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use file_diff::diff;
|
||||||
use filetime::{set_file_times, FileTime};
|
use filetime::{set_file_times, FileTime};
|
||||||
use uucore::backup_control::{self, BackupMode};
|
use uucore::backup_control::{self, BackupMode};
|
||||||
use uucore::entries::{grp2gid, usr2uid};
|
use uucore::entries::{grp2gid, usr2uid};
|
||||||
use uucore::error::{FromIo, UCustomError, UIoError, UResult, USimpleError};
|
use uucore::error::{FromIo, UError, UIoError, UResult, USimpleError};
|
||||||
use uucore::perms::{wrap_chgrp, wrap_chown, Verbosity};
|
use uucore::perms::{wrap_chgrp, wrap_chown, Verbosity};
|
||||||
|
|
||||||
use libc::{getegid, geteuid};
|
use libc::{getegid, geteuid};
|
||||||
|
@ -66,7 +66,7 @@ enum InstallError {
|
||||||
OmittingDirectory(PathBuf),
|
OmittingDirectory(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UCustomError for InstallError {
|
impl UError for InstallError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
InstallError::Unimplemented(_) => 2,
|
InstallError::Unimplemented(_) => 2,
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
use clap::{crate_version, App, Arg};
|
use clap::{crate_version, App, Arg};
|
||||||
use uucore::error::{UCustomError, UResult};
|
use uucore::error::{UError, UResult};
|
||||||
|
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -79,7 +79,7 @@ impl Display for LnError {
|
||||||
|
|
||||||
impl Error for LnError {}
|
impl Error for LnError {}
|
||||||
|
|
||||||
impl UCustomError for LnError {
|
impl UError for LnError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
Self::TargetIsDirectory(_) => 1,
|
Self::TargetIsDirectory(_) => 1,
|
||||||
|
|
|
@ -39,7 +39,7 @@ use std::{
|
||||||
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 uucore::error::{set_exit_code, FromIo, UError, UResult};
|
||||||
|
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -135,7 +135,7 @@ enum LsError {
|
||||||
NoMetadata(PathBuf),
|
NoMetadata(PathBuf),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UCustomError for LsError {
|
impl UError for LsError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
LsError::InvalidLineWidth(_) => 2,
|
LsError::InvalidLineWidth(_) => 2,
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
extern crate uucore;
|
extern crate uucore;
|
||||||
|
|
||||||
use clap::{crate_version, App, Arg};
|
use clap::{crate_version, App, Arg};
|
||||||
use uucore::error::{FromIo, UCustomError, UResult};
|
use uucore::error::{FromIo, UError, UResult};
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
@ -49,7 +49,7 @@ enum MkTempError {
|
||||||
InvalidTemplate(String),
|
InvalidTemplate(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UCustomError for MkTempError {}
|
impl UError for MkTempError {}
|
||||||
|
|
||||||
impl Error for MkTempError {}
|
impl Error for MkTempError {}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::Utf8Error;
|
use std::str::Utf8Error;
|
||||||
use unicode_width::UnicodeWidthStr;
|
use unicode_width::UnicodeWidthStr;
|
||||||
use uucore::error::{set_exit_code, UCustomError, UResult, USimpleError, UUsageError};
|
use uucore::error::{set_exit_code, UError, UResult, USimpleError, UUsageError};
|
||||||
use uucore::parse_size::{parse_size, ParseSizeError};
|
use uucore::parse_size::{parse_size, ParseSizeError};
|
||||||
use uucore::version_cmp::version_cmp;
|
use uucore::version_cmp::version_cmp;
|
||||||
use uucore::InvalidEncodingHandling;
|
use uucore::InvalidEncodingHandling;
|
||||||
|
@ -164,7 +164,7 @@ enum SortError {
|
||||||
|
|
||||||
impl Error for SortError {}
|
impl Error for SortError {}
|
||||||
|
|
||||||
impl UCustomError for SortError {
|
impl UError for SortError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
SortError::Disorder { .. } => 1,
|
SortError::Disorder { .. } => 1,
|
||||||
|
@ -1238,7 +1238,7 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
|
||||||
if separator.len() != 1 {
|
if separator.len() != 1 {
|
||||||
return Err(UUsageError::new(
|
return Err(UUsageError::new(
|
||||||
2,
|
2,
|
||||||
"separator must be exactly one character long".into(),
|
"separator must be exactly one character long",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
settings.separator = Some(separator.chars().next().unwrap())
|
settings.separator = Some(separator.chars().next().unwrap())
|
||||||
|
@ -1517,7 +1517,7 @@ fn exec(
|
||||||
file_merger.write_all(settings, output)
|
file_merger.write_all(settings, output)
|
||||||
} else if settings.check {
|
} else if settings.check {
|
||||||
if files.len() > 1 {
|
if files.len() > 1 {
|
||||||
Err(UUsageError::new(2, "only one file allowed with -c".into()))
|
Err(UUsageError::new(2, "only one file allowed with -c"))
|
||||||
} else {
|
} else {
|
||||||
check::check(files.first().unwrap(), settings)
|
check::check(files.first().unwrap(), settings)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use clap::{crate_version, App, Arg, ArgGroup};
|
||||||
use filetime::*;
|
use filetime::*;
|
||||||
use std::fs::{self, File};
|
use std::fs::{self, File};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use uucore::error::{FromIo, UResult, USimpleError};
|
use uucore::error::{FromIo, UError, UResult, USimpleError};
|
||||||
|
|
||||||
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
|
static ABOUT: &str = "Update the access and modification times of each FILE to the current time.";
|
||||||
pub mod options {
|
pub mod options {
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
//! This module provides types to reconcile these exit codes with idiomatic Rust error
|
//! This module provides types to reconcile these exit codes with idiomatic Rust error
|
||||||
//! handling. This has a couple advantages over manually using [`std::process::exit`]:
|
//! handling. This has a couple advantages over manually using [`std::process::exit`]:
|
||||||
//! 1. It enables the use of `?`, `map_err`, `unwrap_or`, etc. in `uumain`.
|
//! 1. It enables the use of `?`, `map_err`, `unwrap_or`, etc. in `uumain`.
|
||||||
//! 1. It encourages the use of `UResult`/`Result` in functions in the utils.
|
//! 1. It encourages the use of [`UResult`]/[`Result`] in functions in the utils.
|
||||||
//! 1. The error messages are largely standardized across utils.
|
//! 1. The error messages are largely standardized across utils.
|
||||||
//! 1. Standardized error messages can be created from external result types
|
//! 1. Standardized error messages can be created from external result types
|
||||||
//! (i.e. [`std::io::Result`] & `clap::ClapResult`).
|
//! (i.e. [`std::io::Result`] & `clap::ClapResult`).
|
||||||
//! 1. `set_exit_code` takes away the burden of manually tracking exit codes for non-fatal errors.
|
//! 1. [`set_exit_code`] takes away the burden of manually tracking exit codes for non-fatal errors.
|
||||||
//!
|
//!
|
||||||
//! # Usage
|
//! # Usage
|
||||||
//! The signature of a typical util should be:
|
//! The signature of a typical util should be:
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
//! ...
|
//! ...
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//! [`UResult`] is a simple wrapper around [`Result`] with a custom error type: [`UError`]. The
|
//! [`UResult`] is a simple wrapper around [`Result`] with a custom error trait: [`UError`]. The
|
||||||
//! most important difference with types implementing [`std::error::Error`] is that [`UError`]s
|
//! most important difference with types implementing [`std::error::Error`] is that [`UError`]s
|
||||||
//! can specify the exit code of the program when they are returned from `uumain`:
|
//! can specify the exit code of the program when they are returned from `uumain`:
|
||||||
//! * When `Ok` is returned, the code set with [`set_exit_code`] is used as exit code. If
|
//! * When `Ok` is returned, the code set with [`set_exit_code`] is used as exit code. If
|
||||||
|
@ -41,8 +41,8 @@
|
||||||
//! [`set_exit_code`]. See the documentation on that function for more information.
|
//! [`set_exit_code`]. See the documentation on that function for more information.
|
||||||
//!
|
//!
|
||||||
//! # Guidelines
|
//! # Guidelines
|
||||||
//! * Use common errors where possible.
|
//! * Use error types from `uucore` where possible.
|
||||||
//! * Add variants to [`UCommonError`] if an error appears in multiple utils.
|
//! * Add error types to `uucore` if an error appears in multiple utils.
|
||||||
//! * Prefer proper custom error types over [`ExitCode`] and [`USimpleError`].
|
//! * Prefer proper custom error types over [`ExitCode`] and [`USimpleError`].
|
||||||
//! * [`USimpleError`] may be used in small utils with simple error handling.
|
//! * [`USimpleError`] may be used in small utils with simple error handling.
|
||||||
//! * Using [`ExitCode`] is not recommended but can be useful for converting utils to use
|
//! * Using [`ExitCode`] is not recommended but can be useful for converting utils to use
|
||||||
|
@ -87,115 +87,10 @@ pub fn set_exit_code(code: i32) {
|
||||||
EXIT_CODE.store(code, Ordering::SeqCst);
|
EXIT_CODE.store(code, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Should be returned by all utils.
|
/// Result type that should be returned by all utils.
|
||||||
///
|
pub type UResult<T> = Result<T, Box<dyn UError>>;
|
||||||
/// Two additional methods are implemented on [`UResult`] on top of the normal [`Result`] methods:
|
|
||||||
/// `map_err_code` & `map_err_code_message`.
|
|
||||||
///
|
|
||||||
/// These methods are used to convert [`UCommonError`]s into errors with a custom error code and
|
|
||||||
/// message.
|
|
||||||
pub type UResult<T> = Result<T, UError>;
|
|
||||||
|
|
||||||
trait UResultTrait<T> {
|
/// Custom errors defined by the utils and `uucore`.
|
||||||
fn map_err_code(self, mapper: fn(&UCommonError) -> Option<i32>) -> Self;
|
|
||||||
fn map_err_code_and_message(self, mapper: fn(&UCommonError) -> Option<(i32, String)>) -> Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> UResultTrait<T> for UResult<T> {
|
|
||||||
fn map_err_code(self, mapper: fn(&UCommonError) -> Option<i32>) -> Self {
|
|
||||||
if let Err(UError::Common(error)) = self {
|
|
||||||
if let Some(code) = mapper(&error) {
|
|
||||||
Err(UCommonErrorWithCode { code, error }.into())
|
|
||||||
} else {
|
|
||||||
Err(error.into())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn map_err_code_and_message(self, mapper: fn(&UCommonError) -> Option<(i32, String)>) -> Self {
|
|
||||||
if let Err(UError::Common(ref error)) = self {
|
|
||||||
if let Some((code, message)) = mapper(error) {
|
|
||||||
return Err(USimpleError { code, message }.into());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The error type of [`UResult`].
|
|
||||||
///
|
|
||||||
/// `UError::Common` errors are defined in [`uucore`](crate) while `UError::Custom` errors are
|
|
||||||
/// defined by the utils.
|
|
||||||
/// ```
|
|
||||||
/// use uucore::error::USimpleError;
|
|
||||||
/// let err = USimpleError::new(1, "Error!!".into());
|
|
||||||
/// assert_eq!(1, err.code());
|
|
||||||
/// assert_eq!(String::from("Error!!"), format!("{}", err));
|
|
||||||
/// ```
|
|
||||||
pub enum UError {
|
|
||||||
Common(UCommonError),
|
|
||||||
Custom(Box<dyn UCustomError>),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UError {
|
|
||||||
/// The error code of [`UResult`]
|
|
||||||
///
|
|
||||||
/// This function defines the error code associated with an instance of
|
|
||||||
/// [`UResult`]. To associate error codes for self-defined instances of
|
|
||||||
/// `UResult::Custom` (i.e. [`UCustomError`]), implement the
|
|
||||||
/// [`code`-function there](UCustomError::code).
|
|
||||||
pub fn code(&self) -> i32 {
|
|
||||||
match self {
|
|
||||||
UError::Common(e) => e.code(),
|
|
||||||
UError::Custom(e) => e.code(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether to print usage help for a [`UResult`]
|
|
||||||
///
|
|
||||||
/// Defines if a variant of [`UResult`] should print a short usage message
|
|
||||||
/// below the error. The usage message is printed when this function returns
|
|
||||||
/// `true`. To do this for self-defined instances of `UResult::Custom` (i.e.
|
|
||||||
/// [`UCustomError`]), implement the [`usage`-function
|
|
||||||
/// there](UCustomError::usage).
|
|
||||||
pub fn usage(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
UError::Common(e) => e.usage(),
|
|
||||||
UError::Custom(e) => e.usage(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UCommonError> for UError {
|
|
||||||
fn from(v: UCommonError) -> Self {
|
|
||||||
UError::Common(v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<i32> for UError {
|
|
||||||
fn from(v: i32) -> Self {
|
|
||||||
UError::Custom(Box::new(ExitCode(v)))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<E: UCustomError + 'static> From<E> for UError {
|
|
||||||
fn from(v: E) -> Self {
|
|
||||||
UError::Custom(Box::new(v) as Box<dyn UCustomError>)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for UError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
UError::Common(e) => e.fmt(f),
|
|
||||||
UError::Custom(e) => e.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Custom errors defined by the utils.
|
|
||||||
///
|
///
|
||||||
/// All errors should implement [`std::error::Error`], [`std::fmt::Display`] and
|
/// All errors should implement [`std::error::Error`], [`std::fmt::Display`] and
|
||||||
/// [`std::fmt::Debug`] and have an additional `code` method that specifies the
|
/// [`std::fmt::Debug`] and have an additional `code` method that specifies the
|
||||||
|
@ -204,7 +99,7 @@ impl Display for UError {
|
||||||
/// An example of a custom error from `ls`:
|
/// An example of a custom error from `ls`:
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use uucore::error::{UCustomError, UResult};
|
/// use uucore::error::{UError, UResult};
|
||||||
/// use std::{
|
/// use std::{
|
||||||
/// error::Error,
|
/// error::Error,
|
||||||
/// fmt::{Display, Debug},
|
/// fmt::{Display, Debug},
|
||||||
|
@ -217,7 +112,7 @@ impl Display for UError {
|
||||||
/// NoMetadata(PathBuf),
|
/// NoMetadata(PathBuf),
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl UCustomError for LsError {
|
/// impl UError for LsError {
|
||||||
/// fn code(&self) -> i32 {
|
/// fn code(&self) -> i32 {
|
||||||
/// match self {
|
/// match self {
|
||||||
/// LsError::InvalidLineWidth(_) => 2,
|
/// LsError::InvalidLineWidth(_) => 2,
|
||||||
|
@ -248,12 +143,12 @@ impl Display for UError {
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// The call to `into()` is required to convert the [`UCustomError`] to an
|
/// The call to `into()` is required to convert the `LsError` to
|
||||||
/// instance of [`UError`].
|
/// [`Box<dyn UError>`]. The implementation for `From` is provided automatically.
|
||||||
///
|
///
|
||||||
/// A crate like [`quick_error`](https://crates.io/crates/quick-error) might
|
/// A crate like [`quick_error`](https://crates.io/crates/quick-error) might
|
||||||
/// also be used, but will still require an `impl` for the `code` method.
|
/// also be used, but will still require an `impl` for the `code` method.
|
||||||
pub trait UCustomError: Error + Send {
|
pub trait UError: Error + Send {
|
||||||
/// Error code of a custom error.
|
/// Error code of a custom error.
|
||||||
///
|
///
|
||||||
/// Set a return value for each variant of an enum-type to associate an
|
/// Set a return value for each variant of an enum-type to associate an
|
||||||
|
@ -263,7 +158,7 @@ pub trait UCustomError: Error + Send {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use uucore::error::{UCustomError};
|
/// use uucore::error::{UError};
|
||||||
/// use std::{
|
/// use std::{
|
||||||
/// error::Error,
|
/// error::Error,
|
||||||
/// fmt::{Display, Debug},
|
/// fmt::{Display, Debug},
|
||||||
|
@ -277,7 +172,7 @@ pub trait UCustomError: Error + Send {
|
||||||
/// Bing(),
|
/// Bing(),
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl UCustomError for MyError {
|
/// impl UError for MyError {
|
||||||
/// fn code(&self) -> i32 {
|
/// fn code(&self) -> i32 {
|
||||||
/// match self {
|
/// match self {
|
||||||
/// MyError::Foo(_) => 2,
|
/// MyError::Foo(_) => 2,
|
||||||
|
@ -314,7 +209,7 @@ pub trait UCustomError: Error + Send {
|
||||||
/// # Example
|
/// # Example
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use uucore::error::{UCustomError};
|
/// use uucore::error::{UError};
|
||||||
/// use std::{
|
/// use std::{
|
||||||
/// error::Error,
|
/// error::Error,
|
||||||
/// fmt::{Display, Debug},
|
/// fmt::{Display, Debug},
|
||||||
|
@ -328,7 +223,7 @@ pub trait UCustomError: Error + Send {
|
||||||
/// Bing(),
|
/// Bing(),
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// impl UCustomError for MyError {
|
/// impl UError for MyError {
|
||||||
/// fn usage(&self) -> bool {
|
/// fn usage(&self) -> bool {
|
||||||
/// match self {
|
/// match self {
|
||||||
/// // This will have a short usage help appended
|
/// // This will have a short usage help appended
|
||||||
|
@ -357,47 +252,23 @@ pub trait UCustomError: Error + Send {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Box<dyn UCustomError>> for i32 {
|
impl<T> From<T> for Box<dyn UError>
|
||||||
fn from(e: Box<dyn UCustomError>) -> i32 {
|
where
|
||||||
e.code()
|
T: UError + 'static,
|
||||||
|
{
|
||||||
|
fn from(t: T) -> Box<dyn UError> {
|
||||||
|
Box::new(t)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A [`UCommonError`] with an overridden exit code.
|
/// A simple error type with an exit code and a message that implements [`UError`].
|
||||||
///
|
///
|
||||||
/// This exit code is returned instead of the default exit code for the [`UCommonError`]. This is
|
|
||||||
/// typically created with the either the `UResult::map_err_code` or `UCommonError::with_code`
|
|
||||||
/// method.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct UCommonErrorWithCode {
|
|
||||||
code: i32,
|
|
||||||
error: UCommonError,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for UCommonErrorWithCode {}
|
|
||||||
|
|
||||||
impl Display for UCommonErrorWithCode {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
||||||
self.error.fmt(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UCustomError for UCommonErrorWithCode {
|
|
||||||
fn code(&self) -> i32 {
|
|
||||||
self.code
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A simple error type with an exit code and a message that implements [`UCustomError`].
|
|
||||||
///
|
|
||||||
/// It is typically created with the `UResult::map_err_code_and_message` method. Alternatively, it
|
|
||||||
/// can be constructed by manually:
|
|
||||||
/// ```
|
/// ```
|
||||||
/// use uucore::error::{UResult, USimpleError};
|
/// use uucore::error::{UResult, USimpleError};
|
||||||
/// let err = USimpleError { code: 1, message: "error!".into()};
|
/// let err = USimpleError { code: 1, message: "error!".into()};
|
||||||
/// let res: UResult<()> = Err(err.into());
|
/// let res: UResult<()> = Err(err.into());
|
||||||
/// // or using the `new` method:
|
/// // or using the `new` method:
|
||||||
/// let res: UResult<()> = Err(USimpleError::new(1, "error!".into()));
|
/// let res: UResult<()> = Err(USimpleError::new(1, "error!"));
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct USimpleError {
|
pub struct USimpleError {
|
||||||
|
@ -407,8 +278,11 @@ pub struct USimpleError {
|
||||||
|
|
||||||
impl USimpleError {
|
impl USimpleError {
|
||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
pub fn new(code: i32, message: String) -> UError {
|
pub fn new<S: Into<String>>(code: i32, message: S) -> Box<dyn UError> {
|
||||||
UError::Custom(Box::new(Self { code, message }))
|
Box::new(Self {
|
||||||
|
code,
|
||||||
|
message: message.into(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +294,7 @@ impl Display for USimpleError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UCustomError for USimpleError {
|
impl UError for USimpleError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
self.code
|
self.code
|
||||||
}
|
}
|
||||||
|
@ -434,8 +308,11 @@ pub struct UUsageError {
|
||||||
|
|
||||||
impl UUsageError {
|
impl UUsageError {
|
||||||
#[allow(clippy::new_ret_no_self)]
|
#[allow(clippy::new_ret_no_self)]
|
||||||
pub fn new(code: i32, message: String) -> UError {
|
pub fn new<S: Into<String>>(code: i32, message: S) -> Box<dyn UError> {
|
||||||
UError::Custom(Box::new(Self { code, message }))
|
Box::new(Self {
|
||||||
|
code,
|
||||||
|
message: message.into(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -447,7 +324,7 @@ impl Display for UUsageError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UCustomError for UUsageError {
|
impl UError for UUsageError {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
self.code
|
self.code
|
||||||
}
|
}
|
||||||
|
@ -465,13 +342,13 @@ impl UCustomError for UUsageError {
|
||||||
/// There are two ways to construct this type: with [`UIoError::new`] or by calling the
|
/// There are two ways to construct this type: with [`UIoError::new`] or by calling the
|
||||||
/// [`FromIo::map_err_context`] method on a [`std::io::Result`] or [`std::io::Error`].
|
/// [`FromIo::map_err_context`] method on a [`std::io::Result`] or [`std::io::Error`].
|
||||||
/// ```
|
/// ```
|
||||||
/// use uucore::error::{FromIo, UResult, UIoError, UCommonError};
|
/// use uucore::error::{FromIo, UResult, UIoError, UError};
|
||||||
/// use std::fs::File;
|
/// use std::fs::File;
|
||||||
/// use std::path::Path;
|
/// use std::path::Path;
|
||||||
/// let path = Path::new("test.txt");
|
/// let path = Path::new("test.txt");
|
||||||
///
|
///
|
||||||
/// // Manual construction
|
/// // Manual construction
|
||||||
/// let e: UIoError = UIoError::new(
|
/// let e: Box<dyn UError> = UIoError::new(
|
||||||
/// std::io::ErrorKind::NotFound,
|
/// std::io::ErrorKind::NotFound,
|
||||||
/// format!("cannot access '{}'", path.display())
|
/// format!("cannot access '{}'", path.display())
|
||||||
/// );
|
/// );
|
||||||
|
@ -487,22 +364,17 @@ pub struct UIoError {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UIoError {
|
impl UIoError {
|
||||||
pub fn new(kind: std::io::ErrorKind, context: String) -> Self {
|
#[allow(clippy::new_ret_no_self)]
|
||||||
Self {
|
pub fn new<S: Into<String>>(kind: std::io::ErrorKind, context: S) -> Box<dyn UError> {
|
||||||
context,
|
Box::new(Self {
|
||||||
|
context: context.into(),
|
||||||
inner: std::io::Error::new(kind, ""),
|
inner: std::io::Error::new(kind, ""),
|
||||||
}
|
})
|
||||||
}
|
|
||||||
|
|
||||||
pub fn code(&self) -> i32 {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn usage(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl UError for UIoError {}
|
||||||
|
|
||||||
impl Error for UIoError {}
|
impl Error for UIoError {}
|
||||||
|
|
||||||
impl Display for UIoError {
|
impl Display for UIoError {
|
||||||
|
@ -537,46 +409,33 @@ impl Display for UIoError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Enables the conversion from `std::io::Error` to `UError` and from `std::io::Result` to
|
/// Enables the conversion from [`std::io::Error`] to [`UError`] and from [`std::io::Result`] to
|
||||||
/// `UResult`.
|
/// [`UResult`].
|
||||||
pub trait FromIo<T> {
|
pub trait FromIo<T> {
|
||||||
fn map_err_context(self, context: impl FnOnce() -> String) -> T;
|
fn map_err_context(self, context: impl FnOnce() -> String) -> T;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIo<UIoError> for std::io::Error {
|
impl FromIo<Box<UIoError>> for std::io::Error {
|
||||||
fn map_err_context(self, context: impl FnOnce() -> String) -> UIoError {
|
fn map_err_context(self, context: impl FnOnce() -> String) -> Box<UIoError> {
|
||||||
UIoError {
|
Box::new(UIoError {
|
||||||
context: (context)(),
|
context: (context)(),
|
||||||
inner: self,
|
inner: self,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> FromIo<UResult<T>> for std::io::Result<T> {
|
impl<T> FromIo<UResult<T>> for std::io::Result<T> {
|
||||||
fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> {
|
fn map_err_context(self, context: impl FnOnce() -> String) -> UResult<T> {
|
||||||
self.map_err(|e| UError::Common(UCommonError::Io(e.map_err_context(context))))
|
self.map_err(|e| e.map_err_context(context) as Box<dyn UError>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromIo<UIoError> for std::io::ErrorKind {
|
impl FromIo<Box<UIoError>> for std::io::ErrorKind {
|
||||||
fn map_err_context(self, context: impl FnOnce() -> String) -> UIoError {
|
fn map_err_context(self, context: impl FnOnce() -> String) -> Box<UIoError> {
|
||||||
UIoError {
|
Box::new(UIoError {
|
||||||
context: (context)(),
|
context: (context)(),
|
||||||
inner: std::io::Error::new(self, ""),
|
inner: std::io::Error::new(self, ""),
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UIoError> for UCommonError {
|
|
||||||
fn from(e: UIoError) -> UCommonError {
|
|
||||||
UCommonError::Io(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UIoError> for UError {
|
|
||||||
fn from(e: UIoError) -> UError {
|
|
||||||
let common: UCommonError = e.into();
|
|
||||||
common.into()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -647,47 +506,6 @@ macro_rules! uio_error(
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
/// Common errors for utilities.
|
|
||||||
///
|
|
||||||
/// If identical errors appear across multiple utilities, they should be added here.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum UCommonError {
|
|
||||||
Io(UIoError),
|
|
||||||
// Clap(UClapError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UCommonError {
|
|
||||||
pub fn with_code(self, code: i32) -> UCommonErrorWithCode {
|
|
||||||
UCommonErrorWithCode { code, error: self }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn code(&self) -> i32 {
|
|
||||||
1
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn usage(&self) -> bool {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<UCommonError> for i32 {
|
|
||||||
fn from(common: UCommonError) -> i32 {
|
|
||||||
match common {
|
|
||||||
UCommonError::Io(e) => e.code(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for UCommonError {}
|
|
||||||
|
|
||||||
impl Display for UCommonError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), std::fmt::Error> {
|
|
||||||
match self {
|
|
||||||
UCommonError::Io(e) => e.fmt(f),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A special error type that does not print any message when returned from
|
/// A special error type that does not print any message when returned from
|
||||||
/// `uumain`. Especially useful for porting utilities to using [`UResult`].
|
/// `uumain`. Especially useful for porting utilities to using [`UResult`].
|
||||||
///
|
///
|
||||||
|
@ -705,6 +523,13 @@ impl Display for UCommonError {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct ExitCode(pub i32);
|
pub struct ExitCode(pub i32);
|
||||||
|
|
||||||
|
impl ExitCode {
|
||||||
|
#[allow(clippy::new_ret_no_self)]
|
||||||
|
pub fn new(code: i32) -> Box<dyn UError> {
|
||||||
|
Box::new(Self(code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Error for ExitCode {}
|
impl Error for ExitCode {}
|
||||||
|
|
||||||
impl Display for ExitCode {
|
impl Display for ExitCode {
|
||||||
|
@ -713,8 +538,14 @@ impl Display for ExitCode {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UCustomError for ExitCode {
|
impl UError for ExitCode {
|
||||||
fn code(&self) -> i32 {
|
fn code(&self) -> i32 {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Box<dyn UError> {
|
||||||
|
fn from(i: i32) -> Self {
|
||||||
|
ExitCode::new(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue