diff --git a/appmgr/src/install/mod.rs b/appmgr/src/install/mod.rs index d1453a462..121492851 100644 --- a/appmgr/src/install/mod.rs +++ b/appmgr/src/install/mod.rs @@ -935,8 +935,8 @@ pub async fn install_s9pk( .. } = prev { - let mut configured = prev.status.configured; - if let Some(res) = prev_manifest + let prev_is_configured = prev.status.configured; + let prev_migration = prev_manifest .migrations .to( ctx, @@ -945,14 +945,8 @@ pub async fn install_s9pk( &prev_manifest.version, &prev_manifest.volumes, ) - .await? - { - configured &= res.configured; - } - if &prev.manifest.version != version { - cleanup(ctx, &prev.manifest.id, &prev.manifest.version).await?; - } - if let Some(res) = manifest + .map(futures::future::Either::Left); + let migration = manifest .migrations .from( ctx, @@ -961,10 +955,20 @@ pub async fn install_s9pk( version, &manifest.volumes, ) - .await? - { - configured &= res.configured; - } + .map(futures::future::Either::Right); + + let viable_migration = if prev_manifest.version > manifest.version { + prev_migration.or(migration) + } else { + migration.or(prev_migration) + }; + + let configured = prev_is_configured + && if let Some(f) = viable_migration { + f.await?.configured + } else { + false + }; if configured && manifest.config.is_some() { crate::config::configure( ctx, @@ -1002,6 +1006,9 @@ pub async fn install_s9pk( .collect::>(), ) .await?; + if &prev.manifest.version != version { + cleanup(ctx, &prev.manifest.id, &prev.manifest.version).await?; + } } else if let PackageDataEntry::Restoring { .. } = prev { manifest .backup @@ -1051,12 +1058,12 @@ async fn handle_recovered_package( version: &Version, tx: &mut patch_db::Transaction<&mut patch_db::PatchDbHandle>, ) -> Result<(), Error> { - let configured = if let Some(res) = manifest - .migrations - .from(ctx, &recovered.version, pkg_id, version, &manifest.volumes) - .await? + let configured = if let Some(migration) = + manifest + .migrations + .from(ctx, &recovered.version, pkg_id, version, &manifest.volumes) { - res.configured + migration.await?.configured } else { false }; diff --git a/appmgr/src/migration.rs b/appmgr/src/migration.rs index 875701835..a01825141 100644 --- a/appmgr/src/migration.rs +++ b/appmgr/src/migration.rs @@ -1,5 +1,6 @@ use color_eyre::eyre::eyre; use emver::VersionRange; +use futures::{Future, FutureExt, TryFutureExt}; use indexmap::IndexMap; use patch_db::HasModel; use serde::{Deserialize, Serialize}; @@ -20,76 +21,77 @@ pub struct Migrations { } impl Migrations { #[instrument(skip(ctx))] - pub async fn from( - &self, - ctx: &RpcContext, - version: &Version, - pkg_id: &PackageId, - pkg_version: &Version, - volumes: &Volumes, - ) -> Result, Error> { - Ok( - if let Some((_, migration)) = self - .from - .iter() - .find(|(range, _)| version.satisfies(*range)) - { - Some( - migration - .execute( - ctx, - pkg_id, - pkg_version, - Some("Migration"), // Migrations cannot be executed concurrently - volumes, - Some(version), - false, - None, - ) - .await? - .map_err(|e| { - Error::new(eyre!("{}", e.1), crate::ErrorKind::MigrationFailed) - })?, - ) - } else { - None - }, - ) + pub fn from<'a>( + &'a self, + ctx: &'a RpcContext, + version: &'a Version, + pkg_id: &'a PackageId, + pkg_version: &'a Version, + volumes: &'a Volumes, + ) -> Option> + 'a> { + if let Some((_, migration)) = self + .from + .iter() + .find(|(range, _)| version.satisfies(*range)) + { + Some( + migration + .execute( + ctx, + pkg_id, + pkg_version, + Some("Migration"), // Migrations cannot be executed concurrently + volumes, + Some(version), + false, + None, + ) + .map(|r| { + r.and_then(|r| { + r.map_err(|e| { + Error::new(eyre!("{}", e.1), crate::ErrorKind::MigrationFailed) + }) + }) + }), + ) + } else { + None + } } + #[instrument(skip(ctx))] - pub async fn to( - &self, - ctx: &RpcContext, - version: &Version, - pkg_id: &PackageId, - pkg_version: &Version, - volumes: &Volumes, - ) -> Result, Error> { - Ok( - if let Some((_, migration)) = - self.to.iter().find(|(range, _)| version.satisfies(*range)) - { - Some( - migration - .execute( - ctx, - pkg_id, - pkg_version, - Some("Migration"), - volumes, - Some(version), - false, - None, - ) - .await? - .map_err(|e| { - Error::new(eyre!("{}", e.1), crate::ErrorKind::MigrationFailed) - })?, - ) - } else { - None - }, - ) + pub fn to<'a>( + &'a self, + ctx: &'a RpcContext, + version: &'a Version, + pkg_id: &'a PackageId, + pkg_version: &'a Version, + volumes: &'a Volumes, + ) -> Option> + 'a> { + if let Some((_, migration)) = self.to.iter().find(|(range, _)| version.satisfies(*range)) { + Some( + migration + .execute( + ctx, + pkg_id, + pkg_version, + Some("Migration"), + volumes, + Some(version), + false, + None, + ) + .map(|r| { + r.and_then(|r| { + r.map_err(|e| { + Error::new(eyre!("{}", e.1), crate::ErrorKind::MigrationFailed) + }) + }) + }), + ) + } else { + None + } } }