sklink 0.2.4

Install skills into platform directories via a local store and symlinks
Documentation
use sklink::error::AppError;
use sklink::path_utils::resolve_path;
use std::ffi::OsString;
use std::path::{Path, PathBuf};
use std::sync::Mutex;

static ENV_LOCK: Mutex<()> = Mutex::new(());

struct EnvVarGuard {
    key: &'static str,
    old: Option<OsString>,
}

impl Drop for EnvVarGuard {
    fn drop(&mut self) {
        if let Some(old) = self.old.take() {
            std::env::set_var(self.key, old);
        } else {
            std::env::remove_var(self.key);
        }
    }
}

fn set_env_var(key: &'static str, value: Option<&str>) -> EnvVarGuard {
    let old = std::env::var_os(key);
    match value {
        Some(v) => std::env::set_var(key, v),
        None => std::env::remove_var(key),
    }
    EnvVarGuard { key, old }
}

#[test]
fn resolve_path_joins_relative_path_to_base_dir() {
    let base = Path::new("/base");
    let out = resolve_path("skills/foo", base).unwrap();
    assert_eq!(out, PathBuf::from("/base/skills/foo"));
}

#[test]
fn resolve_path_keeps_absolute_path() {
    let base = Path::new("/base");
    let out = resolve_path("/abs/path", base).unwrap();
    assert_eq!(out, PathBuf::from("/abs/path"));
}

#[test]
fn resolve_path_expands_tilde_and_then_joins_relative() {
    let _lock = ENV_LOCK.lock().unwrap();
    let _home = set_env_var("HOME", Some("/home/tester"));

    let base = Path::new("/base");
    let out = resolve_path("~/dir/file", base).unwrap();
    assert_eq!(out, PathBuf::from("/home/tester/dir/file"));
}

#[test]
fn resolve_path_expands_bare_tilde() {
    let _lock = ENV_LOCK.lock().unwrap();
    let _home = set_env_var("HOME", Some("/home/tester"));

    let base = Path::new("/base");
    let out = resolve_path("~", base).unwrap();
    assert_eq!(out, PathBuf::from("/home/tester"));
}

#[test]
fn resolve_path_returns_error_when_home_missing_for_tilde() {
    let _lock = ENV_LOCK.lock().unwrap();
    let _home = set_env_var("HOME", None);

    let base = Path::new("/base");
    let err = resolve_path("~/dir", base).unwrap_err();
    assert!(matches!(err, AppError::HomeMissing));
}