use camino::{Utf8Path, Utf8PathBuf};
use tera::Context;
use crate::Result;
use crate::config::{MountEntry, MountStrategy};
use crate::paths;
use crate::template::{self, Engine};
#[derive(Debug, Clone)]
pub struct ResolvedMount {
pub src: Utf8PathBuf,
pub dst: Utf8PathBuf,
pub strategy: MountStrategy,
}
pub fn resolve(
source: &Utf8Path,
entries: &[MountEntry],
default_strategy: MountStrategy,
engine: &mut Engine,
ctx: &Context,
) -> Result<Vec<ResolvedMount>> {
let mut out = Vec::with_capacity(entries.len());
for e in entries {
if let Some(when) = &e.when {
if !template::eval_truthy(when, engine, ctx)? {
continue;
}
}
let src_str = engine.render(e.src.as_str(), ctx)?;
let src = paths::resolve_mount_src(source, src_str.trim());
let dst_str = engine.render(&e.dst, ctx)?;
let dst = paths::expand_tilde(dst_str.trim());
out.push(ResolvedMount {
src,
dst,
strategy: e.strategy.unwrap_or(default_strategy),
});
}
Ok(out)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::template;
use crate::vars::YuiVars;
fn vars() -> YuiVars {
YuiVars {
os: "linux".into(),
arch: "x86_64".into(),
host: "test".into(),
user: "u".into(),
source: "/dotfiles".into(),
}
}
fn source() -> Utf8PathBuf {
Utf8PathBuf::from("/dotfiles")
}
#[test]
fn renders_dst_and_filters_when_false() {
let entries = vec![
MountEntry {
src: "home".into(),
dst: "/{{ yui.os }}/u".into(),
when: None,
strategy: None,
},
MountEntry {
src: "appdata".into(),
dst: "/appdata".into(),
when: Some("{{ yui.os == 'windows' }}".into()),
strategy: None,
},
];
let mut e = Engine::new();
let ctx = template::config_context(&vars());
let s = source();
let resolved = resolve(&s, &entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
assert_eq!(resolved.len(), 1);
assert_eq!(resolved[0].src, Utf8PathBuf::from("/dotfiles/home"));
assert_eq!(resolved[0].dst, Utf8PathBuf::from("/linux/u"));
assert_eq!(resolved[0].strategy, MountStrategy::Marker);
}
#[test]
fn when_true_keeps_entry() {
let entries = vec![MountEntry {
src: "home".into(),
dst: "/h".into(),
when: Some("{{ yui.os == 'linux' }}".into()),
strategy: None,
}];
let mut e = Engine::new();
let ctx = template::config_context(&vars());
let s = source();
let resolved = resolve(&s, &entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
assert_eq!(resolved.len(), 1);
}
#[test]
fn bare_when_form_works() {
let entries = vec![MountEntry {
src: "home".into(),
dst: "/h".into(),
when: Some("yui.os == 'linux'".into()),
strategy: None,
}];
let mut e = Engine::new();
let ctx = template::config_context(&vars());
let s = source();
let resolved = resolve(&s, &entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
assert_eq!(resolved.len(), 1);
}
#[test]
fn bare_when_form_filters_when_false() {
let entries = vec![MountEntry {
src: "home".into(),
dst: "/h".into(),
when: Some("yui.os == 'no-such-os'".into()),
strategy: None,
}];
let mut e = Engine::new();
let ctx = template::config_context(&vars());
let s = source();
let resolved = resolve(&s, &entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
assert!(resolved.is_empty());
}
#[test]
fn per_entry_strategy_overrides_default() {
let entries = vec![MountEntry {
src: "home".into(),
dst: "/h".into(),
when: None,
strategy: Some(MountStrategy::PerFile),
}];
let mut e = Engine::new();
let ctx = template::config_context(&vars());
let s = source();
let resolved = resolve(&s, &entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
assert_eq!(resolved[0].strategy, MountStrategy::PerFile);
}
#[test]
fn absolute_src_is_returned_verbatim() {
let entries = vec![MountEntry {
src: "/abs/private/home".into(),
dst: "/h".into(),
when: None,
strategy: None,
}];
let mut e = Engine::new();
let ctx = template::config_context(&vars());
let s = source();
let resolved = resolve(&s, &entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
assert_eq!(resolved[0].src, Utf8PathBuf::from("/abs/private/home"));
}
#[test]
fn src_renders_via_tera() {
let entries = vec![MountEntry {
src: "private/{{ yui.host }}/home".into(),
dst: "/h".into(),
when: None,
strategy: None,
}];
let mut e = Engine::new();
let ctx = template::config_context(&vars());
let s = source();
let resolved = resolve(&s, &entries, MountStrategy::Marker, &mut e, &ctx).unwrap();
assert_eq!(
resolved[0].src,
Utf8PathBuf::from("/dotfiles/private/test/home")
);
}
}