use crate::cli::args::BackendArg;
use crate::config::SETTINGS;
use crate::plugins::core::CORE_PLUGINS;
use itertools::Itertools;
use once_cell::sync::Lazy;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::iter::Iterator;
use url::Url;
include!(concat!(env!("OUT_DIR"), "/registry.rs"));
pub static REGISTRY: Lazy<BTreeMap<&str, Vec<String>>> = Lazy::new(|| {
let backend_types = vec![
"core", "ubi", "vfox", "asdf", "aqua", "cargo", "go", "npm", "pipx", "spm",
]
.into_iter()
.filter(|b| !(*b == "asdf" && cfg!(windows)))
.filter(|b| !(*b == "aqua" && cfg!(unix) && !SETTINGS.experimental))
.filter(|b| !SETTINGS.disable_backends.contains(&b.to_string()))
.collect::<HashSet<_>>();
_REGISTRY
.iter()
.filter(|(id, _)| !CORE_PLUGINS.contains_key(*id))
.map(|(id, fulls)| {
let fulls = fulls
.iter()
.filter(|full| {
full.split(':')
.next()
.map_or(false, |b| backend_types.contains(b))
})
.map(|full| full.to_string())
.collect::<Vec<_>>();
(*id, fulls)
})
.filter(|(_, fulls)| !fulls.is_empty())
.collect()
});
pub static REGISTRY_BACKEND_MAP: Lazy<HashMap<&'static str, Vec<BackendArg>>> = Lazy::new(|| {
REGISTRY
.iter()
.map(|(short, full)| {
(
*short,
full.iter().map(|f| BackendArg::new(short, f)).collect(),
)
})
.collect()
});
pub static REGISTRY_VFOX: Lazy<BTreeMap<&str, &str>> = Lazy::new(|| {
_REGISTRY
.iter()
.filter_map(|(id, fulls)| {
let vfox_fulls = fulls
.iter()
.filter(|full| full.starts_with("vfox:"))
.collect_vec();
if vfox_fulls.is_empty() {
None
} else {
Some((id, vfox_fulls[0]))
}
})
.map(|(k, v)| (*k, *v))
.collect()
});
pub static TRUSTED_SHORTHANDS: Lazy<BTreeSet<&'static str>> =
Lazy::new(|| _TRUSTED_IDS.iter().copied().collect());
pub fn is_trusted_plugin(name: &str, remote: &str) -> bool {
let normalized_url = normalize_remote(remote).unwrap_or("INVALID_URL".into());
let is_shorthand = REGISTRY
.get(name)
.and_then(|fulls| fulls.first())
.map(|full| full_to_url(full))
.is_some_and(|s| normalize_remote(&s).unwrap_or_default() == normalized_url);
let is_mise_url = normalized_url.starts_with("github.com/mise-plugins/");
!is_shorthand || is_mise_url || TRUSTED_SHORTHANDS.contains(name)
}
fn normalize_remote(remote: &str) -> eyre::Result<String> {
let url = Url::parse(remote)?;
let host = url.host_str().unwrap();
let path = url.path().trim_end_matches(".git");
Ok(format!("{host}{path}"))
}
pub fn full_to_url(full: &str) -> String {
let (_backend, url) = full.split_once(':').unwrap_or(("", full));
if url.starts_with("https://") {
url.to_string()
} else {
format!("https://github.com/{url}.git")
}
}