1- use std:: collections:: HashMap ;
21use std:: str:: FromStr ;
32
43use crate :: agent_type:: definition:: Variables ;
54use crate :: agent_type:: error:: AgentTypeError ;
5+ use crate :: agent_type:: runtime_config:: on_host:: executable:: { Args , Env } ;
66use crate :: agent_type:: runtime_config:: on_host:: package:: rendered:: { Repository , Version } ;
77use crate :: agent_type:: runtime_config:: templateable_value:: TemplateableValue ;
88use crate :: agent_type:: templates:: Templateable ;
@@ -41,18 +41,22 @@ pub struct Oci {
4141
4242#[ derive( Debug , Deserialize , Clone , PartialEq ) ]
4343pub struct PostDownloadHook {
44- /// Absolute path to the command/executable (e.g., "/bin/bash", "/usr/bin/python3").
45- /// This is the interpreter or tool that will execute the script.
44+ /// Path to the command/executable to run.
45+ /// Can be an absolute path (e.g., "/bin/bash") or a command name to search in PATH (e.g., "bash").
46+ /// Supports shell interpreters or direct binaries.
4647 pub path : TemplateableValue < String > ,
4748
48- /// Arguments passed to the command. First element should be the script path (absolute),
49- /// followed by additional arguments for the script.
50- /// Example: ["install.sh", "--check-dependencies", "--verbose"]
51- pub args : Vec < TemplateableValue < String > > ,
49+ /// Arguments passed to the command.
50+ /// - When using a shell: first arg is typically the script path, followed by script arguments
51+ /// Example: ["/path/to/install.sh", "--check-dependencies", "--verbose"]
52+ /// - When using a binary directly: arguments for that binary (can be empty)
53+ /// Example: ["--flag", "value"] or []
54+ #[ serde( default ) ]
55+ pub args : Args ,
5256
5357 /// Environmental variables passed to the process.
5458 #[ serde( default ) ]
55- pub env : HashMap < String , TemplateableValue < String > > ,
59+ pub env : Env ,
5660}
5761
5862impl Templateable for Package {
@@ -115,25 +119,19 @@ impl Templateable for Oci {
115119impl Templateable for PostDownloadHook {
116120 type Output = rendered:: PostDownloadHook ;
117121 fn template_with ( self , variables : & Variables ) -> Result < Self :: Output , AgentTypeError > {
118- let path = self . path . template_with ( variables ) ? ;
122+ use crate :: agent_type :: runtime_config :: on_host :: executable :: rendered :: Args as RenderedArgs ;
119123
120- let args: Vec < String > = self
121- . args
122- . into_iter ( )
123- . map ( |arg| arg. template_with ( variables) )
124- . collect :: < Result < Vec < String > , AgentTypeError > > ( ) ?;
124+ let path = self . path . template_with ( variables) ?;
125125
126- if args. is_empty ( ) {
127- return Err ( AgentTypeError :: OCIReferenceParsingError (
128- "post_download_hook args must have at least 1 element: the script path" . to_string ( ) ,
129- ) ) ;
130- }
126+ let args = RenderedArgs (
127+ self . args
128+ . 0
129+ . into_iter ( )
130+ . map ( |arg| arg. template_with ( variables) )
131+ . collect :: < Result < Vec < String > , AgentTypeError > > ( ) ?,
132+ ) ;
131133
132- let env: HashMap < String , String > = self
133- . env
134- . into_iter ( )
135- . map ( |( k, v) | v. template_with ( variables) . map ( |templated| ( k, templated) ) )
136- . collect :: < Result < HashMap < _ , _ > , AgentTypeError > > ( ) ?;
134+ let env = self . env . template_with ( variables) ?;
137135
138136 Ok ( Self :: Output { path, args, env } )
139137 }
@@ -196,6 +194,8 @@ mod tests {
196194
197195 #[ test]
198196 fn test_post_download_hook_template_with_variables ( ) {
197+ use std:: collections:: HashMap ;
198+
199199 let mut variables = Variables :: new ( ) ;
200200 variables. insert (
201201 "nr-var:version" . to_string ( ) ,
@@ -210,38 +210,38 @@ mod tests {
210210 Variable :: new_final_string_variable ( "test-value" . to_string ( ) ) ,
211211 ) ;
212212
213- let mut env = HashMap :: new ( ) ;
214- env . insert (
213+ let mut env_map = HashMap :: new ( ) ;
214+ env_map . insert (
215215 "AGENT_VERSION" . to_string ( ) ,
216216 TemplateableValue :: from_template ( "${nr-var:version}" . to_string ( ) ) ,
217217 ) ;
218- env . insert (
218+ env_map . insert (
219219 "CUSTOM_VAR" . to_string ( ) ,
220220 TemplateableValue :: from_template ( "${nr-var:env-value}" . to_string ( ) ) ,
221221 ) ;
222222
223223 let post_download_hook = PostDownloadHook {
224224 path : TemplateableValue :: from_template ( "/bin/bash" . to_string ( ) ) ,
225- args : vec ! [
225+ args : Args ( vec ! [
226226 TemplateableValue :: from_template( "${nr-var:script-path}" . to_string( ) ) ,
227227 TemplateableValue :: from_template( "--version=${nr-var:version}" . to_string( ) ) ,
228- ] ,
229- env,
228+ ] ) ,
229+ env : Env ( env_map ) ,
230230 } ;
231231
232232 let rendered = post_download_hook. template_with ( & variables) . unwrap ( ) ;
233233
234234 assert_eq ! ( rendered. path, "/bin/bash" ) ;
235- assert_eq ! ( rendered. args. len( ) , 2 ) ;
236- assert_eq ! ( rendered. args[ 0 ] , "/opt/install.sh" ) ;
237- assert_eq ! ( rendered. args[ 1 ] , "--version=1.0.0" ) ;
238- assert_eq ! ( rendered. env. len( ) , 2 ) ;
235+ assert_eq ! ( rendered. args. 0 . len( ) , 2 ) ;
236+ assert_eq ! ( rendered. args. 0 [ 0 ] , "/opt/install.sh" ) ;
237+ assert_eq ! ( rendered. args. 0 [ 1 ] , "--version=1.0.0" ) ;
238+ assert_eq ! ( rendered. env. 0 . len( ) , 2 ) ;
239239 assert_eq ! (
240- rendered. env. get( "AGENT_VERSION" ) ,
240+ rendered. env. 0 . get( "AGENT_VERSION" ) ,
241241 Some ( & "1.0.0" . to_string( ) )
242242 ) ;
243243 assert_eq ! (
244- rendered. env. get( "CUSTOM_VAR" ) ,
244+ rendered. env. 0 . get( "CUSTOM_VAR" ) ,
245245 Some ( & "test-value" . to_string( ) )
246246 ) ;
247247 }
0 commit comments