1use breezyshim::tree::WorkingTree;
3use breezyshim::RevisionId;
4use std::collections::HashMap;
5use std::error::Error;
6use std::fmt;
7use std::process::Command;
8
9#[derive(Debug, PartialEq)]
10pub struct PreCheckFailed;
12
13impl fmt::Display for PreCheckFailed {
14 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15 write!(f, "Pre-check failed")
16 }
17}
18
19impl Error for PreCheckFailed {}
20
21pub fn run_pre_check(tree: &dyn WorkingTree, script: &str) -> Result<(), PreCheckFailed> {
23 let path = tree.abspath(std::path::Path::new("")).unwrap();
24 let status = Command::new("sh")
25 .arg("-c")
26 .arg(script)
27 .current_dir(path)
28 .status();
29
30 match status {
31 Ok(status) => {
32 if status.code().unwrap() != 0 {
33 Err(PreCheckFailed)
34 } else {
35 Ok(())
36 }
37 }
38 Err(_) => Err(PreCheckFailed),
39 }
40}
41
42#[derive(Debug, PartialEq)]
43pub struct PostCheckFailed;
45
46impl fmt::Display for PostCheckFailed {
47 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
48 write!(f, "Post-check failed")
49 }
50}
51
52impl Error for PostCheckFailed {}
53
54pub fn run_post_check(
56 tree: &dyn WorkingTree,
57 script: &str,
58 since_revid: &RevisionId,
59) -> Result<(), PostCheckFailed> {
60 let mut env_vars = HashMap::new();
61 env_vars.insert("SINCE_REVID", since_revid.to_string());
62 let path = tree.abspath(std::path::Path::new("")).unwrap();
63
64 let status = Command::new("sh")
65 .arg("-c")
66 .arg(script)
67 .current_dir(path)
68 .envs(&env_vars)
69 .status();
70
71 match status {
72 Ok(status) => {
73 if status.code().unwrap() != 0 {
74 Err(PostCheckFailed)
75 } else {
76 Ok(())
77 }
78 }
79 Err(_) => Err(PostCheckFailed),
80 }
81}
82
83#[cfg(test)]
84mod tests {
85 use super::*;
86 use breezyshim::controldir::ControlDirFormat;
87 use breezyshim::prelude::{Branch, MutableTree};
88 use breezyshim::testing::TestEnv;
89 use serial_test::serial;
90 use std::error::Error as StdError;
91 use std::path::Path;
92 use tempfile::tempdir;
93
94 #[test]
95 fn test_pre_check_failed_display() {
96 let error = PreCheckFailed;
97 assert_eq!(format!("{}", error), "Pre-check failed");
98
99 let error: Box<dyn StdError> = Box::new(PreCheckFailed);
101 assert_eq!(error.to_string(), "Pre-check failed");
102 }
103
104 #[test]
105 fn test_post_check_failed_display() {
106 let error = PostCheckFailed;
107 assert_eq!(format!("{}", error), "Post-check failed");
108
109 let error: Box<dyn StdError> = Box::new(PostCheckFailed);
111 assert_eq!(error.to_string(), "Post-check failed");
112 }
113
114 #[test]
115 fn test_run_pre_check_success() {
116 let td = tempdir().unwrap();
117 let wt = breezyshim::controldir::create_standalone_workingtree(
118 td.path(),
119 &ControlDirFormat::default(),
120 )
121 .unwrap();
122
123 let result = run_pre_check(&wt, "exit 0");
125 assert!(result.is_ok());
126 }
127
128 #[test]
129 fn test_run_pre_check_failure() {
130 let td = tempdir().unwrap();
131 let wt = breezyshim::controldir::create_standalone_workingtree(
132 td.path(),
133 &ControlDirFormat::default(),
134 )
135 .unwrap();
136
137 let result = run_pre_check(&wt, "exit 1");
139 assert!(result.is_err());
140 assert_eq!(result.err().unwrap(), PreCheckFailed);
141 }
142
143 #[test]
144 fn test_run_pre_check_nonexistent_command() {
145 let td = tempdir().unwrap();
146 let wt = breezyshim::controldir::create_standalone_workingtree(
147 td.path(),
148 &ControlDirFormat::default(),
149 )
150 .unwrap();
151
152 let result = run_pre_check(&wt, "nonexistent_command_12345");
154 assert!(result.is_err());
155 assert_eq!(result.err().unwrap(), PreCheckFailed);
156 }
157
158 #[test]
159 fn test_run_pre_check_with_file_creation() {
160 let td = tempdir().unwrap();
161 let wt = breezyshim::controldir::create_standalone_workingtree(
162 td.path(),
163 &ControlDirFormat::default(),
164 )
165 .unwrap();
166
167 let script = "touch test_file.txt && test -f test_file.txt";
169 let result = run_pre_check(&wt, script);
170 assert!(result.is_ok());
171
172 let file_path = Path::new("test_file.txt");
174 let absolute_path = wt.abspath(file_path).unwrap();
175 assert!(absolute_path.exists());
176 }
177
178 #[test]
179 fn test_run_pre_check_with_multiple_commands() {
180 let td = tempdir().unwrap();
181 let wt = breezyshim::controldir::create_standalone_workingtree(
182 td.path(),
183 &ControlDirFormat::default(),
184 )
185 .unwrap();
186
187 let script = "mkdir -p test_dir && cd test_dir && touch test_file.txt && cd .. && test -f test_dir/test_file.txt";
189 let result = run_pre_check(&wt, script);
190 assert!(result.is_ok());
191
192 let dir_path = Path::new("test_dir");
194 let file_path = Path::new("test_dir/test_file.txt");
195 let absolute_dir_path = wt.abspath(dir_path).unwrap();
196 let absolute_file_path = wt.abspath(file_path).unwrap();
197 assert!(absolute_dir_path.exists());
198 assert!(absolute_file_path.exists());
199 }
200
201 #[test]
202 fn test_run_post_check_success() {
203 let td = tempdir().unwrap();
204 let wt = breezyshim::controldir::create_standalone_workingtree(
205 td.path(),
206 &ControlDirFormat::default(),
207 )
208 .unwrap();
209
210 let revid = wt.branch().last_revision();
211
212 let result = run_post_check(&wt, "exit 0", &revid);
214 assert!(result.is_ok());
215 }
216
217 #[test]
218 fn test_run_post_check_failure() {
219 let td = tempdir().unwrap();
220 let wt = breezyshim::controldir::create_standalone_workingtree(
221 td.path(),
222 &ControlDirFormat::default(),
223 )
224 .unwrap();
225
226 let revid = wt.branch().last_revision();
227
228 let result = run_post_check(&wt, "exit 1", &revid);
230 assert!(result.is_err());
231 assert_eq!(result.err().unwrap(), PostCheckFailed);
232 }
233
234 #[test]
235 fn test_run_post_check_environment() {
236 let td = tempdir().unwrap();
237 let wt = breezyshim::controldir::create_standalone_workingtree(
238 td.path(),
239 &ControlDirFormat::default(),
240 )
241 .unwrap();
242
243 let revid = wt.branch().last_revision();
244
245 let result = run_post_check(&wt, "test \"$SINCE_REVID\" = \"null:\"", &revid);
247 assert!(result.is_ok());
248 }
249
250 #[test]
251 #[serial]
252 fn test_run_post_check_with_file_operations() {
253 let _test_env = TestEnv::new();
254 let td = tempdir().unwrap();
255 let wt = breezyshim::controldir::create_standalone_workingtree(
256 td.path(),
257 &ControlDirFormat::default(),
258 )
259 .unwrap();
260
261 std::fs::write(
263 wt.abspath(Path::new("initial.txt")).unwrap(),
264 "initial content",
265 )
266 .unwrap();
267 wt.add(&[Path::new("initial.txt")]).unwrap();
268 let revid = wt
269 .build_commit()
270 .message("Initial commit")
271 .allow_pointless(true)
272 .commit()
273 .unwrap();
274
275 let script = "echo $SINCE_REVID > revid.txt && test -f revid.txt";
277 let result = run_post_check(&wt, script, &revid);
278 assert!(result.is_ok());
279
280 let file_path = wt.abspath(Path::new("revid.txt")).unwrap();
282 assert!(file_path.exists());
283 let content = std::fs::read_to_string(file_path).unwrap();
284 assert_eq!(content.trim(), revid.to_string());
285 }
286
287 #[test]
288 fn test_run_post_check_nonexistent_command() {
289 let td = tempdir().unwrap();
290 let wt = breezyshim::controldir::create_standalone_workingtree(
291 td.path(),
292 &ControlDirFormat::default(),
293 )
294 .unwrap();
295
296 let revid = wt.branch().last_revision();
297
298 let result = run_post_check(&wt, "nonexistent_command_12345", &revid);
300 assert!(result.is_err());
301 assert_eq!(result.err().unwrap(), PostCheckFailed);
302 }
303}