11#[ macro_use]
22extern crate clap;
3- extern crate crossbeam;
43extern crate num_cpus;
54extern crate serde;
65extern crate serde_cbor;
@@ -11,15 +10,13 @@ extern crate toml;
1110mod formats;
1211
1312use clap:: { App , Arg } ;
14- use crossbeam:: channel:: { unbounded, Receiver , Sender } ;
1513use globset:: { Glob , GlobSet , GlobSetBuilder } ;
1614use std:: collections:: { hash_map, HashMap } ;
1715use std:: fmt;
18- use std:: path:: PathBuf ;
16+ use std:: path:: { Path , PathBuf } ;
17+ use std:: process;
1918use std:: str:: FromStr ;
2019use std:: sync:: { Arc , Mutex } ;
21- use std:: { process, thread} ;
22- use walkdir:: { DirEntry , WalkDir } ;
2320
2421use formats:: Format ;
2522
@@ -28,8 +25,9 @@ use rust_code_analysis::LANG;
2825
2926// Structs
3027use rust_code_analysis:: {
31- CommentRm , CommentRmCfg , Count , CountCfg , Dump , DumpCfg , Find , FindCfg , Function , FunctionCfg ,
32- Metrics , MetricsCfg , OpsCfg , OpsCode , PreprocParser , PreprocResults ,
28+ CommentRm , CommentRmCfg , ConcurrentRunner , Count , CountCfg , Dump , DumpCfg , FilesData , Find ,
29+ FindCfg , Function , FunctionCfg , Metrics , MetricsCfg , OpsCfg , OpsCode , PreprocParser ,
30+ PreprocResults ,
3331} ;
3432
3533// Functions
@@ -48,6 +46,7 @@ struct Config {
4846 comments : bool ,
4947 find_filter : Vec < String > ,
5048 count_filter : Vec < String > ,
49+ language : Option < LANG > ,
5150 function : bool ,
5251 metrics : bool ,
5352 ops : bool ,
@@ -61,15 +60,6 @@ struct Config {
6160 count_lock : Option < Arc < Mutex < Count > > > ,
6261}
6362
64- struct JobItem {
65- language : Option < LANG > ,
66- path : PathBuf ,
67- cfg : Arc < Config > ,
68- }
69-
70- type JobReceiver = Receiver < Option < JobItem > > ;
71- type JobSender = Sender < Option < JobItem > > ;
72-
7363fn mk_globset ( elems : clap:: Values ) -> GlobSet {
7464 let mut globset = GlobSetBuilder :: new ( ) ;
7565 for e in elems {
@@ -86,14 +76,14 @@ fn mk_globset(elems: clap::Values) -> GlobSet {
8676 }
8777}
8878
89- fn act_on_file ( language : Option < LANG > , path : PathBuf , cfg : & Config ) -> std:: io:: Result < ( ) > {
79+ fn act_on_file ( path : PathBuf , cfg : & Config ) -> std:: io:: Result < ( ) > {
9080 let source = if let Some ( source) = read_file_with_eol ( & path) ? {
9181 source
9282 } else {
9383 return Ok ( ( ) ) ;
9484 } ;
9585
96- let language = if let Some ( language) = language {
86+ let language = if let Some ( language) = cfg . language {
9787 language
9888 } else if let Some ( language) = guess_language ( & source, & path) . 0 {
9989 language
@@ -174,90 +164,18 @@ fn act_on_file(language: Option<LANG>, path: PathBuf, cfg: &Config) -> std::io::
174164 }
175165}
176166
177- fn consumer ( receiver : JobReceiver ) {
178- while let Ok ( job) = receiver. recv ( ) {
179- if job. is_none ( ) {
180- break ;
181- }
182- let job = job. unwrap ( ) ;
183- let path = job. path . clone ( ) ;
184-
185- if let Err ( err) = act_on_file ( job. language , job. path , & job. cfg ) {
186- eprintln ! ( "{:?} for file {:?}" , err, path) ;
187- }
188- }
189- }
190-
191- fn send_file ( path : PathBuf , cfg : & Arc < Config > , language : Option < LANG > , sender : & JobSender ) {
192- sender
193- . send ( Some ( JobItem {
194- language,
195- path,
196- cfg : Arc :: clone ( cfg) ,
197- } ) )
198- . unwrap ( ) ;
199- }
200-
201- fn is_hidden ( entry : & DirEntry ) -> bool {
202- entry
203- . file_name ( )
204- . to_str ( )
205- . map ( |s| s. starts_with ( '.' ) )
206- . unwrap_or ( false )
207- }
208-
209- fn explore (
210- mut paths : Vec < String > ,
211- cfg : & Arc < Config > ,
212- include : GlobSet ,
213- exclude : GlobSet ,
214- language : Option < LANG > ,
215- sender : & JobSender ,
216- ) -> HashMap < String , Vec < PathBuf > > {
217- let mut all_files: HashMap < String , Vec < PathBuf > > = HashMap :: new ( ) ;
218-
219- for path in paths. drain ( ..) {
220- let path = PathBuf :: from ( path) ;
221- if !path. exists ( ) {
222- eprintln ! ( "Warning: File doesn't exist: {}" , path. to_str( ) . unwrap( ) ) ;
223- continue ;
224- }
225- if path. is_dir ( ) {
226- for entry in WalkDir :: new ( path)
227- . into_iter ( )
228- . filter_entry ( |e| !is_hidden ( e) )
229- {
230- let entry = entry. unwrap ( ) ;
231- let path = entry. path ( ) . to_path_buf ( ) ;
232- if ( include. is_empty ( ) || include. is_match ( & path) )
233- && ( exclude. is_empty ( ) || !exclude. is_match ( & path) )
234- && path. is_file ( )
235- {
236- if cfg. preproc_lock . is_some ( ) {
237- let file_name = path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
238- let path = path. clone ( ) ;
239- match all_files. entry ( file_name) {
240- hash_map:: Entry :: Occupied ( l) => {
241- l. into_mut ( ) . push ( path) ;
242- }
243- hash_map:: Entry :: Vacant ( p) => {
244- p. insert ( vec ! [ path] ) ;
245- }
246- } ;
247- }
248-
249- send_file ( path, cfg, language, sender) ;
250- }
167+ fn process_dir_path ( all_files : & mut HashMap < String , Vec < PathBuf > > , path : & Path , cfg : & Config ) {
168+ if cfg. preproc_lock . is_some ( ) {
169+ let file_name = path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
170+ match all_files. entry ( file_name) {
171+ hash_map:: Entry :: Occupied ( l) => {
172+ l. into_mut ( ) . push ( path. to_path_buf ( ) ) ;
251173 }
252- } else if ( include. is_empty ( ) || include. is_match ( & path) )
253- && ( exclude. is_empty ( ) || !exclude. is_match ( & path) )
254- && path. is_file ( )
255- {
256- send_file ( path, cfg, language, sender) ;
257- }
174+ hash_map:: Entry :: Vacant ( p) => {
175+ p. insert ( vec ! [ path. to_path_buf( ) ] ) ;
176+ }
177+ } ;
258178 }
259-
260- all_files
261179}
262180
263181fn parse_or_exit < T > ( s : & str ) -> T
@@ -503,12 +421,16 @@ fn main() {
503421 None
504422 } ;
505423
506- let cfg = Arc :: new ( Config {
424+ let include = mk_globset ( matches. values_of ( "include" ) . unwrap ( ) ) ;
425+ let exclude = mk_globset ( matches. values_of ( "exclude" ) . unwrap ( ) ) ;
426+
427+ let cfg = Config {
507428 dump,
508429 in_place,
509430 comments,
510431 find_filter,
511432 count_filter,
433+ language,
512434 function,
513435 metrics,
514436 ops,
@@ -520,51 +442,24 @@ fn main() {
520442 preproc_lock : preproc_lock. clone ( ) ,
521443 preproc,
522444 count_lock : count_lock. clone ( ) ,
523- } ) ;
524-
525- let ( sender, receiver) = unbounded ( ) ;
526-
527- let producer = {
528- let sender = sender. clone ( ) ;
529- let include = mk_globset ( matches. values_of ( "include" ) . unwrap ( ) ) ;
530- let exclude = mk_globset ( matches. values_of ( "exclude" ) . unwrap ( ) ) ;
531-
532- thread:: Builder :: new ( )
533- . name ( String :: from ( "Producer" ) )
534- . spawn ( move || explore ( paths, & cfg, include, exclude, language, & sender) )
535- . unwrap ( )
536445 } ;
537446
538- let mut receivers = Vec :: with_capacity ( num_jobs) ;
539- for i in 0 ..num_jobs {
540- let receiver = receiver. clone ( ) ;
541-
542- let t = thread:: Builder :: new ( )
543- . name ( format ! ( "Consumer {}" , i) )
544- . spawn ( move || {
545- consumer ( receiver) ;
546- } )
547- . unwrap ( ) ;
548-
549- receivers. push ( t) ;
550- }
551-
552- let all_files = if let Ok ( res) = producer. join ( ) {
553- res
554- } else {
555- process:: exit ( 1 ) ;
447+ let files_data = FilesData {
448+ include,
449+ exclude,
450+ paths,
556451 } ;
557452
558- // Poison the receiver, now that the producer is finished.
559- for _ in 0 ..num_jobs {
560- sender . send ( None ) . unwrap ( ) ;
561- }
562-
563- for receiver in receivers {
564- if receiver . join ( ) . is_err ( ) {
453+ let all_files = match ConcurrentRunner :: new ( num_jobs , act_on_file )
454+ . set_proc_dir_paths ( process_dir_path )
455+ . run ( cfg , files_data )
456+ {
457+ Ok ( all_files ) => all_files ,
458+ Err ( e ) => {
459+ eprintln ! ( "{:?}" , e ) ;
565460 process:: exit ( 1 ) ;
566461 }
567- }
462+ } ;
568463
569464 if let Some ( count) = count_lock {
570465 let count = Arc :: try_unwrap ( count) . unwrap ( ) . into_inner ( ) . unwrap ( ) ;
0 commit comments