Walk: tracked paths hidden by ignore rules found by a merge, not a lookup each (refs #41) f57bf6702628
- Author
- Andy McCall @andymccall <[email protected]>
- When
- · 2026-09-30 22:03 UTC
- Signature
- ✔ signed by Andy McCall
- Hash
f57bf6702628cfd73668d771071a01c34e4a363eb9029e74b434799743df934b- Depends on
- 4dee277c327a 982864068a59 9ac1fbe211b4 d616faf5d136 e7ddd552b619
- Depended on by
- nothing yet
- In bookmarks
- agents-in-readme bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
- In tags
- v0.10.0 v0.11.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
- Edits
- 5 atoms, 0 tree operations, 2 files
Browse the tree at this change
modified crates/oxy-core/src/repo/mod.rs +40 −2
| … | 1324 unchanged lines |
||
| 1325 | 1325 | out.insert(rel, FsEntry::new(NodeKind::Subrepo, false, pin.encode())); |
|
| 1326 | 1326 | } |
|
| 1327 | 1327 | // Tracked paths the ignore rules hid. |
|
| 1328 | - | for (rel, (kind, blob)) in tracked { |
|
| 1329 | - | if out.contains_key(rel) || !self.in_scope(rel) { |
|
| 1328 | + | for (rel, (kind, blob)) in missing_from(tracked, &out) { |
|
| 1329 | + | if !self.in_scope(rel) { |
|
| 1330 | 1330 | continue; |
|
| 1331 | 1331 | } |
|
| 1332 | 1332 | let path = self.root.join(rel); |
|
| … | 405 unchanged lines |
||
| 1738 | 1738 | e.stat = stat; |
|
| 1739 | 1739 | Ok(e) |
|
| 1740 | 1740 | } |
|
| 1741 | + | ||
| 1742 | + | /// Two maps side by side in key order: each key of either, with its value |
|
| 1743 | + | /// in each. Linear, with no lookups, for maps of a whole tree. |
|
| 1744 | + | pub(crate) fn join<'a, A, B>( |
|
| 1745 | + | a: &'a BTreeMap<String, A>, |
|
| 1746 | + | b: &'a BTreeMap<String, B>, |
|
| 1747 | + | ) -> impl Iterator<Item = (&'a String, Option<&'a A>, Option<&'a B>)> { |
|
| 1748 | + | let (mut a, mut b) = (a.iter().peekable(), b.iter().peekable()); |
|
| 1749 | + | std::iter::from_fn(move || match (a.peek(), b.peek()) { |
|
| 1750 | + | (None, None) => None, |
|
| 1751 | + | (Some(_), None) => a.next().map(|(k, v)| (k, Some(v), None)), |
|
| 1752 | + | (None, Some(_)) => b.next().map(|(k, v)| (k, None, Some(v))), |
|
| 1753 | + | (Some((ka, _)), Some((kb, _))) => match ka.cmp(kb) { |
|
| 1754 | + | std::cmp::Ordering::Less => a.next().map(|(k, v)| (k, Some(v), None)), |
|
| 1755 | + | std::cmp::Ordering::Greater => b.next().map(|(k, v)| (k, None, Some(v))), |
|
| 1756 | + | std::cmp::Ordering::Equal => { |
|
| 1757 | + | let (k, va) = a.next()?; |
|
| 1758 | + | let (_, vb) = b.next()?; |
|
| 1759 | + | Some((k, Some(va), Some(vb))) |
|
| 1760 | + | } |
|
| 1761 | + | }, |
|
| 1762 | + | }) |
|
| 1763 | + | } |
|
| 1764 | + | ||
| 1765 | + | /// The entries of `a` whose keys `b` lacks, in key order: linear, with no |
|
| 1766 | + | /// lookups. |
|
| 1767 | + | pub(crate) fn missing_from<'a, A, B>( |
|
| 1768 | + | a: &'a BTreeMap<String, A>, |
|
| 1769 | + | b: &BTreeMap<String, B>, |
|
| 1770 | + | ) -> Vec<(&'a String, &'a A)> { |
|
| 1771 | + | let mut keys = b.keys().peekable(); |
|
| 1772 | + | a.iter() |
|
| 1773 | + | .filter(|(k, _)| { |
|
| 1774 | + | while keys.next_if(|kb| *kb < *k).is_some() {} |
|
| 1775 | + | keys.peek() != Some(k) |
|
| 1776 | + | }) |
|
| 1777 | + | .collect() |
|
| 1778 | + | } |
modified crates/oxy-core/src/repo/snapshot.rs +17 −23
| … | 2644 unchanged lines |
||
| 2645 | 2645 | (shared * 100 / a.len().max(b.len())) as u32 |
|
| 2646 | 2646 | } |
|
| 2647 | 2647 | ||
| 2648 | - | /// Two maps side by side in key order: each key of either, with its value |
|
| 2649 | - | /// in each. Linear, with no lookups, for maps of a whole tree. |
|
| 2650 | - | fn join<'a, A, B>( |
|
| 2651 | - | a: &'a BTreeMap<String, A>, |
|
| 2652 | - | b: &'a BTreeMap<String, B>, |
|
| 2653 | - | ) -> impl Iterator<Item = (&'a String, Option<&'a A>, Option<&'a B>)> { |
|
| 2654 | - | let (mut a, mut b) = (a.iter().peekable(), b.iter().peekable()); |
|
| 2655 | - | std::iter::from_fn(move || match (a.peek(), b.peek()) { |
|
| 2656 | - | (None, None) => None, |
|
| 2657 | - | (Some(_), None) => a.next().map(|(k, v)| (k, Some(v), None)), |
|
| 2658 | - | (None, Some(_)) => b.next().map(|(k, v)| (k, None, Some(v))), |
|
| 2659 | - | (Some((ka, _)), Some((kb, _))) => match ka.cmp(kb) { |
|
| 2660 | - | std::cmp::Ordering::Less => a.next().map(|(k, v)| (k, Some(v), None)), |
|
| 2661 | - | std::cmp::Ordering::Greater => b.next().map(|(k, v)| (k, None, Some(v))), |
|
| 2662 | - | std::cmp::Ordering::Equal => { |
|
| 2663 | - | let (k, va) = a.next()?; |
|
| 2664 | - | let (_, vb) = b.next()?; |
|
| 2665 | - | Some((k, Some(va), Some(vb))) |
|
| 2666 | - | } |
|
| 2667 | - | }, |
|
| 2668 | - | }) |
|
| 2669 | - | } |
|
| 2670 | - | ||
| 2671 | 2648 | #[cfg(test)] |
|
| 2672 | 2649 | mod join_tests { |
|
| 2673 | 2650 | use super::*; |
|
| 2651 | + | ||
| 2652 | + | #[test] |
|
| 2653 | + | fn missing_from_finds_what_the_other_lacks() { |
|
| 2654 | + | let a: BTreeMap<String, u8> = [("a", 1), ("b", 2), ("c/d", 3), ("e", 4)] |
|
| 2655 | + | .into_iter() |
|
| 2656 | + | .map(|(k, v)| (k.to_string(), v)) |
|
| 2657 | + | .collect(); |
|
| 2658 | + | let b: BTreeMap<String, ()> = [("0", ()), ("b", ()), ("c", ()), ("e", ())] |
|
| 2659 | + | .into_iter() |
|
| 2660 | + | .map(|(k, v)| (k.to_string(), v)) |
|
| 2661 | + | .collect(); |
|
| 2662 | + | let got: Vec<&str> = missing_from(&a, &b) |
|
| 2663 | + | .iter() |
|
| 2664 | + | .map(|(k, _)| k.as_str()) |
|
| 2665 | + | .collect(); |
|
| 2666 | + | assert_eq!(got, vec!["a", "c/d"]); |
|
| 2667 | + | } |
|
| 2674 | 2668 | ||
| 2675 | 2669 | #[test] |
|
| 2676 | 2670 | fn join_pairs_every_key_in_order() { |
|
| … | 21 unchanged lines |