1
1
use futures:: stream:: FuturesUnordered ;
2
2
use futures:: StreamExt ;
3
3
use pbr:: MultiBar ;
4
+ use serde:: { Deserialize , Serialize } ;
4
5
use std:: collections:: HashMap ;
5
- use std:: path:: Path ;
6
+ use std:: path:: { Path , PathBuf } ;
6
7
use std:: process:: Output ;
7
8
use tokio:: process:: Command ;
8
9
use tokio:: task:: spawn_blocking;
@@ -12,9 +13,21 @@ use crate::error::Error;
12
13
13
14
const DEFAULT_RETRY_LIMIT : i32 = 5 ;
14
15
16
+ /// Used for ExecutorBuilder.
17
+ ///
18
+ /// Specify the format of your config file. Default to `ConfigFormat::Toml`
19
+ #[ derive( Debug , Serialize , Deserialize , Clone ) ]
20
+ pub enum ConfigFormat {
21
+ Ron ,
22
+ Json ,
23
+ Toml ,
24
+ Yaml ,
25
+ }
26
+
15
27
#[ derive( Debug , Clone ) ]
16
28
pub struct Executor < T : Default + BuildParam < P > , P : BuildCmd > {
17
29
config_path : String ,
30
+ config_format : ConfigFormat ,
18
31
ns3_path : String ,
19
32
task_concurrent : usize ,
20
33
retry_limit : u32 ,
@@ -25,6 +38,7 @@ pub struct Executor<T: Default + BuildParam<P>, P: BuildCmd> {
25
38
#[ derive( Debug , Clone ) ]
26
39
pub struct ExecutorBuilder {
27
40
pub config_path : Option < String > ,
41
+ pub config_format : Option < ConfigFormat > ,
28
42
pub ns3_path : Option < String > ,
29
43
pub task_concurrent : Option < usize > ,
30
44
pub retry_limit : Option < u32 > ,
@@ -43,6 +57,10 @@ impl<T: Default + BuildParam<P>, P: BuildCmd> Executor<T, P> {
43
57
& self . config_path
44
58
}
45
59
60
+ pub fn get_config_format ( & self ) -> & ConfigFormat {
61
+ & self . config_format
62
+ }
63
+
46
64
pub fn get_ns3_path ( & self ) -> & str {
47
65
& self . ns3_path
48
66
}
@@ -121,6 +139,56 @@ impl<T: Default + BuildParam<P>, P: BuildCmd> Executor<T, P> {
121
139
}
122
140
}
123
141
142
+ fn check_config_file ( config_path : & String , ext : & ConfigFormat ) -> Result < PathBuf , Error > {
143
+ let config_file_path = match Path :: new ( & config_path) . canonicalize ( ) {
144
+ Ok ( path) => path,
145
+ Err ( e) => {
146
+ return Err ( Error :: FileNotFound ( format ! (
147
+ "Can not locate config file: {:?}." ,
148
+ e
149
+ ) ) ) ;
150
+ }
151
+ } ;
152
+ match config_file_path. extension ( ) {
153
+ Some ( t) => match ext {
154
+ ConfigFormat :: Ron => {
155
+ if t != "ron" {
156
+ return Err ( Error :: InvalidConfig (
157
+ "Config file must be a ron file." . to_string ( ) ,
158
+ ) ) ;
159
+ }
160
+ }
161
+ ConfigFormat :: Json => {
162
+ if t != "json" {
163
+ return Err ( Error :: InvalidConfig (
164
+ "Config file must be a json file." . to_string ( ) ,
165
+ ) ) ;
166
+ }
167
+ }
168
+ ConfigFormat :: Toml => {
169
+ if t != "toml" {
170
+ return Err ( Error :: InvalidConfig (
171
+ "Config file must be a toml file." . to_string ( ) ,
172
+ ) ) ;
173
+ }
174
+ }
175
+ ConfigFormat :: Yaml => {
176
+ if t != "yaml" {
177
+ return Err ( Error :: InvalidConfig (
178
+ "Config file must be a yaml file." . to_string ( ) ,
179
+ ) ) ;
180
+ }
181
+ }
182
+ } ,
183
+ None => {
184
+ return Err ( Error :: InvalidConfig (
185
+ "Config file must have a valid file extension." . to_string ( ) ,
186
+ ) ) ;
187
+ }
188
+ }
189
+ Ok ( config_file_path)
190
+ }
191
+
124
192
impl Default for ExecutorBuilder {
125
193
fn default ( ) -> Self {
126
194
Self :: new ( )
@@ -131,6 +199,7 @@ impl ExecutorBuilder {
131
199
pub fn new ( ) -> Self {
132
200
Self {
133
201
config_path : None ,
202
+ config_format : None ,
134
203
ns3_path : None ,
135
204
task_concurrent : None ,
136
205
retry_limit : None ,
@@ -142,6 +211,11 @@ impl ExecutorBuilder {
142
211
self
143
212
}
144
213
214
+ pub fn config_format ( mut self , config_format : ConfigFormat ) -> Self {
215
+ self . config_format = Some ( config_format) ;
216
+ self
217
+ }
218
+
145
219
pub fn ns3_path ( mut self , ns3_path : & str ) -> Self {
146
220
self . ns3_path = Some ( ns3_path. to_string ( ) ) ;
147
221
self
@@ -157,41 +231,21 @@ impl ExecutorBuilder {
157
231
self
158
232
}
159
233
160
- pub fn build < ' de , T : Default + BuildParam < P > + serde:: de:: Deserialize < ' de > , P : BuildCmd > (
234
+ pub fn build < T : Default + BuildParam < P > + serde:: de:: DeserializeOwned , P : BuildCmd > (
161
235
self ,
162
236
) -> Result < Executor < T , P > , Error > {
163
- let mut config_path = self
164
- . config_path
165
- . unwrap_or_else ( || "config.toml" . to_string ( ) ) ;
237
+ let config_format = self . config_format . unwrap_or ( ConfigFormat :: Toml ) ;
238
+ let mut config_path = self . config_path . unwrap_or_else ( || match & config_format {
239
+ ConfigFormat :: Ron => "config.ron" . to_string ( ) ,
240
+ ConfigFormat :: Toml => "config.toml" . to_string ( ) ,
241
+ ConfigFormat :: Json => "config.json" . to_string ( ) ,
242
+ ConfigFormat :: Yaml => "config.yaml" . to_string ( ) ,
243
+ } ) ;
166
244
let mut ns3_path = self . ns3_path . unwrap_or_else ( || "/" . to_string ( ) ) ;
167
245
let task_concurrent = self . task_concurrent . unwrap_or_else ( num_cpus:: get) ;
168
- let retry_limit = self
169
- . retry_limit
170
- . unwrap_or_else ( || DEFAULT_RETRY_LIMIT as u32 ) ;
246
+ let retry_limit = self . retry_limit . unwrap_or ( DEFAULT_RETRY_LIMIT as u32 ) ;
171
247
// Check config file
172
- let config_file_path = match Path :: new ( & config_path) . canonicalize ( ) {
173
- Ok ( path) => path,
174
- Err ( e) => {
175
- return Err ( Error :: FileNotFound ( format ! (
176
- "Can not locate config file: {:?}." ,
177
- e
178
- ) ) ) ;
179
- }
180
- } ;
181
- match config_file_path. extension ( ) {
182
- Some ( t) => {
183
- if t != "toml" {
184
- return Err ( Error :: InvalidConfig (
185
- "Config file must be a toml file." . to_string ( ) ,
186
- ) ) ;
187
- }
188
- }
189
- None => {
190
- return Err ( Error :: InvalidConfig (
191
- "Config file must have a valid file extension." . to_string ( ) ,
192
- ) ) ;
193
- }
194
- }
248
+ let config_file_path = check_config_file ( & config_path, & config_format) ?;
195
249
config_path = config_file_path. display ( ) . to_string ( ) ;
196
250
// check ns3 directory
197
251
let ns3_dir_path = match Path :: new ( & ns3_path) . join ( "waf" ) . canonicalize ( ) {
@@ -204,36 +258,44 @@ impl ExecutorBuilder {
204
258
}
205
259
} ;
206
260
ns3_path = ns3_dir_path. parent ( ) . unwrap ( ) . display ( ) . to_string ( ) ;
207
- let configuration = match std:: fs:: read_to_string ( config_file_path) {
208
- Ok ( c) => c,
209
- Err ( e) => {
210
- return Err ( Error :: InvalidConfig ( format ! (
211
- "Config file cannot be opened at {}. Err: {:?}." ,
212
- & config_path, e
213
- ) ) )
261
+ let configs: HashMap < String , T > = match config_format {
262
+ ConfigFormat :: Ron => {
263
+ let f = std:: fs:: File :: open ( config_file_path) ?;
264
+ ron:: de:: from_reader ( f) ?
214
265
}
215
- } ;
216
- let configs: toml:: value:: Table = match toml:: from_str ( & configuration) {
217
- Ok ( t) => t,
218
- Err ( e) => {
219
- return Err ( Error :: InvalidTomlFormat ( format ! (
220
- "Config file is not a valid toml file. Err: {:?}." ,
221
- e
222
- ) ) ) ;
266
+ ConfigFormat :: Json => {
267
+ let f = std:: fs:: File :: open ( config_file_path) ?;
268
+ serde_json:: from_reader ( f) ?
269
+ }
270
+ ConfigFormat :: Yaml => {
271
+ let f = std:: fs:: File :: open ( config_file_path) ?;
272
+ serde_yaml:: from_reader ( f) ?
273
+ }
274
+ ConfigFormat :: Toml => {
275
+ let configuration = std:: fs:: read_to_string ( config_file_path) ?;
276
+ let configs: toml:: value:: Table = match toml:: from_str ( & configuration) {
277
+ Ok ( t) => t,
278
+ Err ( e) => {
279
+ return Err ( Error :: InvalidConfigFormat ( format ! (
280
+ "Config file is not a valid toml file. Err: {:?}." ,
281
+ e
282
+ ) ) ) ;
283
+ }
284
+ } ;
285
+ configs
286
+ . iter ( )
287
+ . map ( |( k, v) | ( k. to_owned ( ) , v. to_owned ( ) . try_into ( ) . unwrap ( ) ) )
288
+ . collect ( )
223
289
}
224
290
} ;
225
-
226
- let configs: HashMap < String , T > = configs
227
- . iter ( )
228
- . map ( |( k, v) | ( k. to_owned ( ) , v. to_owned ( ) . try_into ( ) . unwrap ( ) ) )
229
- . collect ( ) ;
230
291
let outputs: HashMap < String , Vec < Task < P > > > = configs
231
292
. iter ( )
232
293
. map ( |( k, _) | ( k. to_owned ( ) , vec ! [ ] ) )
233
294
. collect ( ) ;
234
295
235
296
Ok ( Executor {
236
297
config_path,
298
+ config_format,
237
299
ns3_path,
238
300
task_concurrent,
239
301
retry_limit,
0 commit comments