goup_version/
dir.rs

1use std::{
2    env,
3    fs::{self, File},
4    ops::{Deref, DerefMut},
5    path::{Path, PathBuf},
6};
7
8use anyhow::anyhow;
9
10use super::consts::GOUP_HOME;
11
12/// Dir `${path}/.goup` contain a `PathBuf`.
13#[derive(Debug, Clone, PartialEq)]
14pub struct Dir {
15    path: PathBuf,
16}
17
18impl Dir {
19    /// Returns the path to the user's home directory.
20    pub fn home_dir() -> Result<PathBuf, anyhow::Error> {
21        dirs::home_dir().ok_or_else(|| anyhow!("home dir get failed"))
22    }
23    /// Allocates a Dir as `${path}/.goup`
24    pub fn new<P: AsRef<Path>>(p: P) -> Self {
25        let mut path: PathBuf = p.as_ref().into();
26        path.push(".goup");
27        Self { path }
28    }
29    /// Allocates a `GOUP_HOME` Dir as Environment Or `${HOME}/.goup`
30    pub fn goup_home() -> Result<Self, anyhow::Error> {
31        env::var(GOUP_HOME)
32            .ok()
33            .filter(|s| !s.is_empty())
34            .map(|s| {
35                Ok(Self {
36                    path: PathBuf::from(s),
37                })
38            })
39            .unwrap_or_else(|| Self::home_dir().map(Self::new))
40    }
41    // Creates an owned [`Dir`] with `path` adjoined to `self`.
42    pub fn join_path<P: AsRef<Path>>(&self, path: P) -> Self {
43        Self {
44            path: self.path.join(path),
45        }
46    }
47    /// Extends `self` with `env`
48    pub fn env(&self) -> Self {
49        self.join_path("env")
50    }
51    /// Extends `self` with `current`.
52    pub fn current(&self) -> Self {
53        self.join_path("current")
54    }
55    /// Extends `self` with `/current/bin`
56    pub fn current_bin(&self) -> Self {
57        let mut d = self.join_path("current");
58        d.push("bin");
59        d
60    }
61    /// Extends `self` with `/bin`
62    pub fn bin(&self) -> Self {
63        self.join_path("bin")
64    }
65    /// Extends `self` with `{version}`
66    pub fn version<P: AsRef<Path>>(&self, ver: P) -> Self {
67        self.join_path(ver)
68    }
69    /// Extends `self` with `cache`
70    pub fn cache(&self) -> Self {
71        self.join_path("cache")
72    }
73    /// Extends `self` with `cache/{filename}`
74    pub fn cache_file<P: AsRef<Path>>(&self, p: P) -> Self {
75        let mut d = self.join_path("cache");
76        d.push(p);
77        d
78    }
79    /// Extends `self` with `{version}/go`
80    pub fn version_go<P: AsRef<Path>>(&self, ver: P) -> Self {
81        let mut d = self.join_path(ver);
82        d.push("go");
83        d
84    }
85    /// Extends `self` with `{version}/.unpacked-success`
86    fn version_dot_unpacked_success<P: AsRef<Path>>(&self, ver: P) -> Self {
87        let mut d = self.join_path(ver);
88        d.push(".unpacked-success");
89        d
90    }
91    /// `${path}/.goup/{version}/.unpacked-success` is exist.
92    pub fn is_dot_unpacked_success_file_exists<P>(&self, ver: P) -> bool
93    where
94        P: AsRef<Path>,
95    {
96        self.version_dot_unpacked_success(&ver).exists()
97    }
98    /// create `${path}/.goup/{version}/.unpacked-success` file
99    pub fn create_dot_unpacked_success_file<P>(&self, ver: P) -> Result<(), anyhow::Error>
100    where
101        P: AsRef<Path>,
102    {
103        let dot_unpacked_success_file = self.version_dot_unpacked_success(&ver);
104        let parent = dot_unpacked_success_file.parent();
105        if let Some(parent) = parent {
106            fs::create_dir_all(parent)?;
107        }
108        File::create(&dot_unpacked_success_file)?;
109        Ok(())
110    }
111}
112
113impl AsRef<Path> for Dir {
114    fn as_ref(&self) -> &Path {
115        &self.path
116    }
117}
118
119impl Deref for Dir {
120    type Target = PathBuf;
121
122    fn deref(&self) -> &Self::Target {
123        &self.path
124    }
125}
126
127impl DerefMut for Dir {
128    fn deref_mut(&mut self) -> &mut Self::Target {
129        &mut self.path
130    }
131}
132
133impl Default for Dir {
134    fn default() -> Self {
135        Self {
136            path: PathBuf::new(),
137        }
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144    use std::ffi::OsStr;
145
146    #[test]
147    fn test_home_dir() {
148        println!("Dir - home_dir: {:?}", Dir::home_dir());
149        println!("Dir - from_home_dir: {:?}", Dir::goup_home());
150    }
151    #[test]
152    fn test_dir() {
153        let home_dir = Path::new("/home/dev");
154
155        assert_eq!(Dir::new(home_dir).as_ref(), Path::new("/home/dev/.goup"));
156        assert_eq!(Dir::new(home_dir).file_name(), Some(OsStr::new(".goup")));
157
158        assert_eq!(
159            Dir::new(home_dir).env().as_ref(),
160            Path::new("/home/dev/.goup/env")
161        );
162        assert_eq!(
163            Dir::new(home_dir).current().as_ref(),
164            Path::new("/home/dev/.goup/current")
165        );
166        assert_eq!(
167            Dir::new(home_dir).current_bin().as_ref(),
168            Path::new("/home/dev/.goup/current/bin")
169        );
170        assert_eq!(
171            Dir::new(home_dir).bin().as_ref(),
172            Path::new("/home/dev/.goup/bin")
173        );
174        assert_eq!(
175            Dir::new(home_dir).cache().as_ref(),
176            Path::new("/home/dev/.goup/cache")
177        );
178        assert_eq!(
179            Dir::new(home_dir).cache_file("file").as_ref(),
180            Path::new("/home/dev/.goup/cache/file")
181        );
182        assert_eq!(
183            Dir::new(home_dir).version("go1.21.2").as_ref(),
184            Path::new("/home/dev/.goup/go1.21.2")
185        );
186        assert_eq!(
187            Dir::new(home_dir).version_go("go1.21.2").as_ref(),
188            Path::new("/home/dev/.goup/go1.21.2/go")
189        );
190        assert_eq!(
191            Dir::new(home_dir).version_go("go1.21.2").as_ref(),
192            Path::new("/home/dev/.goup/go1.21.2/go")
193        );
194        assert_eq!(
195            Dir::new(home_dir).version_go("go1.21.2").as_ref(),
196            Path::new("/home/dev/.goup/go1.21.2/go")
197        );
198    }
199
200    #[test]
201    fn test_dot_unpacked_success_file() -> Result<(), anyhow::Error> {
202        let tmp_home_dir = tempfile::tempdir()?;
203        let tmp_goup_home = Dir::new(tmp_home_dir);
204        println!("{}", tmp_goup_home.display());
205        assert!(!tmp_goup_home.is_dot_unpacked_success_file_exists("go1.21.2"));
206        tmp_goup_home.create_dot_unpacked_success_file("go1.21.2")?;
207        assert!(tmp_goup_home.is_dot_unpacked_success_file_exists("go1.21.2"));
208        Ok(())
209    }
210}