diff --git a/backend/src/install/update.rs b/backend/src/install/update.rs index 9b4b7b42f..9acac4830 100644 --- a/backend/src/install/update.rs +++ b/backend/src/install/update.rs @@ -1,20 +1,66 @@ use std::collections::BTreeMap; -use patch_db::{DbHandle, LockType}; +use patch_db::{DbHandle, LockReceipt, LockTargetId, LockType, Verifier}; use rpc_toolkit::command; +use tracing::instrument; +use crate::config::not_found; use crate::context::RpcContext; -use crate::dependencies::{break_transitive, BreakageRes, DependencyError}; +use crate::db::model::CurrentDependents; +use crate::dependencies::{ + break_transitive, BreakTransitiveReceipts, BreakageRes, DependencyError, +}; use crate::s9pk::manifest::PackageId; use crate::util::serde::display_serializable; use crate::util::Version; use crate::Error; +pub struct UpdateReceipts { + break_receipts: BreakTransitiveReceipts, + current_dependents: LockReceipt, + dependency: LockReceipt, +} + +impl UpdateReceipts { + pub async fn new<'a>(db: &'a mut impl DbHandle) -> Result { + let mut locks = Vec::new(); + + let setup = Self::setup(&mut locks); + Ok(setup(&db.lock_all(locks).await?)?) + } + + pub fn setup(locks: &mut Vec) -> impl FnOnce(&Verifier) -> Result { + let break_receipts = BreakTransitiveReceipts::setup(locks); + let current_dependents = crate::db::DatabaseModel::new() + .package_data() + .star() + .installed() + .map(|x| x.current_dependents()) + .make_locker(LockType::Write) + .add_to_keys(locks); + let dependency = crate::db::DatabaseModel::new() + .package_data() + .star() + .installed() + .map(|x| x.manifest().dependencies().star()) + .make_locker(LockType::Write) + .add_to_keys(locks); + move |skeleton_key| { + Ok(Self { + break_receipts: break_receipts(skeleton_key)?, + current_dependents: current_dependents.verify(skeleton_key)?, + dependency: dependency.verify(skeleton_key)?, + }) + } + } +} + #[command(subcommands(dry))] pub async fn update() -> Result<(), Error> { Ok(()) } +#[instrument(skip(ctx))] #[command(display(display_serializable))] pub async fn dry( #[context] ctx: RpcContext, @@ -24,52 +70,34 @@ pub async fn dry( let mut db = ctx.db.handle(); let mut tx = db.begin().await?; let mut breakages = BTreeMap::new(); - let receipts = crate::dependencies::BreakTransitiveReceipts::new(&mut tx).await?; - crate::db::DatabaseModel::new() - .package_data() - .lock(&mut tx, LockType::Read) - .await?; + let receipts = UpdateReceipts::new(&mut tx).await?; - for dependent in crate::db::DatabaseModel::new() - .package_data() - .idx_model(&id) - .and_then(|m| m.installed()) - .expect(&mut tx) - .await? - .current_dependents() - .keys(&mut tx, true) + for dependent in receipts + .current_dependents + .get(&mut tx, &id) .await? + .ok_or_else(not_found)? + .0 + .keys() .into_iter() - .filter(|dependent| &id != dependent) + .filter(|dependent| &&id != dependent) { - let version_req = crate::db::DatabaseModel::new() - .package_data() - .idx_model(&dependent) - .and_then(|m| m.installed()) - .expect(&mut tx) - .await? - .manifest() - .dependencies() - .idx_model(&id) - .expect(&mut tx) - .await? - .get(&mut tx, true) - .await? - .into_owned() - .version; - if !version.satisfies(&version_req) { - break_transitive( - &mut tx, - &dependent, - &id, - DependencyError::IncorrectVersion { - expected: version_req, - received: version.clone(), - }, - &mut breakages, - &receipts, - ) - .await?; + if let Some(dep_info) = receipts.dependency.get(&mut tx, (&dependent, &id)).await? { + let version_req = dep_info.version; + if !version.satisfies(&version_req) { + break_transitive( + &mut tx, + &dependent, + &id, + DependencyError::IncorrectVersion { + expected: version_req, + received: version.clone(), + }, + &mut breakages, + &receipts.break_receipts, + ) + .await?; + } } } tx.abort().await?;