Add --max-filesize option to cli

The --max-filesize option allows filtering files which are larger than
the specified limit. This is potentially useful if one is attempting to
search a number of large files without common file-types/suffixes.

See #369.
This commit is contained in:
tiehuis
2017-02-28 17:53:52 +13:00
committed by Andrew Gallant
parent 49fd668712
commit 714ae82241
7 changed files with 96 additions and 3 deletions

View File

@@ -1,6 +1,7 @@
use std::collections::HashMap;
use clap::{App, AppSettings, Arg, ArgSettings};
use regex::Regex;
const ABOUT: &'static str = "
ripgrep (rg) recursively searches your current directory for a regex pattern.
@@ -145,6 +146,9 @@ fn app<F>(next_line_help: bool, doc: F) -> App<'static, 'static>
.arg(flag("max-count")
.short("m").value_name("NUM").takes_value(true)
.validator(validate_number))
.arg(flag("max-filesize")
.value_name("NUM+SUFFIX?").takes_value(true)
.validator(validate_max_filesize))
.arg(flag("maxdepth")
.value_name("NUM").takes_value(true)
.validator(validate_number))
@@ -371,6 +375,13 @@ lazy_static! {
doc!(h, "max-count",
"Limit the number of matches.",
"Limit the number of matching lines per file searched to NUM.");
doc!(h, "max-filesize",
"Ignore files larger than NUM in size.",
"Ignore files larger than NUM in size. Does not ignore directories. \
\n\nThe input format accepts suffixes of K, M or G which \
correspond to kilobytes, megabytes and gigabytes. If no suffix is \
provided the input is treated as bytes. \
\n\nExample: --max-filesize 50K or --max-filesize 80M");
doc!(h, "maxdepth",
"Descend at most NUM directories.",
"Limit the depth of directory traversal to NUM levels beyond \
@@ -491,3 +502,24 @@ lazy_static! {
fn validate_number(s: String) -> Result<(), String> {
s.parse::<usize>().map(|_|()).map_err(|err| err.to_string())
}
fn validate_max_filesize(s: String) -> Result<(), String> {
let re = Regex::new(r#"^(\d+)([KMG])?$"#).unwrap();
let caps = try!(re.captures(&s)
.ok_or("invalid format for max-filesize argument"));
let value = caps.get(1);
let suffix = caps.get(2).map(|x| x.as_str());
match value {
Some(value) => {
try!(value.as_str().parse::<u64>().map_err(|err| err.to_string()));
}
None => ()
}
match suffix {
None | Some("K") | Some("M") | Some("G") => Ok(()),
_ => Err(From::from("invalid suffix for max-filesize argument"))
}
}

View File

@@ -55,6 +55,7 @@ pub struct Args {
line_number: bool,
line_per_match: bool,
max_count: Option<u64>,
max_filesize: Option<u64>,
maxdepth: Option<usize>,
mmap: bool,
no_ignore: bool,
@@ -285,6 +286,7 @@ impl Args {
wd.follow_links(self.follow);
wd.hidden(!self.hidden);
wd.max_depth(self.maxdepth);
wd.max_filesize(self.max_filesize);
wd.overrides(self.glob_overrides.clone());
wd.types(self.types.clone());
wd.git_global(!self.no_ignore && !self.no_ignore_vcs);
@@ -342,6 +344,7 @@ impl<'a> ArgMatches<'a> {
line_number: self.line_number(),
line_per_match: self.is_present("vimgrep"),
max_count: try!(self.usize_of("max-count")).map(|max| max as u64),
max_filesize: try!(self.max_filesize()),
maxdepth: try!(self.usize_of("maxdepth")),
mmap: mmap,
no_ignore: self.no_ignore(),
@@ -779,6 +782,33 @@ impl<'a> ArgMatches<'a> {
btypes.build().map_err(From::from)
}
/// Parses the max-filesize argument option into a byte count.
fn max_filesize(&self) -> Result<Option<u64>> {
use regex::Regex;
let max_filesize = match self.value_of_lossy("max-filesize") {
Some(x) => x,
None => return Ok(None)
};
let re = Regex::new(r#"^(\d+)([KMG])?$"#).unwrap();
let caps = try!(re.captures(&max_filesize)
.ok_or("invalid format for max-filesize argument"));
let value = match caps.get(1) {
Some(value) => Some(try!(value.as_str().parse::<u64>())),
None => None
};
let suffix = caps.get(2).map(|x| x.as_str());
match suffix {
None => Ok(value),
Some("K") => Ok(value.map(|x| x * 1024)),
Some("M") => Ok(value.map(|x| x * 1024 * 1024)),
Some("G") => Ok(value.map(|x| x * 1024 * 1024 * 1024)),
_ => Err(From::from("invalid suffix for max-filesize argument"))
}
}
/// Returns true if ignore files should be ignored.
fn no_ignore(&self) -> bool {
self.is_present("no-ignore")