use std::collections::HashMap;
use anyhow::{anyhow, bail, ensure, Context as _, Result};
use serde_json::json;
use wash_lib::cli::link::{delete_link, get_links, LinkDelCommand};
use wash_lib::cli::{CommandOutput, OutputKind};
use wash_lib::config::WashConnectionOptions;
use wash_lib::generate::interactive::prompt_for_choice;
use wash_lib::generate::project_variables::StringEntry;
use crate::appearance::spinner::Spinner;
pub async fn invoke(
LinkDelCommand {
source_id,
link_name,
wit_namespace: namespace,
wit_package: package,
opts,
all,
force,
}: LinkDelCommand,
output_kind: OutputKind,
) -> Result<CommandOutput> {
let wco: WashConnectionOptions = opts.try_into()?;
if all {
let delete_links = |wco: WashConnectionOptions| async move {
let sp: Spinner = Spinner::new(&output_kind)?;
let links = get_links(wco.clone())
.await
.context("failed to retrieve links")?;
let mut deleted_links = Vec::with_capacity(links.len());
for link in &links {
sp.update_spinner_message(format!(
"Deleting link for {} on {}:{} ({}) ... ",
link.source_id(),
link.wit_namespace(),
link.wit_package(),
link.name(),
));
if let Err(e) = delete_link(
wco.clone(),
link.source_id(),
link.name(),
link.wit_namespace(),
link.wit_package(),
)
.await
.context("failed to delete link, aborting delete all operation")
{
return Ok::<CommandOutput, anyhow::Error>(CommandOutput::new(
format!("Deleted some {} links successfully", links.len(),),
HashMap::from([
("error".into(), json!(e.to_string())),
(
"deleted".into(),
json!(deleted_links.into_iter().collect::<Vec<_>>()),
),
]),
));
}
deleted_links.push(link);
}
sp.finish_and_clear();
Ok::<CommandOutput, anyhow::Error>(CommandOutput::new(
format!("Deleted all links ({}) successfully", links.len(),),
HashMap::from([(
"deleted".into(),
json!(deleted_links.into_iter().collect::<Vec<_>>()),
)]),
))
};
if force {
return delete_links(wco.clone())
.await
.context("failed to delete all links");
} else {
match prompt_for_choice(
&StringEntry {
default: Some("cancel".to_string()),
choices: Some(vec!["Delete all links".to_string(), "Cancel".to_string()]),
regex: None,
},
"Are you sure you want to delete all links in the cluster? (this action cannot be reversed)",
) {
Ok(0) => return delete_links(wco.clone()).await.context("failed to delete all links"),
Ok(1) => bail!("Link deletion cancelled"),
_ => unreachable!("unexpected choice received"),
}
}
}
let sp: Spinner = Spinner::new(&output_kind)?;
let package = package.context("missing required argument package")?;
let source_id = source_id.context("missing required argument source_id")?;
let namespace = namespace.context("missing required argument namespace")?;
if link_name.is_none() {
let similar_link_count = get_links(wco.clone())
.await
.map_err(|e| {
anyhow!(e).context("failed to retrieve links while checking for multiple")
})?
.into_iter()
.filter(|l| {
l.source_id() == source_id
&& l.wit_namespace() == namespace
&& l.wit_package() == package
})
.collect::<Vec<_>>()
.len();
ensure!(
similar_link_count <= 1,
"More than one similar link found, please specify link name explicitly"
);
};
let link_name = link_name.clone().unwrap_or_else(|| "default".to_string());
sp.update_spinner_message(format!(
"Deleting link for {source_id} on {namespace}:{package} ({link_name}) ... ",
));
let failure = delete_link(wco, &source_id, &link_name, &namespace, &package)
.await
.map_or_else(|e| Some(format!("{e}")), |_| None);
link_del_output(&source_id, &link_name, &namespace, &package, failure)
}
fn link_del_output(
source_id: &str,
link_name: &str,
wit_namespace: &str,
wit_package: &str,
failure: Option<String>,
) -> Result<CommandOutput> {
match failure {
None => {
let mut map = HashMap::new();
map.insert("source_id".to_string(), json!(source_id));
map.insert("wit_namespace".to_string(), json!(wit_namespace));
map.insert("wit_package".to_string(), json!(wit_package));
map.insert("link_name".to_string(), json!(link_name));
Ok(CommandOutput::new(
format!(
"Deleted link for {source_id} on {wit_namespace}:{wit_package} ({link_name}) successfully"
),
map,
))
}
Some(f) => bail!("Error deleting link: {}", f),
}
}