124 lines
3.6 KiB
Rust
124 lines
3.6 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use serde_yml;
|
|
|
|
use std::fs;
|
|
use pad::PadStr;
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
enum UserConfigItem {
|
|
String {
|
|
name: String,
|
|
max_length: u64
|
|
},
|
|
IPv4 {
|
|
name: String,
|
|
},
|
|
Boolean {
|
|
name: String
|
|
},
|
|
Number {
|
|
name: String,
|
|
max: Option<i32>,
|
|
min: Option<i32>
|
|
},
|
|
Submenu(UserConfigData)
|
|
}
|
|
|
|
#[derive(Deserialize, Serialize, Debug)]
|
|
struct UserConfigData {
|
|
name: String,
|
|
config_items: Vec<UserConfigItem>
|
|
}
|
|
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
pub enum ConfigotronError {
|
|
#[error("IO Operation failed: {}", ._0.to_string())]
|
|
IoError(#[from] std::io::Error),
|
|
|
|
#[error("Failed to parse YAML File: {}", ._0.to_string())]
|
|
YamlParsingError(#[from] serde_yml::Error),
|
|
|
|
#[error("Missing field {} (line {} col {}) {}", .missing_filed, .line, .col, .context)]
|
|
MissingFieldError{
|
|
col: i32,
|
|
line: i32,
|
|
missing_filed: Box<str>,
|
|
context: Box<str>
|
|
}
|
|
}
|
|
|
|
fn read_and_parse_yaml_file(input_file: &str) -> Result<UserConfigData, ConfigotronError> {
|
|
let file_content = fs::read_to_string(&input_file)?;
|
|
let config: UserConfigData = serde_yml::from_str(&file_content)?;
|
|
return Ok(config);
|
|
}
|
|
|
|
|
|
fn generate_text_report_from_item(item: &UserConfigItem) -> Vec<String> {
|
|
return match item {
|
|
UserConfigItem::Boolean {name} => vec![String::from(name), String::from("[y/n]")] ,
|
|
UserConfigItem::IPv4 { name } => vec![String::from(name), format!("[ipv4]")],
|
|
UserConfigItem::String { name, max_length } => vec![String::from(name), format!("[text, max length {}]", max_length)],
|
|
UserConfigItem::Number { name, min, max } => match (min, max) {
|
|
(None, None) => vec![String::from(name), String::from("[number]")],
|
|
(None, Some(maximum)) => vec![String::from(name), format!("[number, ..{}]", maximum)],
|
|
(Some(minmum), None) => vec![String::from(name), format!("[number, {}..]", minmum)],
|
|
(Some(minmum), Some(maximum)) => vec![String::from(name), format!("[number, {}..{}]", minmum, maximum)],
|
|
},
|
|
UserConfigItem::Submenu(c) => generate_text_report(c)
|
|
}
|
|
}
|
|
|
|
fn generate_text_report(config: &UserConfigData) -> Vec<String> {
|
|
let lines: Vec<Vec<String>> = config.config_items
|
|
.iter()
|
|
.map(|i| generate_text_report_from_item(i))
|
|
.collect();
|
|
|
|
let block_width = lines
|
|
.iter()
|
|
.map(|l: &Vec<String>|
|
|
l
|
|
.iter()
|
|
.map(|s: &String| s.chars().count())
|
|
.max().unwrap_or(0)
|
|
)
|
|
.max().unwrap_or(0);
|
|
|
|
let line_seperator = format!("+{}+", "-".repeat(block_width + 2));
|
|
|
|
let config_name_width = config.name.chars().count() + 2;
|
|
let mut lines_flattend: Vec<String> = lines
|
|
.iter()
|
|
.map(|i| i
|
|
.iter()
|
|
.map(|s| format!("| {} |", s.pad_to_width(block_width)))
|
|
.collect::<Vec<String>>()
|
|
)
|
|
.flat_map(|seg| [seg, vec![String::from(&line_seperator)]])
|
|
.flatten()
|
|
.into_iter()
|
|
.map(|e| format!("{}{}", " ".repeat(config_name_width), e))
|
|
.collect();
|
|
|
|
lines_flattend.insert(0, format!("{}{}", config.name.pad_to_width(config_name_width), line_seperator));
|
|
|
|
return lines_flattend;
|
|
}
|
|
|
|
fn main() {
|
|
|
|
let data = match read_and_parse_yaml_file("example.yml") {
|
|
Ok(d) => d,
|
|
Err(error) => {
|
|
println!("{}", error);
|
|
return;
|
|
}
|
|
};
|
|
let res = generate_text_report(&data).join("\n");
|
|
println!("{}", res);
|
|
|
|
println!("Hello, world!");
|
|
}
|