@@ -106,37 +106,60 @@ fn path_from_args(args: &HashMap<String, tera::Value>) -> tera::Result<String> {
106106 Ok ( from_value :: < String > ( file. clone ( ) ) ?)
107107}
108108
109- fn yamlloader ( args : & HashMap < String , tera :: Value > ) -> tera :: Result < tera :: Value > {
110- let path = path_from_args ( args ) ? ;
111- let f = std :: fs :: File :: open ( path ) ? ;
112- serde_yaml :: from_reader ( f ) . map_err ( |_| "Failed to read file" . into ( ) )
109+ enum LoaderType {
110+ Yaml ,
111+ Json ,
112+ Toml ,
113113}
114114
115- fn jsonloader ( args : & HashMap < String , tera:: Value > ) -> tera:: Result < tera:: Value > {
116- let path = path_from_args ( args) ?;
117- let f = std:: fs:: File :: open ( path) ?;
118- serde_json:: from_reader ( f) . map_err ( |_| "Failed to read file" . into ( ) )
119- }
120-
121- fn tomlloader ( args : & HashMap < String , tera:: Value > ) -> tera:: Result < tera:: Value > {
122- let path = path_from_args ( args) ?;
123- let contents = std:: fs:: read_to_string ( path) ?;
124- toml:: from_str ( & contents) . map_err ( |_| "Failed to read file" . into ( ) )
115+ fn makeloader ( path : & Path , loader : LoaderType ) -> impl tera:: Function {
116+ // Get the dirname of the Path given (if a file), or just the directory.
117+ let directory = if path. is_file ( ) {
118+ path. parent ( ) . expect ( "File should have a parent directory" )
119+ } else {
120+ path
121+ }
122+ . to_path_buf ( ) ;
123+
124+ Box :: new ( move |args : & HashMap < String , tera:: Value > | {
125+ path_from_args ( args)
126+ // Calculate the full path using the parent directory
127+ . map ( |path| directory. join ( path) )
128+ // Read the file as a string
129+ . and_then ( |full_path| std:: fs:: read_to_string ( full_path) . map_err ( Into :: into) )
130+ // Parse the file using the relevant parser
131+ . and_then ( |contents| match loader {
132+ LoaderType :: Yaml => serde_yaml:: from_str ( & contents)
133+ . map_err ( |err| format ! ( "Failed to parse file as YAML: {err}" ) . into ( ) ) ,
134+ LoaderType :: Json => serde_json:: from_str ( & contents)
135+ . map_err ( |err| format ! ( "Failed to parse file as JSON: {err}" ) . into ( ) ) ,
136+ LoaderType :: Toml => toml:: from_str ( & contents)
137+ . map_err ( |err| format ! ( "Failed to parse file as TOML: {err}" ) . into ( ) ) ,
138+ } )
139+ } )
125140}
126141
127142// Renders a template from a given string.
128143pub fn render_template ( template : & str , source_filename : & Path ) -> Result < String , FlokiError > {
129144 let template_path = source_filename. display ( ) . to_string ( ) ;
130-
131145 debug ! ( "Rendering template: {template_path}" ) ;
132146
147+ // Get the canonical path for the template.
148+ let canonical_path = std:: fs:: canonicalize ( source_filename) . map_err ( |err| {
149+ FlokiError :: ProblemNormalizingFilePath {
150+ name : template_path. clone ( ) ,
151+ error : err,
152+ }
153+ } ) ?;
154+ debug ! ( "Canonical path: {canonical_path:?}" ) ;
155+
133156 // Read the template using tera
134157 let mut tera = Tera :: default ( ) ;
135158
136159 // Allow templates to load variables files as Values.
137- tera. register_function ( "yaml" , yamlloader ) ;
138- tera. register_function ( "json" , jsonloader ) ;
139- tera. register_function ( "toml" , tomlloader ) ;
160+ tera. register_function ( "yaml" , makeloader ( & canonical_path , LoaderType :: Yaml ) ) ;
161+ tera. register_function ( "json" , makeloader ( & canonical_path , LoaderType :: Json ) ) ;
162+ tera. register_function ( "toml" , makeloader ( & canonical_path , LoaderType :: Toml ) ) ;
140163
141164 tera. add_raw_template ( & template_path, template)
142165 . map_err ( |e| FlokiError :: ProblemRenderingTemplate {
@@ -327,7 +350,7 @@ mod test {
327350 fn test_tera_yamlload ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
328351 let template =
329352 r#"{% set values = yaml(file="test_resources/values.yaml") %}shell: {{ values.foo }}"# ;
330- let config = render_template ( template, Path :: new ( "floki" ) ) ?;
353+ let config = render_template ( template, Path :: new ( "floki.yaml " ) ) ?;
331354 assert_eq ! ( config, "shell: bar" ) ;
332355 Ok ( ( ) )
333356 }
@@ -336,7 +359,7 @@ mod test {
336359 fn test_tera_jsonload ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
337360 let template =
338361 r#"{% set values = json(file="test_resources/values.json") %}shell: {{ values.foo }}"# ;
339- let config = render_template ( template, Path :: new ( "floki" ) ) ?;
362+ let config = render_template ( template, Path :: new ( "floki.yaml " ) ) ?;
340363 assert_eq ! ( config, "shell: bar" ) ;
341364 Ok ( ( ) )
342365 }
@@ -345,7 +368,7 @@ mod test {
345368 fn test_tera_tomlload ( ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
346369 let template =
347370 r#"{% set values = toml(file="Cargo.toml") %}floki: {{ values.package.name }}"# ;
348- let config = render_template ( template, Path :: new ( "floki" ) ) ?;
371+ let config = render_template ( template, Path :: new ( "floki.yaml " ) ) ?;
349372 assert_eq ! ( config, "floki: floki" ) ;
350373 Ok ( ( ) )
351374 }
0 commit comments