use std::collections::HashSet;
use crate::registry::{
schema::registry::PkgRegistryEntry,
search::{SearchEngine, SearchResult},
};
struct SearchNode {
registry_ref: String,
depth: usize,
}
impl SearchEngine {
pub async fn search_in_registry(
&mut self,
registry_ref: &str,
namespaces: Vec<&str>,
package: &str,
authority: Option<&str>,
version: Option<&str>,
hash: Option<&str>,
out: &mut Vec<SearchResult>,
) -> anyhow::Result<()> {
let mut visited = HashSet::new();
let mut stack = Vec::new();
stack.push(SearchNode {
registry_ref: registry_ref.to_owned(),
depth: 0,
});
while let Some(node) = stack.pop() {
if !visited.insert(node.registry_ref.clone()) {
continue;
}
let registry = self.load_registry(&node.registry_ref).await?;
if node.depth < namespaces.len() {
let wanted = namespaces[node.depth];
if let Some(authorities) = registry.authorities() {
for authority in authorities {
for reg in authority.registries() {
if reg.namespace() == wanted {
stack.push(SearchNode {
registry_ref: reg.ref_().to_owned(),
depth: node.depth + 1,
});
}
}
}
}
continue;
}
if let Some(packages) = registry.packages() {
for pkg in packages {
if match_pkg(&pkg, package, authority, version, hash) {
out.push(SearchResult::from_pkg_registry_entry(
pkg,
&node.registry_ref,
));
}
}
}
}
Ok(())
}
}
fn match_pkg(
x: &PkgRegistryEntry<'_>,
package: &str,
authority: Option<&str>,
version: Option<&str>,
hash: Option<&str>,
) -> bool {
if x.name() != package {
return false;
}
if let Some(authority) = authority {
if x.authority() != authority {
return false;
}
}
if let Some(version) = version {
let mut found = false;
if let Some(versions) = x.versions() {
for v in versions {
let normal = format!("{}.{}.{}", v.major(), v.minor(), v.patch());
let tagged = format!(
"{}.{}.{}-{}",
v.major(),
v.minor(),
v.patch(),
v.tag().unwrap_or("")
);
if version == normal || version == tagged {
found = true;
break;
}
}
}
if !found {
return false;
}
}
if let Some(hash) = hash {
if let Some(versions) = x.versions() {
for v in versions {
if let Some(h) = v.hash() {
let current =
format!("{:016x}{:016x}{:016x}{:016x}", h.a(), h.b(), h.c(), h.d());
if current == hash {
return true;
}
}
}
}
return false;
}
true
}