11use crate :: args:: { Backend , ShellTrust } ;
2- use crate :: config:: ValueDefinition ;
2+ use crate :: config:: { Config , Content , Template , VariableDefinition } ;
33use async_trait:: async_trait;
4+ use std:: collections:: BTreeMap ;
45use std:: io:: { Error , ErrorKind , Result } ;
56
7+ pub async fn render ( template : & str , values : & BTreeMap < String , String > ) -> Result < String > {
8+ fn recursive_add (
9+ namespace : & mut std:: collections:: VecDeque < String > ,
10+ parent : & mut serde_json:: Value ,
11+ value : & str ,
12+ ) {
13+ let current_namespace = namespace. pop_front ( ) . unwrap ( ) ;
14+ match namespace. len ( ) {
15+ 0 => {
16+ parent
17+ . as_object_mut ( )
18+ . unwrap ( )
19+ . entry ( & current_namespace)
20+ . or_insert ( serde_json:: Value :: String ( value. to_owned ( ) ) ) ;
21+ }
22+ _ => {
23+ let p = parent
24+ . as_object_mut ( )
25+ . unwrap ( )
26+ . entry ( & current_namespace)
27+ . or_insert ( serde_json:: Value :: Object ( serde_json:: Map :: new ( ) ) ) ;
28+ recursive_add ( namespace, p, value) ;
29+ }
30+ }
31+ }
32+
33+ let mut hb = handlebars:: Handlebars :: new ( ) ;
34+ hb. set_strict_mode ( true ) ;
35+
36+ let mut values_json = serde_json:: Value :: Object ( serde_json:: Map :: new ( ) ) ;
37+ for val in values {
38+ let namespaces_vec: Vec < String > = val. 0 . split ( '.' ) . map ( |s| s. to_string ( ) ) . collect ( ) ;
39+ let mut namespaces = std:: collections:: VecDeque :: from ( namespaces_vec) ;
40+ recursive_add ( & mut namespaces, & mut values_json, val. 1 ) ;
41+ }
42+
43+ let rendered_template = hb. render_template ( template, & values_json) . unwrap ( ) ;
44+ Ok ( rendered_template)
45+ }
46+
47+ #[ allow( clippy:: needless_lifetimes) ]
48+ pub async fn select_template < ' a > ( config : & ' a Config , backend : & Backend ) -> Result < & ' a Template > {
49+ let keys: Vec < String > = config. templates . keys ( ) . map ( |t| t. to_owned ( ) ) . collect ( ) ;
50+
51+ let be = backend. to_input ( ) ?;
52+ let selection = be. select ( "" , keys. as_slice ( ) ) . await ?;
53+
54+ match config. templates . get ( & selection) {
55+ Some ( x) => Ok ( x) ,
56+ None => Err ( std:: io:: Error :: new ( std:: io:: ErrorKind :: Other , "failed" ) ) ,
57+ }
58+ }
59+
60+ pub async fn populate_variables (
61+ vars : & std:: collections:: BTreeMap < String , VariableDefinition > ,
62+ shell_trust : & ShellTrust ,
63+ backend : & Backend ,
64+ ) -> Result < BTreeMap < String , String > > {
65+ let mut values = BTreeMap :: new ( ) ;
66+ for var in vars {
67+ values. insert ( var. 0 . to_owned ( ) , var. 1 . execute ( shell_trust, backend) . await ?) ;
68+ }
69+ Ok ( values)
70+ }
71+
72+ pub async fn select_and_render ( invoke_options : crate :: args:: PrintArguments ) -> Result < String > {
73+ let cfg: Config = serde_yaml:: from_str ( & invoke_options. configuration ) . unwrap ( ) ;
74+
75+ let template = select_template ( & cfg, & invoke_options. backend ) . await ?;
76+ let template_str = match & template. content {
77+ Content :: Inline ( x) => x. to_owned ( ) ,
78+ Content :: File ( x) => std:: fs:: read_to_string ( x) ?,
79+ } ;
80+ let values = populate_variables (
81+ & template. values ,
82+ & invoke_options. shell_trust ,
83+ & invoke_options. backend ,
84+ )
85+ . await ?;
86+ render ( & template_str, & values) . await
87+ }
88+
689#[ async_trait]
7- pub trait Print {
90+ pub trait Resolve {
891 async fn execute ( & self , shell_trust : & ShellTrust , backend : & Backend ) -> Result < String > ;
992}
1093
@@ -28,16 +111,18 @@ impl Backend {
28111}
29112
30113#[ async_trait]
31- impl Print for ValueDefinition {
114+ impl Resolve for VariableDefinition {
32115 async fn execute ( & self , shell_trust : & ShellTrust , backend : & Backend ) -> Result < String > {
33116 let backend_impl = backend. to_input ( ) ?;
34117
35118 match self {
36- ValueDefinition :: Static ( v) => Ok ( v. to_owned ( ) ) ,
37- ValueDefinition :: Prompt ( v) => backend_impl. prompt ( v) . await ,
38- ValueDefinition :: Shell ( cmd) => backend_impl. shell ( cmd, shell_trust) . await ,
39- ValueDefinition :: Select { text, options } => backend_impl. select ( text, options) . await ,
40- ValueDefinition :: Check { text, options } => backend_impl. check ( text, options) . await ,
119+ VariableDefinition :: Static ( v) => Ok ( v. to_owned ( ) ) ,
120+ VariableDefinition :: Prompt ( v) => backend_impl. prompt ( v) . await ,
121+ VariableDefinition :: Shell ( cmd) => backend_impl. shell ( cmd, shell_trust) . await ,
122+ VariableDefinition :: Select { text, options } => {
123+ backend_impl. select ( text, options) . await
124+ }
125+ VariableDefinition :: Check { text, options } => backend_impl. check ( text, options) . await ,
41126 }
42127 }
43128}
0 commit comments