pacenotes_installer\restore/
execute.rs1#[derive(Debug, Default)]
4pub struct Prepared {
5 pub files: std::collections::BTreeMap<String, Vec<crate::zip::FileEntry>>,
7 pub install_bytes: u64,
8}
9
10pub fn prepare(
13 plan: &super::Plan,
14 cache: &crate::cache::Cache,
15 facts: crate::engine::HostFacts,
16 game_dir: &std::path::Path,
17 watcher: &mut dyn crate::engine::Watcher,
18) -> Result<Prepared, crate::engine::PreflightError> {
19 if facts.game_running {
20 return Err(crate::engine::PreflightError::GameRunning);
21 }
22 crate::engine::probe_writable(game_dir)?;
23
24 let mut prepared = Prepared::default();
25 let count = plan.put_back.len() as u64;
26 for (index, wanted) in plan.put_back.iter().enumerate() {
27 let phase = crate::engine::Phase::Checking;
28 watcher.phase(phase, &wanted.key, index as u64, count);
29 let listed = crate::engine::verified_files(cache, &wanted.key, &wanted.sha256)?;
30 prepared.install_bytes += listed.iter().map(|file| file.size).sum::<u64>();
31 prepared.files.insert(wanted.key.clone(), listed);
32 }
33 crate::engine::check_space(prepared.install_bytes, facts)?;
34 Ok(prepared)
35}
36
37pub fn execute(
43 target: &super::Snapshot,
44 plan: &super::Plan,
45 prepared: &Prepared,
46 game_dir: &std::path::Path,
47 cache: &crate::cache::Cache,
48 ledger: &mut crate::ledger::Ledger,
49 watcher: &mut dyn crate::engine::Watcher,
50) -> Result<crate::engine::Outcome, crate::engine::ExecuteError> {
51 let mut outcome = crate::engine::Outcome::default();
52 if plan.is_empty() {
53 return Ok(outcome);
54 }
55 let live = ledger.packages().clone();
56 let point = crate::engine::open_restore_point(game_dir, ledger, watcher)?;
57 outcome.restore_point = Some(point.clone());
58 let run = &mut crate::engine::RunContext {
59 game_dir,
60 cache,
61 ledger,
62 watcher,
63 };
64
65 let count = plan.remove.len() as u64;
66 for (index, key) in plan.remove.iter().enumerate() {
67 let phase = crate::engine::Phase::Uninstalling;
68 run.watcher.phase(phase, key, index as u64, count);
69 crate::engine::uninstall_package(run, key, &mut outcome)?;
70 }
71
72 let put_back = put_back_all(target, plan, prepared, run, &point, &mut outcome);
73 let failed: Vec<String> = plan
74 .put_back
75 .iter()
76 .map(|wanted| wanted.key.clone())
77 .filter(|key| !outcome.installed.contains(key))
78 .collect();
79 run.ledger
80 .replace_all(super::ledger_after(target, &live, plan, &failed))
81 .map_err(crate::engine::ExecuteError::ledger)?;
82 put_back?;
83
84 for wanted in &plan.unavailable {
85 run.watcher.log(&format!(
86 "{} could not be put back: the download it needs is no longer in the cache, \
87 so what is installed was left alone",
88 wanted.key
89 ));
90 }
91 Ok(outcome)
92}
93
94fn put_back_all(
96 target: &super::Snapshot,
97 plan: &super::Plan,
98 prepared: &Prepared,
99 run: &mut crate::engine::RunContext,
100 point: &str,
101 outcome: &mut crate::engine::Outcome,
102) -> Result<(), crate::engine::ExecuteError> {
103 let mut progress = crate::engine::Progress {
104 written: 0,
105 total: prepared.install_bytes,
106 };
107 for wanted in &plan.put_back {
108 let files = prepared
109 .files
110 .get(&wanted.key)
111 .map_or(&[][..], Vec::as_slice);
112 let group = target
113 .get(&wanted.key)
114 .and_then(|entry| entry.exclusive_group.as_deref());
115 let what = crate::engine::Installing {
116 key: &wanted.key,
117 sha256: &wanted.sha256,
118 version: &wanted.version,
119 exclusive_group: group,
120 };
121 crate::engine::install_package(run, &what, files, point, &mut progress)?;
122 outcome.installed.push(wanted.key.clone());
123 }
124 Ok(())
125}