use std::{fs, path}; use std::io::ErrorKind; use toml; enum PathType { Exclude, DoNotScan, Okay, } pub struct Config { config: toml::Value, commands: toml::Value, } impl Config { pub fn new() -> Config { println!("Using built-in config"); Config { config: toml::toml!{ source = "src" build_dir = "build" do_not_scan = [] exclude = [] file_delim = ":?" command_delim = ":!" commands_file = "commands.toml" }, commands: toml::toml!{ empty = "" } } } pub fn import(config: &str) -> Config { println!("Using found config"); let config: toml::Value = toml::from_str(config).expect("Could not load config"); let config = config.get("config").expect("Could not find \"[config]\" field"); // Attempt to read commands file let commands: toml::Value = match config.get("commands_file") { Some(n) => { if n.is_str() { let file_string = n.as_str().unwrap(); let file_string = match fs::read_to_string(file_string) { Ok(n) => n, Err(_) => { println!("Could not load commands from file"); String::from("[commands]") }, }; toml::from_str(file_string.as_str()).expect("Invalid toml") } else { panic!() } }, None => {println!("Could not load commands from file"); toml::toml!{[commands]}}, }; let commands = commands.get("commands").expect("Could not find \"[commands]\" field"); Config { config: config.clone(), commands: commands.clone(), } } pub fn get_str(&self, string: &str) -> Option<&str> { match self.config.get(string) { Some(n) => n.as_str(), None => None } } pub fn get_cmd_str(&self, string: &str) -> Option<&str> { match self.commands.get(string) { Some(n) => n.as_str(), None => None } } } pub struct S3G { config: Config, } impl S3G { pub fn new(config: Config) -> S3G { S3G { config, } } pub fn run(&self) { let source = self.config.get_str("source").unwrap(); let build = self.config.get_str("build_dir").unwrap(); // Create build directory or panic S3G::create_dir(&path::PathBuf::from(build)).unwrap(); self.directory_scan(path::PathBuf::from(source)); } fn create_dir(path: &path::PathBuf) -> Result<(), ()> { match fs::create_dir(path) { Ok(_) => (), Err(n) => match n.kind() { ErrorKind::AlreadyExists => (), _ => return Err(()), } } return Ok(()) } fn remove_path_head(path: &path::PathBuf) -> path::PathBuf { let mut path = path.to_str().unwrap().split("/"); path.next(); let path: path::PathBuf = path.collect(); return path } fn append_path_head(path: &path::PathBuf, head: &str) -> path::PathBuf { let mut head = path::PathBuf::from(head); head.push(path); return head } fn replace_path_head(path: &path::PathBuf, head: &str) -> path::PathBuf { let path = S3G::remove_path_head(path); S3G::append_path_head(&path, head) } fn check_path(&self, path: &path::PathBuf) -> PathType { // GET EXCLUDE AND DNS LISTS let excludes: Vec = vec![path::PathBuf::from("nav.html")]; let dns: Vec = vec![path::PathBuf::from("assets/")]; // Convert path to str for comparisons let path = path.to_str().unwrap(); // Excludes for ex_path in excludes { let ex_path = ex_path.to_str().unwrap(); if &path.contains(&ex_path) == &true { return PathType::Exclude; } } // Do not scans (copy files) for dns_path in dns { let dns_path = dns_path.to_str().unwrap(); if &path.contains(&dns_path) == &true { return PathType::DoNotScan; } } return PathType::Okay; } fn copy_file(&self, path: &path::PathBuf) { let build_path = S3G::replace_path_head(&path, "build/"); match fs::copy(path, build_path) { Ok(_) => (), Err(n) => { if n.kind() != ErrorKind::AlreadyExists { panic!() } }, } } fn directory_scan(&self, path: path::PathBuf) { println!("Scanning: {:?}", &path); // Check the path match self.check_path(&path) { PathType::Exclude => return, _ => (), }; // Create the dir in the build tree let build_path = S3G::replace_path_head(&path, "build/"); S3G::create_dir(&build_path).unwrap(); // Iterate over path contents for x in fs::read_dir(path).unwrap() { let x = x.as_ref().unwrap().path(); if x.is_dir() { self.directory_scan(x); } else { match self.file_scan(&x) { None => (), Some(n) => self.file_write(&x, n).unwrap(), } } } } fn file_scan(&self, path: &path::PathBuf) -> Option { // Check path match self.check_path(&path) { PathType::Okay => println!("Scanning: \"{}\"", &path.to_str().unwrap()), PathType::DoNotScan => { self.copy_file(&path); println!("Not scanning: \"{}\"", &path.to_str().unwrap()); return None }, PathType::Exclude => (), }; // File scanning let mut file_string = String::new(); for line in fs::read_to_string(&path).unwrap().lines() { // NEED TO FOR LOOP ON COMMANDS AND FILES PREFIXES if line.contains(":?") { let v: Vec<&str> = line.trim().split(":?").collect(); println!("{:?}", v); for s in v { let s = match s { "" => String::from(""), // Scan the file from the path n => self.file_scan(&path::PathBuf::from(n)).unwrap_or(String::from("")), }; // Push matching and scanned string file_string.push_str(&s); file_string.push('\n'); } } else { // Push unmatching line file_string.push_str(line); file_string.push('\n'); } } // Return the final file_string if file_string != "" { return Some(file_string); } else { return None; } } fn file_write(&self, path: &path::PathBuf, contents: String) -> Result<(),()> { match self.check_path(&path) { PathType::Exclude => return Ok(()), _ => (), } let dest = S3G::replace_path_head(&path, "build/"); match fs::write(dest, contents) { Ok(_) => Ok(()), Err(_) => Err(()), } } }