@@ -341,6 +341,8 @@ impl Configurator {
341341 ///
342342 /// This function will return an error if the underlying resource fails.
343343 pub fn invoke_get ( & mut self ) -> Result < ConfigurationGetResult , DscError > {
344+ self . unroll_copy_loops ( ) ?;
345+
344346 let mut result = ConfigurationGetResult :: new ( ) ;
345347 let resources = get_resource_invocation_order ( & self . config , & mut self . statement_parser , & self . context ) ?;
346348 let mut progress = ProgressBar :: new ( resources. len ( ) as u64 , self . progress_format ) ?;
@@ -421,6 +423,8 @@ impl Configurator {
421423 /// This function will return an error if the underlying resource fails.
422424 #[ allow( clippy:: too_many_lines) ]
423425 pub fn invoke_set ( & mut self , skip_test : bool ) -> Result < ConfigurationSetResult , DscError > {
426+ self . unroll_copy_loops ( ) ?;
427+
424428 let mut result = ConfigurationSetResult :: new ( ) ;
425429 let resources = get_resource_invocation_order ( & self . config , & mut self . statement_parser , & self . context ) ?;
426430 let mut progress = ProgressBar :: new ( resources. len ( ) as u64 , self . progress_format ) ?;
@@ -575,6 +579,8 @@ impl Configurator {
575579 ///
576580 /// This function will return an error if the underlying resource fails.
577581 pub fn invoke_test ( & mut self ) -> Result < ConfigurationTestResult , DscError > {
582+ self . unroll_copy_loops ( ) ?;
583+
578584 let mut result = ConfigurationTestResult :: new ( ) ;
579585 let resources = get_resource_invocation_order ( & self . config , & mut self . statement_parser , & self . context ) ?;
580586 let mut progress = ProgressBar :: new ( resources. len ( ) as u64 , self . progress_format ) ?;
@@ -651,6 +657,8 @@ impl Configurator {
651657 ///
652658 /// This function will return an error if the underlying resource fails.
653659 pub fn invoke_export ( & mut self ) -> Result < ConfigurationExportResult , DscError > {
660+ self . unroll_copy_loops ( ) ?;
661+
654662 let mut result = ConfigurationExportResult :: new ( ) ;
655663 let mut conf = config_doc:: Configuration :: new ( ) ;
656664 conf. metadata . clone_from ( & self . config . metadata ) ;
@@ -874,7 +882,7 @@ impl Configurator {
874882 }
875883
876884 fn validate_config ( & mut self ) -> Result < ( ) , DscError > {
877- let mut config: Configuration = serde_json:: from_str ( self . json . as_str ( ) ) ?;
885+ let config: Configuration = serde_json:: from_str ( self . json . as_str ( ) ) ?;
878886 check_security_context ( config. metadata . as_ref ( ) ) ?;
879887
880888 // Perform discovery of resources used in config
@@ -886,15 +894,33 @@ impl Configurator {
886894 if !discovery_filter. contains ( & filter) {
887895 discovery_filter. push ( filter) ;
888896 }
889- // if the resource contains `Copy`, we need to unroll
897+ // defer actual unrolling until parameters are available
890898 if let Some ( copy) = & resource. copy {
891- debug ! ( "{}" , t!( "configure.mod.unrollingCopy " , name = & copy. name, count = copy. count) ) ;
899+ debug ! ( "{}" , t!( "configure.mod.validateCopy " , name = & copy. name, count = copy. count) ) ;
892900 if copy. mode . is_some ( ) {
893901 return Err ( DscError :: Validation ( t ! ( "configure.mod.copyModeNotSupported" ) . to_string ( ) ) ) ;
894902 }
895903 if copy. batch_size . is_some ( ) {
896904 return Err ( DscError :: Validation ( t ! ( "configure.mod.copyBatchSizeNotSupported" ) . to_string ( ) ) ) ;
897905 }
906+ }
907+ }
908+
909+ self . discovery . find_resources ( & discovery_filter, self . progress_format ) ;
910+ self . config = config;
911+ Ok ( ( ) )
912+ }
913+
914+ /// Unroll copy loops in the configuration.
915+ /// This method should be called after parameters have been set in the context.
916+ fn unroll_copy_loops ( & mut self ) -> Result < ( ) , DscError > {
917+ let mut config = self . config . clone ( ) ;
918+ let config_copy = config. clone ( ) ;
919+
920+ for resource in config_copy. resources {
921+ // if the resource contains `Copy`, unroll it
922+ if let Some ( copy) = & resource. copy {
923+ debug ! ( "{}" , t!( "configure.mod.unrollingCopy" , name = & copy. name, count = copy. count) ) ;
898924 self . context . process_mode = ProcessMode :: Copy ;
899925 self . context . copy_current_loop_name . clone_from ( & copy. name ) ;
900926 let mut copy_resources = Vec :: < Resource > :: new ( ) ;
@@ -905,6 +931,7 @@ impl Configurator {
905931 return Err ( DscError :: Parser ( t ! ( "configure.mod.copyNameResultNotString" ) . to_string ( ) ) )
906932 } ;
907933 new_resource. name = new_name. to_string ( ) ;
934+
908935 new_resource. copy = None ;
909936 copy_resources. push ( new_resource) ;
910937 }
@@ -914,8 +941,7 @@ impl Configurator {
914941 config. resources . extend ( copy_resources) ;
915942 }
916943 }
917-
918- self . discovery . find_resources ( & discovery_filter, self . progress_format ) ;
944+
919945 self . config = config;
920946 Ok ( ( ) )
921947 }
0 commit comments