char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
7e18c89
main
1use std:: collections:: HashMap ; 2use std:: io; 3use std:: path::{ Path , PathBuf }; 4use std:: sync:: Arc ; 5 6use crate :: EnvMap ; 7use crate :: graph:: Task ; 8 9# [ derive ( Debug , thiserror :: Error )] 10pub enum Error { 11# [ error ( "Cannot load env file {}: {source}" , . path . display ())] 12Load { 13path : PathBuf , 14# [ source ] 15source : io:: Error , 16}, 17} 18 19fn parse ( source : & str ) -> io:: Result < Vec <( String , String )>> { 20if source. contains ( '\0' ) { 21return Err ( io:: Error :: new ( 22 io:: ErrorKind :: InvalidInput , 23"Environment files cannot contain NUL" , 24)); 25} 26let source = source. replace ( '\r' , "" ); 27let mut rest = source. strip_prefix ( '\u{feff}' ). unwrap_or ( & source); 28let mut values =Vec :: new (); 29while !rest. is_empty () { 30 rest = rest. trim_start_matches ([ ' ' , '\t' , '\n' ]); 31let ( line, next) = rest. split_once ( '\n' ). unwrap_or (( rest, "" )); 32let Some (( raw_key, _)) = line. split_once ( '=' ) else { 33 rest = next; 34continue ; 35}; 36if line. starts_with ( '#' ) { 37 rest = next; 38continue ; 39} 40let mut key = raw_key. trim_matches ([ ' ' , '\t' ]); 41if let Some ( exported) = key. strip_prefix ( "export " ) { 42 key = exported. trim_start_matches ([ ' ' , '\t' ]); 43} 44if key. is_empty () { 45 rest = next; 46continue ; 47} 48let value = rest[ raw_key. len () +1 ..]. trim_start_matches ([ ' ' , '\t' ]); 49if let Some ( quote @( b'\'' |b'"' |b'`' )) = value. as_bytes (). first (). copied () { 50let quote = quoteas char ; 51if let Some ( end) = value[ 1 ..]. find ( quote). map ( |index| index +1 ) { 52let quoted =& value[ 1 ..end]; 53let parsed =if quote =='"' { 54 quoted. replace ( "\\n" , "\n" ) 55} else { 56 quoted. to_owned () 57}; 58 values. push (( key. to_owned (), parsed)); 59 rest = value[ end +1 ..] 60. split_once ( '\n' ) 61. map_or ( "" , |( _, next) | next); 62continue ; 63} 64let ( value, next) = value. split_once ( '\n' ). unwrap_or (( value, "" )); 65 values. push (( key. to_owned (), value. to_owned ())); 66 rest = next; 67continue ; 68} 69let ( value, next) = value. split_once ( '\n' ). unwrap_or (( value, "" )); 70let value = value. split_once ( '#' ). map_or ( value, |( value, _) | value); 71 values. push (( key. to_owned (), value. trim_matches ([ ' ' , '\t' ]). to_owned ())); 72 rest = next; 73} 74Ok ( values) 75} 76 77pub fn load_values ( paths : & [ PathBuf ]) ->Result < Vec <( String , String )>, Error > { 78let mut values =Vec :: new (); 79for pathin paths{ 80let source = std:: fs:: read_to_string ( path) 81. map_err ( |source|Error :: Load { path : path. clone (), source}) ?; 82 values. extend ( parse ( & source). map_err ( |source|Error :: Load { path : path. clone (), source}) ?); 83} 84Ok ( values) 85} 86 87pub ( crate ) struct EnvLoader { 88root : PathBuf , 89cache : HashMap < PathBuf , Arc < Vec <( String , String )>>>, 90} 91 92impl EnvLoader { 93pub ( crate ) fn new ( root : PathBuf ) ->Self { 94EnvLoader { root, cache : HashMap :: new () } 95} 96 97fn load ( & mut self , relative : & Path ) ->crate :: Result < Arc < Vec <( String , String )>>> { 98let path =self . root . join ( relative); 99if let Some ( values) =self . cache . get ( & path) { 100return Ok ( values. clone ()); 101} 102let values =Arc :: new ( load_values ( std:: slice:: from_ref ( & path)) ?); 103self . cache . insert ( path, values. clone ()); 104Ok ( values) 105} 106 107/// The environment a task runs with: inherited values, overridden by 108/// its own env file when it declares one. 109pub ( crate ) fn effective ( & mut self , task : & Task , inherited : & EnvMap ) ->crate :: Result < EnvMap > { 110let mut env = inherited. clone (); 111let Some ( file) =& task. env_file else { 112return Ok ( env); 113}; 114for ( key, value) in self . load ( file) ?. iter () { 115let key = avril_caps:: env_name ( key). map_err ( |_|crate :: Error :: EnvName ( key. clone ())) ?; 116 env. insert ( key. into_owned (), value. clone ()); 117} 118Ok ( env) 119} 120}