comtrya_lib/atoms/file/
remove.rs

1use std::path::PathBuf;
2
3use tracing::error;
4
5use crate::atoms::{Atom, Outcome};
6
7use super::FileAtom;
8
9pub struct Remove {
10    pub target: PathBuf,
11}
12
13impl FileAtom for Remove {
14    fn get_path(&self) -> &std::path::PathBuf {
15        &self.target
16    }
17}
18
19impl std::fmt::Display for Remove {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        write!(f, "The file {} needs to be removed", self.target.display())
22    }
23}
24
25impl Atom for Remove {
26    fn plan(&self) -> anyhow::Result<crate::atoms::Outcome> {
27        if !self.target.is_file() {
28            error!(
29                "Cannot plan: target isn`t a file: {}",
30                self.target.display()
31            );
32
33            return Ok(Outcome {
34                side_effects: vec![],
35                should_run: false,
36            });
37        }
38
39        let metadata = self.target.parent().map(|p| p.metadata());
40
41        match metadata {
42            Some(v) => {
43                if v?.permissions().readonly() {
44                    error!(
45                        "Cannot plan: Dont have permission to delete {}",
46                        self.target.display()
47                    );
48
49                    return Ok(Outcome {
50                        side_effects: vec![],
51                        should_run: false,
52                    });
53                }
54            }
55            None => {
56                error!(
57                    "Cannot plan: Failed to get parent directory of file: {}",
58                    self.target.display()
59                );
60
61                return Ok(Outcome {
62                    side_effects: vec![],
63                    should_run: false,
64                });
65            }
66        };
67
68        Ok(Outcome {
69            side_effects: vec![],
70            should_run: true,
71        })
72    }
73
74    fn execute(&mut self) -> anyhow::Result<()> {
75        std::fs::remove_file(&self.target)?;
76        Ok(())
77    }
78}
79
80#[cfg(test)]
81mod tests {
82    use super::*;
83    use pretty_assertions::assert_eq;
84
85    #[test]
86    fn it_can_plan() {
87        let target_file = match tempfile::NamedTempFile::new() {
88            std::result::Result::Ok(file) => file,
89            std::result::Result::Err(_) => {
90                assert_eq!(false, true);
91                return;
92            }
93        };
94
95        let file_remove = Remove {
96            target: target_file.path().to_path_buf(),
97        };
98
99        assert_eq!(true, file_remove.plan().unwrap().should_run)
100    }
101
102    #[test]
103    fn it_can_execute() {
104        let target_file = match tempfile::NamedTempFile::new() {
105            std::result::Result::Ok(file) => file,
106            std::result::Result::Err(_) => {
107                assert_eq!(false, true);
108                return;
109            }
110        };
111
112        let mut file_remove = Remove {
113            target: target_file.path().to_path_buf(),
114        };
115
116        assert_eq!(true, file_remove.plan().unwrap().should_run);
117        assert_eq!(true, file_remove.execute().is_ok());
118        assert_eq!(false, file_remove.plan().unwrap().should_run)
119    }
120}