Skip to content

Commit f5bdc4f

Browse files
committed
fix!: make fs::walkdir_sorted_new() sort entries by paths literally (#1928)
This follows up 7b1b5bf. Since packed-refs appears to be sorted by full ref name, loose-refs should also be emitted in that order. The comparison function is copied from gix::diff::object::tree::EntryRef. Non-utf8 file names are simply mapped to "" on Windows. We could add some fallback, but callers can't handle such file names anyway.
1 parent c151b8d commit f5bdc4f

File tree

6 files changed

+25
-29
lines changed

6 files changed

+25
-29
lines changed

Cargo.lock

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

gix-features/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ parallel = ["dep:crossbeam-channel", "dep:parking_lot"]
4848
once_cell = ["dep:once_cell"]
4949
## Makes facilities of the `walkdir` crate partially available.
5050
## In conjunction with the **parallel** feature, directory walking will be parallel instead behind a compatible interface.
51-
walkdir = ["dep:walkdir", "dep:gix-utils"]
51+
walkdir = ["dep:walkdir", "dep:gix-path", "dep:gix-utils"]
5252
#* an in-memory unidirectional pipe using `bytes` as efficient transfer mechanism.
5353
io-pipe = ["dep:bytes"]
5454
## provide a proven and fast `crc32` implementation.
@@ -106,6 +106,7 @@ required-features = ["io-pipe"]
106106
gix-trace = { version = "^0.1.12", path = "../gix-trace" }
107107

108108
# for walkdir
109+
gix-path = { version = "^0.10.15", path = "../gix-path", optional = true }
109110
gix-utils = { version = "^0.2.0", path = "../gix-utils", optional = true }
110111

111112
# 'parallel' feature

gix-features/src/fs.rs

+10-10
Original file line numberDiff line numberDiff line change
@@ -217,19 +217,19 @@ pub mod walkdir {
217217
///
218218
/// Use `precompose_unicode` to represent the `core.precomposeUnicode` configuration option.
219219
pub fn walkdir_sorted_new(root: &Path, _: Parallelism, precompose_unicode: bool) -> WalkDir {
220-
fn ft_to_number(ft: std::fs::FileType) -> usize {
221-
if ft.is_file() {
222-
1
223-
} else {
224-
2
225-
}
226-
}
227220
WalkDir {
228221
inner: WalkDirImpl::new(root)
229222
.sort_by(|a, b| {
230-
ft_to_number(a.file_type())
231-
.cmp(&ft_to_number(b.file_type()))
232-
.then_with(|| a.file_name().cmp(b.file_name()))
223+
// Ignore non-utf8 file name on Windows, which would probably be rejected by caller.
224+
let a_name = gix_path::os_str_into_bstr(a.file_name()).unwrap_or("".as_ref());
225+
let b_name = gix_path::os_str_into_bstr(b.file_name()).unwrap_or("".as_ref());
226+
// "common." < "common/" < "common0"
227+
let common = a_name.len().min(b_name.len());
228+
a_name[..common].cmp(&b_name[..common]).then_with(|| {
229+
let a = a_name.get(common).or_else(|| a.file_type().is_dir().then_some(&b'/'));
230+
let b = b_name.get(common).or_else(|| b.file_type().is_dir().then_some(&b'/'));
231+
a.cmp(&b)
232+
})
233233
})
234234
.into(),
235235
precompose_unicode,

gix-ref/tests/refs/file/store/iter.rs

+9-15
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ mod with_namespace {
3131
.map(|r: gix_ref::Reference| r.name)
3232
.collect::<Vec<_>>();
3333
let expected_namespaced_refs = vec![
34-
"refs/namespaces/bar/refs/multi-link",
3534
"refs/namespaces/bar/refs/heads/multi-link-target1",
35+
"refs/namespaces/bar/refs/multi-link",
3636
"refs/namespaces/bar/refs/remotes/origin/multi-link-target3",
3737
"refs/namespaces/bar/refs/tags/multi-link-target2",
3838
];
@@ -50,8 +50,8 @@ mod with_namespace {
5050
.map(|r| r.name.into_inner())
5151
.collect::<Vec<_>>(),
5252
[
53-
"refs/namespaces/bar/refs/multi-link",
5453
"refs/namespaces/bar/refs/heads/multi-link-target1",
54+
"refs/namespaces/bar/refs/multi-link",
5555
"refs/namespaces/bar/refs/tags/multi-link-target2"
5656
]
5757
);
@@ -149,8 +149,8 @@ mod with_namespace {
149149
let packed = ns_store.open_packed_buffer()?;
150150

151151
let expected_refs = vec![
152-
"refs/multi-link",
153152
"refs/heads/multi-link-target1",
153+
"refs/multi-link",
154154
"refs/remotes/origin/multi-link-target3",
155155
"refs/tags/multi-link-target2",
156156
];
@@ -198,8 +198,8 @@ mod with_namespace {
198198
.map(|r| r.name.into_inner())
199199
.collect::<Vec<_>>(),
200200
[
201-
"refs/multi-link",
202201
"refs/heads/multi-link-target1",
202+
"refs/multi-link",
203203
"refs/tags/multi-link-target2",
204204
],
205205
"loose iterators have namespace support as well"
@@ -214,8 +214,8 @@ mod with_namespace {
214214
.map(|r| r.name.into_inner())
215215
.collect::<Vec<_>>(),
216216
[
217-
"refs/namespaces/bar/refs/multi-link",
218217
"refs/namespaces/bar/refs/heads/multi-link-target1",
218+
"refs/namespaces/bar/refs/multi-link",
219219
"refs/namespaces/bar/refs/tags/multi-link-target2",
220220
"refs/namespaces/foo/refs/remotes/origin/HEAD"
221221
],
@@ -291,14 +291,14 @@ fn loose_iter_with_broken_refs() -> crate::Result {
291291
ref_paths,
292292
vec![
293293
"d1",
294-
"loop-a",
295-
"loop-b",
296-
"multi-link",
297294
"heads/A",
298295
"heads/d1",
299296
"heads/dt1",
300297
"heads/main",
301298
"heads/multi-link-target1",
299+
"loop-a",
300+
"loop-b",
301+
"multi-link",
302302
"remotes/origin/HEAD",
303303
"remotes/origin/main",
304304
"remotes/origin/multi-link-target3",
@@ -483,7 +483,7 @@ fn overlay_iter_reproduce_1928() -> crate::Result {
483483
(
484484
"refs/heads/a/b",
485485
Object(
486-
Sha1(2222222222222222222222222222222222222222),
486+
Sha1(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb),
487487
),
488488
),
489489
(
@@ -492,12 +492,6 @@ fn overlay_iter_reproduce_1928() -> crate::Result {
492492
Sha1(cccccccccccccccccccccccccccccccccccccccc),
493493
),
494494
),
495-
(
496-
"refs/heads/a/b",
497-
Object(
498-
Sha1(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb),
499-
),
500-
),
501495
]
502496
"#);
503497
Ok(())

gix-submodule/tests/file/baseline.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ fn common_values_and_names_by_path() -> crate::Result {
2424
"recursive-clone/submodule/.gitmodules",
2525
"relative-clone/.gitmodules",
2626
"relative-clone/submodule/.gitmodules",
27-
"super/.gitmodules",
28-
"super/submodule/.gitmodules",
2927
"super-clone/.gitmodules",
3028
"super-clone/submodule/.gitmodules",
29+
"super/.gitmodules",
30+
"super/submodule/.gitmodules",
3131
"top-only-clone/.gitmodules"
3232
]
3333
.into_iter()

gix/tests/gix/repository/reference.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,10 @@ mod iter_references {
102102
"refs/heads/d1",
103103
"refs/heads/dt1",
104104
"refs/heads/main",
105+
"refs/heads/multi-link-target1",
105106
"refs/loop-a",
106107
"refs/loop-b",
107108
"refs/multi-link",
108-
"refs/heads/multi-link-target1",
109109
"refs/remotes/origin/HEAD",
110110
"refs/remotes/origin/main",
111111
"refs/remotes/origin/multi-link-target3",

0 commit comments

Comments
 (0)