use std::path::PathBuf;
use tokio::fs;
use super::LocalStore;
use crate::namespace::Namespace;
pub(super) struct Found {
pub path: PathBuf,
pub oid: String,
}
pub(super) struct Walk {
pub objects: Vec<Found>,
pub complete: bool,
}
impl LocalStore {
pub(super) async fn objects_of(&self, ns: &Namespace) -> Walk {
let mut walk = Walk {
objects: Vec::new(),
complete: true,
};
let root = self.root.join(ns.org()).join(ns.repo());
let Some(prefixes) = self.entries(&root, &mut walk).await else {
return Walk {
objects: Vec::new(),
complete: true,
};
};
for prefix in prefixes {
let Some(fanouts) = self.entries(&prefix, &mut walk).await else {
continue;
};
for fanout in fanouts {
let Some(objects) = self.entries(&fanout, &mut walk).await else {
continue;
};
for path in objects {
let oid = path
.file_name()
.map(|name| name.to_string_lossy().into_owned())
.unwrap_or_default();
if Self::validate_oid(&oid).is_ok() {
walk.objects.push(Found { path, oid });
}
}
}
}
walk
}
async fn entries(&self, directory: &std::path::Path, walk: &mut Walk) -> Option<Vec<PathBuf>> {
let mut entries = match fs::read_dir(directory).await {
Ok(entries) => entries,
Err(error) => {
tracing::warn!(?directory, %error, "could not be listed");
walk.complete = false;
return None;
}
};
let mut found = Vec::new();
loop {
match entries.next_entry().await {
Ok(Some(entry)) => found.push(entry.path()),
Ok(None) => return Some(found),
Err(error) => {
tracing::warn!(?directory, %error, "listing stopped early");
walk.complete = false;
return Some(found);
}
}
}
}
}