mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-31 04:23:40 +00:00
175 lines
4.6 KiB
Rust
175 lines
4.6 KiB
Rust
use std::collections::HashMap;
|
|
|
|
use anyhow::anyhow;
|
|
use bollard::image::ListImagesOptions;
|
|
use patch_db::{DbHandle, PatchDbHandle};
|
|
|
|
use crate::context::RpcContext;
|
|
use crate::db::model::{InstalledPackageDataEntry, PackageDataEntry};
|
|
use crate::s9pk::manifest::PackageId;
|
|
use crate::util::Version;
|
|
use crate::Error;
|
|
|
|
pub async fn update_dependents<'a, Db: DbHandle, I: IntoIterator<Item = &'a PackageId>>(
|
|
ctx: &RpcContext,
|
|
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(ctx, 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(ctx: &RpcContext, id: &PackageId, version: &Version) -> Result<(), Error> {
|
|
ctx.managers.remove(&(id.clone(), version.clone())).await;
|
|
// docker images start9/$APP_ID/*:$VERSION -q | xargs docker rmi
|
|
let images = ctx
|
|
.docker
|
|
.list_images(Some(ListImagesOptions {
|
|
all: false,
|
|
filters: {
|
|
let mut f = HashMap::new();
|
|
f.insert(
|
|
"reference".to_owned(),
|
|
vec![format!("start9/{}/*:{}", id, version)],
|
|
);
|
|
f
|
|
},
|
|
digests: false,
|
|
}))
|
|
.await?;
|
|
futures::future::try_join_all(images.into_iter().map(|image| async {
|
|
let image = image; // move into future
|
|
ctx.docker.remove_image(&image.id, None, None).await
|
|
}))
|
|
.await?;
|
|
// TODO: delete public dir if not a dependency
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn cleanup_failed<Db: DbHandle>(
|
|
ctx: &RpcContext,
|
|
db: &mut Db,
|
|
id: &PackageId,
|
|
version: &Version,
|
|
) -> Result<(), Error> {
|
|
let pde = crate::db::DatabaseModel::new()
|
|
.package_data()
|
|
.idx_model(id)
|
|
.expect(db)
|
|
.await?
|
|
.get(db, true)
|
|
.await?
|
|
.to_owned();
|
|
if match &pde {
|
|
PackageDataEntry::Installing { .. } => true,
|
|
PackageDataEntry::Updating { manifest, .. } => {
|
|
if &manifest.version != version {
|
|
true
|
|
} else {
|
|
false
|
|
}
|
|
}
|
|
_ => {
|
|
log::warn!("{}: Nothing to clean up!", id);
|
|
false
|
|
}
|
|
} {
|
|
cleanup(ctx, id, version).await?;
|
|
}
|
|
|
|
match pde {
|
|
PackageDataEntry::Installing { .. } => {
|
|
crate::db::DatabaseModel::new()
|
|
.package_data()
|
|
.remove(db, id)
|
|
.await?;
|
|
}
|
|
PackageDataEntry::Updating {
|
|
installed,
|
|
manifest,
|
|
static_files,
|
|
..
|
|
} => {
|
|
crate::db::DatabaseModel::new()
|
|
.package_data()
|
|
.idx_model(id)
|
|
.put(
|
|
db,
|
|
&PackageDataEntry::Installed {
|
|
installed,
|
|
manifest,
|
|
static_files,
|
|
},
|
|
)
|
|
.await?;
|
|
}
|
|
_ => (),
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
pub async fn uninstall(
|
|
ctx: &RpcContext,
|
|
db: &mut PatchDbHandle,
|
|
entry: &InstalledPackageDataEntry,
|
|
) -> Result<(), Error> {
|
|
cleanup(ctx, &entry.manifest.id, &entry.manifest.version).await?;
|
|
let mut tx = db.begin().await?;
|
|
crate::db::DatabaseModel::new()
|
|
.package_data()
|
|
.remove(&mut tx, &entry.manifest.id)
|
|
.await?;
|
|
update_dependents(
|
|
ctx,
|
|
&mut tx,
|
|
&entry.manifest.id,
|
|
entry.current_dependents.keys(),
|
|
)
|
|
.await?;
|
|
tx.commit(None).await?;
|
|
Ok(())
|
|
}
|