conflicts: convert TreeValue to FileId conflict to avoid panic!

By converting a `Conflict<Option<TreeValue>>` to a
`Conflict<Option<FileId>>`, we don't have to check later that
`TreeValue` really is a `File`.
This commit is contained in:
Martin von Zweigbergk 2023-06-05 21:11:44 -07:00 committed by Martin von Zweigbergk
parent ddb07e639c
commit ad667d6bb5

View File

@ -17,7 +17,7 @@ use std::io::Write;
use itertools::Itertools; use itertools::Itertools;
use crate::backend::{BackendResult, ConflictId, ObjectId, TreeValue}; use crate::backend::{BackendResult, ConflictId, FileId, ObjectId, TreeValue};
use crate::diff::{find_line_ranges, Diff, DiffHunk}; use crate::diff::{find_line_ranges, Diff, DiffHunk};
use crate::files::{ConflictHunk, MergeHunk, MergeResult}; use crate::files::{ConflictHunk, MergeHunk, MergeResult};
use crate::repo_path::RepoPath; use crate::repo_path::RepoPath;
@ -150,27 +150,35 @@ pub fn describe_conflict(
Ok(()) Ok(())
} }
fn file_terms(terms: &[Option<TreeValue>]) -> Vec<Option<&TreeValue>> { fn to_file_conflict(conflict: &Conflict<Option<TreeValue>>) -> Option<Conflict<Option<FileId>>> {
terms fn collect_file_terms(terms: &[Option<TreeValue>]) -> Option<Vec<Option<FileId>>> {
.iter() let mut file_terms = vec![];
.filter_map(|term| match term { for term in terms {
Some( match term {
value @ TreeValue::File { None => {
executable: false, .. file_terms.push(None);
}, }
) => Some(Some(value)), Some(TreeValue::File {
None => Some(None), id,
_ => None, executable: false,
}) }) => {
.collect_vec() file_terms.push(Some(id.clone()));
}
_ => {
return None;
}
}
}
Some(file_terms)
}
let file_removes = collect_file_terms(conflict.removes())?;
let file_adds = collect_file_terms(conflict.adds())?;
Some(Conflict::new(file_removes, file_adds))
} }
fn get_file_contents(store: &Store, path: &RepoPath, term: Option<&TreeValue>) -> Vec<u8> { fn get_file_contents(store: &Store, path: &RepoPath, term: &Option<FileId>) -> Vec<u8> {
match term { match term {
Some(TreeValue::File { Some(id) => {
id,
executable: false,
}) => {
let mut content = vec![]; let mut content = vec![];
store store
.read_file(path, id) .read_file(path, id)
@ -182,7 +190,6 @@ fn get_file_contents(store: &Store, path: &RepoPath, term: Option<&TreeValue>) -
// If the conflict had removed the file on one side, we pretend that the file // If the conflict had removed the file on one side, we pretend that the file
// was empty there. // was empty there.
None => vec![], None => vec![],
_ => panic!("unexpectedly got a non-file conflict term"),
} }
} }
@ -232,18 +239,16 @@ pub fn extract_file_conflict_as_single_hunk(
path: &RepoPath, path: &RepoPath,
conflict: &Conflict<Option<TreeValue>>, conflict: &Conflict<Option<TreeValue>>,
) -> Option<ConflictHunk> { ) -> Option<ConflictHunk> {
let file_removes = file_terms(conflict.removes()); let file_conflict = to_file_conflict(conflict)?;
let file_adds = file_terms(conflict.adds()); let removes_content = file_conflict
if file_removes.len() != conflict.removes().len() || file_adds.len() != conflict.adds().len() { .removes()
return None;
}
let removes_content = file_removes
.iter() .iter()
.map(|term| get_file_contents(store, path, *term)) .map(|term| get_file_contents(store, path, term))
.collect_vec(); .collect_vec();
let adds_content = file_adds let adds_content = file_conflict
.adds()
.iter() .iter()
.map(|term| get_file_contents(store, path, *term)) .map(|term| get_file_contents(store, path, term))
.collect_vec(); .collect_vec();
Some(ConflictHunk { Some(ConflictHunk {