OXYGENHUB

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