1- mod outputs;
2-
31use anyhow:: { bail, Context } ;
42use clap:: { arg, command} ;
53use rustfmt_wrapper:: rustfmt;
4+ use serde:: { Deserialize , Serialize } ;
5+ use std:: collections:: BTreeMap ;
66use std:: path:: Path ;
7- use tera:: { from_value, to_value, Value } ;
7+ use tera:: { from_value, to_value} ;
88
9- use outputs:: build_output_pairs;
9+ // use outputs::build_output_pairs;
1010
1111const GLAM_ROOT : & str = ".." ;
12+ const CONFIG_FILE : & str = "codegen.json" ;
13+
14+ #[ derive( Serialize , Deserialize ) ]
15+ struct Config {
16+ version : u32 ,
17+ template_root : String ,
18+ templates : BTreeMap < String , Template > ,
19+ }
20+
21+ #[ derive( Default , Debug , Serialize , Deserialize ) ]
22+ struct Template {
23+ properties : BTreeMap < String , Option < serde_json:: Value > > ,
24+ outputs : BTreeMap < String , Output > ,
25+ }
26+
27+ #[ derive( Default , Debug , Serialize , Deserialize ) ]
28+ struct Output {
29+ properties : BTreeMap < String , serde_json:: Value > ,
30+ }
31+
32+ impl Config {
33+ fn from_file < P : AsRef < Path > > ( path : P ) -> anyhow:: Result < Config > {
34+ let file = std:: fs:: File :: open ( path) ?;
35+ let reader = std:: io:: BufReader :: new ( file) ;
36+ let config = serde_json:: from_reader ( reader) ?;
37+ Ok ( config)
38+ }
39+
40+ fn build_output_pairs ( & self ) -> anyhow:: Result < BTreeMap < String , tera:: Context > > {
41+ match self . version {
42+ 1 => self . build_output_pairs_v1 ( ) ,
43+ _ => Err ( anyhow:: Error :: msg ( "Unexpected config file version" ) ) ,
44+ }
45+ }
46+
47+ fn build_output_pairs_v1 ( & self ) -> anyhow:: Result < BTreeMap < String , tera:: Context > > {
48+ let mut output_pairs = BTreeMap :: new ( ) ;
49+ for ( template_path, template) in self . templates . iter ( ) {
50+ for ( output_path, output) in template. outputs . iter ( ) {
51+ let mut context = tera:: Context :: new ( ) ;
52+ context. insert ( "template_path" , template_path) ;
53+ for ( prop_key, prop_value) in template. properties . iter ( ) {
54+ if let Some ( prop_override) = output. properties . get ( prop_key) {
55+ context. insert ( prop_key, prop_override) ;
56+ } else {
57+ // TODO: error message
58+ if let Some ( prop_value) = prop_value {
59+ context. insert ( prop_key, prop_value) ;
60+ } else {
61+ return Err ( anyhow:: Error :: msg ( "Missing property override" ) ) ;
62+ }
63+ }
64+ }
65+ output_pairs. insert ( output_path. clone ( ) , context) ;
66+ }
67+ }
68+ Ok ( output_pairs)
69+ }
70+
71+ // fn from(output_pairs: std::collections::HashMap<&str, tera::Context>) -> Option<Config> {
72+ // let mut config = Config::new();
73+ // for (output_path, tera_context) in output_pairs.into_iter() {
74+ // let json_context = tera_context.into_json();
75+ // let context_map = json_context.as_object()?;
76+ // let template_path = context_map.get("template_path")?.as_str()?;
77+ // if !config.templates.contains_key(template_path) {
78+ // let mut template = Template::default();
79+ // for (property, value) in context_map.iter() {
80+ // if property == "template_path" {
81+ // continue;
82+ // }
83+ // if value.is_boolean() {
84+ // template.properties.insert(
85+ // property.clone(), Some(serde_json::Value::Bool(false))
86+ // );
87+ // } else if value.is_i64() {
88+ // template
89+ // .properties
90+ // .insert(property.clone(), None);
91+ // } else if value.is_string() {
92+ // template
93+ // .properties
94+ // .insert(property.clone(), None);
95+ // } else {
96+ // unimplemented!();
97+ // }
98+ // }
99+ // config.templates.insert(template_path.to_string(), template);
100+ // }
101+ // let mut output = Output::default();
102+ // for (property, value) in context_map.iter() {
103+ // if property == "template_path" {
104+ // continue;
105+ // }
106+ // if let Some(bool_value) = value.as_bool() {
107+ // if bool_value {
108+ // output
109+ // .properties
110+ // .insert(property.clone(), serde_json::Value::Bool(bool_value));
111+ // }
112+ // } else if let Some(i64_value) = value.as_i64() {
113+ // output.properties.insert(
114+ // property.clone(),
115+ // serde_json::Value::Number(i64_value.into()),
116+ // );
117+ // } else if let Some(str_value) = value.as_str() {
118+ // output.properties.insert(
119+ // property.clone(),
120+ // serde_json::Value::String(str_value.to_string()),
121+ // );
122+ // } else {
123+ // unimplemented!();
124+ // }
125+ // }
126+ // config
127+ // .templates
128+ // .get_mut(template_path)?
129+ // .outputs
130+ // .insert(output_path.to_string(), output);
131+ // }
132+ // Some(config)
133+ // }
134+ }
12135
13136fn is_modified ( repo : & git2:: Repository , output_path : & str ) -> anyhow:: Result < bool > {
14137 match repo. status_file ( Path :: new ( output_path) ) {
@@ -61,10 +184,17 @@ fn main() -> anyhow::Result<()> {
61184 } else {
62185 None
63186 } ;
64- let mut tera = tera:: Tera :: new ( "templates/**/*.rs.tera" ) . context ( "tera parsing error(s)" ) ?;
187+
188+ let config = Config :: from_file ( Path :: new ( GLAM_ROOT ) . join ( CONFIG_FILE ) ) ?;
189+
190+ let template_path = Path :: new ( GLAM_ROOT )
191+ . join ( & config. template_root )
192+ . join ( "**/*.rs.tera" ) ;
193+ let mut tera =
194+ tera:: Tera :: new ( template_path. to_str ( ) . unwrap ( ) ) . context ( "tera parsing error(s)" ) ?;
65195 tera. register_filter (
66196 "snake_case" ,
67- |value : & Value , _: & _ | -> tera:: Result < Value > {
197+ |value : & tera :: Value , _: & _ | -> tera:: Result < tera :: Value > {
68198 let input = from_value :: < String > ( value. clone ( ) ) ?;
69199 let mut iter = input. chars ( ) ;
70200
@@ -84,11 +214,11 @@ fn main() -> anyhow::Result<()> {
84214 } ,
85215 ) ;
86216
217+ let output_pairs = config. build_output_pairs ( ) ?;
218+
87219 let repo = git2:: Repository :: open ( GLAM_ROOT ) . context ( "failed to open git repo" ) ?;
88220 let workdir = repo. workdir ( ) . unwrap ( ) ;
89221
90- let output_pairs = build_output_pairs ( ) ;
91-
92222 let mut output_paths = vec ! [ ] ;
93223 if let Some ( glob) = glob {
94224 for k in output_pairs. keys ( ) {
0 commit comments