@@ -11,15 +11,13 @@ extern crate toml;
1111mod formats;
1212
1313use clap:: { App , Arg } ;
14- use crossbeam:: channel:: { unbounded, Receiver , Sender } ;
1514use globset:: { Glob , GlobSet , GlobSetBuilder } ;
1615use std:: collections:: { hash_map, HashMap } ;
1716use std:: fmt;
18- use std:: path:: PathBuf ;
17+ use std:: path:: { Path , PathBuf } ;
18+ use std:: process;
1919use std:: str:: FromStr ;
2020use std:: sync:: { Arc , Mutex } ;
21- use std:: { process, thread} ;
22- use walkdir:: { DirEntry , WalkDir } ;
2321
2422use formats:: Format ;
2523
@@ -28,8 +26,9 @@ use rust_code_analysis::LANG;
2826
2927// Structs
3028use rust_code_analysis:: {
31- CommentRm , CommentRmCfg , Count , CountCfg , Dump , DumpCfg , Find , FindCfg , Function , FunctionCfg ,
32- Metrics , MetricsCfg , OpsCfg , OpsCode , PreprocParser , PreprocResults ,
29+ CommentRm , CommentRmCfg , ConcurrentRunner , Count , CountCfg , Dump , DumpCfg , FilesData , Find ,
30+ FindCfg , Function , FunctionCfg , Metrics , MetricsCfg , OpsCfg , OpsCode , PreprocParser ,
31+ PreprocResults ,
3332} ;
3433
3534// Functions
@@ -48,6 +47,7 @@ struct Config {
4847 comments : bool ,
4948 find_filter : Vec < String > ,
5049 count_filter : Vec < String > ,
50+ language : Option < LANG > ,
5151 function : bool ,
5252 metrics : bool ,
5353 ops : bool ,
@@ -61,15 +61,6 @@ struct Config {
6161 count_lock : Option < Arc < Mutex < Count > > > ,
6262}
6363
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-
7364fn mk_globset ( elems : clap:: Values ) -> GlobSet {
7465 let mut globset = GlobSetBuilder :: new ( ) ;
7566 for e in elems {
@@ -86,14 +77,14 @@ fn mk_globset(elems: clap::Values) -> GlobSet {
8677 }
8778}
8879
89- fn act_on_file ( language : Option < LANG > , path : PathBuf , cfg : & Config ) -> std:: io:: Result < ( ) > {
80+ fn act_on_file ( path : PathBuf , cfg : & Config ) -> std:: io:: Result < ( ) > {
9081 let source = if let Some ( source) = read_file_with_eol ( & path) ? {
9182 source
9283 } else {
9384 return Ok ( ( ) ) ;
9485 } ;
9586
96- let language = if let Some ( language) = language {
87+ let language = if let Some ( language) = cfg . language {
9788 language
9889 } else if let Some ( language) = guess_language ( & source, & path) . 0 {
9990 language
@@ -174,90 +165,18 @@ fn act_on_file(language: Option<LANG>, path: PathBuf, cfg: &Config) -> std::io::
174165 }
175166}
176167
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- }
168+ fn process_dir_path ( all_files : & mut HashMap < String , Vec < PathBuf > > , path : & Path , cfg : & Config ) {
169+ if cfg. preproc_lock . is_some ( ) {
170+ let file_name = path. file_name ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
171+ match all_files. entry ( file_name) {
172+ hash_map:: Entry :: Occupied ( l) => {
173+ l. into_mut ( ) . push ( path. to_path_buf ( ) ) ;
251174 }
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- }
175+ hash_map:: Entry :: Vacant ( p) => {
176+ p. insert ( vec ! [ path. to_path_buf( ) ] ) ;
177+ }
178+ } ;
258179 }
259-
260- all_files
261180}
262181
263182fn parse_or_exit < T > ( s : & str ) -> T
@@ -503,12 +422,16 @@ fn main() {
503422 None
504423 } ;
505424
506- let cfg = Arc :: new ( Config {
425+ let include = mk_globset ( matches. values_of ( "include" ) . unwrap ( ) ) ;
426+ let exclude = mk_globset ( matches. values_of ( "exclude" ) . unwrap ( ) ) ;
427+
428+ let cfg = Config {
507429 dump,
508430 in_place,
509431 comments,
510432 find_filter,
511433 count_filter,
434+ language,
512435 function,
513436 metrics,
514437 ops,
@@ -520,51 +443,24 @@ fn main() {
520443 preproc_lock : preproc_lock. clone ( ) ,
521444 preproc,
522445 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 ( )
536446 } ;
537447
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 ) ;
448+ let files_data = FilesData {
449+ include,
450+ exclude,
451+ paths,
556452 } ;
557453
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 ( ) {
454+ let all_files = match ConcurrentRunner :: new ( num_jobs , act_on_file )
455+ . set_proc_dir_paths ( process_dir_path )
456+ . run ( cfg , files_data )
457+ {
458+ Ok ( all_files ) => all_files ,
459+ Err ( e ) => {
460+ eprintln ! ( "{:?}" , e ) ;
565461 process:: exit ( 1 ) ;
566462 }
567- }
463+ } ;
568464
569465 if let Some ( count) = count_lock {
570466 let count = Arc :: try_unwrap ( count) . unwrap ( ) . into_inner ( ) . unwrap ( ) ;
0 commit comments