@@ -5,7 +5,12 @@ use crate::config::{
5
5
use colored:: * ;
6
6
use indexmap:: IndexMap ;
7
7
use serde:: Serialize ;
8
- use std:: collections:: BTreeMap ;
8
+ use std:: {
9
+ collections:: BTreeMap ,
10
+ fs:: { create_dir_all, File } ,
11
+ io:: Write ,
12
+ path:: PathBuf ,
13
+ } ;
9
14
use structopt:: StructOpt ;
10
15
use toml:: Value ;
11
16
@@ -46,6 +51,10 @@ pub struct Opts {
46
51
/// is then up to you to restructure the `inputs` of each component to build
47
52
/// the topology you need.
48
53
expression : String ,
54
+
55
+ /// Generate config as a file
56
+ #[ structopt( long, parse( from_os_str) ) ]
57
+ file : Option < PathBuf > ,
49
58
}
50
59
51
60
#[ derive( Serialize ) ]
@@ -71,7 +80,11 @@ pub struct Config {
71
80
pub sinks : Option < IndexMap < String , SinkOuter > > ,
72
81
}
73
82
74
- fn generate_example ( include_globals : bool , expression : & str ) -> Result < String , Vec < String > > {
83
+ fn generate_example (
84
+ include_globals : bool ,
85
+ expression : & str ,
86
+ file : & Option < PathBuf > ,
87
+ ) -> Result < String , Vec < String > > {
75
88
let components: Vec < Vec < _ > > = expression
76
89
. split ( |c| c == '|' || c == '/' )
77
90
. map ( |s| {
@@ -309,6 +322,16 @@ fn generate_example(include_globals: bool, expression: &str) -> Result<String, V
309
322
}
310
323
}
311
324
325
+ if file. is_some ( ) {
326
+ match write_config ( file. as_ref ( ) . unwrap ( ) , & builder) {
327
+ Ok ( _) => println ! (
328
+ "Config file written to {:?}" ,
329
+ & file. as_ref( ) . unwrap( ) . join( "\n " )
330
+ ) ,
331
+ Err ( e) => errs. push ( format ! ( "failed to write to file: {}" , e) ) ,
332
+ } ;
333
+ } ;
334
+
312
335
if !errs. is_empty ( ) {
313
336
Err ( errs)
314
337
} else {
@@ -317,7 +340,7 @@ fn generate_example(include_globals: bool, expression: &str) -> Result<String, V
317
340
}
318
341
319
342
pub fn cmd ( opts : & Opts ) -> exitcode:: ExitCode {
320
- match generate_example ( !opts. fragment , & opts. expression ) {
343
+ match generate_example ( !opts. fragment , & opts. expression , & opts . file ) {
321
344
Ok ( s) => {
322
345
println ! ( "{}" , s) ;
323
346
exitcode:: OK
@@ -329,6 +352,20 @@ pub fn cmd(opts: &Opts) -> exitcode::ExitCode {
329
352
}
330
353
}
331
354
355
+ fn write_config ( filepath : & PathBuf , body : & str ) -> Result < usize , crate :: Error > {
356
+ if filepath. exists ( ) {
357
+ // If the file exists, we don't want to overwrite, that's just rude.
358
+ Err ( format ! ( "{:?} already exists" , & filepath) . into ( ) )
359
+ } else {
360
+ if let Some ( directory) = filepath. parent ( ) {
361
+ create_dir_all ( directory) ?;
362
+ }
363
+ File :: create ( filepath)
364
+ . and_then ( |mut file| file. write ( body. as_bytes ( ) ) )
365
+ . map_err ( Into :: into)
366
+ }
367
+ }
368
+
332
369
#[ cfg( test) ]
333
370
mod tests {
334
371
use super :: * ;
@@ -339,23 +376,23 @@ mod tests {
339
376
340
377
for name in SourceDescription :: types ( ) {
341
378
let param = format ! ( "{}//" , name) ;
342
- let cfg = generate_example ( true , & param) . unwrap ( ) ;
379
+ let cfg = generate_example ( true , & param, & None ) . unwrap ( ) ;
343
380
if let Err ( error) = toml:: from_str :: < crate :: config:: ConfigBuilder > ( & cfg) {
344
381
errors. push ( ( param, error) ) ;
345
382
}
346
383
}
347
384
348
385
for name in TransformDescription :: types ( ) {
349
386
let param = format ! ( "/{}/" , name) ;
350
- let cfg = generate_example ( true , & param) . unwrap ( ) ;
387
+ let cfg = generate_example ( true , & param, & None ) . unwrap ( ) ;
351
388
if let Err ( error) = toml:: from_str :: < crate :: config:: ConfigBuilder > ( & cfg) {
352
389
errors. push ( ( param, error) ) ;
353
390
}
354
391
}
355
392
356
393
for name in SinkDescription :: types ( ) {
357
394
let param = format ! ( "//{}" , name) ;
358
- let cfg = generate_example ( true , & param) . unwrap ( ) ;
395
+ let cfg = generate_example ( true , & param, & None ) . unwrap ( ) ;
359
396
if let Err ( error) = toml:: from_str :: < crate :: config:: ConfigBuilder > ( & cfg) {
360
397
errors. push ( ( param, error) ) ;
361
398
}
@@ -371,7 +408,7 @@ mod tests {
371
408
#[ test]
372
409
fn generate_basic ( ) {
373
410
assert_eq ! (
374
- generate_example( true , "stdin/json_parser/console" ) ,
411
+ generate_example( true , "stdin/json_parser/console" , & None ) ,
375
412
Ok ( r#"data_dir = "/var/lib/vector/"
376
413
377
414
[sources.source0]
@@ -402,7 +439,7 @@ when_full = "block"
402
439
) ;
403
440
404
441
assert_eq ! (
405
- generate_example( true , "stdin|json_parser|console" ) ,
442
+ generate_example( true , "stdin|json_parser|console" , & None ) ,
406
443
Ok ( r#"data_dir = "/var/lib/vector/"
407
444
408
445
[sources.source0]
@@ -433,7 +470,7 @@ when_full = "block"
433
470
) ;
434
471
435
472
assert_eq ! (
436
- generate_example( true , "stdin//console" ) ,
473
+ generate_example( true , "stdin//console" , & None ) ,
437
474
Ok ( r#"data_dir = "/var/lib/vector/"
438
475
439
476
[sources.source0]
@@ -458,7 +495,7 @@ when_full = "block"
458
495
) ;
459
496
460
497
assert_eq ! (
461
- generate_example( true , "//console" ) ,
498
+ generate_example( true , "//console" , & None ) ,
462
499
Ok ( r#"data_dir = "/var/lib/vector/"
463
500
464
501
[sinks.sink0]
@@ -479,7 +516,7 @@ when_full = "block"
479
516
) ;
480
517
481
518
assert_eq ! (
482
- generate_example( true , "/add_fields,json_parser,remove_fields" ) ,
519
+ generate_example( true , "/add_fields,json_parser,remove_fields" , & None ) ,
483
520
Ok ( r#"data_dir = "/var/lib/vector/"
484
521
485
522
[transforms.transform0]
@@ -504,7 +541,7 @@ type = "remove_fields"
504
541
) ;
505
542
506
543
assert_eq ! (
507
- generate_example( false , "/add_fields,json_parser,remove_fields" ) ,
544
+ generate_example( false , "/add_fields,json_parser,remove_fields" , & None ) ,
508
545
Ok ( r#"
509
546
[transforms.transform0]
510
547
inputs = []
0 commit comments