From c93e8062657c8b11034d596dab09196f692574ad Mon Sep 17 00:00:00 2001 From: Martin von Zweigbergk Date: Sat, 26 Jun 2021 21:41:25 -0700 Subject: [PATCH] conflicts: make materialized tree/file conflicts etc a little more useful When there are conflicts between different types of tree entries, we currently materialize them as "Unresolved complex conflict.". This change makes it so we mention what types were involved and what their ids were (though we still don't have an easy way of resolving an id). --- lib/src/conflicts.rs | 68 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/lib/src/conflicts.rs b/lib/src/conflicts.rs index e2bc3411d..ab3bd4cc8 100644 --- a/lib/src/conflicts.rs +++ b/lib/src/conflicts.rs @@ -14,17 +14,83 @@ use std::io::{Cursor, Write}; +use itertools::Itertools; + use crate::files; use crate::repo_path::RepoPath; -use crate::store::{Conflict, TreeValue}; +use crate::store::{Conflict, ConflictPart, TreeValue}; use crate::store_wrapper::StoreWrapper; +fn describe_conflict_part(part: &ConflictPart) -> String { + match &part.value { + TreeValue::Normal { + id, + executable: false, + } => { + format!("file with id {}", id.hex()) + } + TreeValue::Normal { + id, + executable: true, + } => { + format!("executable file with id {}", id.hex()) + } + TreeValue::Symlink(id) => { + format!("symlink with id {}", id.hex()) + } + TreeValue::Tree(id) => { + format!("tree with id {}", id.hex()) + } + TreeValue::GitSubmodule(id) => { + format!("Git submodule with id {}", id.hex()) + } + TreeValue::Conflict(id) => { + format!("Conflict with id {}", id.hex()) + } + } +} + +fn describe_conflict(conflict: &Conflict, file: &mut dyn Write) -> std::io::Result<()> { + file.write_all(b"Conflict:\n")?; + for part in &conflict.removes { + file.write_all(format!(" Removing {}\n", describe_conflict_part(part)).as_bytes())?; + } + for part in &conflict.adds { + file.write_all(format!(" Adding {}\n", describe_conflict_part(part)).as_bytes())?; + } + Ok(()) +} + +fn file_parts(parts: &[ConflictPart]) -> Vec<&ConflictPart> { + parts + .iter() + .filter(|part| { + matches!( + part.value, + TreeValue::Normal { + executable: false, + .. + } + ) + }) + .collect_vec() +} + pub fn materialize_conflict( store: &StoreWrapper, path: &RepoPath, conflict: &Conflict, file: &mut dyn Write, ) { + let file_adds = file_parts(&conflict.adds); + let file_removes = file_parts(&conflict.removes); + if file_adds.len() != conflict.adds.len() || file_removes.len() != conflict.removes.len() { + // Unless all parts are regular files, we can't do much better than to try to + // describe the conflict. + describe_conflict(conflict, file).unwrap(); + return; + } + match conflict.to_three_way() { None => { file.write_all(b"Unresolved complex conflict.\n").unwrap();