pacenotes_installer\restore/
plan.rs1#[derive(Clone, Debug, PartialEq, Eq)]
3pub struct PutBack {
4 pub key: String,
5 pub sha256: String,
9 pub version: String,
10}
11
12#[derive(Clone, Debug, Default, PartialEq, Eq)]
15pub struct Plan {
16 pub remove: Vec<String>,
19 pub put_back: Vec<PutBack>,
21 pub unavailable: Vec<PutBack>,
24 pub keep: Vec<String>,
26}
27
28impl Plan {
29 pub fn is_empty(&self) -> bool {
31 self.remove.is_empty() && self.put_back.is_empty()
32 }
33
34 pub fn is_partial(&self) -> bool {
36 !self.unavailable.is_empty()
37 }
38}
39
40pub fn plan(
46 target: &super::Snapshot,
47 live: &super::Snapshot,
48 payload_present: &dyn Fn(&str) -> bool,
49) -> Plan {
50 let mut plan = Plan::default();
51 for (key, now) in live {
52 let Some(then) = target.get(key) else {
53 plan.remove.push(key.clone());
54 continue;
55 };
56 if then.sha256 == now.sha256 && now.state == crate::ledger::EntryState::Installed {
58 plan.keep.push(key.clone());
59 } else if payload_present(&then.sha256) {
60 plan.remove.push(key.clone());
61 plan.put_back.push(put_back(key, then));
62 } else {
63 plan.unavailable.push(put_back(key, then));
64 }
65 }
66 for (key, then) in target.iter().filter(|(key, _)| !live.contains_key(*key)) {
67 if payload_present(&then.sha256) {
68 plan.put_back.push(put_back(key, then));
69 } else {
70 plan.unavailable.push(put_back(key, then));
71 }
72 }
73 plan
74}
75
76fn put_back(key: &str, then: &crate::ledger::LedgerEntry) -> PutBack {
77 PutBack {
78 key: key.to_string(),
79 sha256: then.sha256.clone(),
80 version: then.version.clone(),
81 }
82}
83
84pub fn ledger_after(
93 target: &super::Snapshot,
94 live: &super::Snapshot,
95 plan: &Plan,
96 failed: &[String],
97) -> super::Snapshot {
98 let restored = plan
99 .put_back
100 .iter()
101 .filter(|wanted| !failed.contains(&wanted.key))
102 .filter_map(|wanted| Some((wanted.key.clone(), target.get(&wanted.key)?.clone())));
103 let untouched = plan
104 .keep
105 .iter()
106 .chain(plan.unavailable.iter().map(|wanted| &wanted.key))
107 .filter_map(|key| Some((key.clone(), live.get(key)?.clone())));
108 untouched.chain(restored).collect()
109}
110
111pub fn picks(
114 target: &super::Snapshot,
115 choice_categories: &[&str],
116) -> std::collections::BTreeMap<String, String> {
117 choice_categories
118 .iter()
119 .filter_map(|category| {
120 let key = target
121 .keys()
122 .find(|key| pacenotes_shared::category_of_download_path(key) == Some(category))?;
123 Some((category.to_string(), key.clone()))
124 })
125 .collect()
126}