Skip to main content

yui/
mount.rs

1//! Resolve `[[mount.entry]]` definitions: render `dst` via Tera, evaluate
2//! `when`, drop disabled entries.
3
4use camino::Utf8PathBuf;
5use tera::Context;
6
7use crate::Result;
8use crate::config::{MountEntry, MountStrategy};
9use crate::template::Engine;
10
11/// A mount entry after Tera rendering of `dst` and `when`-filtering.
12#[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
44/// `when` rendered output is treated as truthy when literally `"true"` (case
45/// insensitive) or `"1"`. Anything else (including `"false"`, `""`, etc.)
46/// disables the entry.
47fn 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}