mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-08 21:55:47 +00:00
tree: replace uses of backend::Conflict
This commit is contained in:
parent
c378503991
commit
43c55fcbc9
1 changed files with 46 additions and 68 deletions
114
lib/src/tree.rs
114
lib/src/tree.rs
|
@ -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,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue