From 877cf714133b289b31f5d59c5e87db8148a16eeb Mon Sep 17 00:00:00 2001 From: AlexanderHD27 Date: Tue, 20 May 2025 01:59:41 +0200 Subject: [PATCH] Got Config parsed from yaml file --- .gitignore | 1 + .vscode/tasks.json | 21 ++++++ Cargo.lock | 180 +++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 10 +++ example.yml | 34 +++++++++ src/main.rs | 123 +++++++++++++++++++++++++++++++ 6 files changed, 369 insertions(+) create mode 100644 .gitignore create mode 100644 .vscode/tasks.json create mode 100644 Cargo.lock create mode 100644 Cargo.toml create mode 100644 example.yml create mode 100644 src/main.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea8c4bf --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/target diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..fb962c8 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,21 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "type": "cargo", + "command": "run", + "problemMatcher": [ + "$rustc" + ], + "label": "rust: cargo run", + "presentation": { + "echo": true, + "reveal": "always", + "focus": true, + "panel": "dedicated", + "showReuseMessage": true, + "clear": true + } + } + ] +} \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1a72a7e --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,180 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" + +[[package]] +name = "configotron" +version = "0.1.0" +dependencies = [ + "pad", + "serde", + "serde_yml", + "thiserror", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "hashbrown" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3" + +[[package]] +name = "indexmap" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "itoa" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "libyml" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3302702afa434ffa30847a83305f0a69d6abd74293b6554c18ec85c7ef30c980" +dependencies = [ + "anyhow", + "version_check", +] + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "pad" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2ad9b889f1b12e0b9ee24db044b5129150d5eada288edc800f789928dc8c0e3" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "proc-macro2" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "serde" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.219" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_yml" +version = "0.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59e2dd588bf1597a252c3b920e0143eb99b0f76e4e082f4c92ce34fbc9e71ddd" +dependencies = [ + "indexmap", + "itoa", + "libyml", + "memchr", + "ryu", + "serde", + "version_check", +] + +[[package]] +name = "syn" +version = "2.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..25caafb --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "configotron" +version = "0.1.0" +edition = "2021" + +[dependencies] +pad = "0.1.6" +serde = { version = "1.0", features = ["derive"] } +serde_yml = "0.0.12" +thiserror = "1" diff --git a/example.yml b/example.yml new file mode 100644 index 0000000..cf2eb7e --- /dev/null +++ b/example.yml @@ -0,0 +1,34 @@ +name: ssbc_remote +config_items: + - !Submenu + name: network settings + config_items: + - !IPv4 + name: ip + + - !IPv4 + name: subnet_mask + + - !IPv4 + name: gateway + + - !String + name: wifi_ssid + description: The SSID of the Wi-Fi network. + max_length: 64 + + - !String + name: wifi_password + description: The password for the Wi-Fi network. + max_length: 64 + + - !Boolean + name: dhcp_enabled + + - !IPv4 + name: hub_ip + + - !Number + name: hub_port + max: 65535 + min: 1 \ No newline at end of file diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..aa74dda --- /dev/null +++ b/src/main.rs @@ -0,0 +1,123 @@ +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, + min: Option + }, + Submenu(UserConfigData) +} + +#[derive(Deserialize, Serialize, Debug)] +struct UserConfigData { + name: String, + config_items: Vec +} + + +#[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, + context: Box + } +} + +fn read_and_parse_yaml_file(input_file: &str) -> Result { + 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 { + 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 { + let lines: Vec> = config.config_items + .iter() + .map(|i| generate_text_report_from_item(i)) + .collect(); + + let block_width = lines + .iter() + .map(|l: &Vec| + 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 = lines + .iter() + .map(|i| i + .iter() + .map(|s| format!("| {} |", s.pad_to_width(block_width))) + .collect::>() + ) + .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!"); +}