This means tree entries are compared as if they had a / appended to it.
Unified · Split
| @@ -72,7 +72,7 @@ pub struct EntryRef<'a> { · 71 unmodified lines | |||
| 72 | pub filename: &'a BStr, | 72 | pub filename: &'a BStr, |
| 73 | /// The id of the object representing the entry. | 73 | /// The id of the object representing the entry. |
| 74 | // TODO: figure out how these should be called. id or oid? It's inconsistent around the codebase. | 74 | // TODO: figure out how these should be called. id or oid? It's inconsistent around the codebase. |
| 75 | // Answer: make it 'id', as in `git2` | 75 | // Answer: make it 'id', as in `git2` |
| 76 | #[cfg_attr(feature = "serde", serde(borrow))] | 76 | #[cfg_attr(feature = "serde", serde(borrow))] |
| 77 | pub oid: &'a gix_hash::oid, | 77 | pub oid: &'a gix_hash::oid, |
| 78 | } | 78 | } |
| @@ -84,11 +84,14 @@ impl<'a> PartialOrd for EntryRef<'a> { · 5 unmodified lines | |||
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | impl<'a> Ord for EntryRef<'a> { | 86 | impl<'a> Ord for EntryRef<'a> { |
| 87 | /// Entries compare by the common portion of the filename. This is critical for proper functioning of algorithms working on trees. | 87 | fn cmp(&self, b: &Self) -> Ordering { |
| 88 | /// Doing it like this is needed for compatibility with older, potentially broken(?) trees. | 88 | let a = self; |
| 89 | fn cmp(&self, other: &Self) -> Ordering { | 89 | let common = a.filename.len().min(b.filename.len()); |
| 90 | let len = self.filename.len().min(other.filename.len()); | 90 | a.filename[..common].cmp(&b.filename[..common]).then_with(|| { |
| 91 | self.filename[..len].cmp(&other.filename[..len]) | 91 | let a = a.filename.get(common).or_else(|| a.mode.is_tree().then_some(&b'/')); |
| 92 | let b = b.filename.get(common).or_else(|| b.mode.is_tree().then_some(&b'/')); | ||
| 93 | a.cmp(&b) | ||
| 94 | }) | ||
| 92 | } | 95 | } |
| 93 | } | 96 | } |
| 94 | 97 | ||
| @@ -111,12 +114,14 @@ impl PartialOrd for Entry { · 16 unmodified lines | |||
| 111 | } | 114 | } |
| 112 | 115 | ||
| 113 | impl Ord for Entry { | 116 | impl Ord for Entry { |
| 114 | /// Entries compare by the common portion of the filename. This is critical for proper functioning of algorithms working on trees. | 117 | fn cmp(&self, b: &Self) -> Ordering { |
| 115 | fn cmp(&self, other: &Self) -> Ordering { | 118 | let a = self; |
| 116 | let common_len = self.filename.len().min(other.filename.len()); | 119 | let common = a.filename.len().min(b.filename.len()); |
| 117 | self.filename[..common_len] | 120 | a.filename[..common].cmp(&b.filename[..common]).then_with(|| { |
| 118 | .cmp(&other.filename[..common_len]) | 121 | let a = a.filename.get(common).or_else(|| a.mode.is_tree().then_some(&b'/')); |
| 119 | .then_with(|| self.filename.len().cmp(&other.filename.len())) | 122 | let b = b.filename.get(common).or_else(|| b.mode.is_tree().then_some(&b'/')); |
| 123 | a.cmp(&b) | ||
| 124 | }) | ||
| 120 | } | 125 | } |
| 121 | } | 126 | } |
| 122 | 127 | ||
| @@ -53,16 +53,16 @@ impl crate::WriteTo for Tree { · 52 unmodified lines | |||
| 53 | Ok(()) | 53 | Ok(()) |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | fn kind(&self) -> Kind { | ||
| 57 | Kind::Tree | ||
| 58 | } | ||
| 59 | |||
| 56 | fn size(&self) -> usize { | 60 | fn size(&self) -> usize { |
| 57 | self.entries | 61 | self.entries |
| 58 | .iter() | 62 | .iter() |
| 59 | .map(|Entry { mode, filename, oid }| mode.as_bytes().len() + 1 + filename.len() + 1 + oid.as_bytes().len()) | 63 | .map(|Entry { mode, filename, oid }| mode.as_bytes().len() + 1 + filename.len() + 1 + oid.as_bytes().len()) |
| 60 | .sum() | 64 | .sum() |
| 61 | } | 65 | } |
| 62 | |||
| 63 | fn kind(&self) -> Kind { | ||
| 64 | Kind::Tree | ||
| 65 | } | ||
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | /// Serialization | 68 | /// Serialization |
| @@ -96,6 +96,10 @@ impl<'a> crate::WriteTo for TreeRef<'a> { · 27 unmodified lines | |||
| 96 | Ok(()) | 96 | Ok(()) |
| 97 | } | 97 | } |
| 98 | 98 | ||
| 99 | fn kind(&self) -> Kind { | ||
| 100 | Kind::Tree | ||
| 101 | } | ||
| 102 | |||
| 99 | fn size(&self) -> usize { | 103 | fn size(&self) -> usize { |
| 100 | self.entries | 104 | self.entries |
| 101 | .iter() | 105 | .iter() |
| @@ -104,8 +108,4 @@ impl<'a> crate::WriteTo for TreeRef<'a> { · 2 unmodified lines | |||
| 104 | }) | 108 | }) |
| 105 | .sum() | 109 | .sum() |
| 106 | } | 110 | } |
| 107 | |||
| 108 | fn kind(&self) -> Kind { | ||
| 109 | Kind::Tree | ||
| 110 | } | ||
| 111 | } | 111 | } |
| @@ -0,0 +1,3 @@ | |||
| 1 | version https://git-lfs.github.com/spec/v1 | ||
| 2 | oid sha256:9d0ebc472023fffe49d71303e5f41f8c6ca24e28d283468f2426791c6286ecf7 | ||
| 3 | size 10240 | ||
| @@ -0,0 +1,19 @@ | |||
| 1 | #!/bin/bash | ||
| 2 | set -eu -o pipefail | ||
| 3 | |||
| 4 | function baseline() { | ||
| 5 | local revspec=${1:?First argument is the revspec of the object to create a baseline for} | ||
| 6 | local basename=${2:?Second argument is the name of the baseline file} | ||
| 7 | local baseline_file="$basename.baseline" | ||
| 8 | git rev-parse "$revspec" | git cat-file --batch | tail -n +2 > "$baseline_file" | ||
| 9 | truncate -s "$(($(stat -c '%s' "$baseline_file")-1))" "$baseline_file" | ||
| 10 | } | ||
| 11 | |||
| 12 | git init -q | ||
| 13 | mkdir file | ||
| 14 | touch bin bin.d file.to file.toml file.toml.bin file0 file/a | ||
| 15 | |||
| 16 | git add . | ||
| 17 | git commit -m "c1" | ||
| 18 | |||
| 19 | baseline @^{tree} tree | ||
| @@ -130,6 +130,29 @@ mod from_bytes { · 129 unmodified lines | |||
| 130 | } | 130 | } |
| 131 | } | 131 | } |
| 132 | 132 | ||
| 133 | mod entries { | ||
| 134 | use gix_object::{Tree, TreeRef}; | ||
| 135 | |||
| 136 | #[test] | ||
| 137 | fn sort_order_is_correct() -> crate::Result { | ||
| 138 | let root = gix_testtools::scripted_fixture_read_only("make_trees.sh")?; | ||
| 139 | let input = std::fs::read(root.join("tree.baseline"))?; | ||
| 140 | |||
| 141 | let mut tree = TreeRef::from_bytes(&input)?; | ||
| 142 | let expected = tree.entries.clone(); | ||
| 143 | |||
| 144 | tree.entries.sort(); | ||
| 145 | assert_eq!(tree.entries, expected); | ||
| 146 | |||
| 147 | let mut tree: Tree = tree.into(); | ||
| 148 | let expected = tree.entries.clone(); | ||
| 149 | tree.entries.sort(); | ||
| 150 | |||
| 151 | assert_eq!(tree.entries, expected); | ||
| 152 | Ok(()) | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 133 | mod entry_mode { | 156 | mod entry_mode { |
| 134 | use gix_object::tree::EntryMode; | 157 | use gix_object::tree::EntryMode; |
| 135 | 158 | ||