1use crate::{
2 command::CommandExecutor,
3 filesystem::FileSystemClean,
4 models::{RemovalAction, RemovalCandidate},
5};
6use eyre::Report;
7use eyre::Result;
8
9pub struct Cleaner<CS, CE, FS, N>
10where
11 CS: IntoIterator<Item = RemovalCandidate>,
12 FS: FileSystemClean,
13 CE: CommandExecutor,
14 N: CleanerNotifier,
15{
16 candidates: CS,
17 fs: FS,
18 command_executor: CE,
19 notifier: N,
20}
21
22pub trait CleanerNotifier {
23 fn notify_removal_started(&self, candidate: &RemovalCandidate);
24 fn notify_removal_success(&self, candidate: RemovalCandidate);
25 fn notify_removal_failed(&self, candidate: RemovalCandidate, report: Report);
26 fn notify_removal_finish(&self);
27}
28
29impl<CS, CE, FS, N> Cleaner<CS, CE, FS, N>
30where
31 CS: IntoIterator<Item = RemovalCandidate>,
32 FS: FileSystemClean,
33 CE: CommandExecutor,
34 N: CleanerNotifier,
35{
36 pub fn new(candidates: CS, fs: FS, command_executor: CE, notifier: N) -> Self {
37 Self {
38 candidates,
39 fs,
40 command_executor,
41 notifier,
42 }
43 }
44
45 pub fn clean(self) {
46 for candidate in self.candidates {
47 self.notifier.notify_removal_started(&candidate);
48 match clean_candidate(&self.fs, &self.command_executor, &candidate) {
49 Ok(_) => {
50 self.notifier.notify_removal_success(candidate);
51 }
52 Err(report) => {
53 self.notifier.notify_removal_failed(candidate, report);
54 }
55 }
56 }
57 self.notifier.notify_removal_finish();
58 }
59}
60
61fn clean_candidate(
62 fs: &impl FileSystemClean,
63 command_executor: &impl CommandExecutor,
64 candidate: &RemovalCandidate,
65) -> Result<()> {
66 match &candidate.action {
67 RemovalAction::Delete { file_info, .. } => fs.remove_file(file_info),
68 RemovalAction::RunCommand { work_dir, command } => {
69 command_executor.execute_command(work_dir, command)
70 }
71 }
72}