11use serde:: { Deserialize , Serialize } ;
22use serde_json;
33use serde_yaml;
4+ use std:: error:: Error ;
45use std:: fs;
6+ use std:: path:: Path ;
7+ use std:: collections:: HashMap ;
58
69#[ derive( Debug , Deserialize , Serialize , Clone ) ]
710pub struct BodoConfig {
8- pub tasks : Option < Vec < TaskConfig > > ,
911 pub env_files : Option < Vec < String > > ,
1012 pub executable_map : Option < Vec < ExecutableMap > > ,
1113 pub max_concurrency : Option < usize > ,
@@ -14,7 +16,6 @@ pub struct BodoConfig {
1416
1517#[ derive( Debug , Deserialize , Serialize , Clone ) ]
1618pub struct TaskConfig {
17- pub name : String ,
1819 pub command : String ,
1920 pub cwd : Option < String > ,
2021 pub env : Option < Vec < String > > ,
@@ -28,10 +29,20 @@ pub struct ExecutableMap {
2829 pub path : Option < String > ,
2930}
3031
32+ #[ derive( Debug , Deserialize , Serialize , Clone ) ]
33+ pub struct ScriptConfig {
34+ pub name : String ,
35+ pub description : Option < String > ,
36+ pub exec_paths : Option < Vec < String > > ,
37+ pub env : Option < HashMap < String , String > > ,
38+ #[ serde( rename = "defaultTask" ) ]
39+ pub default_task : TaskConfig ,
40+ pub subtasks : Option < HashMap < String , TaskConfig > > ,
41+ }
42+
3143impl Default for BodoConfig {
3244 fn default ( ) -> Self {
3345 Self {
34- tasks : None ,
3546 env_files : None ,
3647 executable_map : None ,
3748 max_concurrency : None ,
@@ -40,7 +51,7 @@ impl Default for BodoConfig {
4051 }
4152}
4253
43- pub fn load_bodo_config ( ) -> BodoConfig {
54+ pub fn load_bodo_config ( ) -> Result < BodoConfig , Box < dyn Error > > {
4455 let config_paths = [
4556 "bodo.json" ,
4657 "bodo.yaml" ,
@@ -59,12 +70,25 @@ pub fn load_bodo_config() -> BodoConfig {
5970 } ;
6071
6172 if let Some ( config) = config {
62- return config;
73+ return Ok ( config) ;
6374 }
6475 }
6576 }
6677
67- BodoConfig :: default ( )
78+ Ok ( BodoConfig :: default ( ) )
79+ }
80+
81+ pub fn load_script_config ( task_name : & str ) -> Result < ScriptConfig , Box < dyn Error > > {
82+ let script_path = format ! ( "scripts/{}/script.yaml" , task_name) ;
83+ let path = Path :: new ( & script_path) ;
84+
85+ if !path. exists ( ) {
86+ return Err ( format ! ( "Script file not found: {}" , script_path) . into ( ) ) ;
87+ }
88+
89+ let contents = fs:: read_to_string ( path) ?;
90+ let config: ScriptConfig = serde_yaml:: from_str ( & contents) ?;
91+ Ok ( config)
6892}
6993
7094#[ cfg( test) ]
@@ -77,10 +101,10 @@ mod tests {
77101 fn create_temp_config_file ( content : & str , extension : & str ) -> PathBuf {
78102 let mut temp_path = std:: env:: temp_dir ( ) ;
79103 temp_path. push ( format ! ( "test_config.{}" , extension) ) ;
80-
104+
81105 let mut file = File :: create ( & temp_path) . unwrap ( ) ;
82106 file. write_all ( content. as_bytes ( ) ) . unwrap ( ) ;
83-
107+
84108 temp_path
85109 }
86110
@@ -91,7 +115,6 @@ mod tests {
91115 #[ test]
92116 fn test_default_config ( ) {
93117 let config = BodoConfig :: default ( ) ;
94- assert ! ( config. tasks. is_none( ) ) ;
95118 assert ! ( config. env_files. is_none( ) ) ;
96119 assert ! ( config. executable_map. is_none( ) ) ;
97120 assert ! ( config. max_concurrency. is_none( ) ) ;
@@ -101,16 +124,6 @@ mod tests {
101124 #[ test]
102125 fn test_load_json_config ( ) {
103126 let content = r#"{
104- "tasks": [
105- {
106- "name": "test",
107- "command": "echo hello",
108- "cwd": ".",
109- "env": ["TEST=true"],
110- "dependencies": ["prep"],
111- "plugins": ["test-plugin"]
112- }
113- ],
114127 "env_files": [".env"],
115128 "executable_map": [
116129 {
@@ -121,35 +134,21 @@ mod tests {
121134 "max_concurrency": 4,
122135 "plugins": ["plugin1"]
123136 }"# ;
124-
137+
125138 let temp_path = create_temp_config_file ( content, "json" ) ;
126139 std:: env:: set_current_dir ( temp_path. parent ( ) . unwrap ( ) ) . unwrap ( ) ;
127-
140+
128141 let config: BodoConfig = serde_json:: from_str ( content) . unwrap ( ) ;
129- assert ! ( config. tasks. is_some( ) ) ;
130- assert_eq ! ( config. tasks. as_ref( ) . unwrap( ) . len( ) , 1 ) ;
131-
132- let task = & config. tasks . as_ref ( ) . unwrap ( ) [ 0 ] ;
133- assert_eq ! ( task. name, "test" ) ;
134- assert_eq ! ( task. command, "echo hello" ) ;
135- assert_eq ! ( task. cwd, Some ( "." . to_string( ) ) ) ;
136-
142+ assert ! ( config. env_files. is_some( ) ) ;
143+ assert ! ( config. executable_map. is_some( ) ) ;
144+ assert_eq ! ( config. max_concurrency, Some ( 4 ) ) ;
145+
137146 cleanup_temp_file ( temp_path) ;
138147 }
139148
140149 #[ test]
141150 fn test_load_yaml_config ( ) {
142151 let content = r#"
143- tasks:
144- - name: test
145- command: echo hello
146- cwd: .
147- env:
148- - TEST=true
149- dependencies:
150- - prep
151- plugins:
152- - test-plugin
153152env_files:
154153 - .env
155154executable_map:
@@ -159,19 +158,15 @@ max_concurrency: 4
159158plugins:
160159 - plugin1
161160"# ;
162-
161+
163162 let temp_path = create_temp_config_file ( content, "yaml" ) ;
164163 std:: env:: set_current_dir ( temp_path. parent ( ) . unwrap ( ) ) . unwrap ( ) ;
165-
164+
166165 let config: BodoConfig = serde_yaml:: from_str ( content) . unwrap ( ) ;
167- assert ! ( config. tasks. is_some( ) ) ;
168- assert_eq ! ( config. tasks. as_ref( ) . unwrap( ) . len( ) , 1 ) ;
169-
170- let task = & config. tasks . as_ref ( ) . unwrap ( ) [ 0 ] ;
171- assert_eq ! ( task. name, "test" ) ;
172- assert_eq ! ( task. command, "echo hello" ) ;
173- assert_eq ! ( task. cwd, Some ( "." . to_string( ) ) ) ;
174-
166+ assert ! ( config. env_files. is_some( ) ) ;
167+ assert ! ( config. executable_map. is_some( ) ) ;
168+ assert_eq ! ( config. max_concurrency, Some ( 4 ) ) ;
169+
175170 cleanup_temp_file ( temp_path) ;
176171 }
177172
@@ -181,8 +176,8 @@ plugins:
181176 executable : Some ( "node" . to_string ( ) ) ,
182177 path : Some ( "/usr/local/bin/node" . to_string ( ) ) ,
183178 } ;
184-
179+
185180 assert_eq ! ( map. executable. as_ref( ) . unwrap( ) , "node" ) ;
186181 assert_eq ! ( map. path. as_ref( ) . unwrap( ) , "/usr/local/bin/node" ) ;
187182 }
188- }
183+ }
0 commit comments