sneakerweb 1.2.0

A parallel web transported by physical media
use crate::util::*;
use anyhow::{Context, Result, bail};
use clap::Args;
use std::collections::BTreeSet;
use std::path::PathBuf;
use willow25::{prelude::*, storage::*};

#[derive(Args)]
pub struct RemoveArgs {
    /// The sneakerweb domain(s) to remove.
    pub domain: Vec<String>,
    /// A path to the collection from which to remove the domain.
    ///
    /// If no collection is specified, the specified domain is removed from the
    /// default collection (either specified by the `DEFAULT_SNEAKERWEB_COLLECTION` environment
    /// variable, or stored at ~/.sneakerweb if no default is set).
    #[arg(short, long)]
    pub collection: Option<PathBuf>,
}

pub async fn remove(args: &RemoveArgs) -> Result<()> {
    let mut domains = args
        .domain
        .iter()
        .map(|domain| parse_domain(domain))
        .collect::<Result<BTreeSet<_>>>()
        .context("one or more of the specified domains are invalid")?;

    if domains.is_empty() {
        domains.insert(get_domain(None, "remove")?);
    }

    let sneakerweb_fs_path = sneakerweb_dir(args.collection.as_ref()).await?;

    let mut store = PersistentStore::new(&sneakerweb_fs_path)
        .await
        .context("could not open sneakerweb storage")?;

    let mut any_failed = false;

    for domain in domains {
        let (domain_id, domain) = domain;

        match store
            .forget_area(
                &NamespaceId::from_bytes(&SNEAKERWEB_NAMESPACE_ID_BYTES),
                &Area::new_subspace_area(domain_id),
            )
            .await
        {
            Ok(_) => {
                yay(&format!(
                    "forgot entries for domain {}",
                    domain_style(&domain)
                ))
                .await
            }
            Err(_) => {
                any_failed = true;
                oh_no(&format!(
                    "failed to forget sneakerweb entries for domain {}",
                    domain_style(&domain)
                ))
                .await
            }
        }
    }

    if any_failed {
        bail!("one or more of the requested domains were not removed sucessfully");
    }

    Ok(())
}