1use std::{path::PathBuf, time::SystemTime};
2use uuid::Uuid;
3
4#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone)]
6pub struct OutputLocation(pub String);
7
8impl Default for OutputLocation {
9 fn default() -> Self {
10 Self("./artifacts/".to_string())
11 }
12}
13
14#[derive(Debug, Default, PartialEq, Eq, PartialOrd, Ord, Clone)]
16pub struct FileSource {
17 pub id: Uuid,
19 pub path: String,
21 pub source: Option<String>,
23 pub access: Option<SystemTime>,
25 pub dependencies: Option<Vec<FileSource>>,
27}
28
29impl FileSource {
30 pub fn fully_flatten(&self) -> String {
38 let mut full_source = if let Some(s) = &self.source { s.clone() } else { "".to_string() };
40
41 match &self.dependencies {
43 Some(vfs) => {
44 for fs in vfs {
45 full_source.push_str(&fs.fully_flatten())
46 }
47 }
48 None => {}
49 }
50
51 full_source
53 }
54
55 pub fn derive_dir(path: &str) -> Option<String> {
57 let path = PathBuf::from(path);
58 match path.parent() {
59 Some(p) => p.to_str().map(String::from),
60 None => None,
61 }
62 }
63
64 pub fn localize_file(parent: &str, child: &str) -> Option<String> {
66 let mut prefix = match FileSource::derive_dir(parent) {
67 Some(p) => {
68 if p.is_empty() {
69 String::from(".")
70 } else {
71 p
72 }
73 }
74 None => String::from("."),
75 };
76 if child.starts_with("../") {
77 let mut res_str = child.to_string();
78 while res_str.starts_with("../") {
79 let path = PathBuf::from(prefix.clone());
80 match path.parent() {
81 Some(p) => match p.to_str().map(String::from) {
82 Some(pref) => {
83 if pref.is_empty() || prefix.ends_with("..") {
84 if prefix.is_empty() || prefix == "." {
85 prefix = "..".to_string();
86 } else {
87 prefix = format!("../{}", prefix);
88 }
89 } else {
90 prefix = pref
91 }
92 }
93 None => {
94 tracing::warn!("Failed to convert path to string");
95 return None
96 }
97 },
98 None => {
99 tracing::warn!("Failed to find parent for path: {:?}", path);
100 return None
101 }
102 }
103 res_str = res_str.replacen("../", "", 1);
104 }
105 Some(format!("{}/{}", prefix, res_str))
106 } else if child.starts_with("./") {
107 Some(child.replacen("./", &format!("{}/", prefix), 1))
108 } else if child.starts_with('/') {
109 Some(child.to_string())
110 } else {
111 Some(format!("{}/{}", prefix, child))
112 }
113 }
114}