22// Licensed under the MIT License.
33
44use crate :: configure:: config_doc:: Resource ;
5- use crate :: configure:: Configuration ;
5+ use crate :: configure:: { Configuration , IntOrExpression , ProcessMode , invoke_property_expressions } ;
66use crate :: DscError ;
77use crate :: parser:: Statement ;
88
99use rust_i18n:: t;
10+ use serde_json:: Value ;
1011use super :: context:: Context ;
1112use tracing:: debug;
1213
@@ -23,7 +24,7 @@ use tracing::debug;
2324/// # Errors
2425///
2526/// * `DscError::Validation` - The configuration is invalid
26- pub fn get_resource_invocation_order ( config : & Configuration , parser : & mut Statement , context : & Context ) -> Result < Vec < Resource > , DscError > {
27+ pub fn get_resource_invocation_order ( config : & Configuration , parser : & mut Statement , context : & mut Context ) -> Result < Vec < Resource > , DscError > {
2728 debug ! ( "Getting resource invocation order" ) ;
2829 let mut order: Vec < Resource > = Vec :: new ( ) ;
2930 for resource in & config. resources {
@@ -54,7 +55,7 @@ pub fn get_resource_invocation_order(config: &Configuration, parser: &mut Statem
5455 continue ;
5556 }
5657 // add the dependency to the order
57- order . push ( dependency_resource. clone ( ) ) ;
58+ unroll_and_push ( & mut order , dependency_resource, parser , context ) ? ;
5859 dependency_already_in_order = false ;
5960 }
6061 }
@@ -84,13 +85,52 @@ pub fn get_resource_invocation_order(config: &Configuration, parser: &mut Statem
8485 continue ;
8586 }
8687
87- order . push ( resource. clone ( ) ) ;
88+ unroll_and_push ( & mut order , resource, parser , context ) ? ;
8889 }
8990
9091 debug ! ( "{}: {order:?}" , t!( "configure.dependsOn.invocationOrder" ) ) ;
9192 Ok ( order)
9293}
9394
95+ fn unroll_and_push ( order : & mut Vec < Resource > , resource : & Resource , parser : & mut Statement , context : & mut Context ) -> Result < ( ) , DscError > {
96+ // if the resource contains `Copy`, unroll it
97+ if let Some ( copy) = & resource. copy {
98+ debug ! ( "{}" , t!( "configure.mod.unrollingCopy" , name = & copy. name, count = copy. count) ) ;
99+ context. process_mode = ProcessMode :: Copy ;
100+ context. copy_current_loop_name . clone_from ( & copy. name ) ;
101+ let mut copy_resources = Vec :: < Resource > :: new ( ) ;
102+ let count: i64 = match & copy. count {
103+ IntOrExpression :: Int ( i) => * i,
104+ IntOrExpression :: Expression ( e) => {
105+ let Value :: Number ( n) = parser. parse_and_execute ( e, context) ? else {
106+ return Err ( DscError :: Parser ( t ! ( "configure.mod.copyCountResultNotInteger" , expression = e) . to_string ( ) ) )
107+ } ;
108+ n. as_i64 ( ) . ok_or_else ( || DscError :: Parser ( t ! ( "configure.mod.copyCountResultNotInteger" , expression = e) . to_string ( ) ) ) ?
109+ } ,
110+ } ;
111+ for i in 0 ..count {
112+ context. copy . insert ( copy. name . clone ( ) , i) ;
113+ let mut new_resource = resource. clone ( ) ;
114+ let Value :: String ( new_name) = parser. parse_and_execute ( & resource. name , context) ? else {
115+ return Err ( DscError :: Parser ( t ! ( "configure.mod.copyNameResultNotString" ) . to_string ( ) ) )
116+ } ;
117+ new_resource. name = new_name. to_string ( ) ;
118+
119+ if let Some ( properties) = & resource. properties {
120+ new_resource. properties = invoke_property_expressions ( parser, context, Some ( properties) ) ?;
121+ }
122+
123+ new_resource. copy = None ;
124+ copy_resources. push ( new_resource) ;
125+ }
126+ context. process_mode = ProcessMode :: Normal ;
127+ order. extend ( copy_resources. clone ( ) ) ;
128+ } else {
129+ order. push ( resource. clone ( ) ) ;
130+ }
131+ Ok ( ( ) )
132+ }
133+
94134fn get_type_and_name ( statement : & str ) -> Result < ( & str , String ) , DscError > {
95135 let parts: Vec < & str > = statement. split ( ':' ) . collect ( ) ;
96136 if parts. len ( ) != 2 {
@@ -122,7 +162,8 @@ mod tests {
122162
123163 let config: Configuration = serde_yaml:: from_str ( config_yaml) . unwrap ( ) ;
124164 let mut parser = parser:: Statement :: new ( ) . unwrap ( ) ;
125- let order = get_resource_invocation_order ( & config, & mut parser, & Context :: new ( ) ) . unwrap ( ) ;
165+ let mut context = Context :: new ( ) ;
166+ let order = get_resource_invocation_order ( & config, & mut parser, & mut context) . unwrap ( ) ;
126167 assert_eq ! ( order[ 0 ] . name, "First" ) ;
127168 assert_eq ! ( order[ 1 ] . name, "Second" ) ;
128169 }
@@ -144,7 +185,8 @@ mod tests {
144185
145186 let config: Configuration = serde_yaml:: from_str ( config_yaml) . unwrap ( ) ;
146187 let mut parser = parser:: Statement :: new ( ) . unwrap ( ) ;
147- let order = get_resource_invocation_order ( & config, & mut parser, & Context :: new ( ) ) ;
188+ let mut context = Context :: new ( ) ;
189+ let order = get_resource_invocation_order ( & config, & mut parser, & mut context) ;
148190 assert ! ( order. is_err( ) ) ;
149191 }
150192
@@ -161,7 +203,8 @@ mod tests {
161203
162204 let config: Configuration = serde_yaml:: from_str ( config_yaml) . unwrap ( ) ;
163205 let mut parser = parser:: Statement :: new ( ) . unwrap ( ) ;
164- let order = get_resource_invocation_order ( & config, & mut parser, & Context :: new ( ) ) ;
206+ let mut context = Context :: new ( ) ;
207+ let order = get_resource_invocation_order ( & config, & mut parser, & mut context) ;
165208 assert ! ( order. is_err( ) ) ;
166209 }
167210
@@ -184,7 +227,8 @@ mod tests {
184227
185228 let config: Configuration = serde_yaml:: from_str ( config_yaml) . unwrap ( ) ;
186229 let mut parser = parser:: Statement :: new ( ) . unwrap ( ) ;
187- let order = get_resource_invocation_order ( & config, & mut parser, & Context :: new ( ) ) . unwrap ( ) ;
230+ let mut context = Context :: new ( ) ;
231+ let order = get_resource_invocation_order ( & config, & mut parser, & mut context) . unwrap ( ) ;
188232 assert_eq ! ( order[ 0 ] . name, "First" ) ;
189233 assert_eq ! ( order[ 1 ] . name, "Second" ) ;
190234 assert_eq ! ( order[ 2 ] . name, "Third" ) ;
@@ -207,7 +251,8 @@ mod tests {
207251
208252 let config: Configuration = serde_yaml:: from_str ( config_yaml) . unwrap ( ) ;
209253 let mut parser = parser:: Statement :: new ( ) . unwrap ( ) ;
210- let order = get_resource_invocation_order ( & config, & mut parser, & Context :: new ( ) ) ;
254+ let mut context = Context :: new ( ) ;
255+ let order = get_resource_invocation_order ( & config, & mut parser, & mut context) ;
211256 assert ! ( order. is_err( ) ) ;
212257 }
213258
@@ -229,7 +274,8 @@ mod tests {
229274
230275 let config: Configuration = serde_yaml:: from_str ( config_yaml) . unwrap ( ) ;
231276 let mut parser = parser:: Statement :: new ( ) . unwrap ( ) ;
232- let order = get_resource_invocation_order ( & config, & mut parser, & Context :: new ( ) ) . unwrap ( ) ;
277+ let mut context = Context :: new ( ) ;
278+ let order = get_resource_invocation_order ( & config, & mut parser, & mut context) . unwrap ( ) ;
233279 assert_eq ! ( order[ 0 ] . name, "First" ) ;
234280 assert_eq ! ( order[ 1 ] . name, "Second" ) ;
235281 assert_eq ! ( order[ 2 ] . name, "Third" ) ;
@@ -257,7 +303,8 @@ mod tests {
257303
258304 let config: Configuration = serde_yaml:: from_str ( config_yaml) . unwrap ( ) ;
259305 let mut parser = parser:: Statement :: new ( ) . unwrap ( ) ;
260- let order = get_resource_invocation_order ( & config, & mut parser, & Context :: new ( ) ) ;
306+ let mut context = Context :: new ( ) ;
307+ let order = get_resource_invocation_order ( & config, & mut parser, & mut context) ;
261308 assert ! ( order. is_err( ) ) ;
262309 }
263310
@@ -285,7 +332,8 @@ mod tests {
285332
286333 let config: Configuration = serde_yaml:: from_str ( config_yaml) . unwrap ( ) ;
287334 let mut parser = parser:: Statement :: new ( ) . unwrap ( ) ;
288- let order = get_resource_invocation_order ( & config, & mut parser, & Context :: new ( ) ) . unwrap ( ) ;
335+ let mut context = Context :: new ( ) ;
336+ let order = get_resource_invocation_order ( & config, & mut parser, & mut context) . unwrap ( ) ;
289337 assert_eq ! ( order[ 0 ] . name, "First" ) ;
290338 assert_eq ! ( order[ 1 ] . name, "Second" ) ;
291339 assert_eq ! ( order[ 2 ] . name, "Third" ) ;
0 commit comments