1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
//! What:
//! What can go wrong in a pass over the folder of saved copies, the words that say it, and the listing that carries both.
//! Why:
//! `discarded_prune.rs` finds, plans and removes; the problems and the listing are plain values that the doctor and the guard read, so they live in a file of their own that `discarded_prune.rs` imports.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! const text = problem.message(); // the line the doctor prints
//! ```
use crate::discarded_prune_stamps::Stamped;
use std::path::PathBuf;
/// What went wrong with the folder or one of its directories; each is kept, never guessed at.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ProblemKind {
/// The folder cannot be used as a store: a link stands where it should be, or it cannot be opened.
StoreUnusable,
/// A directory could not be read, so its size is unknown and it is kept.
EntryUnreadable,
/// A directory was replaced or changed between the listing and the removal, and was kept.
EntryChanged,
/// A removal failed after some files were gone.
PartiallyRemoved,
/// A removal failed before anything was removed.
NotRemoved,
/// The audit file could not be opened for appending, so nothing was removed.
AuditUnwritable,
/// A directory was removed but its audit line could not be written.
RemovedWithoutAudit,
}
/// One thing a pass or a listing could not do, with the path it concerns and the reason in plain words.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct Problem {
/// The folder or directory concerned.
pub path: PathBuf,
/// What kind of trouble.
pub kind: ProblemKind,
/// The reason, as the system gave it.
pub detail: String,
}
/// What a listing found: the directories named like the wrapper's own, and what it could not read.
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Listing {
/// The directories, oldest first.
pub entries: Vec<Stamped>,
/// What could not be read.
pub problems: Vec<Problem>,
/// How many files the entries hold.
pub files: usize,
/// The files each entry held when it was listed, by the entry's name, so that a removal can tell a directory that only
/// lost files (another pass removing them) from one that gained a file after it was judged.
pub listed_files: std::collections::HashMap<String, std::collections::HashSet<String>>,
}
impl Problem {
/// What:
/// The sentence that tells a person what was kept or not done, which input it concerns and what to do about it.
/// Why:
/// The copies are what a person may need back, so every case where the limits could not be applied, or an audit line
/// is missing, is said where the person sees it (the notice of the command, and `git monochromatic-git-policy-cli doctor`).
///
/// In TS you'd write (pseudocode):
/// ```ts
/// `${problem.path} was kept: ${problem.detail}`
/// ```
pub fn message(&self) -> String {
let path = self.path.display();
let detail: &str = self.detail.as_str();
return match self.kind {
ProblemKind::StoreUnusable => format!(
"monochromatic-git-policy-cli: the saved copies of replaced files in {path} were not pruned, and the age and size limits did not apply: {detail}. \
Make it a real directory (move the copies there and remove the link) and the next save prunes it again.\n"
),
ProblemKind::EntryUnreadable => format!(
"monochromatic-git-policy-cli: {path} was kept and not counted: it cannot be read ({detail}). Fix its permissions or remove it yourself; \
until then the size limit sees the folder as smaller than it is.\n"
),
ProblemKind::EntryChanged => format!(
"monochromatic-git-policy-cli: {path} was kept: it was replaced or changed while the pass ran ({detail}), so it is not the directory the pass judged.\n"
),
ProblemKind::PartiallyRemoved => format!(
"monochromatic-git-policy-cli: {path} was only partly removed ({detail}). The audit file lists the copies that went and the rest are still there; \
fix the cause and the next pass finishes the removal.\n"
),
ProblemKind::NotRemoved => format!("monochromatic-git-policy-cli: {path} could not be removed and was left whole ({detail}). The next pass tries again.\n"),
ProblemKind::AuditUnwritable => format!(
"monochromatic-git-policy-cli: no saved copy was removed because the audit file {path} cannot be appended to ({detail}); every removal needs its \
line there. Fix the file or its permissions and the next pass removes what the limits allow.\n"
),
ProblemKind::RemovedWithoutAudit => format!(
"monochromatic-git-policy-cli: {path} was removed but its line in the audit file could not be written ({detail}). Its copies were older or \
larger than the limits allow.\n"
),
};
}
}