2016-10-18 23:37:49 -04:00
|
|
|
extern crate ctrlc;
|
2016-02-27 11:07:26 -05:00
|
|
|
extern crate docopt;
|
2016-08-28 01:37:12 -04:00
|
|
|
extern crate env_logger;
|
2016-06-20 16:53:48 -04:00
|
|
|
extern crate grep;
|
2016-10-11 19:57:09 -04:00
|
|
|
extern crate ignore;
|
2016-09-05 17:36:41 -04:00
|
|
|
#[cfg(windows)]
|
|
|
|
extern crate kernel32;
|
2016-09-03 21:48:23 -04:00
|
|
|
#[macro_use]
|
|
|
|
extern crate lazy_static;
|
2016-09-05 17:36:41 -04:00
|
|
|
extern crate libc;
|
2016-08-28 01:37:12 -04:00
|
|
|
#[macro_use]
|
|
|
|
extern crate log;
|
2016-03-10 20:48:44 -05:00
|
|
|
extern crate memchr;
|
|
|
|
extern crate memmap;
|
2016-08-25 21:44:37 -04:00
|
|
|
extern crate num_cpus;
|
2016-02-27 11:07:26 -05:00
|
|
|
extern crate regex;
|
|
|
|
extern crate rustc_serialize;
|
2016-09-05 17:36:41 -04:00
|
|
|
extern crate term;
|
|
|
|
#[cfg(windows)]
|
|
|
|
extern crate winapi;
|
2016-02-27 11:07:26 -05:00
|
|
|
|
|
|
|
use std::error::Error;
|
2016-09-26 19:57:23 -04:00
|
|
|
use std::io;
|
2016-10-18 23:37:49 -04:00
|
|
|
use std::io::Write;
|
2016-02-27 11:07:26 -05:00
|
|
|
use std::process;
|
|
|
|
use std::result;
|
2016-09-05 19:55:31 -04:00
|
|
|
use std::sync::{Arc, Mutex};
|
2016-11-05 21:44:15 -04:00
|
|
|
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
|
|
|
|
use std::sync::mpsc;
|
2016-08-28 01:37:12 -04:00
|
|
|
use std::thread;
|
2016-09-24 17:29:14 -07:00
|
|
|
use std::cmp;
|
2016-02-27 11:07:26 -05:00
|
|
|
|
2016-09-07 21:54:28 -04:00
|
|
|
use term::Terminal;
|
2016-08-25 21:44:37 -04:00
|
|
|
|
2016-09-05 00:52:23 -04:00
|
|
|
use args::Args;
|
2016-11-05 21:44:15 -04:00
|
|
|
use worker::Work;
|
2016-08-27 01:01:06 -04:00
|
|
|
|
2016-08-25 21:44:37 -04:00
|
|
|
macro_rules! errored {
|
|
|
|
($($tt:tt)*) => {
|
|
|
|
return Err(From::from(format!($($tt)*)));
|
|
|
|
}
|
|
|
|
}
|
2016-02-27 11:07:26 -05:00
|
|
|
|
2016-08-25 21:44:37 -04:00
|
|
|
macro_rules! eprintln {
|
|
|
|
($($tt:tt)*) => {{
|
|
|
|
use std::io::Write;
|
|
|
|
let _ = writeln!(&mut ::std::io::stderr(), $($tt)*);
|
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2016-09-05 00:52:23 -04:00
|
|
|
mod args;
|
2016-09-10 00:05:20 -04:00
|
|
|
mod atty;
|
2016-09-05 00:52:23 -04:00
|
|
|
mod out;
|
2016-09-15 22:06:04 -04:00
|
|
|
mod pathutil;
|
2016-08-28 01:37:12 -04:00
|
|
|
mod printer;
|
2016-09-06 21:47:33 -04:00
|
|
|
mod search_buffer;
|
2016-09-10 00:08:42 -04:00
|
|
|
mod search_stream;
|
2016-09-13 21:11:46 -04:00
|
|
|
#[cfg(windows)]
|
|
|
|
mod terminal_win;
|
2016-11-05 21:44:15 -04:00
|
|
|
mod worker;
|
2016-03-10 20:48:44 -05:00
|
|
|
|
2016-08-28 01:37:12 -04:00
|
|
|
pub type Result<T> = result::Result<T, Box<Error + Send + Sync>>;
|
|
|
|
|
2016-02-27 11:07:26 -05:00
|
|
|
fn main() {
|
2016-11-05 21:44:15 -04:00
|
|
|
match Args::parse().map(Arc::new).and_then(run) {
|
2016-09-05 00:52:23 -04:00
|
|
|
Ok(count) if count == 0 => process::exit(1),
|
2016-09-13 21:11:46 -04:00
|
|
|
Ok(_) => process::exit(0),
|
2016-02-27 11:07:26 -05:00
|
|
|
Err(err) => {
|
2016-09-05 17:36:41 -04:00
|
|
|
eprintln!("{}", err);
|
2016-02-27 11:07:26 -05:00
|
|
|
process::exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
fn run(args: Arc<Args>) -> Result<u64> {
|
2016-11-06 13:09:53 -05:00
|
|
|
if args.never_match() {
|
|
|
|
return Ok(0);
|
|
|
|
}
|
2016-11-05 21:44:15 -04:00
|
|
|
{
|
|
|
|
let args = args.clone();
|
|
|
|
ctrlc::set_handler(move || {
|
|
|
|
let stdout = io::stdout();
|
|
|
|
let mut stdout = stdout.lock();
|
2016-10-18 23:37:49 -04:00
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
let _ = args.stdout().reset();
|
|
|
|
let _ = stdout.flush();
|
2016-10-18 23:37:49 -04:00
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
process::exit(1);
|
|
|
|
});
|
|
|
|
}
|
2016-09-25 21:27:17 -04:00
|
|
|
let threads = cmp::max(1, args.threads() - 1);
|
2016-09-05 00:52:23 -04:00
|
|
|
if args.files() {
|
2016-11-05 21:44:15 -04:00
|
|
|
if threads == 1 || args.is_one_path() {
|
|
|
|
run_files_one_thread(args)
|
|
|
|
} else {
|
|
|
|
run_files_parallel(args)
|
|
|
|
}
|
|
|
|
} else if args.type_list() {
|
|
|
|
run_types(args)
|
|
|
|
} else if threads == 1 || args.is_one_path() {
|
|
|
|
run_one_thread(args)
|
|
|
|
} else {
|
|
|
|
run_parallel(args)
|
2016-09-25 21:27:17 -04:00
|
|
|
}
|
2016-11-05 21:44:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
fn run_parallel(args: Arc<Args>) -> Result<u64> {
|
2016-09-08 21:46:14 -04:00
|
|
|
let out = Arc::new(Mutex::new(args.out()));
|
2016-09-28 20:50:50 -04:00
|
|
|
let quiet_matched = QuietMatched::new(args.quiet());
|
2016-11-05 21:44:15 -04:00
|
|
|
let paths_searched = Arc::new(AtomicUsize::new(0));
|
|
|
|
let match_count = Arc::new(AtomicUsize::new(0));
|
|
|
|
|
|
|
|
args.walker_parallel().run(|| {
|
|
|
|
let args = args.clone();
|
|
|
|
let quiet_matched = quiet_matched.clone();
|
|
|
|
let paths_searched = paths_searched.clone();
|
|
|
|
let match_count = match_count.clone();
|
|
|
|
let out = out.clone();
|
|
|
|
let mut outbuf = args.outbuf();
|
|
|
|
let mut worker = args.worker();
|
|
|
|
Box::new(move |result| {
|
|
|
|
use ignore::WalkState::*;
|
2016-08-28 20:18:34 -04:00
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
if quiet_matched.has_match() {
|
|
|
|
return Quit;
|
|
|
|
}
|
2016-11-06 14:36:08 -05:00
|
|
|
let dent = match get_or_log_dir_entry(result, args.no_messages()) {
|
2016-11-05 21:44:15 -04:00
|
|
|
None => return Continue,
|
|
|
|
Some(dent) => dent,
|
2016-08-28 20:18:34 -04:00
|
|
|
};
|
2016-11-05 21:44:15 -04:00
|
|
|
paths_searched.fetch_add(1, Ordering::SeqCst);
|
|
|
|
outbuf.clear();
|
|
|
|
{
|
|
|
|
// This block actually executes the search and prints the
|
|
|
|
// results into outbuf.
|
|
|
|
let mut printer = args.printer(&mut outbuf);
|
|
|
|
let count =
|
|
|
|
if dent.is_stdin() {
|
|
|
|
worker.run(&mut printer, Work::Stdin)
|
|
|
|
} else {
|
|
|
|
worker.run(&mut printer, Work::DirEntry(dent))
|
|
|
|
};
|
|
|
|
match_count.fetch_add(count as usize, Ordering::SeqCst);
|
|
|
|
if quiet_matched.set_match(count > 0) {
|
|
|
|
return Quit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !outbuf.get_ref().is_empty() {
|
|
|
|
// This should be the only mutex in all of ripgrep. Since the
|
|
|
|
// common case is to report a small number of matches relative
|
|
|
|
// to the corpus, this really shouldn't matter much.
|
|
|
|
//
|
|
|
|
// Still, it'd be nice to send this on a channel, but then we'd
|
|
|
|
// need to manage a pool of outbufs, which would complicate the
|
|
|
|
// code.
|
|
|
|
let mut out = out.lock().unwrap();
|
|
|
|
out.write(&outbuf);
|
|
|
|
}
|
|
|
|
Continue
|
|
|
|
})
|
|
|
|
});
|
|
|
|
if !args.paths().is_empty() && paths_searched.load(Ordering::SeqCst) == 0 {
|
2016-11-06 14:36:08 -05:00
|
|
|
if !args.no_messages() {
|
|
|
|
eprint_nothing_searched();
|
|
|
|
}
|
2016-08-28 20:18:34 -04:00
|
|
|
}
|
2016-11-05 21:44:15 -04:00
|
|
|
Ok(match_count.load(Ordering::SeqCst) as u64)
|
2016-08-28 20:18:34 -04:00
|
|
|
}
|
2016-08-25 21:44:37 -04:00
|
|
|
|
2016-09-25 21:27:17 -04:00
|
|
|
fn run_one_thread(args: Arc<Args>) -> Result<u64> {
|
2016-11-05 21:44:15 -04:00
|
|
|
let mut worker = args.worker();
|
2016-09-25 21:27:17 -04:00
|
|
|
let mut term = args.stdout();
|
|
|
|
let mut paths_searched: u64 = 0;
|
2016-11-05 21:44:15 -04:00
|
|
|
let mut match_count = 0;
|
|
|
|
for result in args.walker() {
|
2016-11-06 14:36:08 -05:00
|
|
|
let dent = match get_or_log_dir_entry(result, args.no_messages()) {
|
2016-11-05 21:44:15 -04:00
|
|
|
None => continue,
|
|
|
|
Some(dent) => dent,
|
|
|
|
};
|
2016-10-11 19:57:09 -04:00
|
|
|
let mut printer = args.printer(&mut term);
|
2016-11-05 21:44:15 -04:00
|
|
|
if match_count > 0 {
|
2016-10-11 19:57:09 -04:00
|
|
|
if args.quiet() {
|
|
|
|
break;
|
2016-09-25 21:27:17 -04:00
|
|
|
}
|
2016-10-11 19:57:09 -04:00
|
|
|
if let Some(sep) = args.file_separator() {
|
|
|
|
printer = printer.file_separator(sep);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
paths_searched += 1;
|
2016-11-05 21:44:15 -04:00
|
|
|
match_count +=
|
|
|
|
if dent.is_stdin() {
|
|
|
|
worker.run(&mut printer, Work::Stdin)
|
|
|
|
} else {
|
|
|
|
worker.run(&mut printer, Work::DirEntry(dent))
|
2016-10-11 19:57:09 -04:00
|
|
|
};
|
2016-09-25 21:27:17 -04:00
|
|
|
}
|
2016-10-11 19:57:09 -04:00
|
|
|
if !args.paths().is_empty() && paths_searched == 0 {
|
2016-11-06 14:36:08 -05:00
|
|
|
if !args.no_messages() {
|
|
|
|
eprint_nothing_searched();
|
|
|
|
}
|
2016-09-25 21:27:17 -04:00
|
|
|
}
|
2016-11-05 21:44:15 -04:00
|
|
|
Ok(match_count)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_files_parallel(args: Arc<Args>) -> Result<u64> {
|
|
|
|
let print_args = args.clone();
|
|
|
|
let (tx, rx) = mpsc::channel::<ignore::DirEntry>();
|
|
|
|
let print_thread = thread::spawn(move || {
|
|
|
|
let term = print_args.stdout();
|
|
|
|
let mut printer = print_args.printer(term);
|
|
|
|
let mut file_count = 0;
|
|
|
|
for dent in rx.iter() {
|
|
|
|
printer.path(dent.path());
|
|
|
|
file_count += 1;
|
|
|
|
}
|
|
|
|
file_count
|
|
|
|
});
|
2016-11-06 14:36:08 -05:00
|
|
|
let no_messages = args.no_messages();
|
2016-11-05 21:44:15 -04:00
|
|
|
args.walker_parallel().run(move || {
|
|
|
|
let tx = tx.clone();
|
|
|
|
Box::new(move |result| {
|
2016-11-06 14:36:08 -05:00
|
|
|
if let Some(dent) = get_or_log_dir_entry(result, no_messages) {
|
2016-11-05 21:44:15 -04:00
|
|
|
tx.send(dent).unwrap();
|
|
|
|
}
|
|
|
|
ignore::WalkState::Continue
|
|
|
|
})
|
|
|
|
});
|
|
|
|
Ok(print_thread.join().unwrap())
|
2016-09-25 21:27:17 -04:00
|
|
|
}
|
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
fn run_files_one_thread(args: Arc<Args>) -> Result<u64> {
|
2016-09-13 21:11:46 -04:00
|
|
|
let term = args.stdout();
|
2016-09-08 21:46:14 -04:00
|
|
|
let mut printer = args.printer(term);
|
2016-09-05 00:52:23 -04:00
|
|
|
let mut file_count = 0;
|
2016-11-05 21:44:15 -04:00
|
|
|
for result in args.walker() {
|
2016-11-06 14:36:08 -05:00
|
|
|
let dent = match get_or_log_dir_entry(result, args.no_messages()) {
|
2016-11-05 21:44:15 -04:00
|
|
|
None => continue,
|
|
|
|
Some(dent) => dent,
|
|
|
|
};
|
2016-10-11 19:57:09 -04:00
|
|
|
printer.path(dent.path());
|
|
|
|
file_count += 1;
|
2016-09-03 21:48:23 -04:00
|
|
|
}
|
2016-09-05 00:52:23 -04:00
|
|
|
Ok(file_count)
|
|
|
|
}
|
2016-09-03 21:48:23 -04:00
|
|
|
|
2016-09-13 21:11:46 -04:00
|
|
|
fn run_types(args: Arc<Args>) -> Result<u64> {
|
|
|
|
let term = args.stdout();
|
2016-09-08 21:46:14 -04:00
|
|
|
let mut printer = args.printer(term);
|
2016-09-05 00:52:23 -04:00
|
|
|
let mut ty_count = 0;
|
|
|
|
for def in args.type_defs() {
|
|
|
|
printer.type_def(def);
|
|
|
|
ty_count += 1;
|
2016-09-03 21:48:23 -04:00
|
|
|
}
|
2016-09-05 00:52:23 -04:00
|
|
|
Ok(ty_count)
|
2016-08-27 01:01:06 -04:00
|
|
|
}
|
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
fn get_or_log_dir_entry(
|
|
|
|
result: result::Result<ignore::DirEntry, ignore::Error>,
|
2016-11-06 14:36:08 -05:00
|
|
|
no_messages: bool,
|
2016-11-05 21:44:15 -04:00
|
|
|
) -> Option<ignore::DirEntry> {
|
|
|
|
match result {
|
|
|
|
Err(err) => {
|
2016-11-06 14:36:08 -05:00
|
|
|
if !no_messages {
|
|
|
|
eprintln!("{}", err);
|
|
|
|
}
|
2016-11-05 21:44:15 -04:00
|
|
|
None
|
2016-08-28 01:37:12 -04:00
|
|
|
}
|
2016-11-05 21:44:15 -04:00
|
|
|
Ok(dent) => {
|
|
|
|
if let Some(err) = dent.error() {
|
2016-11-06 14:36:08 -05:00
|
|
|
if !no_messages {
|
|
|
|
eprintln!("{}", err);
|
|
|
|
}
|
2016-09-05 10:15:13 -04:00
|
|
|
}
|
2016-11-05 21:44:15 -04:00
|
|
|
if !dent.file_type().map_or(true, |x| x.is_file()) {
|
|
|
|
None
|
|
|
|
} else {
|
|
|
|
Some(dent)
|
|
|
|
}
|
2016-09-05 10:15:13 -04:00
|
|
|
}
|
2016-09-05 00:52:23 -04:00
|
|
|
}
|
2016-11-05 21:44:15 -04:00
|
|
|
}
|
2016-09-05 00:52:23 -04:00
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
fn eprint_nothing_searched() {
|
|
|
|
eprintln!("No files were searched, which means ripgrep probably \
|
|
|
|
applied a filter you didn't expect. \
|
|
|
|
Try running again with --debug.");
|
2016-09-03 21:48:23 -04:00
|
|
|
}
|
2016-09-28 20:50:50 -04:00
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
/// A simple thread safe abstraction for determining whether a search should
|
|
|
|
/// stop if the user has requested quiet mode.
|
2016-09-28 20:50:50 -04:00
|
|
|
#[derive(Clone, Debug)]
|
2016-11-05 21:44:15 -04:00
|
|
|
pub struct QuietMatched(Arc<Option<AtomicBool>>);
|
2016-09-28 20:50:50 -04:00
|
|
|
|
|
|
|
impl QuietMatched {
|
2016-11-05 21:44:15 -04:00
|
|
|
/// Create a new QuietMatched value.
|
|
|
|
///
|
|
|
|
/// If quiet is true, then set_match and has_match will reflect whether
|
|
|
|
/// a search should quit or not because it found a match.
|
|
|
|
///
|
|
|
|
/// If quiet is false, then set_match is always a no-op and has_match
|
|
|
|
/// always returns false.
|
|
|
|
pub fn new(quiet: bool) -> QuietMatched {
|
2016-09-28 20:50:50 -04:00
|
|
|
let atomic = if quiet { Some(AtomicBool::new(false)) } else { None };
|
|
|
|
QuietMatched(Arc::new(atomic))
|
|
|
|
}
|
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
/// Returns true if and only if quiet mode is enabled and a match has
|
|
|
|
/// occurred.
|
|
|
|
pub fn has_match(&self) -> bool {
|
2016-09-28 20:50:50 -04:00
|
|
|
match *self.0 {
|
|
|
|
None => false,
|
|
|
|
Some(ref matched) => matched.load(Ordering::SeqCst),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-05 21:44:15 -04:00
|
|
|
/// Sets whether a match has occurred or not.
|
|
|
|
///
|
|
|
|
/// If quiet mode is disabled, then this is a no-op.
|
|
|
|
pub fn set_match(&self, yes: bool) -> bool {
|
2016-09-28 20:50:50 -04:00
|
|
|
match *self.0 {
|
|
|
|
None => false,
|
|
|
|
Some(_) if !yes => false,
|
|
|
|
Some(ref m) => { m.store(true, Ordering::SeqCst); true }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|