Skip to main content

pacenotes_installer\worker/
restore_run.rs

1/// Everything the restore run needs, owned, because it crosses a thread.
2///
3/// The plan comes from the UI thread, because it is the preview the user
4/// approved; recomputing it here could carry out something they were never shown.
5pub struct RestoreJob {
6    pub cache_root: std::path::PathBuf,
7    pub game_dir: std::path::PathBuf,
8    pub game: pacenotes_installer::gamedir::Game,
9    /// The state being returned to.
10    pub target: pacenotes_installer::restore::Snapshot,
11    pub plan: pacenotes_installer::restore::Plan,
12    pub choice_categories: Vec<String>,
13    pub facts: pacenotes_installer::engine::HostFacts,
14}
15
16/// The restore scene's run, which reaches no server, since the way back must
17/// work when the server does not.
18pub fn run_restore(job: RestoreJob, reporter: &super::Reporter) -> super::Message {
19    match restore(&job, reporter) {
20        Ok(applied) => super::Message::Installed(super::Outcome::Done { applied }),
21        Err(message) => super::Message::Installed(super::Outcome::Failed(message)),
22    }
23}
24
25/// Puts the folder back, then runs the game's configuration step for the picks
26/// the restored state implies, since those edits live in a file the packages
27/// ship their own defaults for.
28fn restore(job: &RestoreJob, reporter: &super::Reporter) -> Result<super::Applied, String> {
29    let cache = pacenotes_installer::cache::Cache::open(&job.cache_root);
30    let mut watcher = super::apply_selection::PostingWatcher { reporter };
31    let prepared = pacenotes_installer::restore::prepare(
32        &job.plan,
33        &cache,
34        job.facts,
35        &job.game_dir,
36        &mut watcher,
37    )
38    .map_err(|e| e.to_string())?;
39
40    let mut ledger = pacenotes_installer::ledger::Ledger::open(&job.game_dir);
41    let outcome = pacenotes_installer::restore::execute(
42        &job.target,
43        &job.plan,
44        &prepared,
45        &job.game_dir,
46        &cache,
47        &mut ledger,
48        &mut watcher,
49    )
50    .map_err(|e| e.to_string())?;
51
52    // A step rewriting a file it did not need to would look like someone else's edit.
53    let configured = if job.plan.is_empty() {
54        Vec::new()
55    } else {
56        let choices: Vec<&str> = job.choice_categories.iter().map(String::as_str).collect();
57        let picks = pacenotes_installer::restore::picks(&job.target, &choices);
58        super::apply_selection::configure(
59            job.game,
60            &job.game_dir,
61            &picks,
62            &mut ledger,
63            &mut watcher,
64        )?
65    };
66    Ok(super::Applied {
67        installed: outcome.installed,
68        uninstalled: outcome.uninstalled,
69        left_alone: outcome.left_alone,
70        configured,
71        overlaps: 0,
72        restore_point: outcome.restore_point,
73    })
74}