use super::super::slices::in_subtree;
use super::{DIRS, DeleteError};
use crate::prompt::inbox::{inbox_dir, try_acquire};
use crate::template::GitRunner;
use crate::workspace::{self, MARK_REF_ROOT};
use std::collections::BTreeSet;
use std::fs;
use std::io;
use std::path::Path;
pub(super) fn subtree(
ws: &Path,
root: &str,
marks: &[String],
git: &dyn GitRunner,
) -> Result<Vec<String>, DeleteError> {
let refs =
super::super::subtree_refs(&workspace::repo_git(ws), root, git).map_err(|source| {
DeleteError::Git {
op: "branch --list",
source,
}
})?;
let mut ids: BTreeSet<String> = refs
.iter()
.filter_map(|r| r.strip_prefix(workspace::AGENT_REF_PREFIX))
.map(str::to_owned)
.collect();
for dir in DIRS {
ids.extend(entries(&ws.join(dir), root)?);
}
ids.extend(
marks
.iter()
.filter_map(|r| r.rsplit('/').next())
.filter(|id| in_subtree(id, root))
.map(str::to_owned),
);
Ok(ids.into_iter().collect())
}
fn entries(dir: &Path, root: &str) -> io::Result<Vec<String>> {
if !dir.is_dir() {
return Ok(Vec::new());
}
let mut found = Vec::new();
for entry in fs::read_dir(dir)? {
let name = entry?.file_name().to_string_lossy().into_owned();
if in_subtree(&name, root) {
found.push(name);
}
}
Ok(found)
}
pub(super) fn mark_refs(repo: &Path, git: &dyn GitRunner) -> Result<Vec<String>, DeleteError> {
let out = git
.run_capture(
repo,
&["for-each-ref", "--format=%(refname)", MARK_REF_ROOT],
)
.map_err(|source| DeleteError::Git {
op: "for-each-ref refs/lernie/",
source,
})?;
Ok(out
.lines()
.map(str::trim)
.filter(|l| !l.is_empty())
.map(str::to_owned)
.collect())
}
pub(super) fn pending(ws: &Path, agent_id: &str) -> io::Result<usize> {
let dir = inbox_dir(ws, agent_id);
if !dir.is_dir() {
return Ok(0);
}
Ok(fs::read_dir(dir)?.count())
}
pub(super) fn require_quiescent(ws: &Path, agent_id: &str) -> Result<(), DeleteError> {
let dir = inbox_dir(ws, agent_id);
if !dir.exists() {
return Ok(());
}
let free = try_acquire(&dir)
.map_err(|source| DeleteError::Probe {
path: dir.clone(),
source,
})?
.is_some();
match free {
true => Ok(()),
false => Err(DeleteError::Driven {
id: agent_id.to_owned(),
lock: dir,
}),
}
}