comtrya_lib/atoms/file/
chmod.rs1use crate::atoms::Outcome;
2
3use super::super::Atom;
4use super::FileAtom;
5use std::path::PathBuf;
6
7pub struct Chmod {
8 pub path: PathBuf,
9 pub mode: u32,
10}
11
12impl FileAtom for Chmod {
13 fn get_path(&self) -> &PathBuf {
14 &self.path
15 }
16}
17
18impl std::fmt::Display for Chmod {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 write!(
21 f,
22 "The permissions on {} need to be set to {:o}",
23 self.path.display(),
24 self.mode
25 )
26 }
27}
28
29#[cfg(unix)]
30use {std::os::unix::prelude::PermissionsExt, tracing::error};
31
32#[cfg(unix)]
33impl Atom for Chmod {
34 fn plan(&self) -> anyhow::Result<Outcome> {
35 if !self.path.exists() {
38 return Ok(Outcome {
39 side_effects: vec![],
40 should_run: true,
41 });
42 }
43
44 let metadata = match std::fs::metadata(&self.path) {
45 Ok(m) => m,
46 Err(err) => {
47 error!(
48 "Couldn't get metadata for {}, rejecting atom: {}",
49 &self.path.display(),
50 err.to_string()
51 );
52
53 return Ok(Outcome {
54 side_effects: vec![],
55 should_run: false,
56 });
57 }
58 };
59
60 Ok(Outcome {
64 side_effects: vec![],
65 should_run: std::fs::Permissions::from_mode(0o100000 + self.mode).mode()
66 != metadata.permissions().mode(),
67 })
68 }
69
70 fn execute(&mut self) -> anyhow::Result<()> {
71 std::fs::set_permissions(
72 self.path.as_path(),
73 std::fs::Permissions::from_mode(self.mode),
74 )?;
75
76 Ok(())
77 }
78}
79
80#[cfg(not(unix))]
81impl Atom for Chmod {
82 fn plan(&self) -> anyhow::Result<Outcome> {
83 Ok(Outcome {
85 side_effects: vec![],
86 should_run: false,
87 })
88 }
89
90 fn execute(&mut self) -> anyhow::Result<()> {
91 Ok(())
92 }
93}
94
95#[cfg(test)]
96#[cfg(unix)]
97mod tests {
98 use super::*;
99 use pretty_assertions::assert_eq;
100
101 #[test]
102 fn it_can_plan() {
103 let temp_dir = match tempfile::tempdir() {
104 std::result::Result::Ok(dir) => dir,
105 std::result::Result::Err(_) => {
106 assert_eq!(false, true);
107 return;
108 }
109 };
110
111 match std::fs::File::create(temp_dir.path().join("644")) {
112 std::result::Result::Ok(file) => file,
113 std::result::Result::Err(_) => {
114 assert_eq!(false, true);
115 return;
116 }
117 };
118
119 assert_eq!(
120 true,
121 std::fs::set_permissions(
122 temp_dir.path().join("644"),
123 std::fs::Permissions::from_mode(0o644)
124 )
125 .is_ok(),
126 );
127
128 let file_chmod = Chmod {
129 path: temp_dir.path().join("644"),
130 mode: 0o644,
131 };
132
133 assert_eq!(false, file_chmod.plan().unwrap().should_run);
134
135 let file_chmod = Chmod {
136 path: temp_dir.path().join("644"),
137 mode: 0o640,
138 };
139
140 assert_eq!(true, file_chmod.plan().unwrap().should_run);
141 }
142
143 #[test]
144 fn it_can_execute() {
145 let temp_dir = match tempfile::tempdir() {
146 std::result::Result::Ok(dir) => dir,
147 std::result::Result::Err(_) => {
148 assert_eq!(false, true);
149 return;
150 }
151 };
152
153 match std::fs::File::create(temp_dir.path().join("644")) {
154 std::result::Result::Ok(file) => file,
155 std::result::Result::Err(_) => {
156 assert_eq!(false, true);
157 return;
158 }
159 };
160
161 assert_eq!(
162 true,
163 std::fs::set_permissions(
164 temp_dir.path().join("644"),
165 std::fs::Permissions::from_mode(0o644)
166 )
167 .is_ok(),
168 );
169
170 let file_chmod = Chmod {
171 path: temp_dir.path().join("644"),
172 mode: 0o644,
173 };
174
175 assert_eq!(false, file_chmod.plan().unwrap().should_run);
176
177 let mut file_chmod = Chmod {
178 path: temp_dir.path().join("644"),
179 mode: 0o640,
180 };
181
182 assert_eq!(true, file_chmod.plan().unwrap().should_run);
183 assert_eq!(true, file_chmod.execute().is_ok());
184 assert_eq!(false, file_chmod.plan().unwrap().should_run);
185 }
186}