|
@@ -1,7 +1,45 @@
|
|
use walkdir::WalkDir;
|
|
use walkdir::WalkDir;
|
|
|
|
|
|
|
|
+#[derive(Debug)]
|
|
struct Args {
|
|
struct Args {
|
|
- targets: Vec<&'static str>,
|
|
|
|
|
|
+ targets: Vec<String>,
|
|
|
|
+ num_threads: u8,
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+impl Args {
|
|
|
|
+ fn parse() -> Args {
|
|
|
|
+ let matches = clap::App::new("rubygrep")
|
|
|
|
+ .version("0.1")
|
|
|
|
+ .author("Getty Ritter <rubygrep@infinitenegativeutility.com>")
|
|
|
|
+ .about("Search Ruby source trees")
|
|
|
|
+ .arg(clap::Arg::with_name("threads")
|
|
|
|
+ .short("j")
|
|
|
|
+ .value_name("THREADS")
|
|
|
|
+ .help("Spawn the specified number of worker threads")
|
|
|
|
+ .takes_value(true))
|
|
|
|
+ .arg(clap::Arg::with_name("targets")
|
|
|
|
+ .help("The Ruby sources and directories to search")
|
|
|
|
+ .multiple(true))
|
|
|
|
+ .get_matches();
|
|
|
|
+
|
|
|
|
+ let targets = if let Some(values) = matches.values_of("targets") {
|
|
|
|
+ values.map(|x| x.to_owned()).collect::<Vec<String>>()
|
|
|
|
+ } else {
|
|
|
|
+ vec![".".to_owned()]
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ let num_threads = if let Some(val) = matches.value_of("threads") {
|
|
|
|
+ match val.parse() {
|
|
|
|
+ Ok(x) => x,
|
|
|
|
+ Err(_) => {
|
|
|
|
+ panic!("Invalid number of threads: {}", val);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ } else {
|
|
|
|
+ 8
|
|
|
|
+ };
|
|
|
|
+ Args { targets, num_threads }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
fn is_ruby_source(path: &std::path::Path) -> bool {
|
|
fn is_ruby_source(path: &std::path::Path) -> bool {
|
|
@@ -12,15 +50,18 @@ fn is_ruby_source(path: &std::path::Path) -> bool {
|
|
}
|
|
}
|
|
|
|
|
|
fn main() {
|
|
fn main() {
|
|
- let args = Args {
|
|
|
|
- targets: vec!["."],
|
|
|
|
- };
|
|
|
|
|
|
+ let args = Args::parse();
|
|
|
|
+ println!("Got args: {:?}", args);
|
|
|
|
+ let Args {
|
|
|
|
+ targets,
|
|
|
|
+ num_threads,
|
|
|
|
+ } = args;
|
|
|
|
|
|
let (work_send, work_recv) = crossbeam::channel::unbounded();
|
|
let (work_send, work_recv) = crossbeam::channel::unbounded();
|
|
|
|
|
|
// produce a thread which populates the channel with work
|
|
// produce a thread which populates the channel with work
|
|
let producer = std::thread::spawn(move || {
|
|
let producer = std::thread::spawn(move || {
|
|
- for target in args.targets {
|
|
|
|
|
|
+ for target in targets {
|
|
for entry in WalkDir::new(target).into_iter().filter_map(|e| e.ok()) {
|
|
for entry in WalkDir::new(target).into_iter().filter_map(|e| e.ok()) {
|
|
if is_ruby_source(entry.path()) {
|
|
if is_ruby_source(entry.path()) {
|
|
work_send.send(entry).expect("Unable to send work from producer thread");
|
|
work_send.send(entry).expect("Unable to send work from producer thread");
|
|
@@ -29,19 +70,37 @@ fn main() {
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
|
|
- // produce a set of threads which
|
|
|
|
- let workers: Vec<std::thread::JoinHandle<()>> = (0..8).map(|id| {
|
|
|
|
|
|
+ // produce a set of threads which can grab work to be done
|
|
|
|
+ let workers: Vec<std::thread::JoinHandle<()>> = (0..num_threads).map(|id| {
|
|
let receiver = work_recv.clone();
|
|
let receiver = work_recv.clone();
|
|
std::thread::spawn(move || {
|
|
std::thread::spawn(move || {
|
|
while let Ok(msg) = receiver.recv() {
|
|
while let Ok(msg) = receiver.recv() {
|
|
- println!("thread {} processing {:?}", id, msg);
|
|
|
|
|
|
+ use std::io::Read;
|
|
|
|
+
|
|
|
|
+ // println!("thread {} processing {:?}", id, msg);
|
|
|
|
+ let mut buf = Vec::new();
|
|
|
|
+ {
|
|
|
|
+ let mut f = std::fs::File::open(msg.path()).expect("Unable to read file");
|
|
|
|
+ f.read_to_end(&mut buf).expect("Unable to read file");
|
|
|
|
+ }
|
|
|
|
+ let parser = lib_ruby_parser::Parser::new(buf, std::default::Default::default());
|
|
|
|
+ let lib_ruby_parser::ParserResult { ast, diagnostics, .. } = parser.do_parse();
|
|
|
|
+ if let Some(_ast) = ast {
|
|
|
|
+ // println!("Got ast: {:?}", ast);
|
|
|
|
+ } else {
|
|
|
|
+ println!("Unable to parse {:?}", msg.path());
|
|
|
|
+ for d in diagnostics {
|
|
|
|
+ println!(" - {:?}", d);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
println!("thread {} done", id);
|
|
println!("thread {} done", id);
|
|
})
|
|
})
|
|
}).collect();
|
|
}).collect();
|
|
|
|
|
|
- producer.join().unwrap();
|
|
|
|
|
|
+ // join all the threads
|
|
|
|
+ producer.join().expect("Producer thread panicked!");
|
|
for w in workers {
|
|
for w in workers {
|
|
- w.join().unwrap();
|
|
|
|
|
|
+ w.join().expect("Worker thread panicked!");
|
|
}
|
|
}
|
|
}
|
|
}
|