@@ -1015,11 +1015,106 @@ pub fn num_cpus() -> usize {
10151015 std:: thread:: available_parallelism ( ) . map_or ( 1 , std:: num:: NonZeroUsize :: get)
10161016}
10171017
1018+ /// Filter out ccache directories from PATH environment variable.
1019+ ///
1020+ /// This prevents double-caching when ccache is installed and has
1021+ /// /usr/lib/ccache or /usr/lib64/ccache in PATH, since those directories
1022+ /// contain wrapper scripts that would call ccache.
1023+ pub fn filter_ccache_from_path ( env_vars : Vec < ( OsString , OsString ) > ) -> Vec < ( OsString , OsString ) > {
1024+ use std:: env;
1025+ use std:: path:: Path ;
1026+
1027+ const CCACHE_DIRS : & [ & str ] = & [ "/usr/lib/ccache" , "/usr/lib64/ccache" ] ;
1028+
1029+ env_vars
1030+ . into_iter ( )
1031+ . map ( |( key, value) | {
1032+ if key == "PATH" {
1033+ let filtered_path = env:: split_paths ( & value)
1034+ . filter ( |p| !CCACHE_DIRS . iter ( ) . any ( |dir| p == Path :: new ( dir) ) )
1035+ . collect :: < Vec < _ > > ( ) ;
1036+ let new_value = env:: join_paths ( filtered_path) . unwrap_or ( value. clone ( ) ) ;
1037+ ( key, new_value)
1038+ } else {
1039+ ( key, value)
1040+ }
1041+ } )
1042+ . collect ( )
1043+ }
1044+
10181045#[ cfg( test) ]
10191046mod tests {
1020- use super :: { OsStrExt , TimeMacroFinder } ;
1047+ use super :: { OsStrExt , TimeMacroFinder , filter_ccache_from_path } ;
10211048 use std:: ffi:: { OsStr , OsString } ;
10221049
1050+ #[ test]
1051+ fn test_filter_ccache_from_path ( ) {
1052+ use std:: env;
1053+
1054+ // Create a PATH with ccache directories
1055+ let path_with_ccache = env:: join_paths ( [
1056+ "/usr/bin" ,
1057+ "/usr/lib64/ccache" ,
1058+ "/usr/local/bin" ,
1059+ "/usr/lib/ccache" ,
1060+ "/home/user/bin" ,
1061+ ] )
1062+ . unwrap ( ) ;
1063+
1064+ let env_vars = vec ! [
1065+ ( OsString :: from( "HOME" ) , OsString :: from( "/home/user" ) ) ,
1066+ ( OsString :: from( "PATH" ) , path_with_ccache) ,
1067+ ( OsString :: from( "LANG" ) , OsString :: from( "en_US.UTF-8" ) ) ,
1068+ ] ;
1069+
1070+ let filtered = filter_ccache_from_path ( env_vars) ;
1071+
1072+ // Other env vars should be unchanged
1073+ assert_eq ! ( filtered. len( ) , 3 ) ;
1074+ assert_eq ! (
1075+ filtered. iter( ) . find( |( k, _) | k == "HOME" ) . unwrap( ) . 1 ,
1076+ OsString :: from( "/home/user" )
1077+ ) ;
1078+ assert_eq ! (
1079+ filtered. iter( ) . find( |( k, _) | k == "LANG" ) . unwrap( ) . 1 ,
1080+ OsString :: from( "en_US.UTF-8" )
1081+ ) ;
1082+
1083+ // PATH should have ccache directories removed
1084+ let new_path = & filtered. iter ( ) . find ( |( k, _) | k == "PATH" ) . unwrap ( ) . 1 ;
1085+ let expected_path =
1086+ env:: join_paths ( [ "/usr/bin" , "/usr/local/bin" , "/home/user/bin" ] ) . unwrap ( ) ;
1087+ assert_eq ! ( new_path, & expected_path) ;
1088+ }
1089+
1090+ #[ test]
1091+ fn test_filter_ccache_from_path_no_ccache ( ) {
1092+ use std:: env;
1093+
1094+ // Create a PATH without ccache directories
1095+ let path_without_ccache = env:: join_paths ( [ "/usr/bin" , "/usr/local/bin" ] ) . unwrap ( ) ;
1096+
1097+ let env_vars = vec ! [ ( OsString :: from( "PATH" ) , path_without_ccache. clone( ) ) ] ;
1098+
1099+ let filtered = filter_ccache_from_path ( env_vars) ;
1100+
1101+ assert_eq ! ( filtered. len( ) , 1 ) ;
1102+ assert_eq ! ( filtered[ 0 ] . 1 , path_without_ccache) ;
1103+ }
1104+
1105+ #[ test]
1106+ fn test_filter_ccache_from_path_no_path ( ) {
1107+ // No PATH variable at all
1108+ let env_vars = vec ! [
1109+ ( OsString :: from( "HOME" ) , OsString :: from( "/home/user" ) ) ,
1110+ ( OsString :: from( "LANG" ) , OsString :: from( "en_US.UTF-8" ) ) ,
1111+ ] ;
1112+
1113+ let filtered = filter_ccache_from_path ( env_vars. clone ( ) ) ;
1114+
1115+ assert_eq ! ( filtered, env_vars) ;
1116+ }
1117+
10231118 #[ test]
10241119 fn simple_starts_with ( ) {
10251120 let a: & OsStr = "foo" . as_ref ( ) ;
0 commit comments