diff --git a/appmgr/src/config/mod.rs b/appmgr/src/config/mod.rs index afe8fa7dd..f464ee837 100644 --- a/appmgr/src/config/mod.rs +++ b/appmgr/src/config/mod.rs @@ -17,7 +17,9 @@ use crate::config::spec::PackagePointerSpecVariant; use crate::context::{EitherContext, ExtendedContext}; use crate::db::model::{CurrentDependencyInfo, InstalledPackageDataEntryModel}; use crate::db::util::WithRevision; -use crate::dependencies::{BreakageRes, DependencyError, TaggedDependencyError}; +use crate::dependencies::{ + update_current_dependents, BreakageRes, DependencyError, TaggedDependencyError, +}; use crate::s9pk::manifest::PackageId; use crate::util::{ display_none, display_serializable, parse_duration, parse_stdin_deserializable, IoFormat, @@ -396,21 +398,7 @@ pub fn configure<'a, Db: DbHandle>( }; // update dependencies - for (dependency, dep_info) in current_dependencies { - if let Some(dependency_model) = crate::db::DatabaseModel::new() - .package_data() - .idx_model(&dependency) - .and_then(|pkg| pkg.installed()) - .check(db) - .await? - { - dependency_model - .current_dependents() - .idx_model(id) - .put(db, &dep_info) - .await?; - } - } + update_current_dependents(db, id, ¤t_dependencies).await?; // cache current config for dependents overrides.insert(id.clone(), config.clone()); diff --git a/appmgr/src/config/spec.rs b/appmgr/src/config/spec.rs index fac60719c..278800abd 100644 --- a/appmgr/src/config/spec.rs +++ b/appmgr/src/config/spec.rs @@ -245,7 +245,7 @@ pub struct WithDescription { pub description: Option, pub name: String, #[serde(skip_serializing_if = "Option::is_none")] - pub change_warning: Option, + pub warning: Option, } #[async_trait] impl ValueSpec for WithDescription @@ -318,7 +318,7 @@ pub enum ValueSpecAny { Enum(WithDescription>), List(ValueSpecList), Number(WithDescription>>), - Object(WithDescription>), + Object(WithDescription), String(WithDescription>>), Union(WithDescription>), Pointer(WithDescription), @@ -947,8 +947,6 @@ impl DefaultableWith for ValueSpecNumber { #[serde(rename_all = "kebab-case")] pub struct ValueSpecObject { pub spec: ConfigSpec, - #[serde(default)] - pub null_by_default: bool, pub display_as: Option, #[serde(default)] pub unique_by: UniqueBy, @@ -1016,11 +1014,7 @@ impl DefaultableWith for ValueSpecObject { _rng: &mut R, _timeout: &Option, ) -> Result { - if self.null_by_default { - Ok(Value::Null) - } else { - Ok(Value::Object(spec.clone())) - } + Ok(Value::Object(spec.clone())) } } impl Defaultable for ValueSpecObject { @@ -1031,11 +1025,7 @@ impl Defaultable for ValueSpecObject { rng: &mut R, timeout: &Option, ) -> Result { - if self.null_by_default { - Ok(Value::Null) - } else { - self.spec.gen(rng, timeout).map(Value::Object) - } + self.spec.gen(rng, timeout).map(Value::Object) } } diff --git a/appmgr/src/dependencies.rs b/appmgr/src/dependencies.rs index e343707a0..0c3c64f6f 100644 --- a/appmgr/src/dependencies.rs +++ b/appmgr/src/dependencies.rs @@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize}; use crate::action::ActionImplementation; use crate::config::{Config, ConfigSpec}; +use crate::db::model::CurrentDependencyInfo; use crate::net::interface::InterfaceId; use crate::s9pk::manifest::PackageId; use crate::status::health_check::{HealthCheckId, HealthCheckResult, HealthCheckResultVariant}; @@ -254,3 +255,26 @@ impl DependencyConfig { .map_err(|e| Error::new(anyhow!("{}", e.1), crate::ErrorKind::AutoConfigure)) } } + +pub async fn update_current_dependents( + db: &mut Db, + dependent_id: &PackageId, + current_dependencies: &IndexMap, +) -> Result<(), Error> { + for (dependency, dep_info) in current_dependencies { + if let Some(dependency_model) = crate::db::DatabaseModel::new() + .package_data() + .idx_model(&dependency) + .and_then(|pkg| pkg.installed()) + .check(db) + .await? + { + dependency_model + .current_dependents() + .idx_model(dependent_id) + .put(db, &dep_info) + .await?; + } + } + Ok(()) +} diff --git a/appmgr/src/install/cleanup.rs b/appmgr/src/install/cleanup.rs index bd2573a12..6940c9f18 100644 --- a/appmgr/src/install/cleanup.rs +++ b/appmgr/src/install/cleanup.rs @@ -1,7 +1,73 @@ +use std::borrow::Cow; + +use anyhow::anyhow; +use patch_db::DbHandle; + use crate::db::model::InstalledPackageDataEntry; +use crate::dependencies::DependencyError; use crate::s9pk::manifest::{Manifest, PackageId}; +use crate::util::Version; use crate::Error; -pub async fn cleanup(info: Result) -> Result<(), Error> { +pub async fn update_dependents<'a, Db: DbHandle, I: IntoIterator>( + db: &mut Db, + id: &PackageId, + deps: I, +) -> Result<(), Error> { + for dep in deps { + let man = crate::db::DatabaseModel::new() + .package_data() + .idx_model(&dep) + .expect(db) + .await? + .installed() + .expect(db) + .await? + .manifest() + .get(db, true) + .await?; + if let Err(e) = man + .dependencies + .0 + .get(id) + .ok_or_else(|| { + Error::new( + anyhow!("missing dependency info"), + crate::ErrorKind::Database, + ) + })? + .satisfied(db, id, None, dep, &man.version, &man.volumes) + .await? + { + let mut errs = crate::db::DatabaseModel::new() + .package_data() + .idx_model(&dep) + .expect(db) + .await? + .installed() + .expect(db) + .await? + .status() + .dependency_errors() + .get_mut(db) + .await?; + errs.0.insert(id.clone(), e); + errs.save(db).await?; + } + } + Ok(()) +} + +pub async fn cleanup( + db: &mut Db, + info: Result, +) -> Result<(), Error> { + let man = match info { + Ok(pde) => { + todo!(); + Cow::Owned(pde.manifest) + } + Err(man) => Cow::Borrowed(man), + }; Ok(()) // TODO } diff --git a/appmgr/src/install/mod.rs b/appmgr/src/install/mod.rs index 563712f78..896774e2e 100644 --- a/appmgr/src/install/mod.rs +++ b/appmgr/src/install/mod.rs @@ -1,3 +1,4 @@ +use std::collections::HashSet; use std::fmt::Display; use std::io::SeekFrom; use std::path::Path; @@ -32,6 +33,8 @@ use crate::db::model::{ CurrentDependencyInfo, InstalledPackageDataEntry, PackageDataEntry, StaticDependencyInfo, StaticFiles, }; +use crate::dependencies::update_current_dependents; +use crate::install::cleanup::update_dependents; use crate::s9pk::manifest::{Manifest, PackageId}; use crate::s9pk::reader::S9pkReader; use crate::status::{DependencyErrors, MainStatus, Status}; @@ -234,8 +237,14 @@ pub async fn download_install_s9pk( .await; if let Err(e) = res { - if let Err(e) = cleanup(Err(temp_manifest)).await { - let mut handle = ctx.db.handle(); + let mut handle = ctx.db.handle(); + if let Err(e) = cleanup(&mut handle, Err(temp_manifest)).await { + log::error!( + "Failed to clean up {}@{}: {}: Adding to broken packages", + pkg_id, + version, + e + ); let mut broken = crate::db::DatabaseModel::new() .broken_packages() .get_mut(&mut handle) @@ -474,6 +483,31 @@ pub async fn install_s9pk( } }) .collect(); + update_current_dependents(&mut tx, pkg_id, ¤t_dependencies).await?; + let current_dependents = { + // search required dependencies + let mut deps = IndexMap::new(); + for package in crate::db::DatabaseModel::new() + .package_data() + .keys(&mut tx, true) + .await? + { + if let Some(dep) = crate::db::DatabaseModel::new() + .package_data() + .idx_model(&package) + .expect(&mut tx) + .await? + .installed() + .and_then(|i| i.current_dependencies().idx_model(pkg_id)) + .get(&mut tx, true) + .await? + .to_owned() + { + deps.insert(package, dep); + } + } + deps + }; let installed = InstalledPackageDataEntry { status: Status { configured: manifest.config.is_none(), @@ -484,30 +518,7 @@ pub async fn install_s9pk( manifest: manifest.clone(), system_pointers: Vec::new(), dependency_info, - current_dependents: { - // search required dependencies - let mut deps = IndexMap::new(); - for package in crate::db::DatabaseModel::new() - .package_data() - .keys(&mut tx, true) - .await? - { - if let Some(dep) = crate::db::DatabaseModel::new() - .package_data() - .idx_model(&package) - .expect(&mut tx) - .await? - .installed() - .and_then(|i| i.current_dependencies().idx_model(pkg_id)) - .get(&mut tx, true) - .await? - .to_owned() - { - deps.insert(package, dep); - } - } - deps - }, + current_dependents: current_dependents.clone(), current_dependencies, interface_addresses, }; @@ -521,12 +532,22 @@ pub async fn install_s9pk( }, ); pde.save(&mut tx).await?; + if let PackageDataEntry::Updating { installed: prev, manifest: prev_manifest, .. } = prev { + update_dependents( + &mut tx, + pkg_id, + current_dependents + .keys() + .chain(prev.current_dependents.keys()) + .collect::>(), + ) + .await?; let mut configured = prev.status.configured; if let Some(res) = prev_manifest .migrations @@ -540,7 +561,7 @@ pub async fn install_s9pk( { configured &= res.configured; } - cleanup(Ok(prev)).await?; + cleanup(&mut tx, Ok(prev)).await?; if let Some(res) = manifest .migrations .from(&prev_manifest.version, pkg_id, version, &manifest.volumes) @@ -562,6 +583,8 @@ pub async fn install_s9pk( .await?; todo!("set as running if viable"); } + } else { + update_dependents(&mut tx, pkg_id, current_dependents.keys()).await?; } sql_tx.commit().await?;