quilt-rs 0.12.0

Rust library for accessing Quilt data packages.
Documentation
use tracing::{debug, info};

use crate::io::storage::Storage;
use crate::lineage::DomainLineage;
use crate::paths;
use crate::uri::Namespace;
use crate::Error;
use crate::Res;

/// Uninstall package: remove files from working directory, manifest from `.quilt` and from
/// `.quilt/lineage.json`.
pub async fn uninstall_package(
    mut lineage: DomainLineage,
    paths: &paths::DomainPaths,
    storage: &impl Storage,
    namespace: Namespace,
) -> Res<DomainLineage> {
    info!("âŗ Uninstalling package {}", namespace);

    debug!("🔍 Checking if package exists in lineage");
    lineage
        .packages
        .remove(&namespace)
        .ok_or(Error::PackageNotInstalled(namespace.to_owned()))?;
    debug!("âœ”ī¸ Package removed from lineage");

    debug!("âŗ Removing installed manifests");
    let manifest_path = paths.installed_manifests(&namespace);
    storage.remove_dir_all(&manifest_path).await?;
    debug!("âœ”ī¸ Removed manifests at: {}", manifest_path.display());

    debug!("âŗ Removing working directory");
    let package_home = paths::package_home(&lineage.home, &namespace);
    storage.remove_dir_all(&package_home).await?;
    debug!("âœ”ī¸ Removed working directory: {}", package_home.display());

    // TODO: Remove object files? But need to make sure no other manifest uses them.
    debug!("â„šī¸ Skipping object files cleanup - may be used by other packages");

    info!("âœ”ī¸ Successfully uninstalled package {}", namespace);
    Ok(lineage)
}

#[cfg(test)]
mod tests {
    use std::collections::BTreeMap;

    use super::*;

    use crate::io::storage::mocks::MockStorage;
    use crate::lineage::Home;
    use crate::lineage::PackageLineage;

    #[tokio::test]
    async fn test_panic_if_no_installed_package() {
        let lineage = DomainLineage::default();
        let storage = MockStorage::default();
        let paths = paths::DomainPaths::default();

        let result = uninstall_package(lineage, &paths, &storage, ("foo", "bar").into()).await;
        assert_eq!(
            result.unwrap_err().to_string(),
            "The given package is not installed: foo/bar"
        )
    }

    #[tokio::test]
    async fn test_uninstall_package() -> Res {
        let (home, _temp_dir) = Home::from_temp_dir()?;

        let namespace = Namespace::from(("foo", "bar"));

        let paths = paths::DomainPaths::default();
        let storage = MockStorage::default();

        paths
            .scaffold_for_installing(&storage, &home, &namespace)
            .await?;

        let lineage = DomainLineage {
            home,
            packages: BTreeMap::from([(namespace.clone(), PackageLineage::default())]),
        };

        let lineage = uninstall_package(lineage, &paths, &storage, namespace).await?;
        assert!(lineage.packages.is_empty());
        Ok(())
    }
}