diff options
-rw-r--r-- | CHANGELOG.md | 3 | ||||
-rw-r--r-- | raidgrep.1.asciidoc | 7 | ||||
-rw-r--r-- | src/main.rs | 47 |
3 files changed, 45 insertions, 12 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bccd70..cbe6001 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,9 @@ All notable changes to this project will be documented in this file. ## Unreleased +### Changed +- The exit code will now be dependent on whether logs matching the filter were + found or not. ## 1.2.0 - 2020-05-16 ### Added diff --git a/raidgrep.1.asciidoc b/raidgrep.1.asciidoc index 584713e..7cb3f38 100644 --- a/raidgrep.1.asciidoc +++ b/raidgrep.1.asciidoc @@ -231,6 +231,13 @@ Any options given in this mode will apply to the whole REPL session. For example, if started with *-l*, all REPL evaluations will only print the file names of the matching files. +== EXIT STATUS + +raidgrep will exit with status 0 (success) if at least one matching log was +found, with status 1 if no logs were found and status 2 if there was an error. + +If used with the REPL mode, raidgrep will always exit with status 0. + == EXAMPLES The following are examples of predicates as they might be entered in the REPL. diff --git a/src/main.rs b/src/main.rs index 84d1063..d048cb0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,13 @@ use playerclass::PlayerClass; /// Application name, as it should be used in configuration directory paths. const APP_NAME: &str = "raidgrep"; +/// Process exit code for when everything went right. +const RETCODE_SUCCESS: i32 = 0; +/// Process exit code for when no results are found. +const RETCODE_NO_RESULTS: i32 = 1; +/// Process exit code for when an error occurred. +const RETCODE_ERROR: i32 = 2; + /// A program that allows you to search through all your evtc logs for specific people. /// /// raidgrep supports different predicates that determine whether a log is included or not. @@ -241,8 +248,12 @@ static INTERRUPTED: AtomicBool = AtomicBool::new(false); fn main() { let result = run(); - if let Err(err) = result { - display_error(&err); + match result { + Ok(retcode) => std::process::exit(retcode), + Err(err) => { + display_error(&err); + std::process::exit(RETCODE_ERROR); + } } } @@ -254,7 +265,7 @@ fn display_error(err: &Error) { } } -fn run() -> Result<()> { +fn run() -> Result<i32> { let opt = Opt::from_args(); if opt.no_color { @@ -271,20 +282,26 @@ fn run() -> Result<()> { guilds::prepare_cache(); } + let retcode; if !opt.repl { - single(&opt)?; + if single(&opt)? { + retcode = RETCODE_SUCCESS; + } else { + retcode = RETCODE_NO_RESULTS; + } } else { repl(&opt)?; + retcode = RETCODE_SUCCESS; } if opt.guilds { guilds::save_cache(); } - Ok(()) + Ok(retcode) } -fn single(opt: &Opt) -> Result<()> { +fn single(opt: &Opt) -> Result<bool> { // As a shortcut, we allow only the regular expression to be given, to retain the behaviour // before the filter changes. if opt.expression.len() == 1 { @@ -304,8 +321,7 @@ fn single(opt: &Opt) -> Result<()> { let expr_string = fexpr::requote(&opt.expression); let filter = build_filter(&expr_string)?; - grep(&opt, &*filter)?; - Ok(()) + grep(&opt, &*filter) } fn repl(opt: &Opt) -> Result<()> { @@ -328,7 +344,7 @@ fn repl(opt: &Opt) -> Result<()> { let parsed = build_filter(&line); INTERRUPTED.store(false, Ordering::Relaxed); match parsed { - Ok(filter) => grep(&opt, &*filter)?, + Ok(filter) => grep(&opt, &*filter).map(|_| ())?, Err(err) => display_error(&err), } } @@ -384,9 +400,13 @@ fn build_filter(expr_string: &str) -> Result<Box<dyn LogFilter>> { } /// Run the grep search with the given options. -fn grep(opt: &Opt, filter: &dyn LogFilter) -> Result<()> { +/// +/// This function returns `false` if no log has been found, and `true` if at least one log matched +/// the filter. +fn grep(opt: &Opt, filter: &dyn LogFilter) -> Result<bool> { let pipeline = output::build_pipeline(opt); let pipeline_ref = &pipeline; + let found_something = &AtomicBool::new(false); let result: Result<()> = rayon::scope(|s| { let walker = WalkDir::new(&opt.path); for entry in walker { @@ -400,7 +420,10 @@ fn grep(opt: &Opt, filter: &dyn LogFilter) -> Result<()> { let search = search_log(&entry, filter); match search { Ok(None) => (), - Ok(Some(result)) => pipeline_ref.push_item(result), + Ok(Some(result)) => { + found_something.store(true, Ordering::Relaxed); + pipeline_ref.push_item(result); + }, Err(err) => { debug!("Runtime error while scanning {:?}: {}", entry.path(), err); } @@ -412,7 +435,7 @@ fn grep(opt: &Opt, filter: &dyn LogFilter) -> Result<()> { }); result?; pipeline.finish(); - Ok(()) + Ok(found_something.load(Ordering::Relaxed)) } /// Search the given single log. |