]> git.proxmox.com Git - rustc.git/blob - vendor/gix-ref/src/store/file/loose/iter.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / gix-ref / src / store / file / loose / iter.rs
1 use std::path::{Path, PathBuf};
2
3 use gix_features::fs::walkdir::DirEntryIter;
4 use gix_object::bstr::ByteSlice;
5
6 use crate::{file::iter::LooseThenPacked, store_impl::file, BString, FullName};
7
8 /// An iterator over all valid loose reference paths as seen from a particular base directory.
9 pub(in crate::store_impl::file) struct SortedLoosePaths {
10 pub(crate) base: PathBuf,
11 filename_prefix: Option<BString>,
12 file_walk: Option<DirEntryIter>,
13 }
14
15 impl SortedLoosePaths {
16 pub fn at(path: &Path, base: PathBuf, filename_prefix: Option<BString>) -> Self {
17 SortedLoosePaths {
18 base,
19 filename_prefix,
20 file_walk: path.is_dir().then(|| {
21 // serial iteration as we expect most refs in packed-refs anyway.
22 gix_features::fs::walkdir_sorted_new(path, gix_features::fs::walkdir::Parallelism::Serial).into_iter()
23 }),
24 }
25 }
26 }
27
28 impl Iterator for SortedLoosePaths {
29 type Item = std::io::Result<(PathBuf, FullName)>;
30
31 fn next(&mut self) -> Option<Self::Item> {
32 for entry in self.file_walk.as_mut()?.by_ref() {
33 match entry {
34 Ok(entry) => {
35 if !entry.file_type().is_file() {
36 continue;
37 }
38 let full_path = entry.path().to_owned();
39 if let Some((prefix, name)) = self
40 .filename_prefix
41 .as_deref()
42 .and_then(|prefix| full_path.file_name().map(|name| (prefix, name)))
43 {
44 match gix_path::os_str_into_bstr(name) {
45 Ok(name) => {
46 if !name.starts_with(prefix) {
47 continue;
48 }
49 }
50 Err(_) => continue, // TODO: silently skipping ill-formed UTF-8 on windows - maybe this can be better?
51 }
52 }
53 let full_name = full_path
54 .strip_prefix(&self.base)
55 .expect("prefix-stripping cannot fail as prefix is our root");
56 let full_name = match gix_path::try_into_bstr(full_name) {
57 Ok(name) => {
58 let name = gix_path::to_unix_separators_on_windows(name);
59 name.into_owned()
60 }
61 Err(_) => continue, // TODO: silently skipping ill-formed UTF-8 on windows here, maybe there are better ways?
62 };
63
64 if gix_validate::reference::name_partial(full_name.as_bstr()).is_ok() {
65 let name = FullName(full_name);
66 return Some(Ok((full_path, name)));
67 } else {
68 continue;
69 }
70 }
71 Err(err) => return Some(Err(err.into_io_error().expect("no symlink related errors"))),
72 }
73 }
74 None
75 }
76 }
77
78 impl file::Store {
79 /// Return an iterator over all loose references, notably not including any packed ones, in lexical order.
80 /// Each of the references may fail to parse and the iterator will not stop if parsing fails, allowing the caller
81 /// to see all files that look like references whether valid or not.
82 ///
83 /// Reference files that do not constitute valid names will be silently ignored.
84 pub fn loose_iter(&self) -> std::io::Result<LooseThenPacked<'_, '_>> {
85 self.iter_packed(None)
86 }
87
88 /// Return an iterator over all loose references that start with the given `prefix`.
89 ///
90 /// Otherwise it's similar to [`loose_iter()`][file::Store::loose_iter()].
91 pub fn loose_iter_prefixed(&self, prefix: &Path) -> std::io::Result<LooseThenPacked<'_, '_>> {
92 self.iter_prefixed_packed(prefix, None)
93 }
94 }