tinted_builder_rust/operations/build/
utils.rs1use anyhow::{anyhow, Result};
2use serde::Deserialize;
3use std::fs::read_to_string;
4use std::path::{Path, PathBuf};
5use tinted_builder::{Scheme, SchemeSystem};
6
7#[derive(Debug, Clone)]
8pub enum SchemeFile {
9 Yaml(PathBuf),
10 Yml(PathBuf),
11}
12
13impl SchemeFile {
14 pub fn new(path: impl AsRef<Path>) -> Result<Self> {
20 let extension = path
21 .as_ref()
22 .extension()
23 .unwrap_or_default()
24 .to_str()
25 .unwrap_or_default();
26
27 match extension {
28 "yaml" => Ok(Self::Yaml(path.as_ref().to_path_buf())),
29 "yml" => Ok(Self::Yml(path.as_ref().to_path_buf())),
30 _ => Err(anyhow!("Invalid file extension: {extension}")),
31 }
32 }
33
34 pub fn get_scheme(&self) -> Result<Scheme> {
43 match self {
44 Self::Yaml(path) | Self::Yml(path) => {
45 let scheme_str = read_to_string(path)?;
46 let scheme: serde_yaml::Value = serde_yaml::from_str(&scheme_str)?;
47
48 if let serde_yaml::Value::Mapping(map) = scheme {
49 match map.get("system") {
50 Some(serde_yaml::Value::String(system_str))
51 if system_str == &SchemeSystem::Base24.to_string() =>
52 {
53 let scheme_inner =
54 serde_yaml::from_value(serde_yaml::Value::Mapping(map))?;
55 let scheme = Scheme::Base24(scheme_inner);
56
57 Ok(scheme)
58 }
59 None | Some(_) => {
60 let scheme_inner =
61 serde_yaml::from_value(serde_yaml::Value::Mapping(map))?;
62 let scheme = Scheme::Base16(scheme_inner);
63
64 Ok(scheme)
65 }
66 }
67 } else {
68 Err(anyhow!("Unable to get scheme from SchemeFile"))
69 }
70 }
71 }
72 }
73
74 #[must_use]
75 pub fn get_path(&self) -> PathBuf {
76 match self {
77 Self::Yaml(path) | Self::Yml(path) => path.clone(),
78 }
79 }
80}
81
82#[derive(Debug, Deserialize)]
83pub struct TemplateConfig {
84 pub filename: Option<String>,
85
86 #[serde(rename = "supported-systems")]
87 pub supported_systems: Option<Vec<SchemeSystem>>,
88
89 #[deprecated]
90 pub extension: Option<String>,
91
92 #[deprecated]
93 pub output: Option<String>,
94}
95
96#[derive(Debug)]
97pub struct ParsedFilename {
98 pub directory: PathBuf,
99 pub filestem: String,
100 pub file_extension: Option<String>,
101}
102
103impl ParsedFilename {
104 #[must_use]
105 pub fn get_path(&self) -> PathBuf {
106 let directory = &self.directory;
107 let filestem = &self.filestem;
108 let file_extension = &self
109 .file_extension
110 .as_ref()
111 .map(|ext| format!(".{ext}"))
112 .unwrap_or_default();
113
114 directory.join(format!("{filestem}{file_extension}"))
115 }
116}
117
118pub fn get_scheme_files(dirpath: impl AsRef<Path>, is_recursive: bool) -> Result<Vec<SchemeFile>> {
141 let mut scheme_paths: Vec<SchemeFile> = vec![];
142
143 for item in dirpath.as_ref().read_dir()? {
144 let file_path = item?.path();
145 let file_stem = file_path
146 .file_stem()
147 .unwrap_or_default()
148 .to_str()
149 .unwrap_or_default();
150
151 if file_stem.starts_with('.') {
153 continue;
154 }
155
156 if file_path.is_dir() && is_recursive {
157 let inner_scheme_paths_result = get_scheme_files(&file_path, true);
158
159 if let Ok(inner_scheme_paths) = inner_scheme_paths_result {
160 scheme_paths.extend(inner_scheme_paths);
161 }
162
163 continue;
164 }
165
166 let scheme_file_type_result = SchemeFile::new(&file_path);
167
168 if let Ok(scheme_file_type) = scheme_file_type_result {
169 scheme_paths.push(scheme_file_type);
170 }
171 }
172
173 scheme_paths.sort_by_key(SchemeFile::get_path);
174
175 Ok(scheme_paths)
176}
177
178pub fn parse_filename(template_path: impl AsRef<Path>, filepath: &str) -> ParsedFilename {
186 let p = Path::new(filepath);
187
188 let directory: PathBuf = p.parent().map_or_else(
189 || template_path.as_ref().to_path_buf(),
190 |dir| template_path.as_ref().join(dir),
191 );
192
193 let filestem = p
195 .file_stem()
196 .and_then(|s| s.to_str())
197 .filter(|s| !s.is_empty())
198 .map(String::from)
199 .unwrap_or_default();
200
201 let file_extension = p.extension().and_then(|e| e.to_str()).map(String::from);
202
203 ParsedFilename {
204 directory,
205 filestem,
206 file_extension,
207 }
208}
209
210#[cfg(test)]
211mod tests {
212 use super::*;
213 use std::path::Path;
214
215 #[test]
216 fn test_parse_filename_with_directory_and_extension() {
217 let template_path = Path::new("/home/user/templates");
218 let result = parse_filename(template_path, "some-directory/name/file.txt");
219
220 assert_eq!(result.directory, template_path.join("some-directory/name"));
221 assert_eq!(result.filestem, "file");
222 assert_eq!(result.file_extension, Some("txt".to_string()));
223 }
224
225 #[test]
226 fn test_parse_filename_with_filename_and_extension() {
227 let template_path = Path::new("/home/user/templates");
228 let result = parse_filename(template_path, "filename.ext");
229
230 assert_eq!(result.directory, template_path);
231 assert_eq!(result.filestem, "filename");
232 assert_eq!(result.file_extension, Some("ext".to_string()));
233 }
234
235 #[test]
236 fn test_parse_filename_with_only_filename() {
237 let template_path = Path::new("/home/user/templates");
238 let result = parse_filename(template_path, "file");
239
240 assert_eq!(result.directory, template_path);
241 assert_eq!(result.filestem, "file");
242 assert_eq!(result.file_extension, None);
243 }
244
245 #[test]
246 fn test_parse_filename_with_directory_and_no_extension() {
247 let template_path = Path::new("/home/user/templates");
248 let result = parse_filename(template_path, "some-directory/file");
249
250 assert_eq!(result.directory, template_path.join("some-directory"));
251 assert_eq!(result.filestem, "file");
252 assert_eq!(result.file_extension, None);
253 }
254}