1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
pub mod processors;
pub mod project;
use std::collections::{BTreeMap, HashMap};
use std::error::Error;
use std::fs::{create_dir_all, File, read_to_string};
use std::io::Write;
use std::path::Path;
use log::{debug, info};
use serde::{Deserialize, Serialize};
use crate::processors::{create_processor_generators, generate_processors};
use crate::project::{generate_cargo, generate_main};
pub fn read_and_parse_and_generate<P1: AsRef<Path>, P2: AsRef<Path>, P3: AsRef<Path>>(
template_path: P1,
output_path: P2,
core_path: Option<String>,
generators_path: P3,
) -> Result<(), Box<dyn Error>> {
let template = read_template(template_path)?;
info!("Generating output project in {}", output_path.as_ref().display());
create_directories(&output_path)?;
let output_path = output_path.as_ref();
let cargo = generate_cargo(&template, core_path);
let cargo_file = output_path.join("Cargo.toml");
{
info!("Generation of Cargo.toml finished. Writing Cargo.toml.");
let mut cargo_file = File::create(cargo_file)?;
cargo_file.write_all(cargo.as_bytes())?;
}
let generators = create_processor_generators(generators_path)?;
let streams = template.streams.into_iter()
.map(|stream| {
let processors = generate_processors(stream.clone(), &generators)?;
Ok(((stream.input_topic, stream.output_topic), processors))
})
.collect::<Result<BTreeMap<_, _>, Box<dyn Error>>>()?;
let main = generate_main(streams);
let main_file = output_path.join("src").join("main.rs");
{
info!("Generation of main.rs finished. Writing main.rs.");
let mut main_file = File::create(main_file)?;
main_file.write_all(main.as_bytes())?;
}
info!("All files generated.");
Ok(())
}
fn create_directories<P: AsRef<Path>>(base_path: P) -> Result<(), Box<dyn Error>> {
let path = base_path.as_ref();
debug!("Creating directory: {}", path.display());
create_dir_all(path)?;
let src_dir = path.join("src");
debug!("Creating directory: {}", src_dir.display());
create_dir_all(&src_dir)?;
Ok(())
}
fn read_template<P: AsRef<Path>>(path: P) -> Result<Template, Box<dyn Error>> {
let file_content = read_to_string(path)?;
let template = serde_yaml::from_str(&file_content)?;
Ok(template)
}
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
pub struct Template {
name: String,
streams: Vec<Stream>,
}
#[derive(Debug, Serialize, Deserialize, Eq, PartialEq, Clone)]
pub struct Stream {
input_topic: String,
output_topic: String,
processors: Vec<HashMap<String, String>>
}
#[cfg(test)]
mod test {
use std::collections::HashMap;
use crate::{read_template, Stream, Template};
#[test]
fn should_read() {
let result = read_template("../template-examples/basic.yaml");
assert!(result.is_ok());
assert_eq!(Template {
name: "Example processor".to_string(),
streams: vec![
Stream {
input_topic: "in".to_string(),
output_topic: "out".to_string(),
processors: vec![
HashMap::from([
("generator".to_string(), "static_field".to_string()),
("field".to_string(), "$.hello".to_string()),
("value".to_string(), "world".to_string()),
]),
HashMap::from([
("generator".to_string(), "copy_field".to_string()),
("source_field".to_string(), "$.abc[1]".to_string()),
("target_field".to_string(), "$.def".to_string()),
]),
]
}
]
}, result.unwrap())
}
}