@@ -67,9 +67,11 @@ def ps_manager
6767 Pwsh ::Manager . instance ( command ( :powershell ) , Pwsh ::Manager . powershell_args , debug : debug_output )
6868 end
6969
70- # ===== Deferred helpers (instance methods) =====
70+ # ============================================================================
71+ # Deferred helpers (instance methods)
72+ # ============================================================================
7173
72- # Detects if a value (or nested) contains a DeferredValue
74+ # Returns true if obj (or any nested member) is a DeferredValue
7375 def deep_contains_deferred? ( obj )
7476 case obj
7577 when Puppet ::Pops ::Evaluator ::DeferredValue
@@ -89,25 +91,18 @@ def deep_contains_deferred?(obj)
8991 end
9092 end
9193
92- # Force resolution of Deferreds across the catalog before script generation.
93- # This mirrors Puppet's own preprocessing when preprocess_deferred=true.
94- def ensure_deferreds_resolved!
95- # (A) Prefer compiler-based resolution for properties when available
96- props_param = resource . parameters [ :properties ]
97- compiler = Puppet . lookup ( :compiler ) { nil }
98-
99- if props_param
100- pv = props_param . value
101- if deep_contains_deferred? ( pv )
102- Puppet . debug ( 'DSC_lite: Deferred detected in properties; resolving via compiler' ) if compiler
103- if compiler
104- resolved = Puppet ::Pops ::Evaluator ::DeferredResolver . resolve ( pv , compiler )
105- resource [ :properties ] = resolved
106- end
107- end
108- end
94+ # Resolves a value with the current compiler if available; otherwise returns it unchanged
95+ def resolve_value_with_compiler ( value )
96+ compiler = Puppet . lookup ( :compiler ) { nil }
97+ return value unless compiler
98+ Puppet ::Pops ::Evaluator ::DeferredResolver . resolve ( value , compiler )
99+ end
109100
110- # (B) Always run a full catalog resolution pass as a safety net.
101+ # Resolve any lingering Deferreds before script generation:
102+ # A) catalog-wide pass (resolve_and_replace), then
103+ # B) per-parameter pass using compiler resolution for any stragglers
104+ def ensure_deferreds_resolved!
105+ # (A) Catalog-wide resolution (mirrors preprocess_deferred=true behavior)
111106 facts = Puppet ::Node ::Facts . new (
112107 ( resource . catalog . respond_to? ( :host ) && resource . catalog . host ) ||
113108 Facter . value ( :fqdn ) || Facter . value ( :hostname ) || 'localhost' ,
@@ -118,19 +113,32 @@ def ensure_deferreds_resolved!
118113 Puppet . debug ( 'DSC_lite: invoking DeferredResolver.resolve_and_replace on catalog' )
119114 Puppet ::Pops ::Evaluator ::DeferredResolver . resolve_and_replace ( facts , resource . catalog , env , true )
120115
121- # Post-check for diagnostics
122- pp = resource . parameters [ :properties ]
123- if pp && deep_contains_deferred? ( pp . value )
124- Puppet . debug ( 'DSC_lite: WARNING — Deferred still present in properties after resolution pass' )
116+ # (B) Per-parameter scan & fix-up
117+ resource . parameters_with_value . each do |param |
118+ val = param . value
119+ next unless deep_contains_deferred? ( val )
120+
121+ Puppet . debug ( "DSC_lite: Deferred detected in parameter `#{ param . name } `; attempting compiler-based resolution" )
122+ begin
123+ resolved = resolve_value_with_compiler ( val )
124+ resource [ param . name ] = resolved unless resolved . equal? ( val )
125+ rescue => e
126+ raise Puppet ::Error , "DSC_lite: failed to resolve Deferred in parameter `#{ param . name } `: #{ e . class } : #{ e . message } "
127+ end
128+ end
129+
130+ # Post-check diagnostics for the critical :properties blob
131+ props_param = resource . parameters [ :properties ]
132+ if props_param && deep_contains_deferred? ( props_param . value )
133+ Puppet . debug ( 'DSC_lite: WARNING — Deferred still present in `properties` after resolution passes' )
125134 else
126- Puppet . debug ( 'DSC_lite: no Deferred values remain in properties after resolution' )
135+ Puppet . debug ( 'DSC_lite: no Deferred values remain in ` properties` after resolution' )
127136 end
128- rescue => e
129- # Raise a targeted error; this is better than failing later with "unsupported type DeferredValue"
130- raise Puppet ::Error , "DSC_lite: failed while resolving Deferred values: #{ e . class } : #{ e . message } "
131137 end
132138
133- # ===== END Deferred helpers =====
139+ # ============================================================================
140+ # Provider lifecycle
141+ # ============================================================================
134142
135143 def exists?
136144 timeout = set_timeout
@@ -213,20 +221,10 @@ def notify_reboot_pending
213221 end
214222 end
215223
216- # ---- CHANGED: resolve Deferreds right before formatting the hash ----
224+ # Keep formatter behavior identical to main; resolution happens in provider
217225 def self . format_dsc_lite ( dsc_value )
218- # Resolve any direct/nested Deferred values using the current compiler scope if available.
219- compiler = Puppet . lookup ( :compiler ) { nil }
220- value_for_format =
221- if compiler
222- Puppet ::Pops ::Evaluator ::DeferredResolver . resolve ( dsc_value , compiler )
223- else
224- dsc_value
225- end
226-
227- PuppetX ::PuppetLabs ::DscLite ::PowerShellHashFormatter . format ( value_for_format )
226+ PuppetX ::PuppetLabs ::DscLite ::PowerShellHashFormatter . format ( dsc_value )
228227 end
229- # --------------------------------------------------------------------
230228
231229 def self . escape_quotes ( text )
232230 text . gsub ( "'" , "''" )
0 commit comments