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}