merged_tree: propagate errors from from_legacy_tree()

This commit is contained in:
Martin von Zweigbergk 2023-08-28 09:51:07 -07:00 committed by Martin von Zweigbergk
parent 67832a3940
commit 2d50d8a077
2 changed files with 16 additions and 14 deletions

View File

@ -99,10 +99,10 @@ impl MergedTree {
/// Takes a tree in the legacy format (with path-level conflicts in the /// Takes a tree in the legacy format (with path-level conflicts in the
/// tree) and returns a `MergedTree` with any conflicts converted to /// tree) and returns a `MergedTree` with any conflicts converted to
/// tree-level conflicts. /// tree-level conflicts.
pub fn from_legacy_tree(tree: Tree) -> Self { pub fn from_legacy_tree(tree: Tree) -> BackendResult<Self> {
let conflict_ids = tree.conflicts(); let conflict_ids = tree.conflicts();
if conflict_ids.is_empty() { if conflict_ids.is_empty() {
return MergedTree::resolved(tree); return Ok(MergedTree::resolved(tree));
} }
// Find the number of removes in the most complex conflict. We will then // Find the number of removes in the most complex conflict. We will then
// build `2*num_removes + 1` trees // build `2*num_removes + 1` trees
@ -110,7 +110,7 @@ impl MergedTree {
let store = tree.store(); let store = tree.store();
let mut conflicts: Vec<(&RepoPath, Merge<Option<TreeValue>>)> = vec![]; let mut conflicts: Vec<(&RepoPath, Merge<Option<TreeValue>>)> = vec![];
for (path, conflict_id) in &conflict_ids { for (path, conflict_id) in &conflict_ids {
let conflict = store.read_conflict(path, conflict_id).unwrap(); let conflict = store.read_conflict(path, conflict_id)?;
max_num_removes = max(max_num_removes, conflict.removes().len()); max_num_removes = max(max_num_removes, conflict.removes().len());
conflicts.push((path, conflict)); conflicts.push((path, conflict));
} }
@ -140,13 +140,12 @@ impl MergedTree {
let write_tree = |builder: TreeBuilder| { let write_tree = |builder: TreeBuilder| {
let tree_id = builder.write_tree(); let tree_id = builder.write_tree();
store.get_tree(&RepoPath::root(), &tree_id).unwrap() store.get_tree(&RepoPath::root(), &tree_id)
}; };
MergedTree::Merge(Merge::new( let removed_trees = removes.into_iter().map(write_tree).try_collect()?;
removes.into_iter().map(write_tree).collect(), let added_trees = adds.into_iter().map(write_tree).try_collect()?;
adds.into_iter().map(write_tree).collect(), Ok(MergedTree::Merge(Merge::new(removed_trees, added_trees)))
))
} }
/// This tree's directory /// This tree's directory
@ -371,19 +370,22 @@ impl MergedTree {
Ok(MergedTree::legacy(merged_tree)) Ok(MergedTree::legacy(merged_tree))
} else { } else {
// Convert legacy trees to merged trees and unwrap to `Merge<Tree>` // Convert legacy trees to merged trees and unwrap to `Merge<Tree>`
let to_merge = |tree: &MergedTree| -> Merge<Tree> { let to_merge = |tree: &MergedTree| -> Result<Merge<Tree>, TreeMergeError> {
match tree { match tree {
MergedTree::Legacy(tree) => { MergedTree::Legacy(tree) => {
let MergedTree::Merge(tree) = MergedTree::from_legacy_tree(tree.clone()) let MergedTree::Merge(tree) = MergedTree::from_legacy_tree(tree.clone())?
else { else {
unreachable!(); unreachable!();
}; };
tree Ok(tree)
} }
MergedTree::Merge(conflict) => conflict.clone(), MergedTree::Merge(conflict) => Ok(conflict.clone()),
} }
}; };
let nested = Merge::new(vec![to_merge(base)], vec![to_merge(self), to_merge(other)]); let nested = Merge::new(
vec![to_merge(base)?],
vec![to_merge(self)?, to_merge(other)?],
);
let tree = merge_trees(&nested.flatten().simplify())?; let tree = merge_trees(&nested.flatten().simplify())?;
// If the result can be resolved, then `merge_trees()` above would have returned // If the result can be resolved, then `merge_trees()` above would have returned
// a resolved merge. However, that function will always preserve the arity of // a resolved merge. However, that function will always preserve the arity of

View File

@ -116,7 +116,7 @@ fn test_from_legacy_tree() {
let tree_id = tree_builder.write_tree(); let tree_id = tree_builder.write_tree();
let tree = store.get_tree(&RepoPath::root(), &tree_id).unwrap(); let tree = store.get_tree(&RepoPath::root(), &tree_id).unwrap();
let merged_tree = MergedTree::from_legacy_tree(tree.clone()); let merged_tree = MergedTree::from_legacy_tree(tree.clone()).unwrap();
assert_eq!( assert_eq!(
merged_tree.value(&RepoPathComponent::from("missing")), merged_tree.value(&RepoPathComponent::from("missing")),
MergedTreeValue::Resolved(None) MergedTreeValue::Resolved(None)