made config more robust

This commit is contained in:
Bryson Steck 2025-03-02 11:47:29 -07:00
parent d8097ade47
commit 7998e49958
4 changed files with 111 additions and 20 deletions

View file

@ -1,8 +1,12 @@
pub struct Refractr {
pub verbose: u8
}
pub fn verbose(level: u8, msg_lvl: u8, msg: String) { pub fn verbose(level: u8, msg_lvl: u8, msg: String) {
if level < msg_lvl { return }; if level < msg_lvl { return };
let mut prefix = String::new(); let mut prefix = String::new();
for i in 0..msg_lvl { for _ in 0..msg_lvl {
prefix += "="; prefix += "=";
} }

View file

@ -1,14 +1,74 @@
use crate::common;
use core::fmt;
use std::io::Read; use std::io::Read;
use std::path::PathBuf; use std::path::PathBuf;
use std::fs::File; use std::fs;
use std::fs::{File, Metadata};
use toml; use toml;
use serde_derive::Deserialize; use serde_derive::Deserialize;
pub struct ConfigFile {
pub path: String,
pub file: Metadata,
pub config: Config
}
impl fmt::Display for ConfigFile {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let branches_list = match &self.config.branches {
None => String::from("All branches"),
Some(vec) => {
let mut out = String::from("[");
for i in 0..vec.len() {
out = format!("{}{}", out, vec[i]);
if i < vec.len() - 1 {
out.push_str(", ");
}
}
out.push(']');
out
}
};
let mut to_list = String::from("[");
for i in 0..self.config.to.len() {
to_list.push_str(&self.config.to[i]);
if i < self.config.to.len() - 1 {
to_list.push_str(", ");
}
};
to_list.push(']');
write!(f, "Config file: \"{}\"\n \
Is a file: {}\n \
Read only: {}\n \
Configuration:\n \
Git repo to clone: {}\n \
Git repos to push clone to: {}\n \
Branches of clone to push: {}\n \
SSH key for pushing clone: {}\n \
Schedule enabled: {}\n\
{}"
, self.path, self.file.is_file(), self.file.permissions().readonly(), self.config.from
, to_list, branches_list, self.config.git.ssh_identity_file, self.config.schedule.enabled
, match self.config.schedule.interval {
None => {
if !self.config.schedule.enabled {
String::from("")
} else {
String::from("This shouldn't happen!\n")
}
},
Some(int) => format!(" Scheduled interval in seconds: {}\n", int.to_string())
})
}
}
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Config { struct Config {
from: String, from: String,
to: Vec<String>, to: Vec<String>,
branches: Vec<String>, branches: Option<Vec<String>>,
git: Git, git: Git,
schedule: Schedule schedule: Schedule
} }
@ -21,28 +81,43 @@ struct Git {
#[derive(Deserialize)] #[derive(Deserialize)]
struct Schedule { struct Schedule {
enabled: bool, enabled: bool,
duration: i32, interval: Option<i32>,
} }
pub fn read_config(paths: Vec<PathBuf>) -> Vec<Config> { pub fn read_config(paths: Vec<PathBuf>, refractr: &common::Refractr) -> Vec<ConfigFile> {
let mut configs: Vec<Config> = vec![]; let mut config_files: Vec<ConfigFile> = vec![];
for path in paths { for path in paths {
if refractr.verbose >= 1 {
common::verbose(refractr.verbose, 1, format!("Reading config file: \"{}\"", String::from(path.to_string_lossy())));
}
let mut data = String::new(); let mut data = String::new();
let mut file = match File::open(path.as_path()) { let mut file = match File::open(path.as_path()) {
Err(e) => panic!("unable to open {}: {}", path.as_path().display(), e), Err(e) => panic!("refractr: unable to open {}: {}", path.as_path().display(), e),
Ok(file) => file Ok(file) => file
}; };
if let Err(e) = file.read_to_string(&mut data) { if let Err(e) = file.read_to_string(&mut data) {
panic!("unable to read {}: {}", path.as_path().display(), e) panic!("refractr: unable to read {}: {}", path.as_path().display(), e)
} }
configs.push(verify_config(toml::from_str(&data).unwrap())); let config_file = ConfigFile {
path: String::from(path.to_string_lossy()),
file: match fs::metadata(&path) {
Err(e) => panic!("refractr: cannot obtain metadata: {}", path.as_path().display()),
Ok(metadata) => metadata
},
config: verify_config(toml::from_str(&data).unwrap())
};
config_files.push(config_file);
} }
return configs; return config_files;
} }
fn verify_config(config: Config) -> Config { fn verify_config(config: Config) -> Config {
if config.schedule.enabled {
assert_ne!(config.schedule.interval, None);
}
return config; return config;
} }

View file

@ -29,7 +29,7 @@
# This field is REQUIRED. # This field is REQUIRED.
#enabled = false #enabled = false
# The "duration" field is the amount of seconds refractor will wait before # The "interval" field is the amount of seconds refractor will wait before
# pulling updates from the original repository if the schedule feature is enabled. # pulling updates from the original repository if the schedule feature is enabled.
# This field is REQUIRED if "enabled" is set to true, otherwise OPTIONAL # This field is REQUIRED if "enabled" is set to true, otherwise OPTIONAL
#duration = 300 #interval = 300

View file

@ -22,16 +22,28 @@ struct Args {
fn main() { fn main() {
let args = Args::parse(); let args = Args::parse();
if args.verbose >= 1 { let refractr = common::Refractr {
common::verbose(args.verbose, 1, format!("Level {} verbosity enabled", args.verbose.to_string())); verbose: args.verbose
};
if refractr.verbose >= 1 {
common::verbose(refractr.verbose, 1, format!("Level {} verbosity enabled", refractr.verbose.to_string()));
} }
common::verbose(args.verbose, 2, format!("Checking for create flag")); common::verbose(refractr.verbose, 2, format!("Checking for create flag"));
if args.create { if args.create {
common::verbose(args.verbose, 2, format!("Printing sample config")); common::verbose(refractr.verbose, 2, format!("Printing sample config"));
let example = include_str!("example/config.toml"); let example = include_str!("example/config.toml");
println!("{}", example); println!("{}", example);
} else { } else {
let cfg = config::read_config(args.config); let cfgs = config::read_config(args.config, &refractr);
if refractr.verbose >= 2 {
for i in cfgs {
common::verbose(refractr.verbose, 2, format!("{}", i));
}
}
if refractr.verbose >= 1 {
common::verbose(refractr.verbose, 1, format!("Config file(s) read successfully"));
}
} }
} }