1use camino::Utf8PathBuf;
5use tera::Context;
6
7use crate::Result;
8use crate::config::{MountEntry, MountStrategy};
9use crate::paths;
10use crate::template::{self, Engine};
11
12#[derive(Debug, Clone)]
14pub struct ResolvedMount {
15 pub src: Utf8PathBuf,
16 pub dst: Utf8PathBuf,
17 pub strategy: MountStrategy,
18}
19
20pub fn resolve(
21 entries: &[MountEntry],
22 default_strategy: MountStrategy,
23 engine: &mut Engine,
24 ctx: &Context,
25) -> Result<Vec<ResolvedMount>> {
26 let mut out = Vec::with_capacity(entries.len());
27 for e in entries {
28 if let Some(when) = &e.when {
29 if !template::eval_truthy(when, engine, ctx)? {
36 continue;
37 }
38 }
39 let dst_str = engine.render(&e.dst, ctx)?;
40 let dst = paths::expand_tilde(dst_str.trim());
41 out.push(ResolvedMount {
42 src: e.src.clone(),
43 dst,
44 strategy: e.strategy.unwrap_or(default_strategy),
45 });
46 }
47 Ok(out)
48}
49
50#[cfg(test)]
51mod tests {
52 use super::*;
53 use crate::template;
54 use crate::vars::YuiVars;
55
56 fn vars() -> YuiVars {
57 YuiVars {
58 os: "linux".into(),
59 arch: "x86_64".into(),
60 host: "test".into(),
61 user: "u".into(),
62 source: "/dotfiles".into(),
63 }
64 }
65
66 #[test]
67 fn renders_dst_and_filters_when_false() {
68 let entries = vec![
69 MountEntry {
70 src: "home".into(),
71 dst: "/{{ yui.os }}/u".into(),
72 when: None,
73 strategy: None,
74 },
75 MountEntry {
76 src: "appdata".into(),
77 dst: "/appdata".into(),
78 when: Some("{{ yui.os == 'windows' }}".into()),
79 strategy: None,
80 },
81 ];
82 let mut e = Engine::new();
83 let ctx = template::config_context(&vars());
84 let resolved = resolve(&entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
85 assert_eq!(resolved.len(), 1);
86 assert_eq!(resolved[0].src, Utf8PathBuf::from("home"));
87 assert_eq!(resolved[0].dst, Utf8PathBuf::from("/linux/u"));
88 assert_eq!(resolved[0].strategy, MountStrategy::Marker);
89 }
90
91 #[test]
92 fn when_true_keeps_entry() {
93 let entries = vec![MountEntry {
94 src: "home".into(),
95 dst: "/h".into(),
96 when: Some("{{ yui.os == 'linux' }}".into()),
97 strategy: None,
98 }];
99 let mut e = Engine::new();
100 let ctx = template::config_context(&vars());
101 let resolved = resolve(&entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
102 assert_eq!(resolved.len(), 1);
103 }
104
105 #[test]
106 fn bare_when_form_works() {
107 let entries = vec![MountEntry {
112 src: "home".into(),
113 dst: "/h".into(),
114 when: Some("yui.os == 'linux'".into()),
115 strategy: None,
116 }];
117 let mut e = Engine::new();
118 let ctx = template::config_context(&vars());
119 let resolved = resolve(&entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
120 assert_eq!(resolved.len(), 1);
121 }
122
123 #[test]
124 fn bare_when_form_filters_when_false() {
125 let entries = vec![MountEntry {
126 src: "home".into(),
127 dst: "/h".into(),
128 when: Some("yui.os == 'no-such-os'".into()),
129 strategy: None,
130 }];
131 let mut e = Engine::new();
132 let ctx = template::config_context(&vars());
133 let resolved = resolve(&entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
134 assert!(resolved.is_empty());
135 }
136
137 #[test]
138 fn per_entry_strategy_overrides_default() {
139 let entries = vec![MountEntry {
140 src: "home".into(),
141 dst: "/h".into(),
142 when: None,
143 strategy: Some(MountStrategy::PerFile),
144 }];
145 let mut e = Engine::new();
146 let ctx = template::config_context(&vars());
147 let resolved = resolve(&entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
148 assert_eq!(resolved[0].strategy, MountStrategy::PerFile);
149 }
150}