eunomia_rs/
lib.rs

1//!  SPDX-License-Identifier: MIT
2//!
3//! Copyright (c) 2023, eunomia-bpf
4//! All rights reserved.
5//!
6use 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
15/// Get eunomia home directory
16pub 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        // tmp workspace exist, return as well
56        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    /// Create a temporary directory with random suffix
71    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    /// Return path of temporary directory
88    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}