]> git.proxmox.com Git - rustc.git/blame - vendor/gix/src/revision/spec/parse/delegate/navigate.rs
New upstream version 1.74.1+dfsg1
[rustc.git] / vendor / gix / src / revision / spec / parse / delegate / navigate.rs
CommitLineData
0a29b90c
FG
1use std::collections::HashSet;
2
3use gix_hash::ObjectId;
4use gix_revision::spec::parse::{
5 delegate,
6 delegate::{PeelTo, Traversal},
7};
8use gix_traverse::commit::Sorting;
9
10use crate::{
11 bstr::{BStr, ByteSlice},
12 ext::ObjectIdExt,
13 object,
14 revision::spec::parse::{
15 delegate::{handle_errors_and_replacements, peel, Replacements},
16 Delegate, Error,
17 },
781aab86 18 Object,
0a29b90c
FG
19};
20
21impl<'repo> delegate::Navigate for Delegate<'repo> {
22 fn traverse(&mut self, kind: Traversal) -> Option<()> {
23 self.unset_disambiguate_call();
24 self.follow_refs_to_objects_if_needed()?;
25
26 let mut replacements = Replacements::default();
27 let mut errors = Vec::new();
28 let objs = self.objs[self.idx].as_mut()?;
29 let repo = self.repo;
30
31 for obj in objs.iter() {
32 match kind {
33 Traversal::NthParent(num) => {
34 match self.repo.find_object(*obj).map_err(Error::from).and_then(|obj| {
35 obj.try_into_commit().map_err(|err| {
36 let object::try_into::Error { actual, expected, id } = err;
37 Error::ObjectKind {
38 oid: id.attach(repo).shorten_or_id(),
39 actual,
40 expected,
41 }
42 })
43 }) {
44 Ok(commit) => match commit.parent_ids().nth(num.saturating_sub(1)) {
45 Some(id) => replacements.push((commit.id, id.detach())),
46 None => errors.push((
47 commit.id,
48 Error::ParentOutOfRange {
49 oid: commit.id().shorten_or_id(),
50 desired: num,
51 available: commit.parent_ids().count(),
52 },
53 )),
54 },
55 Err(err) => errors.push((*obj, err)),
56 }
57 }
58 Traversal::NthAncestor(num) => {
59 let id = obj.attach(repo);
60 match id
61 .ancestors()
62 .first_parent_only()
63 .all()
64 .expect("cannot fail without sorting")
65 .skip(num)
781aab86 66 .find_map(Result::ok)
0a29b90c 67 {
781aab86 68 Some(commit) => replacements.push((*obj, commit.id)),
0a29b90c
FG
69 None => errors.push((
70 *obj,
71 Error::AncestorOutOfRange {
72 oid: id.shorten_or_id(),
73 desired: num,
74 available: id
75 .ancestors()
76 .first_parent_only()
77 .all()
78 .expect("cannot fail without sorting")
79 .skip(1)
80 .count(),
81 },
82 )),
83 }
84 }
85 }
86 }
87
88 handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
89 }
90
91 fn peel_until(&mut self, kind: PeelTo<'_>) -> Option<()> {
92 self.unset_disambiguate_call();
93 self.follow_refs_to_objects_if_needed()?;
94
95 let mut replacements = Replacements::default();
96 let mut errors = Vec::new();
97 let objs = self.objs[self.idx].as_mut()?;
98 let repo = self.repo;
99
100 match kind {
101 PeelTo::ValidObject => {
102 for obj in objs.iter() {
103 match repo.find_object(*obj) {
104 Ok(_) => {}
105 Err(err) => {
106 errors.push((*obj, err.into()));
107 }
108 };
109 }
110 }
111 PeelTo::ObjectKind(kind) => {
112 let peel = |obj| peel(repo, obj, kind);
113 for obj in objs.iter() {
114 match peel(obj) {
115 Ok(replace) => replacements.push((*obj, replace)),
116 Err(err) => errors.push((*obj, err)),
117 }
118 }
119 }
120 PeelTo::Path(path) => {
121 let lookup_path = |obj: &ObjectId| {
122 let tree_id = peel(repo, obj, gix_object::Kind::Tree)?;
123 if path.is_empty() {
124 return Ok(tree_id);
125 }
781aab86 126 let mut tree = repo.find_object(tree_id)?.into_tree();
0a29b90c 127 let entry =
781aab86 128 tree.peel_to_entry_by_path(gix_path::from_bstr(path))?
0a29b90c
FG
129 .ok_or_else(|| Error::PathNotFound {
130 path: path.into(),
131 object: obj.attach(repo).shorten_or_id(),
132 tree: tree_id.attach(repo).shorten_or_id(),
133 })?;
134 Ok(entry.object_id())
135 };
136 for obj in objs.iter() {
137 match lookup_path(obj) {
138 Ok(replace) => replacements.push((*obj, replace)),
139 Err(err) => errors.push((*obj, err)),
140 }
141 }
142 }
143 PeelTo::RecursiveTagObject => {
144 for oid in objs.iter() {
781aab86 145 match oid.attach(repo).object().and_then(Object::peel_tags_to_end) {
0a29b90c
FG
146 Ok(obj) => replacements.push((*oid, obj.id)),
147 Err(err) => errors.push((*oid, err.into())),
148 }
149 }
150 }
151 }
152
153 handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
154 }
155
156 fn find(&mut self, regex: &BStr, negated: bool) -> Option<()> {
157 self.unset_disambiguate_call();
158 self.follow_refs_to_objects_if_needed()?;
159
781aab86 160 #[cfg(not(feature = "revparse-regex"))]
0a29b90c 161 let matches = |message: &BStr| -> bool { message.contains_str(regex) ^ negated };
781aab86 162 #[cfg(feature = "revparse-regex")]
0a29b90c
FG
163 let matches = match regex::bytes::Regex::new(regex.to_str_lossy().as_ref()) {
164 Ok(compiled) => {
165 let needs_regex = regex::escape(compiled.as_str()) != regex;
166 move |message: &BStr| -> bool {
167 if needs_regex {
168 compiled.is_match(message) ^ negated
169 } else {
170 message.contains_str(regex) ^ negated
171 }
172 }
173 }
174 Err(err) => {
175 self.err.push(err.into());
176 return None;
177 }
178 };
179
180 match self.objs[self.idx].as_mut() {
181 Some(objs) => {
182 let repo = self.repo;
183 let mut errors = Vec::new();
184 let mut replacements = Replacements::default();
185 for oid in objs.iter() {
186 match oid
187 .attach(repo)
188 .ancestors()
189 .sorting(Sorting::ByCommitTimeNewestFirst)
190 .all()
191 {
192 Ok(iter) => {
193 let mut matched = false;
194 let mut count = 0;
195 let commits = iter.map(|res| {
781aab86
FG
196 res.map_err(Error::from).and_then(|commit| {
197 commit.id().object().map_err(Error::from).map(Object::into_commit)
0a29b90c
FG
198 })
199 });
200 for commit in commits {
201 count += 1;
202 match commit {
203 Ok(commit) => {
204 if matches(commit.message_raw_sloppy()) {
205 replacements.push((*oid, commit.id));
206 matched = true;
207 break;
208 }
209 }
210 Err(err) => errors.push((*oid, err)),
211 }
212 }
213 if !matched {
214 errors.push((
215 *oid,
216 Error::NoRegexMatch {
217 regex: regex.into(),
218 commits_searched: count,
219 oid: oid.attach(repo).shorten_or_id(),
220 },
221 ))
222 }
223 }
224 Err(err) => errors.push((*oid, err.into())),
225 }
226 }
227 handle_errors_and_replacements(&mut self.err, objs, errors, &mut replacements)
228 }
229 None => match self.repo.references() {
230 Ok(references) => match references.all() {
231 Ok(references) => {
232 match self
233 .repo
234 .rev_walk(
235 references
236 .peeled()
237 .filter_map(Result::ok)
238 .filter(|r| {
239 r.id()
240 .object()
241 .ok()
fe692bf9 242 .map_or(false, |obj| obj.kind == gix_object::Kind::Commit)
0a29b90c
FG
243 })
244 .filter_map(|r| r.detach().peeled),
245 )
246 .sorting(Sorting::ByCommitTimeNewestFirst)
247 .all()
248 {
249 Ok(iter) => {
250 let mut matched = false;
251 let mut count = 0;
252 let commits = iter.map(|res| {
781aab86
FG
253 res.map_err(Error::from).and_then(|commit| {
254 commit.id().object().map_err(Error::from).map(Object::into_commit)
0a29b90c
FG
255 })
256 });
257 for commit in commits {
258 count += 1;
259 match commit {
260 Ok(commit) => {
261 if matches(commit.message_raw_sloppy()) {
262 self.objs[self.idx]
263 .get_or_insert_with(HashSet::default)
264 .insert(commit.id);
265 matched = true;
266 break;
267 }
268 }
269 Err(err) => self.err.push(err),
270 }
271 }
272 if matched {
273 Some(())
274 } else {
275 self.err.push(Error::NoRegexMatchAllRefs {
276 regex: regex.into(),
277 commits_searched: count,
278 });
279 None
280 }
281 }
282 Err(err) => {
283 self.err.push(err.into());
284 None
285 }
286 }
287 }
288 Err(err) => {
289 self.err.push(err.into());
290 None
291 }
292 },
293 Err(err) => {
294 self.err.push(err.into());
295 None
296 }
297 },
298 }
299 }
300
301 fn index_lookup(&mut self, path: &BStr, stage: u8) -> Option<()> {
302 self.unset_disambiguate_call();
303 match self.repo.index() {
304 Ok(index) => match index.entry_by_path_and_stage(path, stage.into()) {
305 Some(entry) => {
306 self.objs[self.idx]
307 .get_or_insert_with(HashSet::default)
308 .insert(entry.id);
309 Some(())
310 }
311 None => {
312 let stage_hint = [0, 1, 2]
313 .iter()
314 .filter(|our_stage| **our_stage != stage)
315 .find_map(|stage| {
316 index
317 .entry_index_by_path_and_stage(path, (*stage).into())
318 .map(|_| (*stage).into())
319 });
320 let exists = self
321 .repo
322 .work_dir()
323 .map_or(false, |root| root.join(gix_path::from_bstr(path)).exists());
324 self.err.push(Error::IndexLookup {
325 desired_path: path.into(),
326 desired_stage: stage.into(),
327 exists,
328 stage_hint,
329 });
330 None
331 }
332 },
333 Err(err) => {
334 self.err.push(err.into());
335 None
336 }
337 }
338 }
339}