@@ -6,7 +6,7 @@ use std::{
66
77use error_stack:: { Report , Result , ResultExt } ;
88use fast_glob:: glob_match;
9- use ignore:: { WalkBuilder , WalkParallel , WalkState } ;
9+ use ignore:: { DirEntry , WalkBuilder , WalkParallel , WalkState } ;
1010use rayon:: iter:: { IntoParallelIterator , ParallelIterator } ;
1111use tracing:: { instrument, warn} ;
1212
@@ -53,25 +53,36 @@ impl<'a> ProjectBuilder<'a> {
5353 pub fn build ( & mut self ) -> Result < Project , Error > {
5454 let mut builder = WalkBuilder :: new ( & self . base_path ) ;
5555 builder. hidden ( false ) ;
56+ builder. follow_links ( false ) ;
57+ // Prune traversal early: skip heavy and irrelevant directories
58+ let skip_dirs = [ "node_modules" , ".git" , ".hg" , ".svn" , "target" , ".idea" , ".vscode" , "tmp" ] ;
59+ builder. filter_entry ( move |entry : & DirEntry | {
60+ let _path = entry. path ( ) ;
61+ let file_name = entry. file_name ( ) . to_str ( ) . unwrap_or ( "" ) ;
62+ if let Some ( ft) = entry. file_type ( ) {
63+ if ft. is_dir ( ) && skip_dirs. iter ( ) . any ( |d| * d == file_name) {
64+ return false ;
65+ }
66+ }
67+ true
68+ } ) ;
69+
5670 let walk_parallel: WalkParallel = builder. build_parallel ( ) ;
5771
58- let collected_entry_types = Arc :: new ( Mutex :: new ( Vec :: with_capacity ( INITIAL_VECTOR_CAPACITY ) ) ) ;
59- let collected_for_threads = Arc :: clone ( & collected_entry_types) ;
72+ let ( tx, rx) = crossbeam_channel:: unbounded :: < EntryType > ( ) ;
6073 let error_holder: Arc < Mutex < Option < Report < Error > > > > = Arc :: new ( Mutex :: new ( None ) ) ;
6174 let error_holder_for_threads = Arc :: clone ( & error_holder) ;
6275
6376 let this: & ProjectBuilder < ' a > = self ;
6477
6578 walk_parallel. run ( move || {
66- let collected = Arc :: clone ( & collected_for_threads) ;
6779 let error_holder = Arc :: clone ( & error_holder_for_threads) ;
80+ let tx = tx. clone ( ) ;
6881 Box :: new ( move |res| {
6982 if let Ok ( entry) = res {
7083 match this. build_entry_type ( entry) {
7184 Ok ( entry_type) => {
72- if let Ok ( mut v) = collected. lock ( ) {
73- v. push ( entry_type) ;
74- }
85+ let _ = tx. send ( entry_type) ;
7586 }
7687 Err ( report) => {
7788 if let Ok ( mut slot) = error_holder. lock ( ) {
@@ -87,19 +98,7 @@ impl<'a> ProjectBuilder<'a> {
8798 } ) ;
8899
89100 // Take ownership of the collected entry types
90- let entry_types = match Arc :: try_unwrap ( collected_entry_types) {
91- Ok ( mutex) => match mutex. into_inner ( ) {
92- Ok ( entries) => entries,
93- Err ( poisoned) => poisoned. into_inner ( ) ,
94- } ,
95- Err ( arc) => match arc. lock ( ) {
96- Ok ( mut guard) => std:: mem:: take ( & mut * guard) ,
97- Err ( poisoned) => {
98- let mut guard = poisoned. into_inner ( ) ;
99- std:: mem:: take ( & mut * guard)
100- }
101- } ,
102- } ;
101+ let entry_types: Vec < EntryType > = rx. iter ( ) . collect ( ) ;
103102
104103 // If any error occurred while building entry types, return it
105104 let maybe_error = match Arc :: try_unwrap ( error_holder) {
@@ -179,16 +178,16 @@ impl<'a> ProjectBuilder<'a> {
179178 project_files. push ( project_file) ;
180179 }
181180 EntryType :: Directory ( absolute_path, relative_path) => {
182- if relative_path. parent ( ) == Some ( Path :: new ( & self . config . vendored_gems_path ) ) {
183- if let Some ( file_name) = relative_path. file_name ( ) {
184- gems. push ( VendoredGem {
185- path : absolute_path,
186- name : file_name. to_string_lossy ( ) . to_string ( ) ,
187- } ) ;
188- } else {
189- warn ! ( "Vendored gem path without file name: {:?}" , relative_path) ;
190- }
191- }
181+ if relative_path. parent ( ) == Some ( Path :: new ( & self . config . vendored_gems_path ) ) {
182+ if let Some ( file_name) = relative_path. file_name ( ) {
183+ gems. push ( VendoredGem {
184+ path : absolute_path,
185+ name : file_name. to_string_lossy ( ) . to_string ( ) ,
186+ } ) ;
187+ } else {
188+ warn ! ( "Vendored gem path without file name: {:?}" , relative_path) ;
189+ }
190+ }
192191 }
193192 EntryType :: RubyPackage ( absolute_path, relative_path) => {
194193 match ruby_package_owner ( & absolute_path) {
0 commit comments