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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
use std::path::{Path, PathBuf};
use bstr::{BStr, ByteSlice};
use git_hash::oid;
use super::Cache;
use crate::{fs, fs::PathOidMapping};
#[derive(Clone)]
pub enum State {
CreateDirectoryAndAttributesStack {
unlink_on_collision: bool,
#[cfg(debug_assertions)]
test_mkdir_calls: usize,
attributes: state::Attributes,
},
AttributesAndIgnoreStack {
attributes: state::Attributes,
ignore: state::Ignore,
},
IgnoreStack(state::Ignore),
}
#[cfg(debug_assertions)]
impl<'paths> Cache<'paths> {
pub fn set_case(&mut self, case: git_glob::pattern::Case) {
self.case = case;
}
pub fn num_mkdir_calls(&self) -> usize {
match self.state {
State::CreateDirectoryAndAttributesStack { test_mkdir_calls, .. } => test_mkdir_calls,
_ => 0,
}
}
pub fn reset_mkdir_calls(&mut self) {
if let State::CreateDirectoryAndAttributesStack { test_mkdir_calls, .. } = &mut self.state {
*test_mkdir_calls = 0;
}
}
pub fn unlink_on_collision(&mut self, value: bool) {
if let State::CreateDirectoryAndAttributesStack {
unlink_on_collision, ..
} = &mut self.state
{
*unlink_on_collision = value;
}
}
}
#[must_use]
pub struct Platform<'a, 'paths> {
parent: &'a Cache<'paths>,
is_dir: Option<bool>,
}
impl<'paths> Cache<'paths> {
pub fn new(
worktree_root: impl Into<PathBuf>,
state: State,
case: git_glob::pattern::Case,
buf: Vec<u8>,
attribute_files_in_index: Vec<PathOidMapping<'paths>>,
) -> Self {
let root = worktree_root.into();
Cache {
stack: fs::Stack::new(root),
state,
case,
buf,
attribute_files_in_index,
}
}
pub fn at_path<Find, E>(
&mut self,
relative: impl AsRef<Path>,
is_dir: Option<bool>,
find: Find,
) -> std::io::Result<Platform<'_, 'paths>>
where
Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<git_object::BlobRef<'a>, E>,
E: std::error::Error + Send + Sync + 'static,
{
let mut delegate = platform::StackDelegate {
state: &mut self.state,
buf: &mut self.buf,
is_dir: is_dir.unwrap_or(false),
attribute_files_in_index: &self.attribute_files_in_index,
find,
};
self.stack.make_relative_path_current(relative, &mut delegate)?;
Ok(Platform { parent: self, is_dir })
}
pub fn at_entry<'r, Find, E>(
&mut self,
relative: impl Into<&'r BStr>,
is_dir: Option<bool>,
find: Find,
) -> std::io::Result<Platform<'_, 'paths>>
where
Find: for<'a> FnMut(&oid, &'a mut Vec<u8>) -> Result<git_object::BlobRef<'a>, E>,
E: std::error::Error + Send + Sync + 'static,
{
let relative = relative.into();
let relative_path = git_path::from_bstr(relative);
self.at_path(
relative_path,
is_dir.or_else(|| relative.ends_with_str("/").then(|| true)),
find,
)
}
pub fn base(&self) -> &Path {
self.stack.root()
}
}
mod platform;
pub mod state;