git_policy_cli/
standards_review_append.rs1use super::private_storage::{create_private_directory_all, write_private_file_unsynced};
18use super::standards_review_entry::SHORT_SHA_LENGTH;
19use std::io::Write;
20use std::path::{Path, PathBuf};
21use std::time::SystemTime;
22
23pub const REPAIR_WINDOW: usize = 16;
25
26pub const SPOOL_KEPT: usize = 4 * REPAIR_WINDOW;
28
29#[derive(Clone, Copy, Debug, Eq, PartialEq)]
31pub enum Delivery {
32 Appended,
34 AlreadyThere,
36}
37
38pub fn spool_directory(common_dir: &Path, repository: &str) -> PathBuf {
49 let mut hash: u64 = 0xcbf2_9ce4_8422_2325;
50 for byte in repository.bytes() {
51 hash ^= u64::from(byte);
52 hash = hash.wrapping_mul(0x0100_0000_01b3);
53 }
54 return common_dir.join("cli-git").join("review-entries").join(format!("{hash:016x}"));
55}
56
57fn token(sha: &str) -> String {
59 return sha.chars().take(SHORT_SHA_LENGTH).collect();
60}
61
62pub fn names_commit(log: &Path, sha: &str) -> bool {
64 return std::fs::read_to_string(log).is_ok_and(|text| return text.contains(token(sha).as_str()));
65}
66
67fn append_existing(log: &Path, text: &str) -> std::io::Result<()> {
69 let mut file: std::fs::File = std::fs::OpenOptions::new().append(true).create(false).open(log)?;
70 return file.write_all(text.as_bytes());
71}
72
73fn spooled(spool: &Path) -> Vec<(String, PathBuf, String)> {
75 let mut found: Vec<(SystemTime, String, PathBuf)> = Vec::new();
76 if let Ok(listing) = std::fs::read_dir(spool) {
77 for entry in listing.flatten() {
78 let modified: SystemTime = entry.metadata().and_then(|meta| return meta.modified()).unwrap_or(SystemTime::UNIX_EPOCH);
79 found.push((modified, entry.file_name().to_string_lossy().into_owned(), entry.path()));
80 }
81 }
82 found.sort_by(|left, right| return right.0.cmp(&left.0).then_with(|| return right.1.cmp(&left.1)));
83 return found
84 .into_iter()
85 .map(|(_, name, path)| return (name, path.clone(), std::fs::read_to_string(path).unwrap_or_default()))
86 .collect();
87}
88
89pub fn repair_recent(log: &Path, spool: &Path) -> usize {
100 let entries: Vec<(String, PathBuf, String)> = spooled(spool);
101 let mut present: String = std::fs::read_to_string(log).unwrap_or_default();
102 let mut repaired: usize = 0;
103 for (name, _, text) in entries.iter().take(REPAIR_WINDOW) {
104 if text.is_empty() || present.contains(name.as_str()) {
105 continue;
106 }
107 if append_existing(log, text.as_str()).is_ok() {
108 present.push_str(text.as_str());
109 repaired += 1;
110 }
111 }
112 for (_, path, _) in entries.iter().skip(SPOOL_KEPT) {
113 let _removed = std::fs::remove_file(path);
114 }
115 return repaired;
116}
117
118pub fn deliver(log: &Path, spool: Option<&Path>, sha: &str, text: &str) -> Result<Delivery, String> {
130 let current: String = std::fs::read_to_string(log).map_err(|error| return format!("reading {} failed: {error}", log.display()))?;
131 let name: String = token(sha);
132 if current.contains(name.as_str()) {
133 return Ok(Delivery::AlreadyThere);
134 }
135 if let Some(directory) = spool {
136 create_private_directory_all(directory).map_err(|error| return format!("creating the entry spool failed: {error}"))?;
137 let kept: std::io::Result<()> = write_private_file_unsynced(directory.join(name.as_str()).as_path(), text.as_bytes());
138 if let Err(error) = kept && error.kind() != std::io::ErrorKind::AlreadyExists {
139 return Err(format!("keeping the entry failed: {error}"));
140 }
141 }
142 append_existing(log, text).map_err(|error| return format!("appending to {} failed: {error}", log.display()))?;
143 if let Some(directory) = spool {
144 let _repaired = repair_recent(log, directory);
145 }
146 return Ok(Delivery::Appended);
147}
148
149#[cfg(test)]
151#[path = "standards_review_append_tests.rs"]
152mod tests;