pray_core/
package_upstream_overlay.rs1use std::collections::BTreeMap;
2
3pub enum OverlayFileChange {
4 Changed,
5 LocalOnly,
6 Missing,
7}
8
9pub fn overlay_file_changes(
10 local_content: &BTreeMap<String, Vec<u8>>,
11 upstream_content: &BTreeMap<String, Vec<u8>>,
12) -> Vec<(String, OverlayFileChange)> {
13 let mut paths = BTreeMap::new();
14 for path in local_content.keys().chain(upstream_content.keys()) {
15 paths.insert(path.clone(), ());
16 }
17 let mut changes = Vec::new();
18 for path in paths.keys() {
19 match (local_content.get(path), upstream_content.get(path)) {
20 (Some(local), Some(upstream)) if local != upstream => {
21 changes.push((path.clone(), OverlayFileChange::Changed));
22 }
23 (Some(_), None) => changes.push((path.clone(), OverlayFileChange::LocalOnly)),
24 (None, Some(_)) => changes.push((path.clone(), OverlayFileChange::Missing)),
25 _ => {}
26 }
27 }
28 changes
29}
30
31pub fn overlay_drift_line(
32 fork: &str,
33 upstream_name: &str,
34 upstream_version: &str,
35 path: &str,
36 change: &OverlayFileChange,
37) -> String {
38 match change {
39 OverlayFileChange::Changed => {
40 format!("{fork} {path} differs from {upstream_name} {upstream_version}")
41 }
42 OverlayFileChange::LocalOnly => format!("{fork} {path} local"),
43 OverlayFileChange::Missing => format!("{fork} {path} missing from fork"),
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50
51 #[test]
52 fn overlay_file_changes_name_local_and_missing_paths() {
53 let local = BTreeMap::from([
54 ("README.md".to_string(), b"edit".to_vec()),
55 ("overlays/note.md".to_string(), b"local".to_vec()),
56 ]);
57 let upstream = BTreeMap::from([
58 ("README.md".to_string(), b"up".to_vec()),
59 ("exports/a.md".to_string(), b"a".to_vec()),
60 ]);
61 let changes = overlay_file_changes(&local, &upstream);
62 assert!(changes.iter().any(|(path, change)| {
63 path == "README.md" && matches!(change, OverlayFileChange::Changed)
64 }));
65 assert!(changes.iter().any(|(path, change)| {
66 path == "overlays/note.md" && matches!(change, OverlayFileChange::LocalOnly)
67 }));
68 assert!(changes.iter().any(|(path, change)| {
69 path == "exports/a.md" && matches!(change, OverlayFileChange::Missing)
70 }));
71 }
72}