char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
a29d09f
main
1use std:: collections:: BTreeMap ; 2use std:: path:: PathBuf ; 3 4use serde::{ Deserialize , Serialize }; 5use sha2::{ Digest , Sha256 }; 6 7use crate ::{ Error , Result }; 8 9/// A stable identity for a guest function used as a task action. `id` is 10/// meaningful only to the driver that registered the function; `key` is a 11/// content identity (e.g. a hash of the function source) for fingerprinting. 12# [ derive ( Debug , Clone , PartialEq , Eq , Serialize , Deserialize )] 13pub struct CallbackRef { 14pub id : u32 , 15pub key : String , 16} 17 18# [ derive ( Debug , Clone , PartialEq , Eq , Serialize , Deserialize )] 19pub enum Action { 20None , 21/// Run through the platform shell (`sh -c` / `cmd /C`). 22Shell ( String ), 23/// Spawn directly, without a shell. 24Argv ( Vec < String >), 25/// Invoke a guest function; only drivers with a guest runtime can do this. 26Callback ( CallbackRef ), 27} 28 29impl Action { 30pub fn kind ( & self ) ->&' static str { 31match self { 32Action :: None =>"none" , 33Action :: Shell ( _) =>"shell" , 34Action :: Argv ( _) =>"argv" , 35Action :: Callback ( _) =>"callback" , 36} 37} 38/// The text used for fingerprinting. Distinct kinds can never collide: 39/// only shell commands use the bare string form, for compatibility with 40/// fingerprints recorded by earlier avril versions. 41pub ( crate ) fn fingerprint_text ( & self ) ->String { 42match self { 43Action :: None =>String :: new (), 44Action :: Shell ( command) => command. clone (), 45Action :: Argv ( argv) =>format! ( "argv\0{}" , serde_json:: to_string ( argv). unwrap ()), 46Action :: Callback ( callback) =>format! ( "callback\0{}" , callback. key ), 47} 48} 49pub fn display ( & self ) ->String { 50match self { 51Action :: None =>String :: new (), 52Action :: Shell ( command) => command. clone (), 53Action :: Argv ( argv) => argv 54. iter () 55. map ( |a|shell_quote ( a)) 56. collect ::< Vec < _ >>() 57. join ( " " ), 58Action :: Callback ( _) =>"<function>" . into (), 59} 60} 61} 62 63# [ derive ( Debug , Clone , PartialEq , Serialize , Deserialize )] 64pub struct Task { 65pub description : Option < String >, 66pub action : Action , 67pub dependencies : Vec < String >, 68pub parallel : bool , 69pub env_file : Option < PathBuf >, 70/// Declaring `files` opts the task into result caching. 71pub files : Option < Vec < String >>, 72pub output : Vec < String >, 73pub env : Vec < String >, 74} 75 76impl Default for Task { 77fn default () ->Self { 78Task { 79description : None , 80action : Action :: None , 81dependencies : Vec :: new (), 82parallel : false , 83env_file : None , 84files : None , 85output : Vec :: new (), 86env : Vec :: new (), 87} 88} 89} 90 91# [ derive ( Debug , Clone , Default , PartialEq , Serialize , Deserialize )] 92pub struct Graph { 93pub tasks : BTreeMap < String , Task >, 94} 95 96impl Graph { 97pub fn get ( & self , name : & str ) ->Result < & Task > { 98self . tasks 99. get ( name) 100. ok_or_else ( ||Error :: UnknownTask ( name. to_owned ())) 101} 102 103/// A content digest of the whole graph, for drivers that need to know 104/// whether a re-evaluated graph differs from the previous one. 105pub fn digest ( & self ) ->String { 106let bytes = serde_json:: to_vec ( self ). unwrap (); 107format! ( "{:x}" , Sha256 :: digest ( & bytes)) 108} 109} 110 111# [ cfg ( not ( windows ))] 112pub fn shell_quote ( arg : & str ) ->String { 113if !arg. is_empty () 114 && arg. bytes (). all ( |ch|{ 115 ch. is_ascii_alphanumeric () 116 ||matches! ( 117 ch, 118b'-' |b'_' |b'.' |b'/' |b':' |b'@' |b'%' |b'+' |b'=' |b',' 119) 120}) 121{ 122 arg. to_owned () 123} else { 124format! ( "'{}'" , arg. replace ( '\'' , "'\\''" )) 125} 126} 127 128# [ cfg ( windows )] 129pub fn shell_quote ( arg : & str ) ->String { 130if !arg. is_empty () 131 && arg. bytes (). all ( |ch|{ 132 ch. is_ascii_alphanumeric () ||matches! ( ch, b'-' |b'_' |b'.' |b'/' |b':' |b'@' ) 133}) 134{ 135 arg. to_owned () 136} else { 137format! ( "\"{}\"" , arg. replace ( '"' , "\\\"" )) 138} 139}