1use std::path::{Path, PathBuf};
4
5use crate::constants::CHROOTS;
6use crate::error::Result;
7use crate::scope::validate_chroot_name;
8
9const APP: &str = "unifier";
10
11#[derive(Clone, Debug, PartialEq, Eq)]
13pub struct UnifierHome {
14 global: PathBuf,
15 effective: PathBuf,
16 chroot: Option<String>,
17}
18
19impl UnifierHome {
20 pub fn resolve(explicit: Option<PathBuf>, chroot: Option<String>) -> Result<Self> {
22 let global = resolve_global(explicit)?;
23 let effective = match &chroot {
24 Some(name) => {
25 validate_chroot_name(name)?;
26 global.join(CHROOTS).join(name)
27 }
28 None => global.clone(),
29 };
30 Ok(Self {
31 global,
32 effective,
33 chroot,
34 })
35 }
36
37 pub fn path(&self) -> &Path {
39 &self.effective
40 }
41
42 pub fn global_path(&self) -> &Path {
44 &self.global
45 }
46
47 pub fn chroot_name(&self) -> Option<&str> {
48 self.chroot.as_deref()
49 }
50
51 pub fn ensure(&self) -> Result<()> {
52 std::fs::create_dir_all(self.path())?;
53 Ok(())
54 }
55}
56
57fn resolve_global(explicit: Option<PathBuf>) -> Result<PathBuf> {
58 if let Some(p) = explicit {
59 return Ok(p);
60 }
61 if let Ok(p) = std::env::var("UNIFIER_HOME") {
62 return Ok(PathBuf::from(p));
63 }
64 let base = user_home()?.join(".local");
65 Ok(base.join(APP))
66}
67
68fn user_home() -> Result<PathBuf> {
69 std::env::var_os("HOME")
70 .or_else(|| std::env::var_os("USERPROFILE"))
71 .map(PathBuf::from)
72 .ok_or_else(|| crate::Error::msg("could not resolve home directory"))
73}