use super::super::dispatch::EnvLookup;
use super::super::harness;
use super::{Error, SKILLS_DIR};
use crate::template::{GitRunner, descriptions};
use std::io;
use std::path::{Path, PathBuf};
pub(super) fn followed_commit(
workspace: &Path,
branch: &str,
git: &dyn GitRunner,
) -> Result<String, Error> {
harness::followed_commit(workspace, branch, git).map_err(Error::Lineage)
}
pub(super) fn unknown(
name: String,
worktree: &Path,
commit: &str,
pool: &Path,
git: &dyn GitRunner,
) -> Error {
Error::Unknown {
name,
workspace: committed_skills(worktree, commit, git),
pool: available(pool),
}
}
fn committed_skills(worktree: &Path, commit: &str, git: &dyn GitRunner) -> String {
let spec = format!("{commit}:{SKILLS_DIR}");
let listing = git
.run_capture(worktree, &["ls-tree", "--name-only", &spec])
.unwrap_or_default();
let names: Vec<&str> = listing
.lines()
.map(str::trim)
.filter(|l| !l.is_empty() && *l != descriptions::ARCHIVED_SUBDIR)
.collect();
crate::name::pool(&names)
}
pub(super) fn skills_pool(env: &dyn EnvLookup) -> Result<PathBuf, Error> {
let roots = harness::roots(env).map_err(Error::Root)?;
Ok(roots.data.join(SKILLS_DIR))
}
fn available(pool: &Path) -> String {
let mut names: Vec<String> = match std::fs::read_dir(pool) {
Ok(rd) => rd
.flatten()
.filter(|e| e.path().is_dir())
.map(|e| e.file_name().to_string_lossy().into_owned())
.collect(),
Err(_) => Vec::new(),
};
names.sort();
crate::name::pool(&names)
}
pub(super) fn copy_dir(src: &Path, dest: &Path) -> io::Result<()> {
std::fs::create_dir_all(dest)?;
for entry in std::fs::read_dir(src)? {
let entry = entry?;
let from = entry.path();
let to = dest.join(entry.file_name());
if entry.file_type()?.is_dir() {
copy_dir(&from, &to)?;
} else {
std::fs::copy(&from, &to)?;
}
}
Ok(())
}