33module Puppet ::Pops
44module Evaluator
55
6+ class DeferredValue
7+ def initialize ( proc )
8+ @proc = proc
9+ end
10+
11+ def resolve
12+ @proc . call
13+ end
14+ end
15+
616# Utility class to help resolve instances of Puppet::Pops::Types::PDeferredType::Deferred
717#
818class DeferredResolver
@@ -20,9 +30,9 @@ class DeferredResolver
2030 # are to be mixed into the scope
2131 # @return [nil] does not return anything - the catalog is modified as a side effect
2232 #
23- def self . resolve_and_replace ( facts , catalog , environment = catalog . environment_instance )
24- compiler = Puppet ::Parser ::ScriptCompiler . new ( environment , catalog . name , true )
25- resolver = new ( compiler )
33+ def self . resolve_and_replace ( facts , catalog , environment = catalog . environment_instance , preprocess_deferred = true )
34+ compiler = Puppet ::Parser ::ScriptCompiler . new ( environment , catalog . name , preprocess_deferred )
35+ resolver = new ( compiler , preprocess_deferred )
2636 resolver . set_facts_variable ( facts )
2737 # TODO:
2838 # # When scripting the trusted data are always local, but set them anyway
@@ -53,11 +63,12 @@ def self.resolve(value, compiler)
5363 resolver . resolve ( value )
5464 end
5565
56- def initialize ( compiler )
66+ def initialize ( compiler , preprocess_deferred = true )
5767 @compiler = compiler
5868 # Always resolve in top scope
5969 @scope = @compiler . topscope
6070 @deferred_class = Puppet ::Pops ::Types ::TypeFactory . deferred . implementation_class
71+ @preprocess_deferred = preprocess_deferred
6172 end
6273
6374 # @param facts [Puppet::Node::Facts] the facts to set in $facts in the compiler's topscope
@@ -106,6 +117,24 @@ def resolve(x)
106117 end
107118 end
108119
120+ def resolve_lazy_args ( x )
121+ if x . is_a? ( DeferredValue )
122+ x . resolve
123+ elsif x . is_a? ( Array )
124+ x . map { |v | resolve_lazy_args ( v ) }
125+ elsif x . is_a? ( Hash )
126+ result = { }
127+ x . each_pair { |k , v | result [ k ] = resolve_lazy_args ( v ) }
128+ result
129+ elsif x . is_a? ( Puppet ::Pops ::Types ::PSensitiveType ::Sensitive )
130+ # rewrap in a new Sensitive after resolving any nested deferred values
131+ Puppet ::Pops ::Types ::PSensitiveType ::Sensitive . new ( resolve_lazy_args ( x . unwrap ) )
132+ else
133+ x
134+ end
135+ end
136+ private :resolve_lazy_args
137+
109138 def resolve_future ( f )
110139 # If any of the arguments to a future is a future it needs to be resolved first
111140 func_name = f . name
@@ -117,8 +146,19 @@ def resolve_future(f)
117146 mapped_arguments . insert ( 0 , @scope [ var_name ] )
118147 end
119148
120- # call the function (name in deferred, or 'dig' for a variable)
121- @scope . call_function ( func_name , mapped_arguments )
149+ if @preprocess_deferred
150+ # call the function (name in deferred, or 'dig' for a variable)
151+ @scope . call_function ( func_name , mapped_arguments )
152+ else
153+ # call the function later
154+ DeferredValue . new (
155+ Proc . new {
156+ # deferred functions can have nested deferred arguments
157+ resolved_arguments = mapped_arguments . map { |arg | resolve_lazy_args ( arg ) }
158+ @scope . call_function ( func_name , resolved_arguments )
159+ }
160+ )
161+ end
122162 end
123163
124164 def map_arguments ( args )
0 commit comments