Skip to content

Commit

Permalink
merged_tree: propagate errors from conflict iterator
Browse files Browse the repository at this point in the history
  • Loading branch information
martinvonz committed Nov 23, 2024
1 parent 9ec216a commit 10c90a5
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 16 deletions.
7 changes: 5 additions & 2 deletions cli/src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ use clap_complete::ArgValueCandidates;
use indexmap::IndexMap;
use indexmap::IndexSet;
use itertools::Itertools;
use jj_lib::backend::BackendResult;
use jj_lib::backend::ChangeId;
use jj_lib::backend::CommitId;
use jj_lib::backend::MergedTreeId;
Expand Down Expand Up @@ -2467,7 +2468,7 @@ fn update_stale_working_copy(

#[instrument(skip_all)]
pub fn print_conflicted_paths(
conflicts: Vec<(RepoPathBuf, MergedTreeValue)>,
conflicts: Vec<(RepoPathBuf, BackendResult<MergedTreeValue>)>,
formatter: &mut dyn Formatter,
workspace_command: &WorkspaceCommandHelper,
) -> Result<(), CommandError> {
Expand All @@ -2481,7 +2482,9 @@ pub fn print_conflicted_paths(
.map(|p| format!("{:width$}", p, width = max_path_len.min(32) + 3));

for ((_, conflict), formatted_path) in std::iter::zip(conflicts, formatted_paths) {
let conflict = conflict.simplify();
// TODO: Display the error for the path instead of failing the whole command if
// `conflict` is an error?
let conflict = conflict?.simplify();
let sides = conflict.num_sides();
let n_adds = conflict.adds().flatten().count();
let deletions = sides - n_adds;
Expand Down
27 changes: 16 additions & 11 deletions lib/src/merged_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ impl MergedTree {
/// all sides are trees, so tree/file conflicts will be reported as a single
/// conflict, not one for each path in the tree.
// TODO: Restrict this by a matcher (or add a separate method for that).
pub fn conflicts(&self) -> impl Iterator<Item = (RepoPathBuf, MergedTreeValue)> {
pub fn conflicts(&self) -> impl Iterator<Item = (RepoPathBuf, BackendResult<MergedTreeValue>)> {
ConflictIterator::new(self)
}

Expand Down Expand Up @@ -651,20 +651,25 @@ impl ConflictIterator {
}

impl Iterator for ConflictIterator {
type Item = (RepoPathBuf, MergedTreeValue);
type Item = (RepoPathBuf, BackendResult<MergedTreeValue>);

fn next(&mut self) -> Option<Self::Item> {
while let Some(top) = self.stack.last_mut() {
if let Some((path, tree_values)) = top.entries.pop() {
// TODO: propagate errors
if let Some(trees) = tree_values.to_tree_merge(&self.store, &path).unwrap() {
// If all sides are trees or missing, descend into the merged tree
self.stack.push(ConflictsDirItem::from(&trees));
} else {
// Otherwise this is a conflict between files, trees, etc. If they could
// be automatically resolved, they should have been when the top-level
// tree conflict was written, so we assume that they can't be.
return Some((path, tree_values));
match tree_values.to_tree_merge(&self.store, &path) {
Ok(Some(trees)) => {
// If all sides are trees or missing, descend into the merged tree
self.stack.push(ConflictsDirItem::from(&trees));
}
Ok(None) => {
// Otherwise this is a conflict between files, trees, etc. If they could
// be automatically resolved, they should have been when the top-level
// tree conflict was written, so we assume that they can't be.
return Some((path, Ok(tree_values)));
}
Err(err) => {
return Some((path, Err(err)));
}
}
} else {
self.stack.pop();
Expand Down
15 changes: 12 additions & 3 deletions lib/tests/test_merged_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -638,7 +638,10 @@ fn test_conflict_iterator() {
vec![base1.clone()],
vec![side1.clone(), side2.clone()],
));
let conflicts = tree.conflicts().collect_vec();
let conflicts = tree
.conflicts()
.map(|(path, conflict)| (path, conflict.unwrap()))
.collect_vec();
let conflict_at = |path: &RepoPath| {
Merge::from_removes_adds(
vec![base1.path_value(path).unwrap()],
Expand Down Expand Up @@ -672,7 +675,10 @@ fn test_conflict_iterator() {

// After we resolve conflicts, there are only non-trivial conflicts left
let tree = tree.resolve().unwrap();
let conflicts = tree.conflicts().collect_vec();
let conflicts = tree
.conflicts()
.map(|(path, conflict)| (path, conflict.unwrap()))
.collect_vec();
assert_eq!(
conflicts,
vec![
Expand Down Expand Up @@ -725,7 +731,10 @@ fn test_conflict_iterator_higher_arity() {
vec![base1.clone(), base2.clone()],
vec![side1.clone(), side2.clone(), side3.clone()],
));
let conflicts = tree.conflicts().collect_vec();
let conflicts = tree
.conflicts()
.map(|(path, conflict)| (path, conflict.unwrap()))
.collect_vec();
let conflict_at = |path: &RepoPath| {
Merge::from_removes_adds(
vec![
Expand Down

0 comments on commit 10c90a5

Please sign in to comment.