Skip to content

Commit 2f2f567

Browse files
committed
enhancement(generator): Adds optional file output
Signed-off-by: Ian Henry <[email protected]>
1 parent 32162bb commit 2f2f567

File tree

1 file changed

+48
-12
lines changed

1 file changed

+48
-12
lines changed

src/generate.rs

Lines changed: 48 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ use crate::config::{
55
use colored::*;
66
use indexmap::IndexMap;
77
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+
};
914
use structopt::StructOpt;
1015
use toml::Value;
1116

@@ -46,6 +51,10 @@ pub struct Opts {
4651
/// is then up to you to restructure the `inputs` of each component to build
4752
/// the topology you need.
4853
expression: String,
54+
55+
/// Generate config as a file
56+
#[structopt(long, parse(from_os_str))]
57+
file: Option<PathBuf>,
4958
}
5059

5160
#[derive(Serialize)]
@@ -71,7 +80,11 @@ pub struct Config {
7180
pub sinks: Option<IndexMap<String, SinkOuter>>,
7281
}
7382

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>> {
7588
let components: Vec<Vec<_>> = expression
7689
.split(|c| c == '|' || c == '/')
7790
.map(|s| {
@@ -309,6 +322,16 @@ fn generate_example(include_globals: bool, expression: &str) -> Result<String, V
309322
}
310323
}
311324

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+
312335
if !errs.is_empty() {
313336
Err(errs)
314337
} else {
@@ -317,7 +340,7 @@ fn generate_example(include_globals: bool, expression: &str) -> Result<String, V
317340
}
318341

319342
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) {
321344
Ok(s) => {
322345
println!("{}", s);
323346
exitcode::OK
@@ -329,6 +352,19 @@ pub fn cmd(opts: &Opts) -> exitcode::ExitCode {
329352
}
330353
}
331354

355+
fn write_config(filepath: &PathBuf, body: &str) -> Result<(), crate::Error> {
356+
if filepath.exists() {
357+
// If the file exists, we don't want to overwrite, that's just rude.
358+
return 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).and_then(|mut file| file.write(body.as_bytes()))?;
364+
}
365+
Ok(())
366+
}
367+
332368
#[cfg(test)]
333369
mod tests {
334370
use super::*;
@@ -339,23 +375,23 @@ mod tests {
339375

340376
for name in SourceDescription::types() {
341377
let param = format!("{}//", name);
342-
let cfg = generate_example(true, &param).unwrap();
378+
let cfg = generate_example(true, &param, &None).unwrap();
343379
if let Err(error) = toml::from_str::<crate::config::ConfigBuilder>(&cfg) {
344380
errors.push((param, error));
345381
}
346382
}
347383

348384
for name in TransformDescription::types() {
349385
let param = format!("/{}/", name);
350-
let cfg = generate_example(true, &param).unwrap();
386+
let cfg = generate_example(true, &param, &None).unwrap();
351387
if let Err(error) = toml::from_str::<crate::config::ConfigBuilder>(&cfg) {
352388
errors.push((param, error));
353389
}
354390
}
355391

356392
for name in SinkDescription::types() {
357393
let param = format!("//{}", name);
358-
let cfg = generate_example(true, &param).unwrap();
394+
let cfg = generate_example(true, &param, &None).unwrap();
359395
if let Err(error) = toml::from_str::<crate::config::ConfigBuilder>(&cfg) {
360396
errors.push((param, error));
361397
}
@@ -371,7 +407,7 @@ mod tests {
371407
#[test]
372408
fn generate_basic() {
373409
assert_eq!(
374-
generate_example(true, "stdin/json_parser/console"),
410+
generate_example(true, "stdin/json_parser/console", &None),
375411
Ok(r#"data_dir = "/var/lib/vector/"
376412
377413
[sources.source0]
@@ -402,7 +438,7 @@ when_full = "block"
402438
);
403439

404440
assert_eq!(
405-
generate_example(true, "stdin|json_parser|console"),
441+
generate_example(true, "stdin|json_parser|console", &None),
406442
Ok(r#"data_dir = "/var/lib/vector/"
407443
408444
[sources.source0]
@@ -433,7 +469,7 @@ when_full = "block"
433469
);
434470

435471
assert_eq!(
436-
generate_example(true, "stdin//console"),
472+
generate_example(true, "stdin//console", &None),
437473
Ok(r#"data_dir = "/var/lib/vector/"
438474
439475
[sources.source0]
@@ -458,7 +494,7 @@ when_full = "block"
458494
);
459495

460496
assert_eq!(
461-
generate_example(true, "//console"),
497+
generate_example(true, "//console", &None),
462498
Ok(r#"data_dir = "/var/lib/vector/"
463499
464500
[sinks.sink0]
@@ -479,7 +515,7 @@ when_full = "block"
479515
);
480516

481517
assert_eq!(
482-
generate_example(true, "/add_fields,json_parser,remove_fields"),
518+
generate_example(true, "/add_fields,json_parser,remove_fields", &None),
483519
Ok(r#"data_dir = "/var/lib/vector/"
484520
485521
[transforms.transform0]
@@ -504,7 +540,7 @@ type = "remove_fields"
504540
);
505541

506542
assert_eq!(
507-
generate_example(false, "/add_fields,json_parser,remove_fields"),
543+
generate_example(false, "/add_fields,json_parser,remove_fields", &None),
508544
Ok(r#"
509545
[transforms.transform0]
510546
inputs = []

0 commit comments

Comments
 (0)