1#![allow(missing_docs)]
16
17use std::fmt::Debug;
18use std::fmt::Error;
19use std::fmt::Formatter;
20use std::hash::Hash;
21use std::hash::Hasher;
22use std::io::Read;
23use std::sync::Arc;
24
25use futures::future::try_join_all;
26use itertools::Itertools;
27use pollster::FutureExt;
28use tracing::instrument;
29
30use crate::backend;
31use crate::backend::BackendError;
32use crate::backend::BackendResult;
33use crate::backend::ConflictId;
34use crate::backend::TreeEntriesNonRecursiveIterator;
35use crate::backend::TreeEntry;
36use crate::backend::TreeId;
37use crate::backend::TreeValue;
38use crate::files;
39use crate::files::MergeResult;
40use crate::matchers::EverythingMatcher;
41use crate::matchers::Matcher;
42use crate::merge::trivial_merge;
43use crate::merge::Merge;
44use crate::merge::MergedTreeVal;
45use crate::object_id::ObjectId;
46use crate::repo_path::RepoPath;
47use crate::repo_path::RepoPathBuf;
48use crate::repo_path::RepoPathComponent;
49use crate::store::Store;
50
51#[derive(Clone)]
52pub struct Tree {
53 store: Arc<Store>,
54 dir: RepoPathBuf,
55 id: TreeId,
56 data: Arc<backend::Tree>,
57}
58
59impl Debug for Tree {
60 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> {
61 f.debug_struct("Tree")
62 .field("dir", &self.dir)
63 .field("id", &self.id)
64 .finish()
65 }
66}
67
68impl PartialEq for Tree {
69 fn eq(&self, other: &Self) -> bool {
70 self.id == other.id && self.dir == other.dir
71 }
72}
73
74impl Eq for Tree {}
75
76impl Hash for Tree {
77 fn hash<H: Hasher>(&self, state: &mut H) {
78 self.dir.hash(state);
79 self.id.hash(state);
80 }
81}
82
83impl Tree {
84 pub fn new(store: Arc<Store>, dir: RepoPathBuf, id: TreeId, data: Arc<backend::Tree>) -> Self {
85 Tree {
86 store,
87 dir,
88 id,
89 data,
90 }
91 }
92
93 pub fn empty(store: Arc<Store>, dir: RepoPathBuf) -> Self {
94 let id = store.empty_tree_id().clone();
95 Tree {
96 store,
97 dir,
98 id,
99 data: Arc::new(backend::Tree::default()),
100 }
101 }
102
103 pub fn store(&self) -> &Arc<Store> {
104 &self.store
105 }
106
107 pub fn dir(&self) -> &RepoPath {
108 &self.dir
109 }
110
111 pub fn id(&self) -> &TreeId {
112 &self.id
113 }
114
115 pub fn data(&self) -> &backend::Tree {
116 &self.data
117 }
118
119 pub fn entries_non_recursive(&self) -> TreeEntriesNonRecursiveIterator {
120 self.data.entries()
121 }
122
123 pub fn entries(&self) -> TreeEntriesIterator<'static> {
124 TreeEntriesIterator::new(self.clone(), &EverythingMatcher)
125 }
126
127 pub fn entries_matching<'matcher>(
128 &self,
129 matcher: &'matcher dyn Matcher,
130 ) -> TreeEntriesIterator<'matcher> {
131 TreeEntriesIterator::new(self.clone(), matcher)
132 }
133
134 pub fn entry(&self, basename: &RepoPathComponent) -> Option<TreeEntry> {
135 self.data.entry(basename)
136 }
137
138 pub fn value(&self, basename: &RepoPathComponent) -> Option<&TreeValue> {
139 self.data.value(basename)
140 }
141
142 pub fn path_value(&self, path: &RepoPath) -> BackendResult<Option<TreeValue>> {
143 assert_eq!(self.dir(), RepoPath::root());
144 match path.split() {
145 Some((dir, basename)) => {
146 let tree = self.sub_tree_recursive(dir)?;
147 Ok(tree.and_then(|tree| tree.data.value(basename).cloned()))
148 }
149 None => Ok(Some(TreeValue::Tree(self.id.clone()))),
150 }
151 }
152
153 pub fn sub_tree(&self, name: &RepoPathComponent) -> BackendResult<Option<Tree>> {
154 if let Some(sub_tree) = self.data.value(name) {
155 match sub_tree {
156 TreeValue::Tree(sub_tree_id) => {
157 let subdir = self.dir.join(name);
158 let sub_tree = self.store.get_tree(subdir, sub_tree_id)?;
159 Ok(Some(sub_tree))
160 }
161 _ => Ok(None),
162 }
163 } else {
164 Ok(None)
165 }
166 }
167
168 fn known_sub_tree(&self, subdir: RepoPathBuf, id: &TreeId) -> Tree {
169 self.store.get_tree(subdir, id).unwrap()
170 }
171
172 pub fn sub_tree_recursive(&self, path: &RepoPath) -> BackendResult<Option<Tree>> {
174 let mut current_tree = self.clone();
175 for name in path.components() {
176 match current_tree.sub_tree(name)? {
177 None => {
178 return Ok(None);
179 }
180 Some(sub_tree) => {
181 current_tree = sub_tree;
182 }
183 }
184 }
185 Ok(Some(current_tree))
189 }
190
191 pub fn conflicts_matching(&self, matcher: &dyn Matcher) -> Vec<(RepoPathBuf, ConflictId)> {
192 let mut conflicts = vec![];
193 for (name, value) in self.entries_matching(matcher) {
194 if let TreeValue::Conflict(id) = value {
195 conflicts.push((name.clone(), id.clone()));
196 }
197 }
198 conflicts
199 }
200
201 #[instrument]
202 pub fn conflicts(&self) -> Vec<(RepoPathBuf, ConflictId)> {
203 self.conflicts_matching(&EverythingMatcher)
204 }
205
206 pub fn has_conflict(&self) -> bool {
207 !self.conflicts().is_empty()
208 }
209}
210
211pub struct TreeEntriesIterator<'matcher> {
212 stack: Vec<TreeEntriesDirItem>,
213 matcher: &'matcher dyn Matcher,
214}
215
216struct TreeEntriesDirItem {
217 tree: Tree,
218 entries: Vec<(RepoPathBuf, TreeValue)>,
219}
220
221impl From<Tree> for TreeEntriesDirItem {
222 fn from(tree: Tree) -> Self {
223 let mut entries = tree
224 .entries_non_recursive()
225 .map(|entry| (tree.dir().join(entry.name()), entry.value().clone()))
226 .collect_vec();
227 entries.reverse();
228 Self { tree, entries }
229 }
230}
231
232impl<'matcher> TreeEntriesIterator<'matcher> {
233 fn new(tree: Tree, matcher: &'matcher dyn Matcher) -> Self {
234 Self {
236 stack: vec![TreeEntriesDirItem::from(tree)],
237 matcher,
238 }
239 }
240}
241
242impl Iterator for TreeEntriesIterator<'_> {
243 type Item = (RepoPathBuf, TreeValue);
244
245 fn next(&mut self) -> Option<Self::Item> {
246 while let Some(top) = self.stack.last_mut() {
247 if let Some((path, value)) = top.entries.pop() {
248 match value {
249 TreeValue::Tree(id) => {
250 if self.matcher.visit(&path).is_nothing() {
252 continue;
253 }
254 let subtree = top.tree.known_sub_tree(path, &id);
255 self.stack.push(TreeEntriesDirItem::from(subtree));
256 }
257 value => {
258 if self.matcher.matches(&path) {
259 return Some((path, value));
260 }
261 }
262 };
263 } else {
264 self.stack.pop();
265 }
266 }
267 None
268 }
269}
270
271struct TreeEntryDiffIterator<'trees> {
272 tree1: &'trees Tree,
273 tree2: &'trees Tree,
274 basename_iter: Box<dyn Iterator<Item = &'trees RepoPathComponent> + 'trees>,
275}
276
277impl<'trees> TreeEntryDiffIterator<'trees> {
278 fn new(tree1: &'trees Tree, tree2: &'trees Tree) -> Self {
279 let basename_iter = Box::new(tree1.data.names().merge(tree2.data.names()).dedup());
280 TreeEntryDiffIterator {
281 tree1,
282 tree2,
283 basename_iter,
284 }
285 }
286}
287
288impl<'trees> Iterator for TreeEntryDiffIterator<'trees> {
289 type Item = (
290 &'trees RepoPathComponent,
291 Option<&'trees TreeValue>,
292 Option<&'trees TreeValue>,
293 );
294
295 fn next(&mut self) -> Option<Self::Item> {
296 for basename in self.basename_iter.by_ref() {
297 let value1 = self.tree1.value(basename);
298 let value2 = self.tree2.value(basename);
299 if value1 != value2 {
300 return Some((basename, value1, value2));
301 }
302 }
303 None
304 }
305}
306
307pub fn merge_trees(side1_tree: &Tree, base_tree: &Tree, side2_tree: &Tree) -> BackendResult<Tree> {
308 let store = base_tree.store();
309 let dir = base_tree.dir();
310 assert_eq!(side1_tree.dir(), dir);
311 assert_eq!(side2_tree.dir(), dir);
312
313 if let Some(resolved) = trivial_merge(&[side1_tree, base_tree, side2_tree]) {
314 return Ok((*resolved).clone());
315 }
316
317 let mut new_tree = side1_tree.data().clone();
320 for (basename, maybe_base, maybe_side2) in TreeEntryDiffIterator::new(base_tree, side2_tree) {
321 let maybe_side1 = side1_tree.value(basename);
322 if maybe_side1 == maybe_base {
323 new_tree.set_or_remove(basename, maybe_side2.cloned());
325 } else if maybe_side1 == maybe_side2 {
326 } else {
329 let new_value =
331 merge_tree_value(store, dir, basename, maybe_base, maybe_side1, maybe_side2)?;
332 new_tree.set_or_remove(basename, new_value);
333 }
334 }
335 store.write_tree(dir, new_tree).block_on()
336}
337
338fn maybe_tree_id<'id>(
341 value: Option<&'id TreeValue>,
342 empty_tree_id: &'id TreeId,
343) -> Option<&'id TreeId> {
344 match value {
345 Some(TreeValue::Tree(id)) => Some(id),
346 None => Some(empty_tree_id),
347 _ => None,
348 }
349}
350
351fn merge_tree_value(
352 store: &Arc<Store>,
353 dir: &RepoPath,
354 basename: &RepoPathComponent,
355 maybe_base: Option<&TreeValue>,
356 maybe_side1: Option<&TreeValue>,
357 maybe_side2: Option<&TreeValue>,
358) -> BackendResult<Option<TreeValue>> {
359 let empty_tree_id = store.empty_tree_id();
366 let base_tree_id = maybe_tree_id(maybe_base, empty_tree_id);
367 let side1_tree_id = maybe_tree_id(maybe_side1, empty_tree_id);
368 let side2_tree_id = maybe_tree_id(maybe_side2, empty_tree_id);
369 Ok(match (base_tree_id, side1_tree_id, side2_tree_id) {
370 (Some(base_id), Some(side1_id), Some(side2_id)) => {
371 let subdir = dir.join(basename);
372 let base_tree = store.get_tree(subdir.clone(), base_id)?;
373 let side1_tree = store.get_tree(subdir.clone(), side1_id)?;
374 let side2_tree = store.get_tree(subdir, side2_id)?;
375 let merged_tree = merge_trees(&side1_tree, &base_tree, &side2_tree)?;
376 if merged_tree.id() == empty_tree_id {
377 None
378 } else {
379 Some(TreeValue::Tree(merged_tree.id().clone()))
380 }
381 }
382 _ => {
383 let conflict = Merge::from_vec(vec![
386 maybe_side1.cloned(),
387 maybe_base.cloned(),
388 maybe_side2.cloned(),
389 ]);
390 let filename = dir.join(basename);
391 let expanded = conflict.try_map(|term| match term {
392 Some(TreeValue::Conflict(id)) => store.read_conflict(&filename, id),
393 _ => Ok(Merge::resolved(term.clone())),
394 })?;
395 let merge = expanded.flatten().simplify();
396 match merge.into_resolved() {
397 Ok(value) => value,
398 Err(conflict) => {
399 let conflict_borrowed = conflict.map(|value| value.as_ref());
400 if let Some(tree_value) =
401 try_resolve_file_conflict(store, &filename, &conflict_borrowed)
402 .block_on()?
403 {
404 Some(tree_value)
405 } else {
406 let conflict_id = store.write_conflict(&filename, &conflict)?;
407 Some(TreeValue::Conflict(conflict_id))
408 }
409 }
410 }
411 }
412 })
413}
414
415pub async fn try_resolve_file_conflict(
420 store: &Store,
421 filename: &RepoPath,
422 conflict: &MergedTreeVal<'_>,
423) -> BackendResult<Option<TreeValue>> {
424 let Some(file_id_conflict) = conflict.maybe_map(|term| match term {
429 Some(TreeValue::File { id, executable: _ }) => Some(id),
430 _ => None,
431 }) else {
432 return Ok(None);
433 };
434 let Some(executable_conflict) = conflict.maybe_map(|term| match term {
435 Some(TreeValue::File { id: _, executable }) => Some(executable),
436 _ => None,
437 }) else {
438 return Ok(None);
439 };
440 let Some(&&executable) = executable_conflict.resolve_trivial() else {
441 return Ok(None);
443 };
444 if let Some(&resolved_file_id) = file_id_conflict.resolve_trivial() {
445 return Ok(Some(TreeValue::File {
448 id: resolved_file_id.clone(),
449 executable,
450 }));
451 }
452
453 let file_id_conflict = file_id_conflict.simplify();
460
461 let content_futures = file_id_conflict.into_iter().map(|file_id| async {
462 let mut content = vec![];
463 let mut reader = store.read_file_async(filename, file_id).await?;
464 reader
465 .read_to_end(&mut content)
466 .map_err(|err| BackendError::ReadObject {
467 object_type: file_id.object_type(),
468 hash: file_id.hex(),
469 source: err.into(),
470 })?;
471 BackendResult::Ok(content)
472 });
473 let contents = Merge::from_vec(try_join_all(content_futures).await?);
474 let merge_result = files::merge(&contents);
475 match merge_result {
476 MergeResult::Resolved(merged_content) => {
477 let id = store
478 .write_file(filename, &mut merged_content.as_slice())
479 .await?;
480 Ok(Some(TreeValue::File { id, executable }))
481 }
482 MergeResult::Conflict(_) => Ok(None),
483 }
484}