From 5e3412d73530eacd3db4a150345b07dc58898c70 Mon Sep 17 00:00:00 2001 From: J H <2364004+Blu-J@users.noreply.github.com> Date: Fri, 29 Sep 2023 12:08:53 -0600 Subject: [PATCH] feat: Change all the dependency errors at once (#2427) * feat: Change all the dependency errors at once * remove deprecated dependency-errors field * set pointers to [] by default * chore: Something about fixing the build * fix migration --------- Co-authored-by: Aiden McClelland --- backend/Cargo.lock | 4 +- backend/src/context/rpc.rs | 63 +++++++++--- backend/src/db/model.rs | 1 + backend/src/init.rs | 11 ++- backend/src/install/mod.rs | 1 - backend/src/status/mod.rs | 2 - backend/src/version/mod.rs | 6 +- backend/src/version/v0_3_5.rs | 98 +++++++++++++++++++ .../apps-routes/app-show/app-show.page.ts | 2 +- .../ui/src/app/services/api/api.fixures.ts | 6 +- .../ui/src/app/services/api/mock-patch.ts | 8 +- .../src/app/services/patch-db/data-model.ts | 2 +- 12 files changed, 170 insertions(+), 34 deletions(-) create mode 100644 backend/src/version/v0_3_5.rs diff --git a/backend/Cargo.lock b/backend/Cargo.lock index 782823a4a..5a65c699f 100644 --- a/backend/Cargo.lock +++ b/backend/Cargo.lock @@ -2120,9 +2120,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.6" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b297dc40733f23a0e52728a58fa9489a5b7638a324932de16b41adc3ef80730" +checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" dependencies = [ "console", "instant", diff --git a/backend/src/context/rpc.rs b/backend/src/context/rpc.rs index f01ec2ce7..cd3f1676c 100644 --- a/backend/src/context/rpc.rs +++ b/backend/src/context/rpc.rs @@ -22,6 +22,7 @@ use crate::account::AccountInfo; use crate::core::rpc_continuations::{RequestGuid, RestHandler, RpcContinuation}; use crate::db::model::{CurrentDependents, Database, PackageDataEntryMatchModelRef}; use crate::db::prelude::PatchDbExt; +use crate::dependencies::compute_dependency_config_errs; use crate::disk::OsPartitionInfo; use crate::init::init_postgres; use crate::install::cleanup::{cleanup_failed, uninstall}; @@ -155,8 +156,7 @@ impl RpcContext { .unwrap_or(SocketAddr::from(([127, 0, 0, 1], 9051))), tor_proxy, base.dns_bind - .as_ref() - .map(|v| v.as_slice()) + .as_deref() .unwrap_or(&[SocketAddr::from(([127, 0, 0, 1], 53))]), SslManager::new(&account)?, &account.hostname, @@ -217,11 +217,8 @@ impl RpcContext { }); let res = Self(seed.clone()); - res.cleanup().await?; + res.cleanup_and_initialize().await?; tracing::info!("Cleaned up transient states"); - let peeked = res.db.peek().await?; - res.managers.init(res.clone(), peeked).await?; - tracing::info!("Initialized Package Managers"); Ok(res) } @@ -236,7 +233,7 @@ impl RpcContext { } #[instrument(skip(self))] - pub async fn cleanup(&self) -> Result<(), Error> { + pub async fn cleanup_and_initialize(&self) -> Result<(), Error> { self.db .mutate(|f| { let mut current_dependents = f @@ -278,9 +275,10 @@ impl RpcContext { Ok(()) }) .await?; + let peek = self.db.peek().await?; + for (package_id, package) in peek.as_package_data().as_entries()?.into_iter() { - let package = package.clone(); let action = match package.as_match() { PackageDataEntryMatchModelRef::Installing(_) | PackageDataEntryMatchModelRef::Restoring(_) @@ -298,7 +296,7 @@ impl RpcContext { &self.datadir, &package_id, &version, - &volume_id, + volume_id, )) .with_kind(ErrorKind::Filesystem)?; if tokio::fs::metadata(&tmp_path).await.is_ok() { @@ -314,7 +312,8 @@ impl RpcContext { tracing::debug!("{:?}", e); } } - self.db + let peek = self + .db .mutate(|v| { for (_, pde) in v.as_package_data_mut().as_entries_mut()? { let status = pde @@ -329,9 +328,49 @@ impl RpcContext { MainStatus::Stopped })?; } + Ok(v.clone()) + }) + .await?; + self.managers.init(self.clone(), peek.clone()).await?; + tracing::info!("Initialized Package Managers"); + + let mut all_dependency_config_errs = BTreeMap::new(); + for (package_id, package) in peek.as_package_data().as_entries()?.into_iter() { + let package = package.clone(); + if let Some(current_dependencies) = package + .as_installed() + .and_then(|x| x.as_current_dependencies().de().ok()) + { + let manifest = package.as_manifest().de()?; + all_dependency_config_errs.insert( + package_id.clone(), + compute_dependency_config_errs( + self, + &peek, + &manifest, + ¤t_dependencies, + &Default::default(), + ) + .await?, + ); + } + } + self.db + .mutate(|v| { + for (package_id, errs) in all_dependency_config_errs { + if let Some(config_errors) = v + .as_package_data_mut() + .as_idx_mut(&package_id) + .and_then(|pde| pde.as_installed_mut()) + .map(|i| i.as_status_mut().as_dependency_config_errors_mut()) + { + config_errors.ser(&errs)?; + } + } Ok(()) }) .await?; + Ok(()) } @@ -389,7 +428,7 @@ impl RpcContext { } impl AsRef for RpcContext { fn as_ref(&self) -> &Jwk { - &*CURRENT_SECRET + &CURRENT_SECRET } } impl Context for RpcContext {} @@ -403,7 +442,7 @@ impl Deref for RpcContext { tracing_error::SpanTrace::capture() ); } - &*self.0 + &self.0 } } impl Drop for RpcContext { diff --git a/backend/src/db/model.rs b/backend/src/db/model.rs index 879feb644..b23a3b149 100644 --- a/backend/src/db/model.rs +++ b/backend/src/db/model.rs @@ -480,6 +480,7 @@ pub struct StaticDependencyInfo { #[serde(rename_all = "kebab-case")] #[model = "Model"] pub struct CurrentDependencyInfo { + #[serde(default)] pub pointers: BTreeSet, pub health_checks: BTreeSet, } diff --git a/backend/src/init.rs b/backend/src/init.rs index 8a5ae2484..3bf8dde64 100644 --- a/backend/src/init.rs +++ b/backend/src/init.rs @@ -200,11 +200,6 @@ pub async fn init(cfg: &RpcContextConfig) -> Result { let account = AccountInfo::load(&secret_store).await?; let db = cfg.db(&account).await?; - db.mutate(|d| { - let model = d.de()?; - d.ser(&model) - }) - .await?; tracing::info!("Opened PatchDB"); let peek = db.peek().await?; let mut server_info = peek.as_server_info().de()?; @@ -375,6 +370,12 @@ pub async fn init(cfg: &RpcContextConfig) -> Result { crate::version::init(&db, &secret_store).await?; + db.mutate(|d| { + let model = d.de()?; + d.ser(&model) + }) + .await?; + if should_rebuild { match tokio::fs::remove_file(SYSTEM_REBUILD_PATH).await { Ok(()) => Ok(()), diff --git a/backend/src/install/mod.rs b/backend/src/install/mod.rs index a85c7c823..4f77ae1fa 100644 --- a/backend/src/install/mod.rs +++ b/backend/src/install/mod.rs @@ -1105,7 +1105,6 @@ pub async fn install_s9pk( status: Status { configured: manifest.config.is_none(), main: MainStatus::Stopped, - dependency_errors: Default::default(), dependency_config_errors: compute_dependency_config_errs( &ctx, &peek, diff --git a/backend/src/status/mod.rs b/backend/src/status/mod.rs index f6290be12..2a5a9391f 100644 --- a/backend/src/status/mod.rs +++ b/backend/src/status/mod.rs @@ -16,8 +16,6 @@ pub struct Status { pub configured: bool, pub main: MainStatus, #[serde(default)] - pub dependency_errors: BTreeMap<(), ()>, // TODO: remove - #[serde(default)] pub dependency_config_errors: DependencyConfigErrors, } diff --git a/backend/src/version/mod.rs b/backend/src/version/mod.rs index e145e324a..efdf1a387 100644 --- a/backend/src/version/mod.rs +++ b/backend/src/version/mod.rs @@ -13,8 +13,9 @@ mod v0_3_4_1; mod v0_3_4_2; mod v0_3_4_3; mod v0_3_4_4; +mod v0_3_5; -pub type Current = v0_3_4_4::Version; +pub type Current = v0_3_5::Version; #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[serde(untagged)] @@ -24,6 +25,7 @@ enum Version { V0_3_4_2(Wrapper), V0_3_4_3(Wrapper), V0_3_4_4(Wrapper), + V0_3_5(Wrapper), Other(emver::Version), } @@ -44,6 +46,7 @@ impl Version { Version::V0_3_4_2(Wrapper(x)) => x.semver(), Version::V0_3_4_3(Wrapper(x)) => x.semver(), Version::V0_3_4_4(Wrapper(x)) => x.semver(), + Version::V0_3_5(Wrapper(x)) => x.semver(), Version::Other(x) => x.clone(), } } @@ -168,6 +171,7 @@ pub async fn init(db: &PatchDb, secrets: &PgPool) -> Result<(), Error> { Version::V0_3_4_2(v) => v.0.migrate_to(&Current::new(), db.clone(), secrets).await?, Version::V0_3_4_3(v) => v.0.migrate_to(&Current::new(), db.clone(), secrets).await?, Version::V0_3_4_4(v) => v.0.migrate_to(&Current::new(), db.clone(), secrets).await?, + Version::V0_3_5(v) => v.0.migrate_to(&Current::new(), db.clone(), secrets).await?, Version::Other(_) => { return Err(Error::new( eyre!("Cannot downgrade"), diff --git a/backend/src/version/v0_3_5.rs b/backend/src/version/v0_3_5.rs new file mode 100644 index 000000000..e3a142470 --- /dev/null +++ b/backend/src/version/v0_3_5.rs @@ -0,0 +1,98 @@ +use std::collections::BTreeMap; +use std::path::Path; + +use async_trait::async_trait; +use emver::VersionRange; +use models::DataUrl; +use sqlx::PgPool; + +use super::v0_3_4::V0_3_0_COMPAT; +use super::{v0_3_4_4, VersionT}; +use crate::prelude::*; + +const V0_3_5: emver::Version = emver::Version::new(0, 3, 5, 0); + +#[derive(Clone, Debug)] +pub struct Version; + +#[async_trait] +impl VersionT for Version { + type Previous = v0_3_4_4::Version; + fn new() -> Self { + Version + } + fn semver(&self) -> emver::Version { + V0_3_5 + } + fn compat(&self) -> &'static VersionRange { + &V0_3_0_COMPAT + } + async fn up(&self, db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + let peek = db.peek().await?; + let mut url_replacements = BTreeMap::new(); + for (_, pde) in peek.as_package_data().as_entries()? { + for (dependency, info) in pde + .as_installed() + .map(|i| i.as_dependency_info().as_entries()) + .transpose()? + .into_iter() + .flatten() + { + if !url_replacements.contains_key(&dependency) { + url_replacements.insert( + dependency, + DataUrl::from_path( + <&Value>::from(info.as_icon()) + .as_str() + .and_then(|i| i.strip_prefix("/public/package-data/")) + .map(|path| { + Path::new("/embassy-data/package-data/public").join(path) + }) + .unwrap_or_default(), + ) + .await + .unwrap_or_else(|_| { + DataUrl::from_slice( + "image/png", + include_bytes!("../install/package-icon.png"), + ) + }), + ); + } + } + } + db.mutate(|v| { + for (_, pde) in v.as_package_data_mut().as_entries_mut()? { + for (dependency, info) in pde + .as_installed_mut() + .map(|i| i.as_dependency_info_mut().as_entries_mut()) + .transpose()? + .into_iter() + .flatten() + { + if let Some(url) = url_replacements.get(&dependency) { + info.as_icon_mut().ser(url)?; + } + let manifest = <&mut Value>::from(&mut *info) + .as_object_mut() + .and_then(|o| o.remove("manifest")); + if let Some(title) = manifest + .as_ref() + .and_then(|m| m.as_object()) + .and_then(|m| m.get("title")) + .and_then(|t| t.as_str()) + .map(|s| s.to_owned()) + { + info.as_title_mut().ser(&title)?; + } + } + } + Ok(()) + }) + .await?; + Ok(()) + } + async fn down(&self, _db: PatchDb, _secrets: &PgPool) -> Result<(), Error> { + Ok(()) + } +} diff --git a/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.ts b/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.ts index 0a82d89b9..4257f916d 100644 --- a/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.ts +++ b/frontend/projects/ui/src/app/pages/apps-routes/app-show/app-show.page.ts @@ -120,7 +120,7 @@ export class AppShowPage { return { id: depId, version: pkgInstalled.manifest.dependencies[depId].version, // do we want this version range? - title: depInfo?.manifest?.title || depId, + title: depInfo?.title || depId, icon: depInfo?.icon || '', errorText: errorText ? `${errorText}. ${pkgInstalled.manifest.title} will not work as expected.` diff --git a/frontend/projects/ui/src/app/services/api/api.fixures.ts b/frontend/projects/ui/src/app/services/api/api.fixures.ts index 7d447573b..e6ca7e07f 100644 --- a/frontend/projects/ui/src/app/services/api/api.fixures.ts +++ b/frontend/projects/ui/src/app/services/api/api.fixures.ts @@ -1958,7 +1958,7 @@ export module Mock { }, 'dependency-info': { bitcoind: { - manifest: Mock.MockManifestBitcoind, + title: Mock.MockManifestBitcoind.title, icon: 'assets/img/service-icons/bitcoind.svg', }, }, @@ -2012,11 +2012,11 @@ export module Mock { }, 'dependency-info': { bitcoind: { - manifest: Mock.MockManifestBitcoind, + title: Mock.MockManifestBitcoind.title, icon: 'assets/img/service-icons/bitcoind.svg', }, 'btc-rpc-proxy': { - manifest: Mock.MockManifestBitcoinProxy, + title: Mock.MockManifestBitcoinProxy.title, icon: 'assets/img/service-icons/btc-rpc-proxy.png', }, }, diff --git a/frontend/projects/ui/src/app/services/api/mock-patch.ts b/frontend/projects/ui/src/app/services/api/mock-patch.ts index 6cf5fa7e1..4672efaa0 100644 --- a/frontend/projects/ui/src/app/services/api/mock-patch.ts +++ b/frontend/projects/ui/src/app/services/api/mock-patch.ts @@ -664,15 +664,11 @@ export const mockPatchData: DataModel = { }, 'dependency-info': { bitcoind: { - manifest: { - title: 'Bitcoin Core', - } as Manifest, + title: 'Bitcoin Core', icon: 'assets/img/service-icons/bitcoind.svg', }, 'btc-rpc-proxy': { - manifest: { - title: 'Bitcoin Proxy', - } as Manifest, + title: 'Bitcoin Proxy', icon: 'assets/img/service-icons/btc-rpc-proxy.png', }, }, diff --git a/frontend/projects/ui/src/app/services/patch-db/data-model.ts b/frontend/projects/ui/src/app/services/patch-db/data-model.ts index 554a0dc30..b175d89ca 100644 --- a/frontend/projects/ui/src/app/services/patch-db/data-model.ts +++ b/frontend/projects/ui/src/app/services/patch-db/data-model.ts @@ -132,7 +132,7 @@ export interface InstalledPackageDataEntry { 'current-dependencies': { [id: string]: CurrentDependencyInfo } 'dependency-info': { [id: string]: { - manifest: Manifest + title: string icon: Url } }