1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
use crate::loose::Db;
use git_features::fs;
#[derive(thiserror::Error, Debug)]
#[allow(missing_docs)]
pub enum Error {
#[error(transparent)]
WalkDir(#[from] fs::walkdir::Error),
}
pub type Type = std::iter::FilterMap<
fs::walkdir::DirEntryIter,
fn(Result<fs::walkdir::DirEntry, fs::walkdir::Error>) -> Option<Result<git_hash::ObjectId, Error>>,
>;
impl Db {
fn iter_filter_map(
res: Result<fs::walkdir::DirEntry, fs::walkdir::Error>,
) -> Option<Result<git_hash::ObjectId, Error>> {
use std::path::Component::Normal;
let mut is_valid_path = false;
let e = res.map_err(Error::WalkDir).map(|e| {
let p = e.path();
let mut ci = p.components();
let (c2, c1) = (ci.next_back(), ci.next_back());
if let (Some(Normal(c1)), Some(Normal(c2))) = (c1, c2) {
if c1.len() == 2 && c2.len() == 38 {
if let (Some(c1), Some(c2)) = (c1.to_str(), c2.to_str()) {
let mut buf = [0u8; 40];
{
let (first_byte, rest) = buf.split_at_mut(2);
first_byte.copy_from_slice(c1.as_bytes());
rest.copy_from_slice(c2.as_bytes());
}
if let Ok(b) = git_hash::ObjectId::from_hex(&buf[..]) {
is_valid_path = true;
return b;
}
}
}
}
git_hash::ObjectId::null_sha1()
});
if is_valid_path {
Some(e)
} else {
None
}
}
pub fn iter(&self) -> Type {
fs::walkdir_new(&self.path)
.min_depth(2)
.max_depth(3)
.follow_links(false)
.into_iter()
.filter_map(Db::iter_filter_map)
}
}