pkg_rs/
fs.rs

1use crate::{
2    Pkg,
3    db::{Db, PkgType},
4};
5use miette::{Diagnostic, IntoDiagnostic, Result};
6use std::path::PathBuf;
7use thiserror::Error;
8
9#[derive(Debug)]
10pub struct Fs {
11    target_dir: PathBuf,
12    load_path: PathBuf,
13    db: Db,
14}
15
16#[derive(Error, Debug, Diagnostic)]
17pub enum FsError {
18    #[error(transparent)]
19    #[diagnostic(code(fs::io_error))]
20    IoError(#[from] std::io::Error),
21
22    #[error("The given load path is exist and is a file {0}")]
23    #[diagnostic(code(fs::load_path_is_file))]
24    LoadPathIsFile(PathBuf),
25}
26
27impl Fs {
28    pub fn new(target_dir: PathBuf, load_path: PathBuf, db_path: &PathBuf) -> Self {
29        let db = Db::new(db_path).unwrap();
30
31        let _ = std::fs::create_dir_all(&target_dir);
32        let _ = std::fs::create_dir_all(&load_path);
33
34        Self {
35            target_dir,
36            load_path,
37            db,
38        }
39    }
40
41    pub fn link(&self) -> Result<()> {
42        let pkgs = self.db.get_pkgs()?;
43
44        if !self.load_path.exists() {
45            std::fs::create_dir_all(&self.load_path).into_diagnostic()?;
46        } else if self.load_path.is_dir() {
47            std::fs::remove_dir_all(&self.load_path).into_diagnostic()?;
48            std::fs::create_dir_all(&self.load_path).into_diagnostic()?;
49        } else {
50            return Err(FsError::LoadPathIsFile(self.load_path.clone())).into_diagnostic()?;
51        }
52
53        for pkg in pkgs {
54            let target = self.load_path.join(pkg.name);
55
56            if target.exists() {
57                std::fs::remove_file(&target).into_diagnostic()?;
58            }
59
60            match pkg.pkg_type {
61                PkgType::SingleExecutable => {
62                    std::os::unix::fs::symlink(&pkg.path, &target).into_diagnostic()?;
63                }
64                PkgType::Directory(ref entry_point) => {
65                    std::os::unix::fs::symlink(entry_point, &target).into_diagnostic()?;
66                }
67            }
68        }
69
70        Ok(())
71    }
72
73    pub fn store_or_overwrite(
74        &self,
75        pkgs: &mut [&mut Pkg],
76        bridge_name: Option<&str>,
77    ) -> Result<()> {
78        if !self.target_dir.exists() {
79            std::fs::create_dir_all(&self.target_dir).into_diagnostic()?;
80        }
81
82        for pkg in pkgs {
83            let target_dir = self.target_dir.join(bridge_name.unwrap_or(""));
84
85            if !target_dir.exists() {
86                std::fs::create_dir_all(&target_dir).into_diagnostic()?;
87            }
88
89            let target = target_dir.join(&pkg.name);
90
91            if target.exists() {
92                if target.is_dir() {
93                    std::fs::remove_dir_all(&target).into_diagnostic()?;
94                } else {
95                    std::fs::remove_file(&target).into_diagnostic()?;
96                }
97            }
98
99            std::fs::rename(&pkg.path, &target).into_diagnostic()?;
100
101            if let PkgType::Directory(ref entry_point) = pkg.pkg_type {
102                // change the entry point parent to the target dir
103                let entry_point_str = entry_point.to_str().unwrap();
104                let old_path_str = pkg.path.to_str().unwrap();
105                let target_str = target.to_str().unwrap();
106
107                let new_entry_point_str = entry_point_str.replace(old_path_str, target_str);
108                pkg.pkg_type = PkgType::Directory(PathBuf::from(new_entry_point_str))
109            };
110
111            pkg.path = target;
112        }
113
114        Ok(())
115    }
116
117    pub fn remove_pkgs(&self, pkgs: &[&String]) -> Result<bool> {
118        let pkgs = pkgs.iter().map(|s| s.to_string()).collect::<Vec<String>>();
119        let pkgs = pkgs.as_slice();
120
121        let mut removed = false;
122
123        let pkgs = self.db.get_pkgs_by_name(pkgs)?;
124
125        for pkg in pkgs {
126            let target = self.target_dir.join(&pkg.name);
127
128            if target.exists() {
129                if target.is_dir() {
130                    std::fs::remove_dir_all(&target).into_diagnostic()?;
131                } else {
132                    std::fs::remove_file(&target).into_diagnostic()?;
133                }
134                removed = true;
135            }
136        }
137        Ok(removed)
138    }
139}