@@ -4,8 +4,8 @@ use crate::{
44} ;
55use fast_glob:: glob_match;
66use memoize:: memoize;
7- use regex:: Regex ;
87use rayon:: prelude:: * ;
8+ use regex:: Regex ;
99use std:: {
1010 collections:: HashMap ,
1111 error:: Error ,
@@ -24,63 +24,50 @@ pub struct Parser {
2424
2525impl Parser {
2626 pub fn teams_from_files_paths ( & self , file_paths : & [ PathBuf ] ) -> Result < HashMap < String , Team > , Box < dyn Error > > {
27- let mut file_inputs: Vec < ( String , String ) > = Vec :: with_capacity ( file_paths. len ( ) ) ;
28- for path in file_paths {
29- let file_path_str = path
30- . to_str ( )
31- . ok_or ( IoError :: new ( std:: io:: ErrorKind :: InvalidInput , "Invalid file path" ) ) ?;
32- let key = file_path_str. to_string ( ) ;
33- let slash_prefixed = if file_path_str. starts_with ( '/' ) {
34- file_path_str. to_string ( )
35- } else {
36- format ! ( "/{}" , file_path_str)
37- } ;
38- file_inputs. push ( ( key, slash_prefixed) ) ;
39- }
27+ let file_inputs: Vec < ( String , String ) > = file_paths
28+ . iter ( )
29+ . map ( |path| {
30+ let file_path_str = path
31+ . to_str ( )
32+ . ok_or ( IoError :: new ( std:: io:: ErrorKind :: InvalidInput , "Invalid file path" ) ) ?;
33+ let original = file_path_str. to_string ( ) ;
34+ let prefixed = if file_path_str. starts_with ( '/' ) {
35+ original. clone ( )
36+ } else {
37+ format ! ( "/{}" , file_path_str)
38+ } ;
39+ Ok ( ( original, prefixed) )
40+ } )
41+ . collect :: < Result < Vec < _ > , IoError > > ( ) ?;
4042
4143 if file_inputs. is_empty ( ) {
4244 return Ok ( HashMap :: new ( ) ) ;
4345 }
4446
45- let codeowners_lines_in_priority = build_codeowners_lines_in_priority (
46- self . codeowners_file_path . to_string_lossy ( ) . into_owned ( ) ,
47- ) ;
48- // Pre-parse lines once to avoid repeated split and to handle malformed lines early
49- let codeowners_entries: Vec < ( String , String ) > = codeowners_lines_in_priority
50- . iter ( )
51- . map ( |line| {
52- line
53- . split_once ( ' ' )
54- . map ( |( glob, team_name) | ( glob. to_string ( ) , team_name. to_string ( ) ) )
55- . ok_or_else ( || IoError :: new ( std:: io:: ErrorKind :: InvalidInput , "Invalid line" ) )
56- } )
57- . collect :: < Result < _ , IoError > > ( )
58- . map_err ( |e| Box :: new ( e) as Box < dyn Error > ) ?;
47+ let codeowners_entries: Vec < ( String , String ) > =
48+ build_codeowners_lines_in_priority ( self . codeowners_file_path . to_string_lossy ( ) . into_owned ( ) )
49+ . iter ( )
50+ . map ( |line| {
51+ line. split_once ( ' ' )
52+ . map ( |( glob, team_name) | ( glob. to_string ( ) , team_name. to_string ( ) ) )
53+ . ok_or_else ( || IoError :: new ( std:: io:: ErrorKind :: InvalidInput , "Invalid line" ) )
54+ } )
55+ . collect :: < Result < _ , IoError > > ( )
56+ . map_err ( |e| Box :: new ( e) as Box < dyn Error > ) ?;
57+
5958 let teams_by_name = teams_by_github_team_name ( self . absolute_team_files_globs ( ) ) ;
6059
61- // Parallelize across files: for each file, scan lines in priority order
62- let result_pairs: Vec < ( String , Team ) > = file_inputs
60+ let result: HashMap < String , Team > = file_inputs
6361 . par_iter ( )
6462 . filter_map ( |( key, prefixed) | {
65- for ( glob, team_name) in & codeowners_entries {
66- if glob_match ( glob, prefixed) {
67- // Stop at first match (highest priority). If team missing, treat as unowned.
68- if let Some ( team) = teams_by_name. get ( team_name) {
69- return Some ( ( key. clone ( ) , team. clone ( ) ) ) ;
70- } else {
71- return None ;
72- }
73- }
74- }
75- None
63+ codeowners_entries
64+ . iter ( )
65+ . find ( |( glob, _) | glob_match ( glob, prefixed) )
66+ . and_then ( |( _, team_name) | teams_by_name. get ( team_name) )
67+ . map ( |team| ( key. clone ( ) , team. clone ( ) ) )
7668 } )
7769 . collect ( ) ;
7870
79- let mut result: HashMap < String , Team > = HashMap :: with_capacity ( result_pairs. len ( ) ) ;
80- for ( k, t) in result_pairs {
81- result. insert ( k, t) ;
82- }
83-
8471 Ok ( result)
8572 }
8673
0 commit comments