use super::git;
use std::io;
use std::path::Path;
pub(super) fn conflict(store: &str, remote: &str, branch: &str, contended: &[String]) -> io::Error {
let who = if contended.is_empty() { "a ball".to_string() } else { contended.join(", ") };
io::Error::other(format!(
"push rejected: `{remote}`'s `{branch}` moved and {who} changed on both sides — the rebase of this \
store's unpublished seals was aborted; nothing was published and nothing local was changed. If \
this was an op it has un-sealed: run `bl sync`, then re-run it (a ball someone else already \
claimed is contention — the later claim loses). If this store still holds seals of its own, \
reconcile them in the store checkout, {store}: `git log FETCH_HEAD..{branch}` lists them; `git \
rebase FETCH_HEAD`, resolve the named file, then `bl sync` publishes — or `git reset --hard \
FETCH_HEAD` to take the remote's version"
))
}
pub(super) fn unmerged_balls(store: &Path) -> Vec<String> {
let mut ids: Vec<String> = git(store, &["ls-files", "-u"])
.unwrap_or_default()
.lines()
.filter_map(|l| l.split('\t').nth(1))
.map(|p| p.strip_prefix("tasks/").and_then(|f| f.strip_suffix(".md")).unwrap_or(p).to_string())
.collect();
ids.sort();
ids.dedup();
ids
}
pub(super) fn fail_open(remote: &str, e: &io::Error) {
let cause = e.to_string().lines().next().unwrap_or_default().to_string();
eprintln!("tracker: `{remote}` is unreachable — this store stays ahead of it, unpublished; the next op or `bl sync` publishes once it is reachable ({cause})");
}