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:: path::{ Path , PathBuf }; 3 4use sha2::{ Digest , Sha256 }; 5 6use crate :: env:: EnvLoader ; 7use crate :: glob::{ expand_files, file_id}; 8use crate :: graph::{ Graph , Task }; 9use crate ::{ EnvMap , Error , Result }; 10 11pub ( crate ) struct Fingerprinter { 12graph : Graph , 13root : PathBuf , 14env : EnvLoader , 15memo : HashMap < String , String >, 16visiting : Vec < String >, 17} 18 19impl Fingerprinter { 20pub ( crate ) fn new ( graph : Graph , root : PathBuf ) ->Self { 21Fingerprinter { 22env : EnvLoader :: new ( root. clone ()), 23 graph, 24 root, 25memo : HashMap :: new (), 26visiting : Vec :: new (), 27} 28} 29 30pub ( crate ) fn fingerprint ( 31& mut self , 32name : & str , 33args : & [ String ], 34env : & EnvMap , 35) ->Result < String > { 36if let Some ( fingerprint) =self . memo . get ( name) { 37return Ok ( fingerprint. clone ()); 38} 39if self . visiting . iter (). any ( |seen| seen == name) { 40let mut cycle =self . visiting . clone (); 41 cycle. push ( name. to_owned ()); 42return Err ( Error :: Cycle ( cycle. join ( " -> " ))); 43} 44let task =self . graph . get ( name) ?. clone (); 45self . visiting . push ( name. to_owned ()); 46let result =self . fingerprint_task ( name, & task, args, env); 47self . visiting . pop (); 48let fingerprint = result?; 49self . memo . insert ( name. to_owned (), fingerprint. clone ()); 50Ok ( fingerprint) 51} 52 53fn fingerprint_task ( 54& mut self , 55name : & str , 56task : & Task , 57args : & [ String ], 58env : & EnvMap , 59) ->Result < String > { 60fn field ( hasher : & mut Sha256 , value : & [ u8 ]) { 61 hasher. update (( value. len () as u64 ). to_be_bytes ()); 62 hasher. update ( value); 63} 64let mut hasher =Sha256 :: new (); 65field ( & mut hasher, b"avril-task-cache-v3" ); 66field ( & mut hasher, self . root . to_string_lossy (). as_bytes ()); 67field ( & mut hasher, name. as_bytes ()); 68field ( & mut hasher, task. action . fingerprint_text (). as_bytes ()); 69field ( 70& mut hasher, 71if task. parallel { 72b"parallel" . as_slice () 73} else { 74b"sequential" . as_slice () 75}, 76); 77for argin args{ 78field ( & mut hasher, arg. as_bytes ()); 79} 80for varin & task. env { 81field ( & mut hasher, var. as_bytes ()); 82match std:: env:: var ( var) { 83Ok ( value) =>{ 84field ( & mut hasher, b"set" ); 85field ( & mut hasher, value. as_bytes ()); 86} 87Err ( _) =>{ 88let normalized = 89 avril_caps:: env_name ( var). unwrap_or_else ( |_| var. as_str (). into ()); 90match env. get ( normalized. as_ref ()) { 91Some ( value) =>{ 92field ( & mut hasher, b"file" ); 93field ( & mut hasher, value. as_bytes ()); 94} 95None =>field ( & mut hasher, b"unset" ), 96} 97} 98} 99} 100for dependencyin & task. dependencies { 101let dependency_task =self . graph . get ( dependency) ?. clone (); 102let dependency_env =self . env . effective ( & dependency_task, env) ?; 103let fingerprint =self . fingerprint ( dependency, & [], & dependency_env) ?; 104field ( & mut hasher, dependency. as_bytes ()); 105field ( & mut hasher, fingerprint. as_bytes ()); 106} 107if let Some ( patterns) =& task. files { 108field ( & mut hasher, b"cached" ); 109for ( relative, path) in expand_files ( & self . root , name, patterns) ?{ 110field ( & mut hasher, relative. as_bytes ()); 111let id =file_id ( & path). map_err ( |source|Error :: Read { 112task : name. to_owned (), 113path : relative. clone (), 114 source, 115}) ?; 116field ( & mut hasher, id. as_bytes ()); 117} 118} 119Ok ( format! ( "{:x}" , hasher. finalize ())) 120} 121} 122 123/// The cache fingerprint of `target` in `graph`, without running anything. 124pub fn graph_fingerprint ( 125graph : & Graph , 126root : & Path , 127target : & str , 128args : & [ String ], 129) ->Result < String > { 130let mut fingerprinter =Fingerprinter :: new ( graph. clone (), root. to_path_buf ()); 131 fingerprinter. fingerprint ( target, args, & EnvMap :: new ()) 132}