1use camino::Utf8PathBuf;
5use tera::Context;
6
7use crate::Result;
8use crate::config::{MountEntry, MountStrategy};
9use crate::template::Engine;
10
11#[derive(Debug, Clone)]
13pub struct ResolvedMount {
14 pub src: Utf8PathBuf,
15 pub dst: Utf8PathBuf,
16 pub strategy: MountStrategy,
17}
18
19pub fn resolve(
20 entries: &[MountEntry],
21 default_strategy: MountStrategy,
22 engine: &mut Engine,
23 ctx: &Context,
24) -> Result<Vec<ResolvedMount>> {
25 let mut out = Vec::with_capacity(entries.len());
26 for e in entries {
27 if let Some(when) = &e.when {
28 let rendered = engine.render(when, ctx)?;
29 if !is_truthy(rendered.trim()) {
30 continue;
31 }
32 }
33 let dst_str = engine.render(&e.dst, ctx)?;
34 let dst = Utf8PathBuf::from(dst_str.trim());
35 out.push(ResolvedMount {
36 src: e.src.clone(),
37 dst,
38 strategy: e.strategy.unwrap_or(default_strategy),
39 });
40 }
41 Ok(out)
42}
43
44fn is_truthy(s: &str) -> bool {
48 let s = s.trim();
49 s.eq_ignore_ascii_case("true") || s == "1"
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use crate::template;
56 use crate::vars::YuiVars;
57
58 fn vars() -> YuiVars {
59 YuiVars {
60 os: "linux".into(),
61 arch: "x86_64".into(),
62 host: "test".into(),
63 user: "u".into(),
64 source: "/dotfiles".into(),
65 }
66 }
67
68 #[test]
69 fn renders_dst_and_filters_when_false() {
70 let entries = vec![
71 MountEntry {
72 src: "home".into(),
73 dst: "/{{ yui.os }}/u".into(),
74 when: None,
75 strategy: None,
76 },
77 MountEntry {
78 src: "appdata".into(),
79 dst: "/appdata".into(),
80 when: Some("{{ yui.os == 'windows' }}".into()),
81 strategy: None,
82 },
83 ];
84 let mut e = Engine::new();
85 let ctx = template::config_context(&vars());
86 let resolved = resolve(&entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
87 assert_eq!(resolved.len(), 1);
88 assert_eq!(resolved[0].src, Utf8PathBuf::from("home"));
89 assert_eq!(resolved[0].dst, Utf8PathBuf::from("/linux/u"));
90 assert_eq!(resolved[0].strategy, MountStrategy::Marker);
91 }
92
93 #[test]
94 fn when_true_keeps_entry() {
95 let entries = vec![MountEntry {
96 src: "home".into(),
97 dst: "/h".into(),
98 when: Some("{{ yui.os == 'linux' }}".into()),
99 strategy: None,
100 }];
101 let mut e = Engine::new();
102 let ctx = template::config_context(&vars());
103 let resolved = resolve(&entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
104 assert_eq!(resolved.len(), 1);
105 }
106
107 #[test]
108 fn per_entry_strategy_overrides_default() {
109 let entries = vec![MountEntry {
110 src: "home".into(),
111 dst: "/h".into(),
112 when: None,
113 strategy: Some(MountStrategy::PerFile),
114 }];
115 let mut e = Engine::new();
116 let ctx = template::config_context(&vars());
117 let resolved = resolve(&entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
118 assert_eq!(resolved[0].strategy, MountStrategy::PerFile);
119 }
120
121 #[test]
122 fn truthy_recognizes_true_and_one() {
123 assert!(is_truthy("true"));
124 assert!(is_truthy("TRUE"));
125 assert!(is_truthy(" 1 "));
126 assert!(!is_truthy("false"));
127 assert!(!is_truthy(""));
128 assert!(!is_truthy("yes"));
129 }
130}