Tholp's bespoke website generator
1use crate::types::{self, InputFile}; 2use std::{ 3 any::Any, 4 fs, 5 iter::{FilterMap, Map}, 6 os::unix::process, 7 path::{Path, PathBuf}, 8 string, 9}; 10use toml::{ser, Table}; 11 12pub struct Project { 13 pub filegroups: Vec<FileGroup>, 14 //pub settings: ProjectSettings, 15 pub context: ProjectContext, 16} 17 18pub struct FileGroup { 19 pub name: String, 20 pub files: Vec<InputFile>, 21 pub pre_insert: PathBuf, 22 pub post_insert: PathBuf, 23 pub process: bool, 24} 25 26// pub struct ProjectSettings { 27 28// } 29 30pub struct ProjectContext { 31 pub input_folder: PathBuf, 32 pub output_folder: PathBuf, 33 pub global_pre_insert: PathBuf, 34 pub global_post_insert: PathBuf, 35 36 pub filemap: Vec<PathBuf>, // mapped to index 37 38 //variables later 39} 40 41macro_rules! get_table_bool_or_default { 42 ($table:ident, $key:expr, $default:expr) => { 43 $table 44 .get($key) 45 .unwrap_or(&toml::Value::try_from($default).unwrap()) 46 .as_bool() 47 .unwrap_or($default) 48 }; 49} 50 51macro_rules! get_table_string_or_default { 52 ($table:ident, $key:expr, $default:expr) => { 53 // $table 54 // .get($key) 55 // .unwrap_or(&toml::Value::try_from($default).unwrap()) 56 // .as_str() 57 // .unwrap_or($default) 58 if $table.contains_key($key) { 59 $table.get($key).unwrap().as_str().unwrap() 60 } else { 61 $default 62 } 63 }; 64} 65 66pub fn parse_project(tomlpath: &Path) -> Project { 67 let tomlfile = fs::read_to_string(tomlpath).expect("Project file unreadable or missing."); 68 69 let mut project: Project = Project { 70 filegroups: Vec::new(), 71 context: ProjectContext { 72 input_folder: PathBuf::new(), 73 output_folder: PathBuf::new(), 74 global_pre_insert: PathBuf::new(), 75 global_post_insert: PathBuf::new(), 76 filemap: Vec::new(), 77 }, 78 }; 79 let config = tomlfile 80 .parse::<Table>() 81 .expect("Project file not in propper toml format"); 82 let settings_section = config["settings"] 83 .as_table() 84 .expect("Project file missing [settings] section"); 85 let filegroups_section = config["fileGroups"] 86 .as_table() 87 .expect("Project file contains no file groups "); 88 89 let project_root = tomlpath 90 .parent() 91 .expect("Project file unreadable or missing."); 92 93 project.context.input_folder = PathBuf::from(get_table_string_or_default!( 94 settings_section, 95 "inputFolder", 96 "skid" 97 )); 98 99 project.context.output_folder = PathBuf::from(get_table_string_or_default!( 100 settings_section, 101 "outputFolder", 102 "content" 103 )); 104 105 project.context.global_pre_insert = project_root.join(get_table_string_or_default!( 106 settings_section, 107 "preInsertGlobal", 108 "" 109 )); 110 project.context.global_post_insert = project_root.join(get_table_string_or_default!( 111 settings_section, 112 "postInsertGlobal", 113 "" 114 )); 115 116 for (k, v) in filegroups_section { 117 if !v.is_table() { 118 continue; 119 } 120 let filegroup_def: &toml::map::Map<String, toml::Value> = v.as_table().unwrap(); 121 let name = k.clone(); 122 let pre_insert = get_table_string_or_default!(filegroup_def, "preInsert", ""); 123 let post_insert = get_table_string_or_default!(filegroup_def, "postInsert", ""); 124 let process = get_table_bool_or_default!(filegroup_def, "process", false); 125 126 let recurse_find = get_table_bool_or_default!(filegroup_def, "recursiveFind", false); 127 128 let dir = get_table_string_or_default!(filegroup_def, "folder", ""); 129 130 let mut group = FileGroup { 131 files: Vec::new(), 132 name: k.clone(), 133 pre_insert: pre_insert.into(), 134 post_insert: post_insert.into(), 135 process, 136 }; 137 138 if filegroup_def.contains_key("files") { 139 let file_array = filegroup_def["files"].as_array().unwrap_or_else(|| { 140 panic!("'files' section of fileGroup.{} needs to be an array", k) 141 }); 142 for file in file_array { 143 let filename = file.as_str().unwrap_or_else(|| { 144 panic!( 145 "'files' section of fileGroup.{} needs to only contain strings", 146 k 147 ) 148 }); 149 let mut new_file = crate::types::InputFile::new(); 150 new_file.file_input = project.context.input_folder.clone(); 151 new_file.file_input.push(filename); 152 153 new_file.file_htmlout = project.context.output_folder.clone(); 154 new_file.file_htmlout.push(filename); 155 new_file.file_htmlout.set_extension("html"); 156 157 new_file.file_skidout = new_file.file_htmlout.clone(); 158 new_file.file_skidout.set_extension("sko"); 159 160 group.files.push(new_file); 161 } 162 } 163 164 project.filegroups.push(group); 165 } 166 167 return project; 168} 169 170pub trait FileIndexing { 171 fn index_of_file(&mut self, f: &PathBuf) -> usize; 172 fn file_for_index(&self, i: usize) -> Option<&PathBuf>; 173} 174 175impl FileIndexing for ProjectContext { 176 fn index_of_file(&mut self, f: &PathBuf) -> usize { 177 let cannonical = f.canonicalize().unwrap(); 178 let mut index = 0; 179 for p in &self.filemap { 180 if cannonical == *p { 181 return index; 182 } 183 index = index + 1; 184 } 185 self.filemap.push(cannonical); 186 return self.filemap.len() - 1; 187 } 188 189 fn file_for_index(&self, i: usize) -> Option<&PathBuf> { 190 if i >= self.filemap.len() { 191 return None; 192 } 193 return Some(&self.filemap[i]); 194 } 195}