Skip to main content

zoi_cli/cmd/
rollback.rs

1//! Rolling back packages and transactions.
2
3use anyhow::{Result, anyhow};
4
5use crate::pkg::{self, transaction};
6use crate::utils;
7
8/// Rolls back a specific package to its previous state.
9///
10/// This looks for an installed package matching the name and triggers a
11/// rollback operation.
12///
13/// # Errors
14///
15/// Returns an error if the package is not found or the rollback operation
16/// fails.
17pub fn run(
18    package_name: &str,
19    yes: bool,
20    plugin_manager: Option<&crate::pkg::plugin::PluginManager>
21) -> Result<()> {
22    let request = pkg::resolve::parse_source_string(package_name)?;
23    let mut candidates = Vec::new();
24    for scope in [
25        pkg::types::Scope::User,
26        pkg::types::Scope::System,
27        pkg::types::Scope::Project
28    ] {
29        candidates.extend(pkg::local::find_installed_manifests_matching(
30            &request, scope
31        )?);
32    }
33    if candidates.is_empty() {
34        return Err(anyhow!("Package '{package_name}' is not installed."));
35    }
36    let chosen = crate::cmd::installed_select::choose_installed_manifest(
37        package_name,
38        &candidates,
39        yes
40    )?;
41
42    if let Some(pm) = plugin_manager {
43        pm.set_context(chosen.scope)?;
44        pm.trigger_hook("on_rollback", None)?;
45    }
46    pkg::rollback::run(&pkg::local::installed_manifest_source(&chosen), yes)
47}
48
49/// Rolls back the most recent transaction.
50///
51/// This reverts all changes made in the last recorded transaction.
52///
53/// # Errors
54///
55/// Returns an error if the transaction rollback fails.
56pub fn run_transaction_rollback(
57    yes: bool,
58    plugin_manager: Option<&crate::pkg::plugin::PluginManager>
59) -> Result<()> {
60    if !utils::ask_for_confirmation(
61        "This will roll back the last recorded transaction. Are you sure?",
62        yes
63    ) {
64        println!("Operation aborted.");
65        return Ok(());
66    }
67
68    if let Some(id) = transaction::get_last_transaction_id()? {
69        println!("Rolling back transaction {id}...");
70        if let Some(pm) = plugin_manager {
71            pm.trigger_hook("on_rollback", None)?;
72        }
73        transaction::rollback(&id)
74    } else {
75        println!("No transactions found to roll back.");
76        Ok(())
77    }
78}