Skip to content

Commit

Permalink
Merge pull request #173 from epage/code
Browse files Browse the repository at this point in the history
fix(cli): Define an error code policy
  • Loading branch information
epage authored Nov 15, 2020
2 parents 8a35a12 + 4ddbdcf commit d84117d
Show file tree
Hide file tree
Showing 4 changed files with 97 additions and 14 deletions.
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ env_logger = "0.8"
bstr = "0.2"
ahash = "0.5.8"
difflib = "0.4"
sysexit = "0.2"

[dev-dependencies]
assert_fs = "1.0"
Expand Down
55 changes: 55 additions & 0 deletions src/exit.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 31 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,34 +11,51 @@ mod checks;
mod config;
mod dict;
mod diff;
mod exit;
mod replace;

use exit::ChainCodeExt;
use exit::ExitCodeResultAnyhowExt;
use exit::ExitCodeResultErrorExt;

fn main() {
let code = match run() {
Ok(code) => code,
Ok(()) => sysexit::Code::Success,
Err(err) => {
eprintln!("{}", err);
1
if let Some(error) = err.error {
eprintln!("{}", error);
}
err.code
}
};
std::process::exit(code);
std::process::exit(code as i32);
}

fn run() -> Result<i32, anyhow::Error> {
let args = args::Args::from_args();
fn run() -> Result<(), exit::ExitCode> {
// 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());

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 {
config::Config::default()
};

let mut typos_found = false;
let mut errors_found = false;
for path in args.path.iter() {
let path = path.canonicalize()?;
let path = path.canonicalize().code(sysexit::Code::Usage)?;
let cwd = if path.is_file() {
path.parent().unwrap()
} else {
Expand All @@ -47,7 +64,7 @@ fn run() -> Result<i32, anyhow::Error> {

let mut config = config.clone();
if !args.isolated {
let derived = config::Config::derive(cwd)?;
let derived = config::Config::derive(cwd).code(sysexit::Code::Config)?;
config.update(&derived);
}
config.update(&args.config);
Expand Down Expand Up @@ -134,18 +151,18 @@ fn run() -> Result<i32, anyhow::Error> {
}

if args.diff {
diff_reporter.show()?;
diff_reporter.show().code(sysexit::Code::Unknown)?;
} else if args.write_changes {
replace_reporter.write()?;
replace_reporter.write().code(sysexit::Code::Unknown)?;
}
}

if errors_found {
Ok(2)
Err(sysexit::Code::Failure.error())
} else if typos_found {
Ok(1)
Err(sysexit::Code::DataErr.error())
} else {
Ok(0)
Ok(())
}
}

Expand Down

0 comments on commit d84117d

Please sign in to comment.