aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel <kingdread@gmx.de>2020-06-07 02:12:28 +0200
committerDaniel <kingdread@gmx.de>2020-06-07 02:12:28 +0200
commitd12aec96e755306f53d7f9b162a95cb6144cab02 (patch)
treef9b760ba7c2aeb280811fad8010e9d35ddaa4c4c
parent642bf28c79cc39def7105460452cd60957958b23 (diff)
downloadraidgrep-d12aec96e755306f53d7f9b162a95cb6144cab02.tar.gz
raidgrep-d12aec96e755306f53d7f9b162a95cb6144cab02.tar.bz2
raidgrep-d12aec96e755306f53d7f9b162a95cb6144cab02.zip
make exit status dependent on search results
-rw-r--r--CHANGELOG.md3
-rw-r--r--raidgrep.1.asciidoc7
-rw-r--r--src/main.rs47
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.