mirror of
https://github.com/crate-ci/typos.git
synced 2024-11-25 02:20:58 -05:00
fix(cli): Define an error code policy
The main goal is to make spelling errors differentiated from other errors. Fixes #170
This commit is contained in:
parent
8a35a12096
commit
4ddbdcf5dd
4 changed files with 97 additions and 14 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -973,6 +973,15 @@ dependencies = [
|
||||||
"unicode-xid 0.2.1",
|
"unicode-xid 0.2.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "sysexit"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a26991bb0e6ef939ac9a8d6b57979efa59921928a3aa0334d818fe6e458aa6a9"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tap"
|
name = "tap"
|
||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
|
@ -1092,6 +1101,7 @@ dependencies = [
|
||||||
"predicates",
|
"predicates",
|
||||||
"serde",
|
"serde",
|
||||||
"structopt",
|
"structopt",
|
||||||
|
"sysexit",
|
||||||
"toml",
|
"toml",
|
||||||
"typos",
|
"typos",
|
||||||
"typos-dict",
|
"typos-dict",
|
||||||
|
|
|
@ -48,6 +48,7 @@ env_logger = "0.8"
|
||||||
bstr = "0.2"
|
bstr = "0.2"
|
||||||
ahash = "0.5.8"
|
ahash = "0.5.8"
|
||||||
difflib = "0.4"
|
difflib = "0.4"
|
||||||
|
sysexit = "0.2"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
assert_fs = "1.0"
|
assert_fs = "1.0"
|
||||||
|
|
55
src/exit.rs
Normal file
55
src/exit.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
pub struct ExitCode {
|
||||||
|
pub code: sysexit::Code,
|
||||||
|
pub error: Option<anyhow::Error>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ExitCode {
|
||||||
|
pub fn code(code: sysexit::Code) -> Self {
|
||||||
|
Self { code, error: None }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(mut self, error: anyhow::Error) -> Self {
|
||||||
|
self.error = Some(error);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<sysexit::Code> for ExitCode {
|
||||||
|
fn from(code: sysexit::Code) -> Self {
|
||||||
|
Self::code(code)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ChainCodeExt {
|
||||||
|
fn error(self) -> ExitCode;
|
||||||
|
fn chain(self, error: anyhow::Error) -> ExitCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChainCodeExt for sysexit::Code {
|
||||||
|
fn error(self) -> ExitCode {
|
||||||
|
ExitCode::code(self)
|
||||||
|
}
|
||||||
|
fn chain(self, error: anyhow::Error) -> ExitCode {
|
||||||
|
ExitCode::code(self).error(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ExitCodeResultErrorExt<T> {
|
||||||
|
fn code(self, code: sysexit::Code) -> Result<T, ExitCode>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E: std::error::Error + Send + Sync + 'static> ExitCodeResultErrorExt<T> for Result<T, E> {
|
||||||
|
fn code(self, code: sysexit::Code) -> Result<T, ExitCode> {
|
||||||
|
self.map_err(|e| ExitCode::code(code).error(e.into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait ExitCodeResultAnyhowExt<T> {
|
||||||
|
fn code(self, code: sysexit::Code) -> Result<T, ExitCode>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ExitCodeResultAnyhowExt<T> for Result<T, anyhow::Error> {
|
||||||
|
fn code(self, code: sysexit::Code) -> Result<T, ExitCode> {
|
||||||
|
self.map_err(|e| ExitCode::code(code).error(e))
|
||||||
|
}
|
||||||
|
}
|
45
src/main.rs
45
src/main.rs
|
@ -11,26 +11,43 @@ mod checks;
|
||||||
mod config;
|
mod config;
|
||||||
mod dict;
|
mod dict;
|
||||||
mod diff;
|
mod diff;
|
||||||
|
mod exit;
|
||||||
mod replace;
|
mod replace;
|
||||||
|
|
||||||
|
use exit::ChainCodeExt;
|
||||||
|
use exit::ExitCodeResultAnyhowExt;
|
||||||
|
use exit::ExitCodeResultErrorExt;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let code = match run() {
|
let code = match run() {
|
||||||
Ok(code) => code,
|
Ok(()) => sysexit::Code::Success,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
eprintln!("{}", err);
|
if let Some(error) = err.error {
|
||||||
1
|
eprintln!("{}", error);
|
||||||
|
}
|
||||||
|
err.code
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
std::process::exit(code);
|
std::process::exit(code as i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run() -> Result<i32, anyhow::Error> {
|
fn run() -> Result<(), exit::ExitCode> {
|
||||||
let args = args::Args::from_args();
|
// clap's `get_matches` uses Failure rather than Usage, so bypass it for `get_matches_safe`.
|
||||||
|
let args = match args::Args::from_args_safe() {
|
||||||
|
Ok(args) => args,
|
||||||
|
Err(e) if e.use_stderr() => {
|
||||||
|
return Err(sysexit::Code::Usage.chain(e.into()));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
println!("{}", e);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
init_logging(args.verbose.log_level());
|
init_logging(args.verbose.log_level());
|
||||||
|
|
||||||
let config = if let Some(path) = args.custom_config.as_ref() {
|
let config = if let Some(path) = args.custom_config.as_ref() {
|
||||||
config::Config::from_file(path)?
|
config::Config::from_file(path).code(sysexit::Code::Config)?
|
||||||
} else {
|
} else {
|
||||||
config::Config::default()
|
config::Config::default()
|
||||||
};
|
};
|
||||||
|
@ -38,7 +55,7 @@ fn run() -> Result<i32, anyhow::Error> {
|
||||||
let mut typos_found = false;
|
let mut typos_found = false;
|
||||||
let mut errors_found = false;
|
let mut errors_found = false;
|
||||||
for path in args.path.iter() {
|
for path in args.path.iter() {
|
||||||
let path = path.canonicalize()?;
|
let path = path.canonicalize().code(sysexit::Code::Usage)?;
|
||||||
let cwd = if path.is_file() {
|
let cwd = if path.is_file() {
|
||||||
path.parent().unwrap()
|
path.parent().unwrap()
|
||||||
} else {
|
} else {
|
||||||
|
@ -47,7 +64,7 @@ fn run() -> Result<i32, anyhow::Error> {
|
||||||
|
|
||||||
let mut config = config.clone();
|
let mut config = config.clone();
|
||||||
if !args.isolated {
|
if !args.isolated {
|
||||||
let derived = config::Config::derive(cwd)?;
|
let derived = config::Config::derive(cwd).code(sysexit::Code::Config)?;
|
||||||
config.update(&derived);
|
config.update(&derived);
|
||||||
}
|
}
|
||||||
config.update(&args.config);
|
config.update(&args.config);
|
||||||
|
@ -134,18 +151,18 @@ fn run() -> Result<i32, anyhow::Error> {
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.diff {
|
if args.diff {
|
||||||
diff_reporter.show()?;
|
diff_reporter.show().code(sysexit::Code::Unknown)?;
|
||||||
} else if args.write_changes {
|
} else if args.write_changes {
|
||||||
replace_reporter.write()?;
|
replace_reporter.write().code(sysexit::Code::Unknown)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if errors_found {
|
if errors_found {
|
||||||
Ok(2)
|
Err(sysexit::Code::Failure.error())
|
||||||
} else if typos_found {
|
} else if typos_found {
|
||||||
Ok(1)
|
Err(sysexit::Code::DataErr.error())
|
||||||
} else {
|
} else {
|
||||||
Ok(0)
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue