use super::{Error, MergeOutcome};
use crate::template::GitRunner;
use crate::workspace::CONFLICTED_REF_PREFIX;
use std::collections::BTreeMap;
use std::path::Path;
pub(super) fn content_conflicts(
parent_worktree: &Path,
git: &dyn GitRunner,
) -> Result<Vec<String>, Error> {
let out = git
.run_capture(parent_worktree, &["ls-files", "-u"])
.map_err(|source| Error::Git {
op: "compaction merge unmerged",
source,
})?;
let mut both: BTreeMap<String, (bool, bool)> = BTreeMap::new();
for line in out.lines() {
let Some((meta, path)) = line.split_once('\t') else {
continue;
};
let entry = both.entry(path.to_string()).or_default();
match meta.rsplit(' ').next() {
Some("2") => entry.0 = true,
Some("3") => entry.1 = true,
_ => {}
}
}
Ok(both
.into_iter()
.filter(|(_, (ours, theirs))| *ours && *theirs)
.map(|(path, _)| path)
.collect())
}
pub(super) fn decline(
parent_worktree: &Path,
compactor_id: &str,
compactor_ref: &str,
paths: Vec<String>,
git: &dyn GitRunner,
) -> Result<MergeOutcome, Error> {
git.run(parent_worktree, &["merge", "--abort"])
.map_err(|source| Error::Git {
op: "compaction merge abort",
source,
})?;
let conflicted_ref = format!("{CONFLICTED_REF_PREFIX}{compactor_id}");
git.run(
parent_worktree,
&["update-ref", conflicted_ref.as_str(), compactor_ref],
)
.map_err(|source| Error::Git {
op: "compaction merge decline update-ref",
source,
})?;
Ok(MergeOutcome::Conflicted(paths))
}