1use anyhow::Result;
7use std::ffi::OsString;
8use std::fs::create_dir_all;
9use std::iter::repeat_with;
10use std::path::{Path, PathBuf};
11use std::{env, fs, io, mem};
12
13static EUNOMIA_HOME_ENV: &str = "EUNOMIA_HOME";
14
15pub fn get_eunomia_home() -> Result<String> {
17 let eunomia_home = std::env::var(EUNOMIA_HOME_ENV);
18 match eunomia_home {
19 Ok(home) => Ok(home),
20 Err(_) => match home::home_dir() {
21 Some(home) => {
22 let home = home.join(".eunomia");
23 if !home.exists() {
24 create_dir_all(&home).unwrap()
25 }
26 Ok(home.to_str().unwrap().to_string())
27 }
28 None => Err(anyhow::anyhow!(
29 "home dir not found. Please set EUNOMIA_HOME env."
30 )),
31 },
32 }
33}
34
35pub struct TempDir {
36 path: Box<Path>,
37}
38
39pub fn copy_dir_all(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> io::Result<()> {
40 fs::create_dir_all(&dst)?;
41 for entry in fs::read_dir(src)? {
42 let entry = entry?;
43 let ty = entry.file_type()?;
44 if ty.is_dir() {
45 copy_dir_all(entry.path(), dst.as_ref().join(entry.file_name()))?;
46 } else {
47 fs::copy(entry.path(), dst.as_ref().join(entry.file_name()))?;
48 }
49 }
50 Ok(())
51}
52
53fn create_tmp_dir(path: PathBuf) -> io::Result<TempDir> {
54 match fs::create_dir_all(&path) {
55 Err(e) if e.kind() == io::ErrorKind::AlreadyExists => Ok(TempDir {
57 path: path.into_boxed_path(),
58 }),
59 Ok(_) => Ok(TempDir {
60 path: path.into_boxed_path(),
61 }),
62 _ => Err(io::Error::new(
63 io::ErrorKind::PermissionDenied,
64 "Cannot create temporary workspace",
65 )),
66 }
67}
68
69impl TempDir {
70 pub fn new() -> io::Result<TempDir> {
72 let tmp_dir_from_env = &env::temp_dir();
73
74 let mut buf = OsString::with_capacity(8 + 6);
75 let mut char_buf = [0u8; 4];
76 buf.push("eunomia.");
77
78 for c in repeat_with(fastrand::alphanumeric).take(6) {
79 buf.push(c.encode_utf8(&mut char_buf));
80 }
81
82 let path = tmp_dir_from_env.join(buf);
83
84 create_tmp_dir(path)
85 }
86
87 pub fn path(&self) -> &Path {
89 self.path.as_ref()
90 }
91
92 pub fn close(mut self) -> io::Result<()> {
93 let result = fs::remove_dir_all(self.path());
94
95 self.path = PathBuf::default().into_boxed_path();
96
97 mem::forget(self);
98
99 result
100 }
101}
102
103impl Drop for TempDir {
104 fn drop(&mut self) {
105 let _ = fs::remove_dir_all(self.path());
106 }
107}
108
109impl Default for TempDir {
110 fn default() -> Self {
111 Self::new().unwrap()
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use crate::{get_eunomia_home, EUNOMIA_HOME_ENV, FHS_EUNOMIA_HOME_ENTRY};
118
119 #[test]
120 fn test_get_eunomia_home() {
121 let eunomia_home_from_env = std::env::var(EUNOMIA_HOME_ENV);
122 let eunomia_home_from_home = home::home_dir().unwrap();
123
124 match eunomia_home_from_env {
125 Ok(path) => assert_eq!(get_eunomia_home().unwrap(), path),
126 Err(_) => {
127 if get_eunomia_home().is_err() {
128 assert!(true)
129 }
130
131 if eunomia_home_from_home.exists() {
132 assert_eq!(
133 get_eunomia_home().unwrap(),
134 eunomia_home_from_home
135 .join(".eunomia")
136 .into_os_string()
137 .into_string()
138 .unwrap()
139 );
140 } else {
141 assert_eq!(
142 get_eunomia_home().unwrap(),
143 FHS_EUNOMIA_HOME_ENTRY.to_string()
144 )
145 }
146 }
147 }
148 }
149}