tree: replace uses of backend::Conflict

This commit is contained in:
Martin von Zweigbergk 2023-05-31 16:04:25 -07:00 committed by Martin von Zweigbergk
parent c378503991
commit 43c55fcbc9

View file

@ -23,9 +23,10 @@ use itertools::Itertools;
use thiserror::Error; use thiserror::Error;
use crate::backend::{ use crate::backend::{
BackendError, Conflict, ConflictId, ConflictTerm, FileId, ObjectId, BackendError, ConflictId, FileId, ObjectId, TreeEntriesNonRecursiveIterator, TreeEntry, TreeId,
TreeEntriesNonRecursiveIterator, TreeEntry, TreeId, TreeValue, TreeValue,
}; };
use crate::conflicts::Conflict;
use crate::files::MergeResult; use crate::files::MergeResult;
use crate::matchers::{EverythingMatcher, Matcher}; use crate::matchers::{EverythingMatcher, Matcher};
use crate::merge::trivial_merge; use crate::merge::trivial_merge;
@ -622,31 +623,19 @@ fn merge_tree_value(
_ => { _ => {
// Start by creating a Conflict object. Conflicts can cleanly represent a single // Start by creating a Conflict object. Conflicts can cleanly represent a single
// resolved state, the absence of a state, or a conflicted state. // resolved state, the absence of a state, or a conflicted state.
let mut conflict = Conflict::default(); let conflict = Conflict::new(
if let Some(base) = maybe_base { vec![maybe_base.cloned()],
conflict.removes.push(ConflictTerm { vec![maybe_side1.cloned(), maybe_side2.cloned()],
value: base.clone(), );
});
}
if let Some(side1) = maybe_side1 {
conflict.adds.push(ConflictTerm {
value: side1.clone(),
});
}
if let Some(side2) = maybe_side2 {
conflict.adds.push(ConflictTerm {
value: side2.clone(),
});
}
let filename = dir.join(basename); let filename = dir.join(basename);
let conflict = simplify_conflict(store, &filename, conflict)?; let conflict = simplify_conflict(store, &filename, conflict)?;
if conflict.adds.is_empty() { if conflict.adds().is_empty() {
// If there are no values to add, then the path doesn't exist // If there are no values to add, then the path doesn't exist
return Ok(None); return Ok(None);
} }
if conflict.removes.is_empty() && conflict.adds.len() == 1 { if conflict.removes().is_empty() && conflict.adds().len() == 1 {
// A single add means that the current state is that state. // A single add means that the current state is that state.
return Ok(Some(conflict.adds[0].value.clone())); return Ok(conflict.adds()[0].clone());
} }
if let Some((merged_content, executable)) = if let Some((merged_content, executable)) =
try_resolve_file_conflict(store, &filename, &conflict)? try_resolve_file_conflict(store, &filename, &conflict)?
@ -654,7 +643,8 @@ fn merge_tree_value(
let id = store.write_file(&filename, &mut merged_content.as_slice())?; let id = store.write_file(&filename, &mut merged_content.as_slice())?;
Some(TreeValue::File { id, executable }) Some(TreeValue::File { id, executable })
} else { } else {
let conflict_id = store.write_conflict(&filename, &conflict)?; let conflict_id =
store.write_conflict(&filename, &conflict.to_backend_conflict())?;
Some(TreeValue::Conflict(conflict_id)) Some(TreeValue::Conflict(conflict_id))
} }
} }
@ -664,25 +654,19 @@ fn merge_tree_value(
fn try_resolve_file_conflict( fn try_resolve_file_conflict(
store: &Store, store: &Store,
filename: &RepoPath, filename: &RepoPath,
conflict: &Conflict, conflict: &Conflict<Option<TreeValue>>,
) -> Result<Option<(Vec<u8>, bool)>, TreeMergeError> { ) -> Result<Option<(Vec<u8>, bool)>, TreeMergeError> {
// If the file was missing from any side (typically a modify/delete conflict), // If there are any non-file or any missing parts in the conflict, we can't
// we can't automatically merge it. // merge it. We check early so we don't waste time reading file contents if
if conflict.adds.len() != conflict.removes.len() + 1 { // we can't merge them anyway. At the same time we determine whether the
return Ok(None); // resulting file should be executable.
}
// If there are any non-file parts in the conflict, we can't merge it. We check
// early so we don't waste time reading file contents if we can't merge them
// anyway. At the same time we determine whether the resulting file should
// be executable.
let mut executable_removes = vec![]; let mut executable_removes = vec![];
let mut executable_adds = vec![]; let mut executable_adds = vec![];
let mut removed_file_ids = vec![]; let mut removed_file_ids = vec![];
let mut added_file_ids = vec![]; let mut added_file_ids = vec![];
for term in conflict.removes.iter() { for term in conflict.removes() {
match &term.value { match term {
TreeValue::File { id, executable } => { Some(TreeValue::File { id, executable }) => {
executable_removes.push(*executable); executable_removes.push(*executable);
removed_file_ids.push(id.clone()); removed_file_ids.push(id.clone());
} }
@ -691,9 +675,9 @@ fn try_resolve_file_conflict(
} }
} }
} }
for term in conflict.adds.iter() { for term in conflict.adds() {
match &term.value { match term {
TreeValue::File { id, executable } => { Some(TreeValue::File { id, executable }) => {
executable_adds.push(*executable); executable_adds.push(*executable);
added_file_ids.push(id.clone()); added_file_ids.push(id.clone());
} }
@ -746,25 +730,22 @@ fn try_resolve_file_conflict(
fn tree_value_to_conflict( fn tree_value_to_conflict(
store: &Store, store: &Store,
path: &RepoPath, path: &RepoPath,
value: TreeValue, value: &TreeValue,
) -> Result<Conflict, BackendError> { ) -> Result<Conflict<Option<TreeValue>>, BackendError> {
match value { match value {
TreeValue::Conflict(id) => { TreeValue::Conflict(id) => {
let conflict = store.read_conflict(path, &id)?; let conflict = store.read_conflict(path, id)?;
Ok(conflict) Ok(Conflict::from_backend_conflict(&conflict))
} }
other => Ok(Conflict { value => Ok(Conflict::new(vec![], vec![Some(value.clone())])),
removes: vec![],
adds: vec![ConflictTerm { value: other }],
}),
} }
} }
fn simplify_conflict( fn simplify_conflict(
store: &Store, store: &Store,
path: &RepoPath, path: &RepoPath,
conflict: Conflict, conflict: Conflict<Option<TreeValue>>,
) -> Result<Conflict, BackendError> { ) -> Result<Conflict<Option<TreeValue>>, BackendError> {
// Important cases to simplify: // Important cases to simplify:
// //
// D // D
@ -799,27 +780,27 @@ fn simplify_conflict(
// First expand any diffs with nested conflicts. // First expand any diffs with nested conflicts.
let mut new_removes = vec![]; let mut new_removes = vec![];
let mut new_adds = vec![]; let mut new_adds = vec![];
for term in conflict.adds { for term in conflict.adds() {
match term.value { match term {
TreeValue::Conflict(_) => { Some(value @ TreeValue::Conflict(_)) => {
let conflict = tree_value_to_conflict(store, path, term.value)?; let conflict = tree_value_to_conflict(store, path, value)?;
new_removes.extend_from_slice(&conflict.removes); new_removes.extend_from_slice(conflict.removes());
new_adds.extend_from_slice(&conflict.adds); new_adds.extend_from_slice(conflict.adds());
} }
_ => { _ => {
new_adds.push(term); new_adds.push(term.clone());
} }
} }
} }
for term in conflict.removes { for term in conflict.removes() {
match term.value { match term {
TreeValue::Conflict(_) => { Some(value @ TreeValue::Conflict(_)) => {
let conflict = tree_value_to_conflict(store, path, term.value)?; let conflict = tree_value_to_conflict(store, path, value)?;
new_removes.extend_from_slice(&conflict.adds); new_removes.extend_from_slice(conflict.adds());
new_adds.extend_from_slice(&conflict.removes); new_adds.extend_from_slice(conflict.removes());
} }
_ => { _ => {
new_removes.push(term); new_removes.push(term.clone());
} }
} }
} }
@ -830,7 +811,7 @@ fn simplify_conflict(
let add = &new_adds[add_index]; let add = &new_adds[add_index];
add_index += 1; add_index += 1;
for (remove_index, remove) in new_removes.iter().enumerate() { for (remove_index, remove) in new_removes.iter().enumerate() {
if remove.value == add.value { if remove == add {
new_removes.remove(remove_index); new_removes.remove(remove_index);
add_index -= 1; add_index -= 1;
new_adds.remove(add_index); new_adds.remove(add_index);
@ -843,8 +824,5 @@ fn simplify_conflict(
// {+A+A}, that would become just {+A}. Similarly {+B-A+B} would be just // {+A+A}, that would become just {+A}. Similarly {+B-A+B} would be just
// {+B-A}. // {+B-A}.
Ok(Conflict { Ok(Conflict::new(new_removes, new_adds))
adds: new_adds,
removes: new_removes,
})
} }