Show More
@@ -5,6 +5,7 b'' | |||||
5 | // This software may be used and distributed according to the terms of the |
|
5 | // This software may be used and distributed according to the terms of the | |
6 | // GNU General Public License version 2 or any later version. |
|
6 | // GNU General Public License version 2 or any later version. | |
7 |
|
7 | |||
|
8 | use crate::dirstate_tree::on_disk::DirstateV2ParseError; | |||
8 | use crate::errors::HgError; |
|
9 | use crate::errors::HgError; | |
9 | use crate::revlog::Node; |
|
10 | use crate::revlog::Node; | |
10 | use crate::utils::hg_path::{HgPath, HgPathBuf}; |
|
11 | use crate::utils::hg_path::{HgPath, HgPathBuf}; | |
@@ -76,12 +77,19 b' const MTIME_UNSET: i32 = -1;' | |||||
76 | pub const SIZE_FROM_OTHER_PARENT: i32 = -2; |
|
77 | pub const SIZE_FROM_OTHER_PARENT: i32 = -2; | |
77 |
|
78 | |||
78 | pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>; |
|
79 | pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>; | |
79 | pub type StateMapIter<'a> = |
|
80 | pub type StateMapIter<'a> = Box< | |
80 | Box<dyn Iterator<Item = (&'a HgPath, DirstateEntry)> + Send + 'a>; |
|
81 | dyn Iterator< | |
|
82 | Item = Result<(&'a HgPath, DirstateEntry), DirstateV2ParseError>, | |||
|
83 | > + Send | |||
|
84 | + 'a, | |||
|
85 | >; | |||
81 |
|
86 | |||
82 | pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>; |
|
87 | pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>; | |
83 | pub type CopyMapIter<'a> = |
|
88 | pub type CopyMapIter<'a> = Box< | |
84 |
|
|
89 | dyn Iterator<Item = Result<(&'a HgPath, &'a HgPath), DirstateV2ParseError>> | |
|
90 | + Send | |||
|
91 | + 'a, | |||
|
92 | >; | |||
85 |
|
93 | |||
86 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] |
|
94 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] | |
87 | pub enum EntryState { |
|
95 | pub enum EntryState { |
@@ -8,13 +8,14 b'' | |||||
8 | //! A multiset of directory names. |
|
8 | //! A multiset of directory names. | |
9 | //! |
|
9 | //! | |
10 | //! Used to counts the references to directories in a manifest or dirstate. |
|
10 | //! Used to counts the references to directories in a manifest or dirstate. | |
|
11 | use crate::dirstate_tree::on_disk::DirstateV2ParseError; | |||
11 | use crate::{ |
|
12 | use crate::{ | |
12 | dirstate::EntryState, |
|
13 | dirstate::EntryState, | |
13 | utils::{ |
|
14 | utils::{ | |
14 | files, |
|
15 | files, | |
15 | hg_path::{HgPath, HgPathBuf, HgPathError}, |
|
16 | hg_path::{HgPath, HgPathBuf, HgPathError}, | |
16 | }, |
|
17 | }, | |
17 | DirstateEntry, DirstateMapError, FastHashMap, |
|
18 | DirstateEntry, DirstateError, DirstateMapError, FastHashMap, | |
18 | }; |
|
19 | }; | |
19 | use std::collections::{hash_map, hash_map::Entry, HashMap, HashSet}; |
|
20 | use std::collections::{hash_map, hash_map::Entry, HashMap, HashSet}; | |
20 |
|
21 | |||
@@ -33,15 +34,18 b' impl DirsMultiset {' | |||||
33 | pub fn from_dirstate<I, P>( |
|
34 | pub fn from_dirstate<I, P>( | |
34 | dirstate: I, |
|
35 | dirstate: I, | |
35 | skip_state: Option<EntryState>, |
|
36 | skip_state: Option<EntryState>, | |
36 |
) -> Result<Self, Dirstate |
|
37 | ) -> Result<Self, DirstateError> | |
37 | where |
|
38 | where | |
38 |
I: IntoIterator< |
|
39 | I: IntoIterator< | |
|
40 | Item = Result<(P, DirstateEntry), DirstateV2ParseError>, | |||
|
41 | >, | |||
39 | P: AsRef<HgPath>, |
|
42 | P: AsRef<HgPath>, | |
40 | { |
|
43 | { | |
41 | let mut multiset = DirsMultiset { |
|
44 | let mut multiset = DirsMultiset { | |
42 | inner: FastHashMap::default(), |
|
45 | inner: FastHashMap::default(), | |
43 | }; |
|
46 | }; | |
44 |
for |
|
47 | for item in dirstate { | |
|
48 | let (filename, entry) = item?; | |||
45 | let filename = filename.as_ref(); |
|
49 | let filename = filename.as_ref(); | |
46 | // This `if` is optimized out of the loop |
|
50 | // This `if` is optimized out of the loop | |
47 | if let Some(skip) = skip_state { |
|
51 | if let Some(skip) = skip_state { | |
@@ -337,8 +341,11 b' mod tests {' | |||||
337 | }; |
|
341 | }; | |
338 | assert_eq!(expected, new); |
|
342 | assert_eq!(expected, new); | |
339 |
|
343 | |||
340 | let new = |
|
344 | let new = DirsMultiset::from_dirstate( | |
341 |
|
|
345 | StateMap::default().into_iter().map(Ok), | |
|
346 | None, | |||
|
347 | ) | |||
|
348 | .unwrap(); | |||
342 | let expected = DirsMultiset { |
|
349 | let expected = DirsMultiset { | |
343 | inner: FastHashMap::default(), |
|
350 | inner: FastHashMap::default(), | |
344 | }; |
|
351 | }; | |
@@ -362,20 +369,17 b' mod tests {' | |||||
362 | }; |
|
369 | }; | |
363 | assert_eq!(expected, new); |
|
370 | assert_eq!(expected, new); | |
364 |
|
371 | |||
365 |
let input_map |
|
372 | let input_map = ["b/x", "a/c", "a/d/x"].iter().map(|f| { | |
366 |
|
|
373 | Ok(( | |
367 | .map(|f| { |
|
374 | HgPathBuf::from_bytes(f.as_bytes()), | |
368 |
|
|
375 | DirstateEntry { | |
369 | HgPathBuf::from_bytes(f.as_bytes()), |
|
376 | state: EntryState::Normal, | |
370 |
|
|
377 | mode: 0, | |
371 |
|
|
378 | mtime: 0, | |
372 |
|
|
379 | size: 0, | |
373 |
|
|
380 | }, | |
374 | size: 0, |
|
381 | )) | |
375 | }, |
|
382 | }); | |
376 | ) |
|
|||
377 | }) |
|
|||
378 | .collect(); |
|
|||
379 | let expected_inner = [("", 2), ("a", 2), ("b", 1), ("a/d", 1)] |
|
383 | let expected_inner = [("", 2), ("a", 2), ("b", 1), ("a/d", 1)] | |
380 | .iter() |
|
384 | .iter() | |
381 | .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v)) |
|
385 | .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v)) | |
@@ -390,7 +394,7 b' mod tests {' | |||||
390 |
|
394 | |||
391 | #[test] |
|
395 | #[test] | |
392 | fn test_dirsmultiset_new_skip() { |
|
396 | fn test_dirsmultiset_new_skip() { | |
393 |
let input_map |
|
397 | let input_map = [ | |
394 | ("a/", EntryState::Normal), |
|
398 | ("a/", EntryState::Normal), | |
395 | ("a/b", EntryState::Normal), |
|
399 | ("a/b", EntryState::Normal), | |
396 | ("a/c", EntryState::Removed), |
|
400 | ("a/c", EntryState::Removed), | |
@@ -398,7 +402,7 b' mod tests {' | |||||
398 | ] |
|
402 | ] | |
399 | .iter() |
|
403 | .iter() | |
400 | .map(|(f, state)| { |
|
404 | .map(|(f, state)| { | |
401 | ( |
|
405 | Ok(( | |
402 | HgPathBuf::from_bytes(f.as_bytes()), |
|
406 | HgPathBuf::from_bytes(f.as_bytes()), | |
403 | DirstateEntry { |
|
407 | DirstateEntry { | |
404 | state: *state, |
|
408 | state: *state, | |
@@ -406,9 +410,8 b' mod tests {' | |||||
406 | mtime: 0, |
|
410 | mtime: 0, | |
407 | size: 0, |
|
411 | size: 0, | |
408 | }, |
|
412 | }, | |
409 | ) |
|
413 | )) | |
410 | }) |
|
414 | }); | |
411 | .collect(); |
|
|||
412 |
|
415 | |||
413 | // "a" incremented with "a/c" and "a/d/" |
|
416 | // "a" incremented with "a/c" and "a/d/" | |
414 | let expected_inner = [("", 1), ("a", 2)] |
|
417 | let expected_inner = [("", 1), ("a", 2)] |
@@ -10,8 +10,8 b' use crate::{' | |||||
10 | dirstate::EntryState, |
|
10 | dirstate::EntryState, | |
11 | pack_dirstate, parse_dirstate, |
|
11 | pack_dirstate, parse_dirstate, | |
12 | utils::hg_path::{HgPath, HgPathBuf}, |
|
12 | utils::hg_path::{HgPath, HgPathBuf}, | |
13 |
CopyMap, DirsMultiset, DirstateEntry, DirstateError, Dirstate |
|
13 | CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateParents, | |
14 |
|
|
14 | StateMap, | |
15 | }; |
|
15 | }; | |
16 | use micro_timer::timed; |
|
16 | use micro_timer::timed; | |
17 | use std::collections::HashSet; |
|
17 | use std::collections::HashSet; | |
@@ -66,7 +66,7 b' impl DirstateMap {' | |||||
66 | filename: &HgPath, |
|
66 | filename: &HgPath, | |
67 | old_state: EntryState, |
|
67 | old_state: EntryState, | |
68 | entry: DirstateEntry, |
|
68 | entry: DirstateEntry, | |
69 |
) -> Result<(), Dirstate |
|
69 | ) -> Result<(), DirstateError> { | |
70 | if old_state == EntryState::Unknown || old_state == EntryState::Removed |
|
70 | if old_state == EntryState::Unknown || old_state == EntryState::Removed | |
71 | { |
|
71 | { | |
72 | if let Some(ref mut dirs) = self.dirs { |
|
72 | if let Some(ref mut dirs) = self.dirs { | |
@@ -104,7 +104,7 b' impl DirstateMap {' | |||||
104 | filename: &HgPath, |
|
104 | filename: &HgPath, | |
105 | old_state: EntryState, |
|
105 | old_state: EntryState, | |
106 | size: i32, |
|
106 | size: i32, | |
107 |
) -> Result<(), Dirstate |
|
107 | ) -> Result<(), DirstateError> { | |
108 | if old_state != EntryState::Unknown && old_state != EntryState::Removed |
|
108 | if old_state != EntryState::Unknown && old_state != EntryState::Removed | |
109 | { |
|
109 | { | |
110 | if let Some(ref mut dirs) = self.dirs { |
|
110 | if let Some(ref mut dirs) = self.dirs { | |
@@ -138,7 +138,7 b' impl DirstateMap {' | |||||
138 | &mut self, |
|
138 | &mut self, | |
139 | filename: &HgPath, |
|
139 | filename: &HgPath, | |
140 | old_state: EntryState, |
|
140 | old_state: EntryState, | |
141 |
) -> Result<bool, Dirstate |
|
141 | ) -> Result<bool, DirstateError> { | |
142 | let exists = self.state_map.remove(filename).is_some(); |
|
142 | let exists = self.state_map.remove(filename).is_some(); | |
143 |
|
143 | |||
144 | if exists { |
|
144 | if exists { | |
@@ -246,20 +246,20 b' impl DirstateMap {' | |||||
246 | /// emulate a Python lazy property, but it is ugly and unidiomatic. |
|
246 | /// emulate a Python lazy property, but it is ugly and unidiomatic. | |
247 | /// TODO One day, rewriting this struct using the typestate might be a |
|
247 | /// TODO One day, rewriting this struct using the typestate might be a | |
248 | /// good idea. |
|
248 | /// good idea. | |
249 |
pub fn set_all_dirs(&mut self) -> Result<(), Dirstate |
|
249 | pub fn set_all_dirs(&mut self) -> Result<(), DirstateError> { | |
250 | if self.all_dirs.is_none() { |
|
250 | if self.all_dirs.is_none() { | |
251 | self.all_dirs = Some(DirsMultiset::from_dirstate( |
|
251 | self.all_dirs = Some(DirsMultiset::from_dirstate( | |
252 | self.state_map.iter().map(|(k, v)| (k, *v)), |
|
252 | self.state_map.iter().map(|(k, v)| Ok((k, *v))), | |
253 | None, |
|
253 | None, | |
254 | )?); |
|
254 | )?); | |
255 | } |
|
255 | } | |
256 | Ok(()) |
|
256 | Ok(()) | |
257 | } |
|
257 | } | |
258 |
|
258 | |||
259 |
pub fn set_dirs(&mut self) -> Result<(), Dirstate |
|
259 | pub fn set_dirs(&mut self) -> Result<(), DirstateError> { | |
260 | if self.dirs.is_none() { |
|
260 | if self.dirs.is_none() { | |
261 | self.dirs = Some(DirsMultiset::from_dirstate( |
|
261 | self.dirs = Some(DirsMultiset::from_dirstate( | |
262 | self.state_map.iter().map(|(k, v)| (k, *v)), |
|
262 | self.state_map.iter().map(|(k, v)| Ok((k, *v))), | |
263 | Some(EntryState::Removed), |
|
263 | Some(EntryState::Removed), | |
264 | )?); |
|
264 | )?); | |
265 | } |
|
265 | } | |
@@ -269,7 +269,7 b' impl DirstateMap {' | |||||
269 | pub fn has_tracked_dir( |
|
269 | pub fn has_tracked_dir( | |
270 | &mut self, |
|
270 | &mut self, | |
271 | directory: &HgPath, |
|
271 | directory: &HgPath, | |
272 |
) -> Result<bool, Dirstate |
|
272 | ) -> Result<bool, DirstateError> { | |
273 | self.set_dirs()?; |
|
273 | self.set_dirs()?; | |
274 | Ok(self.dirs.as_ref().unwrap().contains(directory)) |
|
274 | Ok(self.dirs.as_ref().unwrap().contains(directory)) | |
275 | } |
|
275 | } | |
@@ -277,7 +277,7 b' impl DirstateMap {' | |||||
277 | pub fn has_dir( |
|
277 | pub fn has_dir( | |
278 | &mut self, |
|
278 | &mut self, | |
279 | directory: &HgPath, |
|
279 | directory: &HgPath, | |
280 |
) -> Result<bool, Dirstate |
|
280 | ) -> Result<bool, DirstateError> { | |
281 | self.set_all_dirs()?; |
|
281 | self.set_all_dirs()?; | |
282 | Ok(self.all_dirs.as_ref().unwrap().contains(directory)) |
|
282 | Ok(self.all_dirs.as_ref().unwrap().contains(directory)) | |
283 | } |
|
283 | } |
@@ -43,13 +43,18 b' pub fn parse_dirstate(contents: &[u8]) -' | |||||
43 | copies.push((path, source)); |
|
43 | copies.push((path, source)); | |
44 | } |
|
44 | } | |
45 | entries.push((path, *entry)); |
|
45 | entries.push((path, *entry)); | |
|
46 | Ok(()) | |||
46 | })?; |
|
47 | })?; | |
47 | Ok((parents, entries, copies)) |
|
48 | Ok((parents, entries, copies)) | |
48 | } |
|
49 | } | |
49 |
|
50 | |||
50 | pub fn parse_dirstate_entries<'a>( |
|
51 | pub fn parse_dirstate_entries<'a>( | |
51 | mut contents: &'a [u8], |
|
52 | mut contents: &'a [u8], | |
52 | mut each_entry: impl FnMut(&'a HgPath, &DirstateEntry, Option<&'a HgPath>), |
|
53 | mut each_entry: impl FnMut( | |
|
54 | &'a HgPath, | |||
|
55 | &DirstateEntry, | |||
|
56 | Option<&'a HgPath>, | |||
|
57 | ) -> Result<(), HgError>, | |||
53 | ) -> Result<&'a DirstateParents, HgError> { |
|
58 | ) -> Result<&'a DirstateParents, HgError> { | |
54 | let (parents, rest) = DirstateParents::from_bytes(contents) |
|
59 | let (parents, rest) = DirstateParents::from_bytes(contents) | |
55 | .map_err(|_| HgError::corrupted("Too little data for dirstate."))?; |
|
60 | .map_err(|_| HgError::corrupted("Too little data for dirstate."))?; | |
@@ -75,7 +80,7 b" pub fn parse_dirstate_entries<'a>(" | |||||
75 | iter.next().expect("splitn always yields at least one item"), |
|
80 | iter.next().expect("splitn always yields at least one item"), | |
76 | ); |
|
81 | ); | |
77 | let copy_source = iter.next().map(HgPath::new); |
|
82 | let copy_source = iter.next().map(HgPath::new); | |
78 | each_entry(path, &entry, copy_source); |
|
83 | each_entry(path, &entry, copy_source)?; | |
79 |
|
84 | |||
80 | contents = rest; |
|
85 | contents = rest; | |
81 | } |
|
86 | } |
@@ -9,6 +9,7 b'' | |||||
9 | //! It is currently missing a lot of functionality compared to the Python one |
|
9 | //! It is currently missing a lot of functionality compared to the Python one | |
10 | //! and will only be triggered in narrow cases. |
|
10 | //! and will only be triggered in narrow cases. | |
11 |
|
11 | |||
|
12 | use crate::dirstate_tree::on_disk::DirstateV2ParseError; | |||
12 | use crate::utils::path_auditor::PathAuditor; |
|
13 | use crate::utils::path_auditor::PathAuditor; | |
13 | use crate::{ |
|
14 | use crate::{ | |
14 | dirstate::SIZE_FROM_OTHER_PARENT, |
|
15 | dirstate::SIZE_FROM_OTHER_PARENT, | |
@@ -302,6 +303,8 b' pub enum StatusError {' | |||||
302 | Path(HgPathError), |
|
303 | Path(HgPathError), | |
303 | /// An invalid "ignore" pattern was found |
|
304 | /// An invalid "ignore" pattern was found | |
304 | Pattern(PatternError), |
|
305 | Pattern(PatternError), | |
|
306 | /// Corrupted dirstate | |||
|
307 | DirstateV2ParseError(DirstateV2ParseError), | |||
305 | } |
|
308 | } | |
306 |
|
309 | |||
307 | pub type StatusResult<T> = Result<T, StatusError>; |
|
310 | pub type StatusResult<T> = Result<T, StatusError>; | |
@@ -312,6 +315,9 b' impl fmt::Display for StatusError {' | |||||
312 | StatusError::IO(error) => error.fmt(f), |
|
315 | StatusError::IO(error) => error.fmt(f), | |
313 | StatusError::Path(error) => error.fmt(f), |
|
316 | StatusError::Path(error) => error.fmt(f), | |
314 | StatusError::Pattern(error) => error.fmt(f), |
|
317 | StatusError::Pattern(error) => error.fmt(f), | |
|
318 | StatusError::DirstateV2ParseError(_) => { | |||
|
319 | f.write_str("dirstate-v2 parse error") | |||
|
320 | } | |||
315 | } |
|
321 | } | |
316 | } |
|
322 | } | |
317 | } |
|
323 | } |
@@ -5,6 +5,7 b' use std::convert::TryInto;' | |||||
5 | use std::path::PathBuf; |
|
5 | use std::path::PathBuf; | |
6 |
|
6 | |||
7 | use super::on_disk; |
|
7 | use super::on_disk; | |
|
8 | use super::on_disk::DirstateV2ParseError; | |||
8 | use super::path_with_basename::WithBasename; |
|
9 | use super::path_with_basename::WithBasename; | |
9 | use crate::dirstate::parsers::pack_entry; |
|
10 | use crate::dirstate::parsers::pack_entry; | |
10 | use crate::dirstate::parsers::packed_entry_size; |
|
11 | use crate::dirstate::parsers::packed_entry_size; | |
@@ -15,7 +16,6 b' use crate::utils::hg_path::{HgPath, HgPa' | |||||
15 | use crate::CopyMapIter; |
|
16 | use crate::CopyMapIter; | |
16 | use crate::DirstateEntry; |
|
17 | use crate::DirstateEntry; | |
17 | use crate::DirstateError; |
|
18 | use crate::DirstateError; | |
18 | use crate::DirstateMapError; |
|
|||
19 | use crate::DirstateParents; |
|
19 | use crate::DirstateParents; | |
20 | use crate::DirstateStatus; |
|
20 | use crate::DirstateStatus; | |
21 | use crate::EntryState; |
|
21 | use crate::EntryState; | |
@@ -81,9 +81,12 b" impl<'on_disk> ChildNodes<'on_disk> {" | |||||
81 |
|
81 | |||
82 | pub(super) fn make_mut( |
|
82 | pub(super) fn make_mut( | |
83 | &mut self, |
|
83 | &mut self, | |
84 | ) -> &mut FastHashMap<NodeKey<'on_disk>, Node<'on_disk>> { |
|
84 | ) -> Result< | |
|
85 | &mut FastHashMap<NodeKey<'on_disk>, Node<'on_disk>>, | |||
|
86 | DirstateV2ParseError, | |||
|
87 | > { | |||
85 | match self { |
|
88 | match self { | |
86 | ChildNodes::InMemory(nodes) => nodes, |
|
89 | ChildNodes::InMemory(nodes) => Ok(nodes), | |
87 | } |
|
90 | } | |
88 | } |
|
91 | } | |
89 | } |
|
92 | } | |
@@ -92,11 +95,11 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
92 | pub(super) fn get( |
|
95 | pub(super) fn get( | |
93 | &self, |
|
96 | &self, | |
94 | base_name: &HgPath, |
|
97 | base_name: &HgPath, | |
95 | ) -> Option<NodeRef<'tree, 'on_disk>> { |
|
98 | ) -> Result<Option<NodeRef<'tree, 'on_disk>>, DirstateV2ParseError> { | |
96 | match self { |
|
99 | match self { | |
97 | ChildNodesRef::InMemory(nodes) => nodes |
|
100 | ChildNodesRef::InMemory(nodes) => Ok(nodes | |
98 | .get_key_value(base_name) |
|
101 | .get_key_value(base_name) | |
99 | .map(|(k, v)| NodeRef::InMemory(k, v)), |
|
102 | .map(|(k, v)| NodeRef::InMemory(k, v))), | |
100 | } |
|
103 | } | |
101 | } |
|
104 | } | |
102 |
|
105 | |||
@@ -131,9 +134,14 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
131 | .iter() |
|
134 | .iter() | |
132 | .map(|(k, v)| NodeRef::InMemory(k, v)) |
|
135 | .map(|(k, v)| NodeRef::InMemory(k, v)) | |
133 | .collect(); |
|
136 | .collect(); | |
|
137 | fn sort_key<'a>(node: &'a NodeRef) -> &'a HgPath { | |||
|
138 | match node { | |||
|
139 | NodeRef::InMemory(path, _node) => path.base_name(), | |||
|
140 | } | |||
|
141 | } | |||
134 | // `sort_unstable_by_key` doesnβt allow keys borrowing from the |
|
142 | // `sort_unstable_by_key` doesnβt allow keys borrowing from the | |
135 | // value: https://github.com/rust-lang/rust/issues/34162 |
|
143 | // value: https://github.com/rust-lang/rust/issues/34162 | |
136 |
vec.sort_unstable_by(|a, b| a |
|
144 | vec.sort_unstable_by(|a, b| sort_key(a).cmp(sort_key(b))); | |
137 | vec |
|
145 | vec | |
138 | } |
|
146 | } | |
139 | } |
|
147 | } | |
@@ -141,35 +149,51 b" impl<'tree, 'on_disk> ChildNodesRef<'tre" | |||||
141 | } |
|
149 | } | |
142 |
|
150 | |||
143 | impl<'tree, 'on_disk> NodeRef<'tree, 'on_disk> { |
|
151 | impl<'tree, 'on_disk> NodeRef<'tree, 'on_disk> { | |
144 |
pub(super) fn full_path( |
|
152 | pub(super) fn full_path( | |
|
153 | &self, | |||
|
154 | ) -> Result<&'tree HgPath, DirstateV2ParseError> { | |||
145 | match self { |
|
155 | match self { | |
146 | NodeRef::InMemory(path, _node) => path.full_path(), |
|
156 | NodeRef::InMemory(path, _node) => Ok(path.full_path()), | |
147 | } |
|
157 | } | |
148 | } |
|
158 | } | |
149 |
|
159 | |||
150 | /// Returns a `Cow` that can borrow 'on_disk but is detached from 'tree |
|
160 | /// Returns a `Cow` that can borrow 'on_disk but is detached from 'tree | |
151 |
pub(super) fn full_path_cow( |
|
161 | pub(super) fn full_path_cow( | |
|
162 | &self, | |||
|
163 | ) -> Result<Cow<'on_disk, HgPath>, DirstateV2ParseError> { | |||
152 | match self { |
|
164 | match self { | |
153 | NodeRef::InMemory(path, _node) => path.full_path().clone(), |
|
165 | NodeRef::InMemory(path, _node) => Ok(path.full_path().clone()), | |
|
166 | } | |||
|
167 | } | |||
|
168 | ||||
|
169 | pub(super) fn base_name( | |||
|
170 | &self, | |||
|
171 | ) -> Result<&'tree HgPath, DirstateV2ParseError> { | |||
|
172 | match self { | |||
|
173 | NodeRef::InMemory(path, _node) => Ok(path.base_name()), | |||
154 | } |
|
174 | } | |
155 | } |
|
175 | } | |
156 |
|
176 | |||
157 | pub(super) fn base_name(&self) -> &'tree HgPath { |
|
177 | pub(super) fn children( | |
|
178 | &self, | |||
|
179 | ) -> Result<ChildNodesRef<'tree, 'on_disk>, DirstateV2ParseError> { | |||
158 | match self { |
|
180 | match self { | |
159 |
NodeRef::InMemory(path, |
|
181 | NodeRef::InMemory(_path, node) => Ok(node.children.as_ref()), | |
160 | } |
|
182 | } | |
161 | } |
|
183 | } | |
162 |
|
184 | |||
163 | pub(super) fn children(&self) -> ChildNodesRef<'tree, 'on_disk> { |
|
185 | pub(super) fn has_copy_source(&self) -> bool { | |
164 | match self { |
|
186 | match self { | |
165 |
NodeRef::InMemory(_path, node) => node.c |
|
187 | NodeRef::InMemory(_path, node) => node.copy_source.is_some(), | |
166 | } |
|
188 | } | |
167 | } |
|
189 | } | |
168 |
|
190 | |||
169 |
pub(super) fn copy_source( |
|
191 | pub(super) fn copy_source( | |
|
192 | &self, | |||
|
193 | ) -> Result<Option<&'tree HgPath>, DirstateV2ParseError> { | |||
170 | match self { |
|
194 | match self { | |
171 | NodeRef::InMemory(_path, node) => { |
|
195 | NodeRef::InMemory(_path, node) => { | |
172 | node.copy_source.as_ref().map(|s| &**s) |
|
196 | Ok(node.copy_source.as_ref().map(|s| &**s)) | |
173 | } |
|
197 | } | |
174 | } |
|
198 | } | |
175 | } |
|
199 | } | |
@@ -180,15 +204,20 b" impl<'tree, 'on_disk> NodeRef<'tree, 'on" | |||||
180 | } |
|
204 | } | |
181 | } |
|
205 | } | |
182 |
|
206 | |||
183 | pub(super) fn entry(&self) -> Option<DirstateEntry> { |
|
207 | pub(super) fn entry( | |
|
208 | &self, | |||
|
209 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { | |||
184 | match self { |
|
210 | match self { | |
185 | NodeRef::InMemory(_path, node) => node.entry, |
|
211 | NodeRef::InMemory(_path, node) => Ok(node.entry), | |
186 | } |
|
212 | } | |
187 | } |
|
213 | } | |
188 | pub(super) fn state(&self) -> Option<EntryState> { |
|
214 | ||
|
215 | pub(super) fn state( | |||
|
216 | &self, | |||
|
217 | ) -> Result<Option<EntryState>, DirstateV2ParseError> { | |||
189 | match self { |
|
218 | match self { | |
190 | NodeRef::InMemory(_path, node) => { |
|
219 | NodeRef::InMemory(_path, node) => { | |
191 | node.entry.as_ref().map(|entry| entry.state) |
|
220 | Ok(node.entry.as_ref().map(|entry| entry.state)) | |
192 | } |
|
221 | } | |
193 | } |
|
222 | } | |
194 | } |
|
223 | } | |
@@ -253,7 +282,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
253 | ancestor.tracked_descendants_count += 1 |
|
282 | ancestor.tracked_descendants_count += 1 | |
254 | } |
|
283 | } | |
255 | }, |
|
284 | }, | |
256 | ); |
|
285 | )?; | |
257 | assert!( |
|
286 | assert!( | |
258 | node.entry.is_none(), |
|
287 | node.entry.is_none(), | |
259 | "duplicate dirstate entry in read" |
|
288 | "duplicate dirstate entry in read" | |
@@ -268,6 +297,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
268 | if copy_source.is_some() { |
|
297 | if copy_source.is_some() { | |
269 | map.nodes_with_copy_source_count += 1 |
|
298 | map.nodes_with_copy_source_count += 1 | |
270 | } |
|
299 | } | |
|
300 | Ok(()) | |||
271 | }, |
|
301 | }, | |
272 | )?; |
|
302 | )?; | |
273 | let parents = Some(parents.clone()); |
|
303 | let parents = Some(parents.clone()); | |
@@ -278,18 +308,21 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
278 | fn get_node<'tree>( |
|
308 | fn get_node<'tree>( | |
279 | &'tree self, |
|
309 | &'tree self, | |
280 | path: &HgPath, |
|
310 | path: &HgPath, | |
281 | ) -> Option<NodeRef<'tree, 'on_disk>> { |
|
311 | ) -> Result<Option<NodeRef<'tree, 'on_disk>>, DirstateV2ParseError> { | |
282 | let mut children = self.root.as_ref(); |
|
312 | let mut children = self.root.as_ref(); | |
283 | let mut components = path.components(); |
|
313 | let mut components = path.components(); | |
284 | let mut component = |
|
314 | let mut component = | |
285 | components.next().expect("expected at least one components"); |
|
315 | components.next().expect("expected at least one components"); | |
286 | loop { |
|
316 | loop { | |
287 |
let child = children.get(component)? |
|
317 | if let Some(child) = children.get(component)? { | |
288 | if let Some(next_component) = components.next() { |
|
318 | if let Some(next_component) = components.next() { | |
289 | component = next_component; |
|
319 | component = next_component; | |
290 | children = child.children(); |
|
320 | children = child.children()?; | |
|
321 | } else { | |||
|
322 | return Ok(Some(child)); | |||
|
323 | } | |||
291 | } else { |
|
324 | } else { | |
292 |
return |
|
325 | return Ok(None); | |
293 | } |
|
326 | } | |
294 | } |
|
327 | } | |
295 | } |
|
328 | } | |
@@ -301,18 +334,21 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
301 | fn get_node_mut<'tree>( |
|
334 | fn get_node_mut<'tree>( | |
302 | root: &'tree mut ChildNodes<'on_disk>, |
|
335 | root: &'tree mut ChildNodes<'on_disk>, | |
303 | path: &HgPath, |
|
336 | path: &HgPath, | |
304 | ) -> Option<&'tree mut Node<'on_disk>> { |
|
337 | ) -> Result<Option<&'tree mut Node<'on_disk>>, DirstateV2ParseError> { | |
305 | let mut children = root; |
|
338 | let mut children = root; | |
306 | let mut components = path.components(); |
|
339 | let mut components = path.components(); | |
307 | let mut component = |
|
340 | let mut component = | |
308 | components.next().expect("expected at least one components"); |
|
341 | components.next().expect("expected at least one components"); | |
309 | loop { |
|
342 | loop { | |
310 |
let child = children.make_mut().get_mut(component) |
|
343 | if let Some(child) = children.make_mut()?.get_mut(component) { | |
311 | if let Some(next_component) = components.next() { |
|
344 | if let Some(next_component) = components.next() { | |
312 | component = next_component; |
|
345 | component = next_component; | |
313 | children = &mut child.children; |
|
346 | children = &mut child.children; | |
|
347 | } else { | |||
|
348 | return Ok(Some(child)); | |||
|
349 | } | |||
314 | } else { |
|
350 | } else { | |
315 |
return |
|
351 | return Ok(None); | |
316 | } |
|
352 | } | |
317 | } |
|
353 | } | |
318 | } |
|
354 | } | |
@@ -324,7 +360,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
324 | WithBasename<&'path HgPath>, |
|
360 | WithBasename<&'path HgPath>, | |
325 | ) -> WithBasename<Cow<'on_disk, HgPath>>, |
|
361 | ) -> WithBasename<Cow<'on_disk, HgPath>>, | |
326 | mut each_ancestor: impl FnMut(&mut Node), |
|
362 | mut each_ancestor: impl FnMut(&mut Node), | |
327 | ) -> &'tree mut Node<'on_disk> { |
|
363 | ) -> Result<&'tree mut Node<'on_disk>, DirstateV2ParseError> { | |
328 | let mut child_nodes = root; |
|
364 | let mut child_nodes = root; | |
329 | let mut inclusive_ancestor_paths = |
|
365 | let mut inclusive_ancestor_paths = | |
330 | WithBasename::inclusive_ancestors_of(path); |
|
366 | WithBasename::inclusive_ancestors_of(path); | |
@@ -336,7 +372,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
336 | // map already contains that key, without introducing double |
|
372 | // map already contains that key, without introducing double | |
337 | // lookup? |
|
373 | // lookup? | |
338 | let child_node = child_nodes |
|
374 | let child_node = child_nodes | |
339 | .make_mut() |
|
375 | .make_mut()? | |
340 | .entry(to_cow(ancestor_path)) |
|
376 | .entry(to_cow(ancestor_path)) | |
341 | .or_default(); |
|
377 | .or_default(); | |
342 | if let Some(next) = inclusive_ancestor_paths.next() { |
|
378 | if let Some(next) = inclusive_ancestor_paths.next() { | |
@@ -344,7 +380,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
344 | ancestor_path = next; |
|
380 | ancestor_path = next; | |
345 | child_nodes = &mut child_node.children; |
|
381 | child_nodes = &mut child_node.children; | |
346 | } else { |
|
382 | } else { | |
347 | return child_node; |
|
383 | return Ok(child_node); | |
348 | } |
|
384 | } | |
349 | } |
|
385 | } | |
350 | } |
|
386 | } | |
@@ -354,7 +390,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
354 | path: &HgPath, |
|
390 | path: &HgPath, | |
355 | old_state: EntryState, |
|
391 | old_state: EntryState, | |
356 | new_entry: DirstateEntry, |
|
392 | new_entry: DirstateEntry, | |
357 | ) { |
|
393 | ) -> Result<(), DirstateV2ParseError> { | |
358 | let tracked_count_increment = |
|
394 | let tracked_count_increment = | |
359 | match (old_state.is_tracked(), new_entry.state.is_tracked()) { |
|
395 | match (old_state.is_tracked(), new_entry.state.is_tracked()) { | |
360 | (false, true) => 1, |
|
396 | (false, true) => 1, | |
@@ -376,16 +412,19 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
376 | _ => {} |
|
412 | _ => {} | |
377 | } |
|
413 | } | |
378 | }, |
|
414 | }, | |
379 | ); |
|
415 | )?; | |
380 | if node.entry.is_none() { |
|
416 | if node.entry.is_none() { | |
381 | self.nodes_with_entry_count += 1 |
|
417 | self.nodes_with_entry_count += 1 | |
382 | } |
|
418 | } | |
383 | node.entry = Some(new_entry) |
|
419 | node.entry = Some(new_entry); | |
|
420 | Ok(()) | |||
384 | } |
|
421 | } | |
385 |
|
422 | |||
386 | fn iter_nodes<'tree>( |
|
423 | fn iter_nodes<'tree>( | |
387 | &'tree self, |
|
424 | &'tree self, | |
388 | ) -> impl Iterator<Item = NodeRef<'tree, 'on_disk>> + 'tree { |
|
425 | ) -> impl Iterator< | |
|
426 | Item = Result<NodeRef<'tree, 'on_disk>, DirstateV2ParseError>, | |||
|
427 | > + 'tree { | |||
389 | // Depth first tree traversal. |
|
428 | // Depth first tree traversal. | |
390 | // |
|
429 | // | |
391 | // If we could afford internal iteration and recursion, |
|
430 | // If we could afford internal iteration and recursion, | |
@@ -409,8 +448,12 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
409 | let mut iter = self.root.as_ref().iter(); |
|
448 | let mut iter = self.root.as_ref().iter(); | |
410 | std::iter::from_fn(move || { |
|
449 | std::iter::from_fn(move || { | |
411 | while let Some(child_node) = iter.next() { |
|
450 | while let Some(child_node) = iter.next() { | |
|
451 | let children = match child_node.children() { | |||
|
452 | Ok(children) => children, | |||
|
453 | Err(error) => return Some(Err(error)), | |||
|
454 | }; | |||
412 | // Pseudo-recursion |
|
455 | // Pseudo-recursion | |
413 |
let new_iter = |
|
456 | let new_iter = children.iter(); | |
414 | let old_iter = std::mem::replace(&mut iter, new_iter); |
|
457 | let old_iter = std::mem::replace(&mut iter, new_iter); | |
415 | stack.push((child_node, old_iter)); |
|
458 | stack.push((child_node, old_iter)); | |
416 | } |
|
459 | } | |
@@ -420,7 +463,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
420 | // explicit stack |
|
463 | // explicit stack | |
421 | iter = next_iter; |
|
464 | iter = next_iter; | |
422 |
|
465 | |||
423 | Some(child_node) |
|
466 | Some(Ok(child_node)) | |
424 | } else { |
|
467 | } else { | |
425 | // Reached the bottom of the stack, weβre done |
|
468 | // Reached the bottom of the stack, weβre done | |
426 | None |
|
469 | None | |
@@ -428,17 +471,62 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
428 | }) |
|
471 | }) | |
429 | } |
|
472 | } | |
430 |
|
473 | |||
431 |
fn clear_known_ambiguous_mtimes( |
|
474 | fn clear_known_ambiguous_mtimes( | |
|
475 | &mut self, | |||
|
476 | paths: &[impl AsRef<HgPath>], | |||
|
477 | ) -> Result<(), DirstateV2ParseError> { | |||
432 | for path in paths { |
|
478 | for path in paths { | |
433 | if let Some(node) = |
|
479 | if let Some(node) = | |
434 | Self::get_node_mut(&mut self.root, path.as_ref()) |
|
480 | Self::get_node_mut(&mut self.root, path.as_ref())? | |
435 | { |
|
481 | { | |
436 | if let Some(entry) = node.entry.as_mut() { |
|
482 | if let Some(entry) = node.entry.as_mut() { | |
437 | entry.clear_mtime(); |
|
483 | entry.clear_mtime(); | |
438 | } |
|
484 | } | |
439 | } |
|
485 | } | |
440 | } |
|
486 | } | |
|
487 | Ok(()) | |||
441 | } |
|
488 | } | |
|
489 | ||||
|
490 | /// Return a faillilble iterator of full paths of nodes that have an | |||
|
491 | /// `entry` for which the given `predicate` returns true. | |||
|
492 | /// | |||
|
493 | /// Fallibility means that each iterator item is a `Result`, which may | |||
|
494 | /// indicate a parse error of the on-disk dirstate-v2 format. Such errors | |||
|
495 | /// should only happen if Mercurial is buggy or a repository is corrupted. | |||
|
496 | fn filter_full_paths<'tree>( | |||
|
497 | &'tree self, | |||
|
498 | predicate: impl Fn(&DirstateEntry) -> bool + 'tree, | |||
|
499 | ) -> impl Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + 'tree | |||
|
500 | { | |||
|
501 | filter_map_results(self.iter_nodes(), move |node| { | |||
|
502 | if let Some(entry) = node.entry()? { | |||
|
503 | if predicate(&entry) { | |||
|
504 | return Ok(Some(node.full_path()?)); | |||
|
505 | } | |||
|
506 | } | |||
|
507 | Ok(None) | |||
|
508 | }) | |||
|
509 | } | |||
|
510 | } | |||
|
511 | ||||
|
512 | /// Like `Iterator::filter_map`, but over a fallible iterator of `Result`s. | |||
|
513 | /// | |||
|
514 | /// The callback is only called for incoming `Ok` values. Errors are passed | |||
|
515 | /// through as-is. In order to let it use the `?` operator the callback is | |||
|
516 | /// expected to return a `Result` of `Option`, instead of an `Option` of | |||
|
517 | /// `Result`. | |||
|
518 | fn filter_map_results<'a, I, F, A, B, E>( | |||
|
519 | iter: I, | |||
|
520 | f: F, | |||
|
521 | ) -> impl Iterator<Item = Result<B, E>> + 'a | |||
|
522 | where | |||
|
523 | I: Iterator<Item = Result<A, E>> + 'a, | |||
|
524 | F: Fn(A) -> Result<Option<B>, E> + 'a, | |||
|
525 | { | |||
|
526 | iter.filter_map(move |result| match result { | |||
|
527 | Ok(node) => f(node).transpose(), | |||
|
528 | Err(e) => Some(Err(e)), | |||
|
529 | }) | |||
442 | } |
|
530 | } | |
443 |
|
531 | |||
444 | impl<'on_disk> super::dispatch::DirstateMapMethods for DirstateMap<'on_disk> { |
|
532 | impl<'on_disk> super::dispatch::DirstateMapMethods for DirstateMap<'on_disk> { | |
@@ -453,9 +541,8 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
453 | filename: &HgPath, |
|
541 | filename: &HgPath, | |
454 | old_state: EntryState, |
|
542 | old_state: EntryState, | |
455 | entry: DirstateEntry, |
|
543 | entry: DirstateEntry, | |
456 |
) -> Result<(), Dirstate |
|
544 | ) -> Result<(), DirstateError> { | |
457 |
self.add_or_remove_file(filename, old_state, entry) |
|
545 | Ok(self.add_or_remove_file(filename, old_state, entry)?) | |
458 | Ok(()) |
|
|||
459 | } |
|
546 | } | |
460 |
|
547 | |||
461 | fn remove_file( |
|
548 | fn remove_file( | |
@@ -463,36 +550,48 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
463 | filename: &HgPath, |
|
550 | filename: &HgPath, | |
464 | old_state: EntryState, |
|
551 | old_state: EntryState, | |
465 | size: i32, |
|
552 | size: i32, | |
466 |
) -> Result<(), Dirstate |
|
553 | ) -> Result<(), DirstateError> { | |
467 | let entry = DirstateEntry { |
|
554 | let entry = DirstateEntry { | |
468 | state: EntryState::Removed, |
|
555 | state: EntryState::Removed, | |
469 | mode: 0, |
|
556 | mode: 0, | |
470 | size, |
|
557 | size, | |
471 | mtime: 0, |
|
558 | mtime: 0, | |
472 | }; |
|
559 | }; | |
473 |
self.add_or_remove_file(filename, old_state, entry) |
|
560 | Ok(self.add_or_remove_file(filename, old_state, entry)?) | |
474 | Ok(()) |
|
|||
475 | } |
|
561 | } | |
476 |
|
562 | |||
477 | fn drop_file( |
|
563 | fn drop_file( | |
478 | &mut self, |
|
564 | &mut self, | |
479 | filename: &HgPath, |
|
565 | filename: &HgPath, | |
480 | old_state: EntryState, |
|
566 | old_state: EntryState, | |
481 |
) -> Result<bool, Dirstate |
|
567 | ) -> Result<bool, DirstateError> { | |
482 | struct Dropped { |
|
568 | struct Dropped { | |
483 | was_tracked: bool, |
|
569 | was_tracked: bool, | |
484 | had_entry: bool, |
|
570 | had_entry: bool, | |
485 | had_copy_source: bool, |
|
571 | had_copy_source: bool, | |
486 | } |
|
572 | } | |
487 | fn recur(nodes: &mut ChildNodes, path: &HgPath) -> Option<Dropped> { |
|
573 | fn recur( | |
|
574 | nodes: &mut ChildNodes, | |||
|
575 | path: &HgPath, | |||
|
576 | ) -> Result<Option<Dropped>, DirstateV2ParseError> { | |||
488 | let (first_path_component, rest_of_path) = |
|
577 | let (first_path_component, rest_of_path) = | |
489 | path.split_first_component(); |
|
578 | path.split_first_component(); | |
490 | let node = nodes.make_mut().get_mut(first_path_component)?; |
|
579 | let node = if let Some(node) = | |
|
580 | nodes.make_mut()?.get_mut(first_path_component) | |||
|
581 | { | |||
|
582 | node | |||
|
583 | } else { | |||
|
584 | return Ok(None); | |||
|
585 | }; | |||
491 | let dropped; |
|
586 | let dropped; | |
492 | if let Some(rest) = rest_of_path { |
|
587 | if let Some(rest) = rest_of_path { | |
493 |
|
|
588 | if let Some(d) = recur(&mut node.children, rest)? { | |
494 |
|
|
589 | dropped = d; | |
495 |
|
|
590 | if dropped.was_tracked { | |
|
591 | node.tracked_descendants_count -= 1; | |||
|
592 | } | |||
|
593 | } else { | |||
|
594 | return Ok(None); | |||
496 | } |
|
595 | } | |
497 | } else { |
|
596 | } else { | |
498 | dropped = Dropped { |
|
597 | dropped = Dropped { | |
@@ -510,12 +609,12 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
510 | && node.copy_source.is_none() |
|
609 | && node.copy_source.is_none() | |
511 | && node.children.is_empty() |
|
610 | && node.children.is_empty() | |
512 | { |
|
611 | { | |
513 | nodes.make_mut().remove(first_path_component); |
|
612 | nodes.make_mut()?.remove(first_path_component); | |
514 | } |
|
613 | } | |
515 | Some(dropped) |
|
614 | Ok(Some(dropped)) | |
516 | } |
|
615 | } | |
517 |
|
616 | |||
518 | if let Some(dropped) = recur(&mut self.root, filename) { |
|
617 | if let Some(dropped) = recur(&mut self.root, filename)? { | |
519 | if dropped.had_entry { |
|
618 | if dropped.had_entry { | |
520 | self.nodes_with_entry_count -= 1 |
|
619 | self.nodes_with_entry_count -= 1 | |
521 | } |
|
620 | } | |
@@ -529,20 +628,31 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
529 | } |
|
628 | } | |
530 | } |
|
629 | } | |
531 |
|
630 | |||
532 | fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) { |
|
631 | fn clear_ambiguous_times( | |
|
632 | &mut self, | |||
|
633 | filenames: Vec<HgPathBuf>, | |||
|
634 | now: i32, | |||
|
635 | ) -> Result<(), DirstateV2ParseError> { | |||
533 | for filename in filenames { |
|
636 | for filename in filenames { | |
534 |
if let Some(node) = Self::get_node_mut(&mut self.root, &filename) |
|
637 | if let Some(node) = Self::get_node_mut(&mut self.root, &filename)? | |
|
638 | { | |||
535 | if let Some(entry) = node.entry.as_mut() { |
|
639 | if let Some(entry) = node.entry.as_mut() { | |
536 | entry.clear_ambiguous_mtime(now); |
|
640 | entry.clear_ambiguous_mtime(now); | |
537 | } |
|
641 | } | |
538 | } |
|
642 | } | |
539 | } |
|
643 | } | |
|
644 | Ok(()) | |||
540 | } |
|
645 | } | |
541 |
|
646 | |||
542 |
fn non_normal_entries_contains( |
|
647 | fn non_normal_entries_contains( | |
543 | self.get_node(key) |
|
648 | &mut self, | |
544 | .and_then(|node| node.entry()) |
|
649 | key: &HgPath, | |
545 | .map_or(false, |entry| entry.is_non_normal()) |
|
650 | ) -> Result<bool, DirstateV2ParseError> { | |
|
651 | Ok(if let Some(node) = self.get_node(key)? { | |||
|
652 | node.entry()?.map_or(false, |entry| entry.is_non_normal()) | |||
|
653 | } else { | |||
|
654 | false | |||
|
655 | }) | |||
546 | } |
|
656 | } | |
547 |
|
657 | |||
548 | fn non_normal_entries_remove(&mut self, _key: &HgPath) { |
|
658 | fn non_normal_entries_remove(&mut self, _key: &HgPath) { | |
@@ -552,13 +662,10 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
552 |
|
662 | |||
553 | fn non_normal_or_other_parent_paths( |
|
663 | fn non_normal_or_other_parent_paths( | |
554 | &mut self, |
|
664 | &mut self, | |
555 |
) -> Box<dyn Iterator<Item = &HgPath> + '_> |
|
665 | ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_> | |
556 | Box::new(self.iter_nodes().filter_map(|node| { |
|
666 | { | |
557 | node.entry() |
|
667 | Box::new(self.filter_full_paths(|entry| { | |
558 | .filter(|entry| { |
|
668 | entry.is_non_normal() || entry.is_from_other_parent() | |
559 | entry.is_non_normal() || entry.is_from_other_parent() |
|
|||
560 | }) |
|
|||
561 | .map(|_| node.full_path()) |
|
|||
562 | })) |
|
669 | })) | |
563 | } |
|
670 | } | |
564 |
|
671 | |||
@@ -569,35 +676,33 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
569 |
|
676 | |||
570 | fn iter_non_normal_paths( |
|
677 | fn iter_non_normal_paths( | |
571 | &mut self, |
|
678 | &mut self, | |
572 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
679 | ) -> Box< | |
|
680 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
681 | > { | |||
573 | self.iter_non_normal_paths_panic() |
|
682 | self.iter_non_normal_paths_panic() | |
574 | } |
|
683 | } | |
575 |
|
684 | |||
576 | fn iter_non_normal_paths_panic( |
|
685 | fn iter_non_normal_paths_panic( | |
577 | &self, |
|
686 | &self, | |
578 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
687 | ) -> Box< | |
579 | Box::new(self.iter_nodes().filter_map(|node| { |
|
688 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |
580 | node.entry() |
|
689 | > { | |
581 |
|
|
690 | Box::new(self.filter_full_paths(|entry| entry.is_non_normal())) | |
582 | .map(|_| node.full_path()) |
|
|||
583 | })) |
|
|||
584 | } |
|
691 | } | |
585 |
|
692 | |||
586 | fn iter_other_parent_paths( |
|
693 | fn iter_other_parent_paths( | |
587 | &mut self, |
|
694 | &mut self, | |
588 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
695 | ) -> Box< | |
589 | Box::new(self.iter_nodes().filter_map(|node| { |
|
696 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |
590 | node.entry() |
|
697 | > { | |
591 |
|
|
698 | Box::new(self.filter_full_paths(|entry| entry.is_from_other_parent())) | |
592 | .map(|_| node.full_path()) |
|
|||
593 | })) |
|
|||
594 | } |
|
699 | } | |
595 |
|
700 | |||
596 | fn has_tracked_dir( |
|
701 | fn has_tracked_dir( | |
597 | &mut self, |
|
702 | &mut self, | |
598 | directory: &HgPath, |
|
703 | directory: &HgPath, | |
599 |
) -> Result<bool, Dirstate |
|
704 | ) -> Result<bool, DirstateError> { | |
600 | if let Some(node) = self.get_node(directory) { |
|
705 | if let Some(node) = self.get_node(directory)? { | |
601 | // A node without a `DirstateEntry` was created to hold child |
|
706 | // A node without a `DirstateEntry` was created to hold child | |
602 | // nodes, and is therefore a directory. |
|
707 | // nodes, and is therefore a directory. | |
603 | Ok(!node.has_entry() && node.tracked_descendants_count() > 0) |
|
708 | Ok(!node.has_entry() && node.tracked_descendants_count() > 0) | |
@@ -606,11 +711,8 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
606 | } |
|
711 | } | |
607 | } |
|
712 | } | |
608 |
|
713 | |||
609 | fn has_dir( |
|
714 | fn has_dir(&mut self, directory: &HgPath) -> Result<bool, DirstateError> { | |
610 | &mut self, |
|
715 | if let Some(node) = self.get_node(directory)? { | |
611 | directory: &HgPath, |
|
|||
612 | ) -> Result<bool, DirstateMapError> { |
|
|||
613 | if let Some(node) = self.get_node(directory) { |
|
|||
614 | // A node without a `DirstateEntry` was created to hold child |
|
716 | // A node without a `DirstateEntry` was created to hold child | |
615 | // nodes, and is therefore a directory. |
|
717 | // nodes, and is therefore a directory. | |
616 | Ok(!node.has_entry()) |
|
718 | Ok(!node.has_entry()) | |
@@ -631,25 +733,27 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
631 | // reallocations |
|
733 | // reallocations | |
632 | let mut size = parents.as_bytes().len(); |
|
734 | let mut size = parents.as_bytes().len(); | |
633 | for node in self.iter_nodes() { |
|
735 | for node in self.iter_nodes() { | |
634 |
|
|
736 | let node = node?; | |
|
737 | if let Some(entry) = node.entry()? { | |||
635 | size += |
|
738 | size += | |
636 | packed_entry_size(node.full_path(), node.copy_source()); |
|
739 | packed_entry_size(node.full_path()?, node.copy_source()?); | |
637 | if entry.mtime_is_ambiguous(now) { |
|
740 | if entry.mtime_is_ambiguous(now) { | |
638 | ambiguous_mtimes.push(node.full_path_cow()) |
|
741 | ambiguous_mtimes.push(node.full_path_cow()?) | |
639 | } |
|
742 | } | |
640 | } |
|
743 | } | |
641 | } |
|
744 | } | |
642 | self.clear_known_ambiguous_mtimes(&ambiguous_mtimes); |
|
745 | self.clear_known_ambiguous_mtimes(&ambiguous_mtimes)?; | |
643 |
|
746 | |||
644 | let mut packed = Vec::with_capacity(size); |
|
747 | let mut packed = Vec::with_capacity(size); | |
645 | packed.extend(parents.as_bytes()); |
|
748 | packed.extend(parents.as_bytes()); | |
646 |
|
749 | |||
647 | for node in self.iter_nodes() { |
|
750 | for node in self.iter_nodes() { | |
648 |
|
|
751 | let node = node?; | |
|
752 | if let Some(entry) = node.entry()? { | |||
649 | pack_entry( |
|
753 | pack_entry( | |
650 | node.full_path(), |
|
754 | node.full_path()?, | |
651 | &entry, |
|
755 | &entry, | |
652 | node.copy_source(), |
|
756 | node.copy_source()?, | |
653 | &mut packed, |
|
757 | &mut packed, | |
654 | ); |
|
758 | ); | |
655 | } |
|
759 | } | |
@@ -667,26 +771,27 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
667 | let now: i32 = now.0.try_into().expect("time overflow"); |
|
771 | let now: i32 = now.0.try_into().expect("time overflow"); | |
668 | let mut paths = Vec::new(); |
|
772 | let mut paths = Vec::new(); | |
669 | for node in self.iter_nodes() { |
|
773 | for node in self.iter_nodes() { | |
670 |
|
|
774 | let node = node?; | |
|
775 | if let Some(entry) = node.entry()? { | |||
671 | if entry.mtime_is_ambiguous(now) { |
|
776 | if entry.mtime_is_ambiguous(now) { | |
672 | paths.push(node.full_path_cow()) |
|
777 | paths.push(node.full_path_cow()?) | |
673 | } |
|
778 | } | |
674 | } |
|
779 | } | |
675 | } |
|
780 | } | |
676 | // Borrow of `self` ends here since we collect cloned paths |
|
781 | // Borrow of `self` ends here since we collect cloned paths | |
677 |
|
782 | |||
678 | self.clear_known_ambiguous_mtimes(&paths); |
|
783 | self.clear_known_ambiguous_mtimes(&paths)?; | |
679 |
|
784 | |||
680 | on_disk::write(self, parents) |
|
785 | on_disk::write(self, parents) | |
681 | } |
|
786 | } | |
682 |
|
787 | |||
683 |
fn set_all_dirs(&mut self) -> Result<(), Dirstate |
|
788 | fn set_all_dirs(&mut self) -> Result<(), DirstateError> { | |
684 | // Do nothing, this `DirstateMap` does not a separate `all_dirs` that |
|
789 | // Do nothing, this `DirstateMap` does not a separate `all_dirs` that | |
685 | // needs to be recomputed |
|
790 | // needs to be recomputed | |
686 | Ok(()) |
|
791 | Ok(()) | |
687 | } |
|
792 | } | |
688 |
|
793 | |||
689 |
fn set_dirs(&mut self) -> Result<(), Dirstate |
|
794 | fn set_dirs(&mut self) -> Result<(), DirstateError> { | |
690 | // Do nothing, this `DirstateMap` does not a separate `dirs` that needs |
|
795 | // Do nothing, this `DirstateMap` does not a separate `dirs` that needs | |
691 | // to be recomputed |
|
796 | // to be recomputed | |
692 | Ok(()) |
|
797 | Ok(()) | |
@@ -708,66 +813,97 b" impl<'on_disk> super::dispatch::Dirstate" | |||||
708 | } |
|
813 | } | |
709 |
|
814 | |||
710 | fn copy_map_iter(&self) -> CopyMapIter<'_> { |
|
815 | fn copy_map_iter(&self) -> CopyMapIter<'_> { | |
711 |
Box::new(self.iter_nodes() |
|
816 | Box::new(filter_map_results(self.iter_nodes(), |node| { | |
712 | node.copy_source() |
|
817 | Ok(if let Some(source) = node.copy_source()? { | |
713 |
|
|
818 | Some((node.full_path()?, source)) | |
|
819 | } else { | |||
|
820 | None | |||
|
821 | }) | |||
714 | })) |
|
822 | })) | |
715 | } |
|
823 | } | |
716 |
|
824 | |||
717 |
fn copy_map_contains_key( |
|
825 | fn copy_map_contains_key( | |
718 | if let Some(node) = self.get_node(key) { |
|
826 | &self, | |
719 | node.copy_source().is_some() |
|
827 | key: &HgPath, | |
|
828 | ) -> Result<bool, DirstateV2ParseError> { | |||
|
829 | Ok(if let Some(node) = self.get_node(key)? { | |||
|
830 | node.has_copy_source() | |||
720 | } else { |
|
831 | } else { | |
721 | false |
|
832 | false | |
722 | } |
|
833 | }) | |
723 | } |
|
834 | } | |
724 |
|
835 | |||
725 | fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> { |
|
836 | fn copy_map_get( | |
726 | self.get_node(key)?.copy_source() |
|
837 | &self, | |
|
838 | key: &HgPath, | |||
|
839 | ) -> Result<Option<&HgPath>, DirstateV2ParseError> { | |||
|
840 | if let Some(node) = self.get_node(key)? { | |||
|
841 | if let Some(source) = node.copy_source()? { | |||
|
842 | return Ok(Some(source)); | |||
|
843 | } | |||
|
844 | } | |||
|
845 | Ok(None) | |||
727 | } |
|
846 | } | |
728 |
|
847 | |||
729 | fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> { |
|
848 | fn copy_map_remove( | |
|
849 | &mut self, | |||
|
850 | key: &HgPath, | |||
|
851 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | |||
730 | let count = &mut self.nodes_with_copy_source_count; |
|
852 | let count = &mut self.nodes_with_copy_source_count; | |
731 | Self::get_node_mut(&mut self.root, key).and_then(|node| { |
|
853 | Ok(Self::get_node_mut(&mut self.root, key)?.and_then(|node| { | |
732 | if node.copy_source.is_some() { |
|
854 | if node.copy_source.is_some() { | |
733 | *count -= 1 |
|
855 | *count -= 1 | |
734 | } |
|
856 | } | |
735 | node.copy_source.take().map(Cow::into_owned) |
|
857 | node.copy_source.take().map(Cow::into_owned) | |
736 | }) |
|
858 | })) | |
737 | } |
|
859 | } | |
738 |
|
860 | |||
739 | fn copy_map_insert( |
|
861 | fn copy_map_insert( | |
740 | &mut self, |
|
862 | &mut self, | |
741 | key: HgPathBuf, |
|
863 | key: HgPathBuf, | |
742 | value: HgPathBuf, |
|
864 | value: HgPathBuf, | |
743 | ) -> Option<HgPathBuf> { |
|
865 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | |
744 | let node = Self::get_or_insert_node( |
|
866 | let node = Self::get_or_insert_node( | |
745 | &mut self.root, |
|
867 | &mut self.root, | |
746 | &key, |
|
868 | &key, | |
747 | WithBasename::to_cow_owned, |
|
869 | WithBasename::to_cow_owned, | |
748 | |_ancestor| {}, |
|
870 | |_ancestor| {}, | |
749 | ); |
|
871 | )?; | |
750 | if node.copy_source.is_none() { |
|
872 | if node.copy_source.is_none() { | |
751 | self.nodes_with_copy_source_count += 1 |
|
873 | self.nodes_with_copy_source_count += 1 | |
752 | } |
|
874 | } | |
753 | node.copy_source.replace(value.into()).map(Cow::into_owned) |
|
875 | Ok(node.copy_source.replace(value.into()).map(Cow::into_owned)) | |
754 | } |
|
876 | } | |
755 |
|
877 | |||
756 | fn len(&self) -> usize { |
|
878 | fn len(&self) -> usize { | |
757 | self.nodes_with_entry_count as usize |
|
879 | self.nodes_with_entry_count as usize | |
758 | } |
|
880 | } | |
759 |
|
881 | |||
760 | fn contains_key(&self, key: &HgPath) -> bool { |
|
882 | fn contains_key( | |
761 | self.get(key).is_some() |
|
883 | &self, | |
|
884 | key: &HgPath, | |||
|
885 | ) -> Result<bool, DirstateV2ParseError> { | |||
|
886 | Ok(self.get(key)?.is_some()) | |||
762 | } |
|
887 | } | |
763 |
|
888 | |||
764 | fn get(&self, key: &HgPath) -> Option<DirstateEntry> { |
|
889 | fn get( | |
765 | self.get_node(key)?.entry() |
|
890 | &self, | |
|
891 | key: &HgPath, | |||
|
892 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { | |||
|
893 | Ok(if let Some(node) = self.get_node(key)? { | |||
|
894 | node.entry()? | |||
|
895 | } else { | |||
|
896 | None | |||
|
897 | }) | |||
766 | } |
|
898 | } | |
767 |
|
899 | |||
768 | fn iter(&self) -> StateMapIter<'_> { |
|
900 | fn iter(&self) -> StateMapIter<'_> { | |
769 |
Box::new(self.iter_nodes() |
|
901 | Box::new(filter_map_results(self.iter_nodes(), |node| { | |
770 | node.entry().map(|entry| (node.full_path(), entry)) |
|
902 | Ok(if let Some(entry) = node.entry()? { | |
|
903 | Some((node.full_path()?, entry)) | |||
|
904 | } else { | |||
|
905 | None | |||
|
906 | }) | |||
771 | })) |
|
907 | })) | |
772 | } |
|
908 | } | |
773 | } |
|
909 | } |
@@ -1,13 +1,13 b'' | |||||
1 | use std::path::PathBuf; |
|
1 | use std::path::PathBuf; | |
2 |
|
2 | |||
3 | use crate::dirstate::parsers::Timestamp; |
|
3 | use crate::dirstate::parsers::Timestamp; | |
|
4 | use crate::dirstate_tree::on_disk::DirstateV2ParseError; | |||
4 | use crate::matchers::Matcher; |
|
5 | use crate::matchers::Matcher; | |
5 | use crate::utils::hg_path::{HgPath, HgPathBuf}; |
|
6 | use crate::utils::hg_path::{HgPath, HgPathBuf}; | |
6 | use crate::CopyMapIter; |
|
7 | use crate::CopyMapIter; | |
7 | use crate::DirstateEntry; |
|
8 | use crate::DirstateEntry; | |
8 | use crate::DirstateError; |
|
9 | use crate::DirstateError; | |
9 | use crate::DirstateMap; |
|
10 | use crate::DirstateMap; | |
10 | use crate::DirstateMapError; |
|
|||
11 | use crate::DirstateParents; |
|
11 | use crate::DirstateParents; | |
12 | use crate::DirstateStatus; |
|
12 | use crate::DirstateStatus; | |
13 | use crate::EntryState; |
|
13 | use crate::EntryState; | |
@@ -24,54 +24,64 b' pub trait DirstateMapMethods {' | |||||
24 | filename: &HgPath, |
|
24 | filename: &HgPath, | |
25 | old_state: EntryState, |
|
25 | old_state: EntryState, | |
26 | entry: DirstateEntry, |
|
26 | entry: DirstateEntry, | |
27 |
) -> Result<(), Dirstate |
|
27 | ) -> Result<(), DirstateError>; | |
28 |
|
28 | |||
29 | fn remove_file( |
|
29 | fn remove_file( | |
30 | &mut self, |
|
30 | &mut self, | |
31 | filename: &HgPath, |
|
31 | filename: &HgPath, | |
32 | old_state: EntryState, |
|
32 | old_state: EntryState, | |
33 | size: i32, |
|
33 | size: i32, | |
34 |
) -> Result<(), Dirstate |
|
34 | ) -> Result<(), DirstateError>; | |
35 |
|
35 | |||
36 | fn drop_file( |
|
36 | fn drop_file( | |
37 | &mut self, |
|
37 | &mut self, | |
38 | filename: &HgPath, |
|
38 | filename: &HgPath, | |
39 | old_state: EntryState, |
|
39 | old_state: EntryState, | |
40 |
) -> Result<bool, Dirstate |
|
40 | ) -> Result<bool, DirstateError>; | |
41 |
|
41 | |||
42 | fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32); |
|
42 | fn clear_ambiguous_times( | |
|
43 | &mut self, | |||
|
44 | filenames: Vec<HgPathBuf>, | |||
|
45 | now: i32, | |||
|
46 | ) -> Result<(), DirstateV2ParseError>; | |||
43 |
|
47 | |||
44 |
fn non_normal_entries_contains( |
|
48 | fn non_normal_entries_contains( | |
|
49 | &mut self, | |||
|
50 | key: &HgPath, | |||
|
51 | ) -> Result<bool, DirstateV2ParseError>; | |||
45 |
|
52 | |||
46 | fn non_normal_entries_remove(&mut self, key: &HgPath); |
|
53 | fn non_normal_entries_remove(&mut self, key: &HgPath); | |
47 |
|
54 | |||
48 | fn non_normal_or_other_parent_paths( |
|
55 | fn non_normal_or_other_parent_paths( | |
49 | &mut self, |
|
56 | &mut self, | |
50 | ) -> Box<dyn Iterator<Item = &HgPath> + '_>; |
|
57 | ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_>; | |
51 |
|
58 | |||
52 | fn set_non_normal_other_parent_entries(&mut self, force: bool); |
|
59 | fn set_non_normal_other_parent_entries(&mut self, force: bool); | |
53 |
|
60 | |||
54 | fn iter_non_normal_paths( |
|
61 | fn iter_non_normal_paths( | |
55 | &mut self, |
|
62 | &mut self, | |
56 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>; |
|
63 | ) -> Box< | |
|
64 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
65 | >; | |||
57 |
|
66 | |||
58 | fn iter_non_normal_paths_panic( |
|
67 | fn iter_non_normal_paths_panic( | |
59 | &self, |
|
68 | &self, | |
60 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>; |
|
69 | ) -> Box< | |
|
70 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
71 | >; | |||
61 |
|
72 | |||
62 | fn iter_other_parent_paths( |
|
73 | fn iter_other_parent_paths( | |
63 | &mut self, |
|
74 | &mut self, | |
64 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_>; |
|
75 | ) -> Box< | |
|
76 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
77 | >; | |||
65 |
|
78 | |||
66 | fn has_tracked_dir( |
|
79 | fn has_tracked_dir( | |
67 | &mut self, |
|
80 | &mut self, | |
68 | directory: &HgPath, |
|
81 | directory: &HgPath, | |
69 |
) -> Result<bool, Dirstate |
|
82 | ) -> Result<bool, DirstateError>; | |
70 |
|
83 | |||
71 | fn has_dir( |
|
84 | fn has_dir(&mut self, directory: &HgPath) -> Result<bool, DirstateError>; | |
72 | &mut self, |
|
|||
73 | directory: &HgPath, |
|
|||
74 | ) -> Result<bool, DirstateMapError>; |
|
|||
75 |
|
85 | |||
76 | fn pack_v1( |
|
86 | fn pack_v1( | |
77 | &mut self, |
|
87 | &mut self, | |
@@ -85,9 +95,9 b' pub trait DirstateMapMethods {' | |||||
85 | now: Timestamp, |
|
95 | now: Timestamp, | |
86 | ) -> Result<Vec<u8>, DirstateError>; |
|
96 | ) -> Result<Vec<u8>, DirstateError>; | |
87 |
|
97 | |||
88 |
fn set_all_dirs(&mut self) -> Result<(), Dirstate |
|
98 | fn set_all_dirs(&mut self) -> Result<(), DirstateError>; | |
89 |
|
99 | |||
90 |
fn set_dirs(&mut self) -> Result<(), Dirstate |
|
100 | fn set_dirs(&mut self) -> Result<(), DirstateError>; | |
91 |
|
101 | |||
92 | fn status<'a>( |
|
102 | fn status<'a>( | |
93 | &'a mut self, |
|
103 | &'a mut self, | |
@@ -101,23 +111,36 b' pub trait DirstateMapMethods {' | |||||
101 |
|
111 | |||
102 | fn copy_map_iter(&self) -> CopyMapIter<'_>; |
|
112 | fn copy_map_iter(&self) -> CopyMapIter<'_>; | |
103 |
|
113 | |||
104 |
fn copy_map_contains_key( |
|
114 | fn copy_map_contains_key( | |
|
115 | &self, | |||
|
116 | key: &HgPath, | |||
|
117 | ) -> Result<bool, DirstateV2ParseError>; | |||
105 |
|
118 | |||
106 | fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath>; |
|
119 | fn copy_map_get( | |
|
120 | &self, | |||
|
121 | key: &HgPath, | |||
|
122 | ) -> Result<Option<&HgPath>, DirstateV2ParseError>; | |||
107 |
|
123 | |||
108 | fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf>; |
|
124 | fn copy_map_remove( | |
|
125 | &mut self, | |||
|
126 | key: &HgPath, | |||
|
127 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError>; | |||
109 |
|
128 | |||
110 | fn copy_map_insert( |
|
129 | fn copy_map_insert( | |
111 | &mut self, |
|
130 | &mut self, | |
112 | key: HgPathBuf, |
|
131 | key: HgPathBuf, | |
113 | value: HgPathBuf, |
|
132 | value: HgPathBuf, | |
114 | ) -> Option<HgPathBuf>; |
|
133 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError>; | |
115 |
|
134 | |||
116 | fn len(&self) -> usize; |
|
135 | fn len(&self) -> usize; | |
117 |
|
136 | |||
118 |
fn contains_key(&self, key: &HgPath) |
|
137 | fn contains_key(&self, key: &HgPath) | |
|
138 | -> Result<bool, DirstateV2ParseError>; | |||
119 |
|
139 | |||
120 | fn get(&self, key: &HgPath) -> Option<DirstateEntry>; |
|
140 | fn get( | |
|
141 | &self, | |||
|
142 | key: &HgPath, | |||
|
143 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError>; | |||
121 |
|
144 | |||
122 | fn iter(&self) -> StateMapIter<'_>; |
|
145 | fn iter(&self) -> StateMapIter<'_>; | |
123 | } |
|
146 | } | |
@@ -132,7 +155,7 b' impl DirstateMapMethods for DirstateMap ' | |||||
132 | filename: &HgPath, |
|
155 | filename: &HgPath, | |
133 | old_state: EntryState, |
|
156 | old_state: EntryState, | |
134 | entry: DirstateEntry, |
|
157 | entry: DirstateEntry, | |
135 |
) -> Result<(), Dirstate |
|
158 | ) -> Result<(), DirstateError> { | |
136 | self.add_file(filename, old_state, entry) |
|
159 | self.add_file(filename, old_state, entry) | |
137 | } |
|
160 | } | |
138 |
|
161 | |||
@@ -141,7 +164,7 b' impl DirstateMapMethods for DirstateMap ' | |||||
141 | filename: &HgPath, |
|
164 | filename: &HgPath, | |
142 | old_state: EntryState, |
|
165 | old_state: EntryState, | |
143 | size: i32, |
|
166 | size: i32, | |
144 |
) -> Result<(), Dirstate |
|
167 | ) -> Result<(), DirstateError> { | |
145 | self.remove_file(filename, old_state, size) |
|
168 | self.remove_file(filename, old_state, size) | |
146 | } |
|
169 | } | |
147 |
|
170 | |||
@@ -149,18 +172,25 b' impl DirstateMapMethods for DirstateMap ' | |||||
149 | &mut self, |
|
172 | &mut self, | |
150 | filename: &HgPath, |
|
173 | filename: &HgPath, | |
151 | old_state: EntryState, |
|
174 | old_state: EntryState, | |
152 |
) -> Result<bool, Dirstate |
|
175 | ) -> Result<bool, DirstateError> { | |
153 | self.drop_file(filename, old_state) |
|
176 | self.drop_file(filename, old_state) | |
154 | } |
|
177 | } | |
155 |
|
178 | |||
156 | fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) { |
|
179 | fn clear_ambiguous_times( | |
157 | self.clear_ambiguous_times(filenames, now) |
|
180 | &mut self, | |
|
181 | filenames: Vec<HgPathBuf>, | |||
|
182 | now: i32, | |||
|
183 | ) -> Result<(), DirstateV2ParseError> { | |||
|
184 | Ok(self.clear_ambiguous_times(filenames, now)) | |||
158 | } |
|
185 | } | |
159 |
|
186 | |||
160 |
fn non_normal_entries_contains( |
|
187 | fn non_normal_entries_contains( | |
|
188 | &mut self, | |||
|
189 | key: &HgPath, | |||
|
190 | ) -> Result<bool, DirstateV2ParseError> { | |||
161 | let (non_normal, _other_parent) = |
|
191 | let (non_normal, _other_parent) = | |
162 | self.get_non_normal_other_parent_entries(); |
|
192 | self.get_non_normal_other_parent_entries(); | |
163 | non_normal.contains(key) |
|
193 | Ok(non_normal.contains(key)) | |
164 | } |
|
194 | } | |
165 |
|
195 | |||
166 | fn non_normal_entries_remove(&mut self, key: &HgPath) { |
|
196 | fn non_normal_entries_remove(&mut self, key: &HgPath) { | |
@@ -169,10 +199,11 b' impl DirstateMapMethods for DirstateMap ' | |||||
169 |
|
199 | |||
170 | fn non_normal_or_other_parent_paths( |
|
200 | fn non_normal_or_other_parent_paths( | |
171 | &mut self, |
|
201 | &mut self, | |
172 |
) -> Box<dyn Iterator<Item = &HgPath> + '_> |
|
202 | ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_> | |
|
203 | { | |||
173 | let (non_normal, other_parent) = |
|
204 | let (non_normal, other_parent) = | |
174 | self.get_non_normal_other_parent_entries(); |
|
205 | self.get_non_normal_other_parent_entries(); | |
175 | Box::new(non_normal.union(other_parent).map(|p| &**p)) |
|
206 | Box::new(non_normal.union(other_parent).map(|p| Ok(&**p))) | |
176 | } |
|
207 | } | |
177 |
|
208 | |||
178 | fn set_non_normal_other_parent_entries(&mut self, force: bool) { |
|
209 | fn set_non_normal_other_parent_entries(&mut self, force: bool) { | |
@@ -181,39 +212,42 b' impl DirstateMapMethods for DirstateMap ' | |||||
181 |
|
212 | |||
182 | fn iter_non_normal_paths( |
|
213 | fn iter_non_normal_paths( | |
183 | &mut self, |
|
214 | &mut self, | |
184 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
215 | ) -> Box< | |
|
216 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
217 | > { | |||
185 | let (non_normal, _other_parent) = |
|
218 | let (non_normal, _other_parent) = | |
186 | self.get_non_normal_other_parent_entries(); |
|
219 | self.get_non_normal_other_parent_entries(); | |
187 | Box::new(non_normal.iter().map(|p| &**p)) |
|
220 | Box::new(non_normal.iter().map(|p| Ok(&**p))) | |
188 | } |
|
221 | } | |
189 |
|
222 | |||
190 | fn iter_non_normal_paths_panic( |
|
223 | fn iter_non_normal_paths_panic( | |
191 | &self, |
|
224 | &self, | |
192 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
225 | ) -> Box< | |
|
226 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
227 | > { | |||
193 | let (non_normal, _other_parent) = |
|
228 | let (non_normal, _other_parent) = | |
194 | self.get_non_normal_other_parent_entries_panic(); |
|
229 | self.get_non_normal_other_parent_entries_panic(); | |
195 | Box::new(non_normal.iter().map(|p| &**p)) |
|
230 | Box::new(non_normal.iter().map(|p| Ok(&**p))) | |
196 | } |
|
231 | } | |
197 |
|
232 | |||
198 | fn iter_other_parent_paths( |
|
233 | fn iter_other_parent_paths( | |
199 | &mut self, |
|
234 | &mut self, | |
200 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
235 | ) -> Box< | |
|
236 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
237 | > { | |||
201 | let (_non_normal, other_parent) = |
|
238 | let (_non_normal, other_parent) = | |
202 | self.get_non_normal_other_parent_entries(); |
|
239 | self.get_non_normal_other_parent_entries(); | |
203 | Box::new(other_parent.iter().map(|p| &**p)) |
|
240 | Box::new(other_parent.iter().map(|p| Ok(&**p))) | |
204 | } |
|
241 | } | |
205 |
|
242 | |||
206 | fn has_tracked_dir( |
|
243 | fn has_tracked_dir( | |
207 | &mut self, |
|
244 | &mut self, | |
208 | directory: &HgPath, |
|
245 | directory: &HgPath, | |
209 |
) -> Result<bool, Dirstate |
|
246 | ) -> Result<bool, DirstateError> { | |
210 | self.has_tracked_dir(directory) |
|
247 | self.has_tracked_dir(directory) | |
211 | } |
|
248 | } | |
212 |
|
249 | |||
213 | fn has_dir( |
|
250 | fn has_dir(&mut self, directory: &HgPath) -> Result<bool, DirstateError> { | |
214 | &mut self, |
|
|||
215 | directory: &HgPath, |
|
|||
216 | ) -> Result<bool, DirstateMapError> { |
|
|||
217 | self.has_dir(directory) |
|
251 | self.has_dir(directory) | |
218 | } |
|
252 | } | |
219 |
|
253 | |||
@@ -235,11 +269,11 b' impl DirstateMapMethods for DirstateMap ' | |||||
235 | ) |
|
269 | ) | |
236 | } |
|
270 | } | |
237 |
|
271 | |||
238 |
fn set_all_dirs(&mut self) -> Result<(), Dirstate |
|
272 | fn set_all_dirs(&mut self) -> Result<(), DirstateError> { | |
239 | self.set_all_dirs() |
|
273 | self.set_all_dirs() | |
240 | } |
|
274 | } | |
241 |
|
275 | |||
242 |
fn set_dirs(&mut self) -> Result<(), Dirstate |
|
276 | fn set_dirs(&mut self) -> Result<(), DirstateError> { | |
243 | self.set_dirs() |
|
277 | self.set_dirs() | |
244 | } |
|
278 | } | |
245 |
|
279 | |||
@@ -259,42 +293,61 b' impl DirstateMapMethods for DirstateMap ' | |||||
259 | } |
|
293 | } | |
260 |
|
294 | |||
261 | fn copy_map_iter(&self) -> CopyMapIter<'_> { |
|
295 | fn copy_map_iter(&self) -> CopyMapIter<'_> { | |
262 | Box::new(self.copy_map.iter().map(|(key, value)| (&**key, &**value))) |
|
296 | Box::new( | |
263 | } |
|
297 | self.copy_map | |
264 |
|
298 | .iter() | ||
265 | fn copy_map_contains_key(&self, key: &HgPath) -> bool { |
|
299 | .map(|(key, value)| Ok((&**key, &**value))), | |
266 | self.copy_map.contains_key(key) |
|
300 | ) | |
267 | } |
|
301 | } | |
268 |
|
302 | |||
269 | fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> { |
|
303 | fn copy_map_contains_key( | |
270 | self.copy_map.get(key).map(|p| &**p) |
|
304 | &self, | |
|
305 | key: &HgPath, | |||
|
306 | ) -> Result<bool, DirstateV2ParseError> { | |||
|
307 | Ok(self.copy_map.contains_key(key)) | |||
271 | } |
|
308 | } | |
272 |
|
309 | |||
273 | fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> { |
|
310 | fn copy_map_get( | |
274 | self.copy_map.remove(key) |
|
311 | &self, | |
|
312 | key: &HgPath, | |||
|
313 | ) -> Result<Option<&HgPath>, DirstateV2ParseError> { | |||
|
314 | Ok(self.copy_map.get(key).map(|p| &**p)) | |||
|
315 | } | |||
|
316 | ||||
|
317 | fn copy_map_remove( | |||
|
318 | &mut self, | |||
|
319 | key: &HgPath, | |||
|
320 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | |||
|
321 | Ok(self.copy_map.remove(key)) | |||
275 | } |
|
322 | } | |
276 |
|
323 | |||
277 | fn copy_map_insert( |
|
324 | fn copy_map_insert( | |
278 | &mut self, |
|
325 | &mut self, | |
279 | key: HgPathBuf, |
|
326 | key: HgPathBuf, | |
280 | value: HgPathBuf, |
|
327 | value: HgPathBuf, | |
281 | ) -> Option<HgPathBuf> { |
|
328 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | |
282 | self.copy_map.insert(key, value) |
|
329 | Ok(self.copy_map.insert(key, value)) | |
283 | } |
|
330 | } | |
284 |
|
331 | |||
285 | fn len(&self) -> usize { |
|
332 | fn len(&self) -> usize { | |
286 | (&**self).len() |
|
333 | (&**self).len() | |
287 | } |
|
334 | } | |
288 |
|
335 | |||
289 | fn contains_key(&self, key: &HgPath) -> bool { |
|
336 | fn contains_key( | |
290 | (&**self).contains_key(key) |
|
337 | &self, | |
|
338 | key: &HgPath, | |||
|
339 | ) -> Result<bool, DirstateV2ParseError> { | |||
|
340 | Ok((&**self).contains_key(key)) | |||
291 | } |
|
341 | } | |
292 |
|
342 | |||
293 | fn get(&self, key: &HgPath) -> Option<DirstateEntry> { |
|
343 | fn get( | |
294 | (&**self).get(key).cloned() |
|
344 | &self, | |
|
345 | key: &HgPath, | |||
|
346 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { | |||
|
347 | Ok((&**self).get(key).cloned()) | |||
295 | } |
|
348 | } | |
296 |
|
349 | |||
297 | fn iter(&self) -> StateMapIter<'_> { |
|
350 | fn iter(&self) -> StateMapIter<'_> { | |
298 | Box::new((&**self).iter().map(|(key, value)| (&**key, *value))) |
|
351 | Box::new((&**self).iter().map(|(key, value)| Ok((&**key, *value)))) | |
299 | } |
|
352 | } | |
300 | } |
|
353 | } |
@@ -109,7 +109,10 b' fn _static_assert_size_of() {' | |||||
109 | } |
|
109 | } | |
110 |
|
110 | |||
111 | /// Unexpected file format found in `.hg/dirstate` with the "v2" format. |
|
111 | /// Unexpected file format found in `.hg/dirstate` with the "v2" format. | |
112 | pub(crate) struct DirstateV2ParseError; |
|
112 | /// | |
|
113 | /// This should only happen if Mercurial is buggy or a repository is corrupted. | |||
|
114 | #[derive(Debug)] | |||
|
115 | pub struct DirstateV2ParseError; | |||
113 |
|
116 | |||
114 | impl From<DirstateV2ParseError> for HgError { |
|
117 | impl From<DirstateV2ParseError> for HgError { | |
115 | fn from(_: DirstateV2ParseError) -> Self { |
|
118 | fn from(_: DirstateV2ParseError) -> Self { | |
@@ -295,9 +298,9 b' fn write_nodes(' | |||||
295 | // First accumulate serialized nodes in a `Vec` |
|
298 | // First accumulate serialized nodes in a `Vec` | |
296 | let mut on_disk_nodes = Vec::with_capacity(nodes.len()); |
|
299 | let mut on_disk_nodes = Vec::with_capacity(nodes.len()); | |
297 | for node in nodes { |
|
300 | for node in nodes { | |
298 | let children = write_nodes(node.children(), out)?; |
|
301 | let children = write_nodes(node.children()?, out)?; | |
299 | let full_path = write_slice::<u8>(node.full_path().as_bytes(), out); |
|
302 | let full_path = write_slice::<u8>(node.full_path()?.as_bytes(), out); | |
300 | let copy_source = if let Some(source) = node.copy_source() { |
|
303 | let copy_source = if let Some(source) = node.copy_source()? { | |
301 | write_slice::<u8>(source.as_bytes(), out) |
|
304 | write_slice::<u8>(source.as_bytes(), out) | |
302 | } else { |
|
305 | } else { | |
303 | Slice { |
|
306 | Slice { |
@@ -2,6 +2,7 b' use crate::dirstate::status::IgnoreFnTyp' | |||||
2 | use crate::dirstate_tree::dirstate_map::ChildNodesRef; |
|
2 | use crate::dirstate_tree::dirstate_map::ChildNodesRef; | |
3 | use crate::dirstate_tree::dirstate_map::DirstateMap; |
|
3 | use crate::dirstate_tree::dirstate_map::DirstateMap; | |
4 | use crate::dirstate_tree::dirstate_map::NodeRef; |
|
4 | use crate::dirstate_tree::dirstate_map::NodeRef; | |
|
5 | use crate::dirstate_tree::on_disk::DirstateV2ParseError; | |||
5 | use crate::matchers::get_ignore_function; |
|
6 | use crate::matchers::get_ignore_function; | |
6 | use crate::matchers::Matcher; |
|
7 | use crate::matchers::Matcher; | |
7 | use crate::utils::files::get_bytes_from_os_string; |
|
8 | use crate::utils::files::get_bytes_from_os_string; | |
@@ -60,7 +61,7 b" pub fn status<'tree>(" | |||||
60 | hg_path, |
|
61 | hg_path, | |
61 | &root_dir, |
|
62 | &root_dir, | |
62 | is_at_repo_root, |
|
63 | is_at_repo_root, | |
63 | ); |
|
64 | )?; | |
64 | Ok((common.outcome.into_inner().unwrap(), warnings)) |
|
65 | Ok((common.outcome.into_inner().unwrap(), warnings)) | |
65 | } |
|
66 | } | |
66 |
|
67 | |||
@@ -97,7 +98,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
97 | directory_hg_path: &'tree HgPath, |
|
98 | directory_hg_path: &'tree HgPath, | |
98 | directory_fs_path: &Path, |
|
99 | directory_fs_path: &Path, | |
99 | is_at_repo_root: bool, |
|
100 | is_at_repo_root: bool, | |
100 | ) { |
|
101 | ) -> Result<(), DirstateV2ParseError> { | |
101 | let mut fs_entries = if let Ok(entries) = self.read_dir( |
|
102 | let mut fs_entries = if let Ok(entries) = self.read_dir( | |
102 | directory_hg_path, |
|
103 | directory_hg_path, | |
103 | directory_fs_path, |
|
104 | directory_fs_path, | |
@@ -105,7 +106,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
105 | ) { |
|
106 | ) { | |
106 | entries |
|
107 | entries | |
107 | } else { |
|
108 | } else { | |
108 | return; |
|
109 | return Ok(()); | |
109 | }; |
|
110 | }; | |
110 |
|
111 | |||
111 | // `merge_join_by` requires both its input iterators to be sorted: |
|
112 | // `merge_join_by` requires both its input iterators to be sorted: | |
@@ -115,34 +116,41 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
115 | // https://github.com/rust-lang/rust/issues/34162 |
|
116 | // https://github.com/rust-lang/rust/issues/34162 | |
116 | fs_entries.sort_unstable_by(|e1, e2| e1.base_name.cmp(&e2.base_name)); |
|
117 | fs_entries.sort_unstable_by(|e1, e2| e1.base_name.cmp(&e2.base_name)); | |
117 |
|
118 | |||
|
119 | // Propagate here any error that would happen inside the comparison | |||
|
120 | // callback below | |||
|
121 | for dirstate_node in &dirstate_nodes { | |||
|
122 | dirstate_node.base_name()?; | |||
|
123 | } | |||
118 | itertools::merge_join_by( |
|
124 | itertools::merge_join_by( | |
119 | dirstate_nodes, |
|
125 | dirstate_nodes, | |
120 | &fs_entries, |
|
126 | &fs_entries, | |
121 | |dirstate_node, fs_entry| { |
|
127 | |dirstate_node, fs_entry| { | |
122 | dirstate_node.base_name().cmp(&fs_entry.base_name) |
|
128 | // This `unwrap` never panics because we already propagated | |
|
129 | // those errors above | |||
|
130 | dirstate_node.base_name().unwrap().cmp(&fs_entry.base_name) | |||
123 | }, |
|
131 | }, | |
124 | ) |
|
132 | ) | |
125 | .par_bridge() |
|
133 | .par_bridge() | |
126 |
. |
|
134 | .map(|pair| { | |
127 | use itertools::EitherOrBoth::*; |
|
135 | use itertools::EitherOrBoth::*; | |
128 | match pair { |
|
136 | match pair { | |
129 |
Both(dirstate_node, fs_entry) => |
|
137 | Both(dirstate_node, fs_entry) => self | |
130 |
|
|
138 | .traverse_fs_and_dirstate( | |
131 | fs_entry, |
|
139 | fs_entry, | |
132 | dirstate_node, |
|
140 | dirstate_node, | |
133 | has_ignored_ancestor, |
|
141 | has_ignored_ancestor, | |
134 |
) |
|
142 | ), | |
135 | } |
|
|||
136 | Left(dirstate_node) => { |
|
143 | Left(dirstate_node) => { | |
137 | self.traverse_dirstate_only(dirstate_node) |
|
144 | self.traverse_dirstate_only(dirstate_node) | |
138 | } |
|
145 | } | |
139 | Right(fs_entry) => self.traverse_fs_only( |
|
146 | Right(fs_entry) => Ok(self.traverse_fs_only( | |
140 | has_ignored_ancestor, |
|
147 | has_ignored_ancestor, | |
141 | directory_hg_path, |
|
148 | directory_hg_path, | |
142 | fs_entry, |
|
149 | fs_entry, | |
143 | ), |
|
150 | )), | |
144 | } |
|
151 | } | |
145 | }) |
|
152 | }) | |
|
153 | .collect() | |||
146 | } |
|
154 | } | |
147 |
|
155 | |||
148 | fn traverse_fs_and_dirstate( |
|
156 | fn traverse_fs_and_dirstate( | |
@@ -150,8 +158,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
150 | fs_entry: &DirEntry, |
|
158 | fs_entry: &DirEntry, | |
151 | dirstate_node: NodeRef<'tree, '_>, |
|
159 | dirstate_node: NodeRef<'tree, '_>, | |
152 | has_ignored_ancestor: bool, |
|
160 | has_ignored_ancestor: bool, | |
153 | ) { |
|
161 | ) -> Result<(), DirstateV2ParseError> { | |
154 | let hg_path = dirstate_node.full_path(); |
|
162 | let hg_path = dirstate_node.full_path()?; | |
155 | let file_type = fs_entry.metadata.file_type(); |
|
163 | let file_type = fs_entry.metadata.file_type(); | |
156 | let file_or_symlink = file_type.is_file() || file_type.is_symlink(); |
|
164 | let file_or_symlink = file_type.is_file() || file_type.is_symlink(); | |
157 | if !file_or_symlink { |
|
165 | if !file_or_symlink { | |
@@ -159,8 +167,8 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
159 | // `hg rm` or similar) or deleted before it could be |
|
167 | // `hg rm` or similar) or deleted before it could be | |
160 | // replaced by a directory or something else. |
|
168 | // replaced by a directory or something else. | |
161 | self.mark_removed_or_deleted_if_file( |
|
169 | self.mark_removed_or_deleted_if_file( | |
162 |
|
|
170 | hg_path, | |
163 | dirstate_node.state(), |
|
171 | dirstate_node.state()?, | |
164 | ); |
|
172 | ); | |
165 | } |
|
173 | } | |
166 | if file_type.is_dir() { |
|
174 | if file_type.is_dir() { | |
@@ -171,15 +179,15 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
171 | let is_at_repo_root = false; |
|
179 | let is_at_repo_root = false; | |
172 | self.traverse_fs_directory_and_dirstate( |
|
180 | self.traverse_fs_directory_and_dirstate( | |
173 | is_ignored, |
|
181 | is_ignored, | |
174 | dirstate_node.children(), |
|
182 | dirstate_node.children()?, | |
175 | hg_path, |
|
183 | hg_path, | |
176 | &fs_entry.full_path, |
|
184 | &fs_entry.full_path, | |
177 | is_at_repo_root, |
|
185 | is_at_repo_root, | |
178 |
) |
|
186 | )? | |
179 | } else { |
|
187 | } else { | |
180 | if file_or_symlink && self.matcher.matches(hg_path) { |
|
188 | if file_or_symlink && self.matcher.matches(hg_path) { | |
181 | let full_path = Cow::from(hg_path); |
|
189 | let full_path = Cow::from(hg_path); | |
182 | if let Some(state) = dirstate_node.state() { |
|
190 | if let Some(state) = dirstate_node.state()? { | |
183 | match state { |
|
191 | match state { | |
184 | EntryState::Added => { |
|
192 | EntryState::Added => { | |
185 | self.outcome.lock().unwrap().added.push(full_path) |
|
193 | self.outcome.lock().unwrap().added.push(full_path) | |
@@ -197,7 +205,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
197 | .modified |
|
205 | .modified | |
198 | .push(full_path), |
|
206 | .push(full_path), | |
199 | EntryState::Normal => { |
|
207 | EntryState::Normal => { | |
200 |
self.handle_normal_file(&dirstate_node, fs_entry) |
|
208 | self.handle_normal_file(&dirstate_node, fs_entry)? | |
201 | } |
|
209 | } | |
202 | // This variant is not used in DirstateMap |
|
210 | // This variant is not used in DirstateMap | |
203 | // nodes |
|
211 | // nodes | |
@@ -213,10 +221,11 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
213 | } |
|
221 | } | |
214 | } |
|
222 | } | |
215 |
|
223 | |||
216 | for child_node in dirstate_node.children().iter() { |
|
224 | for child_node in dirstate_node.children()?.iter() { | |
217 | self.traverse_dirstate_only(child_node) |
|
225 | self.traverse_dirstate_only(child_node)? | |
218 | } |
|
226 | } | |
219 | } |
|
227 | } | |
|
228 | Ok(()) | |||
220 | } |
|
229 | } | |
221 |
|
230 | |||
222 | /// A file with `EntryState::Normal` in the dirstate was found in the |
|
231 | /// A file with `EntryState::Normal` in the dirstate was found in the | |
@@ -225,7 +234,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
225 | &self, |
|
234 | &self, | |
226 | dirstate_node: &NodeRef<'tree, '_>, |
|
235 | dirstate_node: &NodeRef<'tree, '_>, | |
227 | fs_entry: &DirEntry, |
|
236 | fs_entry: &DirEntry, | |
228 | ) { |
|
237 | ) -> Result<(), DirstateV2ParseError> { | |
229 | // Keep the low 31 bits |
|
238 | // Keep the low 31 bits | |
230 | fn truncate_u64(value: u64) -> i32 { |
|
239 | fn truncate_u64(value: u64) -> i32 { | |
231 | (value & 0x7FFF_FFFF) as i32 |
|
240 | (value & 0x7FFF_FFFF) as i32 | |
@@ -235,9 +244,9 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
235 | } |
|
244 | } | |
236 |
|
245 | |||
237 | let entry = dirstate_node |
|
246 | let entry = dirstate_node | |
238 | .entry() |
|
247 | .entry()? | |
239 | .expect("handle_normal_file called with entry-less node"); |
|
248 | .expect("handle_normal_file called with entry-less node"); | |
240 | let full_path = Cow::from(dirstate_node.full_path()); |
|
249 | let full_path = Cow::from(dirstate_node.full_path()?); | |
241 | let mode_changed = || { |
|
250 | let mode_changed = || { | |
242 | self.options.check_exec && entry.mode_changed(&fs_entry.metadata) |
|
251 | self.options.check_exec && entry.mode_changed(&fs_entry.metadata) | |
243 | }; |
|
252 | }; | |
@@ -249,7 +258,7 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
249 | // issue6456: Size returned may be longer due to encryption |
|
258 | // issue6456: Size returned may be longer due to encryption | |
250 | // on EXT-4 fscrypt. TODO maybe only do it on EXT4? |
|
259 | // on EXT-4 fscrypt. TODO maybe only do it on EXT4? | |
251 | self.outcome.lock().unwrap().unsure.push(full_path) |
|
260 | self.outcome.lock().unwrap().unsure.push(full_path) | |
252 |
} else if dirstate_node.copy_source |
|
261 | } else if dirstate_node.has_copy_source() | |
253 | || entry.is_from_other_parent() |
|
262 | || entry.is_from_other_parent() | |
254 | || (entry.size >= 0 && (size_changed || mode_changed())) |
|
263 | || (entry.size >= 0 && (size_changed || mode_changed())) | |
255 | { |
|
264 | { | |
@@ -264,18 +273,23 b" impl<'tree, 'a> StatusCommon<'tree, 'a> " | |||||
264 | self.outcome.lock().unwrap().clean.push(full_path) |
|
273 | self.outcome.lock().unwrap().clean.push(full_path) | |
265 | } |
|
274 | } | |
266 | } |
|
275 | } | |
|
276 | Ok(()) | |||
267 | } |
|
277 | } | |
268 |
|
278 | |||
269 | /// A node in the dirstate tree has no corresponding filesystem entry |
|
279 | /// A node in the dirstate tree has no corresponding filesystem entry | |
270 | fn traverse_dirstate_only(&self, dirstate_node: NodeRef<'tree, '_>) { |
|
280 | fn traverse_dirstate_only( | |
|
281 | &self, | |||
|
282 | dirstate_node: NodeRef<'tree, '_>, | |||
|
283 | ) -> Result<(), DirstateV2ParseError> { | |||
271 | self.mark_removed_or_deleted_if_file( |
|
284 | self.mark_removed_or_deleted_if_file( | |
272 | dirstate_node.full_path(), |
|
285 | dirstate_node.full_path()?, | |
273 | dirstate_node.state(), |
|
286 | dirstate_node.state()?, | |
274 | ); |
|
287 | ); | |
275 | dirstate_node |
|
288 | dirstate_node | |
276 | .children() |
|
289 | .children()? | |
277 | .par_iter() |
|
290 | .par_iter() | |
278 |
. |
|
291 | .map(|child_node| self.traverse_dirstate_only(child_node)) | |
|
292 | .collect() | |||
279 | } |
|
293 | } | |
280 |
|
294 | |||
281 | /// A node in the dirstate tree has no corresponding *file* on the |
|
295 | /// A node in the dirstate tree has no corresponding *file* on the |
@@ -83,6 +83,15 b' pub enum DirstateError {' | |||||
83 | Common(errors::HgError), |
|
83 | Common(errors::HgError), | |
84 | } |
|
84 | } | |
85 |
|
85 | |||
|
86 | impl fmt::Display for DirstateError { | |||
|
87 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | |||
|
88 | match self { | |||
|
89 | DirstateError::Map(error) => error.fmt(f), | |||
|
90 | DirstateError::Common(error) => error.fmt(f), | |||
|
91 | } | |||
|
92 | } | |||
|
93 | } | |||
|
94 | ||||
86 | #[derive(Debug, derive_more::From)] |
|
95 | #[derive(Debug, derive_more::From)] | |
87 | pub enum PatternError { |
|
96 | pub enum PatternError { | |
88 | #[from] |
|
97 | #[from] |
@@ -13,7 +13,9 b' use cpython::{' | |||||
13 | }; |
|
13 | }; | |
14 | use std::cell::RefCell; |
|
14 | use std::cell::RefCell; | |
15 |
|
15 | |||
|
16 | use crate::dirstate::dirstate_map::v2_error; | |||
16 | use crate::dirstate::dirstate_map::DirstateMap; |
|
17 | use crate::dirstate::dirstate_map::DirstateMap; | |
|
18 | use hg::dirstate_tree::on_disk::DirstateV2ParseError; | |||
17 | use hg::utils::hg_path::HgPath; |
|
19 | use hg::utils::hg_path::HgPath; | |
18 | use hg::CopyMapIter; |
|
20 | use hg::CopyMapIter; | |
19 |
|
21 | |||
@@ -88,15 +90,16 b' impl CopyMap {' | |||||
88 | } |
|
90 | } | |
89 | fn translate_key( |
|
91 | fn translate_key( | |
90 | py: Python, |
|
92 | py: Python, | |
91 | res: (&HgPath, &HgPath), |
|
93 | res: Result<(&HgPath, &HgPath), DirstateV2ParseError>, | |
92 | ) -> PyResult<Option<PyBytes>> { |
|
94 | ) -> PyResult<Option<PyBytes>> { | |
93 | Ok(Some(PyBytes::new(py, res.0.as_bytes()))) |
|
95 | let (k, _v) = res.map_err(|e| v2_error(py, e))?; | |
|
96 | Ok(Some(PyBytes::new(py, k.as_bytes()))) | |||
94 | } |
|
97 | } | |
95 | fn translate_key_value( |
|
98 | fn translate_key_value( | |
96 | py: Python, |
|
99 | py: Python, | |
97 | res: (&HgPath, &HgPath), |
|
100 | res: Result<(&HgPath, &HgPath), DirstateV2ParseError>, | |
98 | ) -> PyResult<Option<(PyBytes, PyBytes)>> { |
|
101 | ) -> PyResult<Option<(PyBytes, PyBytes)>> { | |
99 | let (k, v) = res; |
|
102 | let (k, v) = res.map_err(|e| v2_error(py, e))?; | |
100 | Ok(Some(( |
|
103 | Ok(Some(( | |
101 | PyBytes::new(py, k.as_bytes()), |
|
104 | PyBytes::new(py, k.as_bytes()), | |
102 | PyBytes::new(py, v.as_bytes()), |
|
105 | PyBytes::new(py, v.as_bytes()), |
@@ -20,7 +20,8 b' use crate::dirstate::extract_dirstate;' | |||||
20 | use hg::{ |
|
20 | use hg::{ | |
21 | errors::HgError, |
|
21 | errors::HgError, | |
22 | utils::hg_path::{HgPath, HgPathBuf}, |
|
22 | utils::hg_path::{HgPath, HgPathBuf}, | |
23 |
DirsMultiset, DirsMultisetIter, DirstateMapError, |
|
23 | DirsMultiset, DirsMultisetIter, DirstateError, DirstateMapError, | |
|
24 | EntryState, | |||
24 | }; |
|
25 | }; | |
25 |
|
26 | |||
26 | py_class!(pub class Dirs |py| { |
|
27 | py_class!(pub class Dirs |py| { | |
@@ -45,9 +46,9 b' py_class!(pub class Dirs |py| {' | |||||
45 | } |
|
46 | } | |
46 | let inner = if let Ok(map) = map.cast_as::<PyDict>(py) { |
|
47 | let inner = if let Ok(map) = map.cast_as::<PyDict>(py) { | |
47 | let dirstate = extract_dirstate(py, &map)?; |
|
48 | let dirstate = extract_dirstate(py, &map)?; | |
48 | let dirstate = dirstate.iter().map(|(k, v)| (k, *v)); |
|
49 | let dirstate = dirstate.iter().map(|(k, v)| Ok((k, *v))); | |
49 | DirsMultiset::from_dirstate(dirstate, skip_state) |
|
50 | DirsMultiset::from_dirstate(dirstate, skip_state) | |
50 |
.map_err(|e: Dirstate |
|
51 | .map_err(|e: DirstateError| { | |
51 | PyErr::new::<exc::ValueError, _>(py, e.to_string()) |
|
52 | PyErr::new::<exc::ValueError, _>(py, e.to_string()) | |
52 | })? |
|
53 | })? | |
53 | } else { |
|
54 | } else { |
@@ -29,13 +29,13 b' use crate::{' | |||||
29 | use hg::{ |
|
29 | use hg::{ | |
30 | dirstate::parsers::Timestamp, |
|
30 | dirstate::parsers::Timestamp, | |
31 | dirstate_tree::dispatch::DirstateMapMethods, |
|
31 | dirstate_tree::dispatch::DirstateMapMethods, | |
|
32 | dirstate_tree::on_disk::DirstateV2ParseError, | |||
32 | errors::HgError, |
|
33 | errors::HgError, | |
33 | revlog::Node, |
|
34 | revlog::Node, | |
34 | utils::files::normalize_case, |
|
35 | utils::files::normalize_case, | |
35 | utils::hg_path::{HgPath, HgPathBuf}, |
|
36 | utils::hg_path::{HgPath, HgPathBuf}, | |
36 | DirsMultiset, DirstateEntry, DirstateError, |
|
37 | DirsMultiset, DirstateEntry, DirstateError, | |
37 |
DirstateMap as RustDirstateMap, Dirstate |
|
38 | DirstateMap as RustDirstateMap, DirstateParents, EntryState, StateMapIter, | |
38 | EntryState, StateMapIter, |
|
|||
39 | }; |
|
39 | }; | |
40 |
|
40 | |||
41 | // TODO |
|
41 | // TODO | |
@@ -90,7 +90,12 b' py_class!(pub class DirstateMap |py| {' | |||||
90 | default: Option<PyObject> = None |
|
90 | default: Option<PyObject> = None | |
91 | ) -> PyResult<Option<PyObject>> { |
|
91 | ) -> PyResult<Option<PyObject>> { | |
92 | let key = key.extract::<PyBytes>(py)?; |
|
92 | let key = key.extract::<PyBytes>(py)?; | |
93 | match self.inner(py).borrow().get(HgPath::new(key.data(py))) { |
|
93 | match self | |
|
94 | .inner(py) | |||
|
95 | .borrow() | |||
|
96 | .get(HgPath::new(key.data(py))) | |||
|
97 | .map_err(|e| v2_error(py, e))? | |||
|
98 | { | |||
94 | Some(entry) => { |
|
99 | Some(entry) => { | |
95 | Ok(Some(make_dirstate_tuple(py, &entry)?)) |
|
100 | Ok(Some(make_dirstate_tuple(py, &entry)?)) | |
96 | }, |
|
101 | }, | |
@@ -124,7 +129,7 b' py_class!(pub class DirstateMap |py| {' | |||||
124 | size: size.extract(py)?, |
|
129 | size: size.extract(py)?, | |
125 | mtime: mtime.extract(py)?, |
|
130 | mtime: mtime.extract(py)?, | |
126 | }, |
|
131 | }, | |
127 |
).and(Ok(py.None())).or_else(|e: Dirstate |
|
132 | ).and(Ok(py.None())).or_else(|e: DirstateError| { | |
128 | Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())) |
|
133 | Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())) | |
129 | }) |
|
134 | }) | |
130 | } |
|
135 | } | |
@@ -190,8 +195,10 b' py_class!(pub class DirstateMap |py| {' | |||||
190 | )) |
|
195 | )) | |
191 | }) |
|
196 | }) | |
192 | .collect(); |
|
197 | .collect(); | |
193 |
self.inner(py) |
|
198 | self.inner(py) | |
194 | .clear_ambiguous_times(files?, now.extract(py)?); |
|
199 | .borrow_mut() | |
|
200 | .clear_ambiguous_times(files?, now.extract(py)?) | |||
|
201 | .map_err(|e| v2_error(py, e))?; | |||
195 | Ok(py.None()) |
|
202 | Ok(py.None()) | |
196 | } |
|
203 | } | |
197 |
|
204 | |||
@@ -199,6 +206,7 b' py_class!(pub class DirstateMap |py| {' | |||||
199 | let mut inner_shared = self.inner(py).borrow_mut(); |
|
206 | let mut inner_shared = self.inner(py).borrow_mut(); | |
200 | let set = PySet::empty(py)?; |
|
207 | let set = PySet::empty(py)?; | |
201 | for path in inner_shared.iter_other_parent_paths() { |
|
208 | for path in inner_shared.iter_other_parent_paths() { | |
|
209 | let path = path.map_err(|e| v2_error(py, e))?; | |||
202 | set.add(py, PyBytes::new(py, path.as_bytes()))?; |
|
210 | set.add(py, PyBytes::new(py, path.as_bytes()))?; | |
203 | } |
|
211 | } | |
204 | Ok(set.into_object()) |
|
212 | Ok(set.into_object()) | |
@@ -210,28 +218,20 b' py_class!(pub class DirstateMap |py| {' | |||||
210 |
|
218 | |||
211 | def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> { |
|
219 | def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> { | |
212 | let key = key.extract::<PyBytes>(py)?; |
|
220 | let key = key.extract::<PyBytes>(py)?; | |
213 |
|
|
221 | self.inner(py) | |
214 | .inner(py) |
|
|||
215 | .borrow_mut() |
|
222 | .borrow_mut() | |
216 |
.non_normal_entries_contains(HgPath::new(key.data(py))) |
|
223 | .non_normal_entries_contains(HgPath::new(key.data(py))) | |
|
224 | .map_err(|e| v2_error(py, e)) | |||
217 | } |
|
225 | } | |
218 |
|
226 | |||
219 | def non_normal_entries_display(&self) -> PyResult<PyString> { |
|
227 | def non_normal_entries_display(&self) -> PyResult<PyString> { | |
220 | Ok( |
|
228 | let mut inner = self.inner(py).borrow_mut(); | |
221 | PyString::new( |
|
229 | let paths = inner | |
222 | py, |
|
230 | .iter_non_normal_paths() | |
223 | &format!( |
|
231 | .collect::<Result<Vec<_>, _>>() | |
224 | "NonNormalEntries: {}", |
|
232 | .map_err(|e| v2_error(py, e))?; | |
225 | hg::utils::join_display( |
|
233 | let formatted = format!("NonNormalEntries: {}", hg::utils::join_display(paths, ", ")); | |
226 | self |
|
234 | Ok(PyString::new(py, &formatted)) | |
227 | .inner(py) |
|
|||
228 | .borrow_mut() |
|
|||
229 | .iter_non_normal_paths(), |
|
|||
230 | ", " |
|
|||
231 | ) |
|
|||
232 | ) |
|
|||
233 | ) |
|
|||
234 | ) |
|
|||
235 | } |
|
235 | } | |
236 |
|
236 | |||
237 | def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> { |
|
237 | def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> { | |
@@ -248,6 +248,7 b' py_class!(pub class DirstateMap |py| {' | |||||
248 |
|
248 | |||
249 | let ret = PyList::new(py, &[]); |
|
249 | let ret = PyList::new(py, &[]); | |
250 | for filename in inner.non_normal_or_other_parent_paths() { |
|
250 | for filename in inner.non_normal_or_other_parent_paths() { | |
|
251 | let filename = filename.map_err(|e| v2_error(py, e))?; | |||
251 | let as_pystring = PyBytes::new(py, filename.as_bytes()); |
|
252 | let as_pystring = PyBytes::new(py, filename.as_bytes()); | |
252 | ret.append(py, as_pystring.into_object()); |
|
253 | ret.append(py, as_pystring.into_object()); | |
253 | } |
|
254 | } | |
@@ -320,7 +321,8 b' py_class!(pub class DirstateMap |py| {' | |||||
320 |
|
321 | |||
321 | def filefoldmapasdict(&self) -> PyResult<PyDict> { |
|
322 | def filefoldmapasdict(&self) -> PyResult<PyDict> { | |
322 | let dict = PyDict::new(py); |
|
323 | let dict = PyDict::new(py); | |
323 |
for |
|
324 | for item in self.inner(py).borrow_mut().iter() { | |
|
325 | let (path, entry) = item.map_err(|e| v2_error(py, e))?; | |||
324 | if entry.state != EntryState::Removed { |
|
326 | if entry.state != EntryState::Removed { | |
325 | let key = normalize_case(path); |
|
327 | let key = normalize_case(path); | |
326 | let value = path; |
|
328 | let value = path; | |
@@ -340,13 +342,21 b' py_class!(pub class DirstateMap |py| {' | |||||
340 |
|
342 | |||
341 | def __contains__(&self, key: PyObject) -> PyResult<bool> { |
|
343 | def __contains__(&self, key: PyObject) -> PyResult<bool> { | |
342 | let key = key.extract::<PyBytes>(py)?; |
|
344 | let key = key.extract::<PyBytes>(py)?; | |
343 | Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py)))) |
|
345 | self.inner(py) | |
|
346 | .borrow() | |||
|
347 | .contains_key(HgPath::new(key.data(py))) | |||
|
348 | .map_err(|e| v2_error(py, e)) | |||
344 | } |
|
349 | } | |
345 |
|
350 | |||
346 | def __getitem__(&self, key: PyObject) -> PyResult<PyObject> { |
|
351 | def __getitem__(&self, key: PyObject) -> PyResult<PyObject> { | |
347 | let key = key.extract::<PyBytes>(py)?; |
|
352 | let key = key.extract::<PyBytes>(py)?; | |
348 | let key = HgPath::new(key.data(py)); |
|
353 | let key = HgPath::new(key.data(py)); | |
349 | match self.inner(py).borrow().get(key) { |
|
354 | match self | |
|
355 | .inner(py) | |||
|
356 | .borrow() | |||
|
357 | .get(key) | |||
|
358 | .map_err(|e| v2_error(py, e))? | |||
|
359 | { | |||
350 | Some(entry) => { |
|
360 | Some(entry) => { | |
351 | Ok(make_dirstate_tuple(py, &entry)?) |
|
361 | Ok(make_dirstate_tuple(py, &entry)?) | |
352 | }, |
|
362 | }, | |
@@ -418,7 +428,8 b' py_class!(pub class DirstateMap |py| {' | |||||
418 | // TODO all copymap* methods, see docstring above |
|
428 | // TODO all copymap* methods, see docstring above | |
419 | def copymapcopy(&self) -> PyResult<PyDict> { |
|
429 | def copymapcopy(&self) -> PyResult<PyDict> { | |
420 | let dict = PyDict::new(py); |
|
430 | let dict = PyDict::new(py); | |
421 |
for |
|
431 | for item in self.inner(py).borrow().copy_map_iter() { | |
|
432 | let (key, value) = item.map_err(|e| v2_error(py, e))?; | |||
422 | dict.set_item( |
|
433 | dict.set_item( | |
423 | py, |
|
434 | py, | |
424 | PyBytes::new(py, key.as_bytes()), |
|
435 | PyBytes::new(py, key.as_bytes()), | |
@@ -430,7 +441,12 b' py_class!(pub class DirstateMap |py| {' | |||||
430 |
|
441 | |||
431 | def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> { |
|
442 | def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> { | |
432 | let key = key.extract::<PyBytes>(py)?; |
|
443 | let key = key.extract::<PyBytes>(py)?; | |
433 | match self.inner(py).borrow().copy_map_get(HgPath::new(key.data(py))) { |
|
444 | match self | |
|
445 | .inner(py) | |||
|
446 | .borrow() | |||
|
447 | .copy_map_get(HgPath::new(key.data(py))) | |||
|
448 | .map_err(|e| v2_error(py, e))? | |||
|
449 | { | |||
434 | Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())), |
|
450 | Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())), | |
435 | None => Err(PyErr::new::<exc::KeyError, _>( |
|
451 | None => Err(PyErr::new::<exc::KeyError, _>( | |
436 | py, |
|
452 | py, | |
@@ -447,10 +463,10 b' py_class!(pub class DirstateMap |py| {' | |||||
447 | } |
|
463 | } | |
448 | def copymapcontains(&self, key: PyObject) -> PyResult<bool> { |
|
464 | def copymapcontains(&self, key: PyObject) -> PyResult<bool> { | |
449 | let key = key.extract::<PyBytes>(py)?; |
|
465 | let key = key.extract::<PyBytes>(py)?; | |
450 |
|
|
466 | self.inner(py) | |
451 | .inner(py) |
|
|||
452 | .borrow() |
|
467 | .borrow() | |
453 |
.copy_map_contains_key(HgPath::new(key.data(py))) |
|
468 | .copy_map_contains_key(HgPath::new(key.data(py))) | |
|
469 | .map_err(|e| v2_error(py, e)) | |||
454 | } |
|
470 | } | |
455 | def copymapget( |
|
471 | def copymapget( | |
456 | &self, |
|
472 | &self, | |
@@ -462,6 +478,7 b' py_class!(pub class DirstateMap |py| {' | |||||
462 | .inner(py) |
|
478 | .inner(py) | |
463 | .borrow() |
|
479 | .borrow() | |
464 | .copy_map_get(HgPath::new(key.data(py))) |
|
480 | .copy_map_get(HgPath::new(key.data(py))) | |
|
481 | .map_err(|e| v2_error(py, e))? | |||
465 | { |
|
482 | { | |
466 | Some(copy) => Ok(Some( |
|
483 | Some(copy) => Ok(Some( | |
467 | PyBytes::new(py, copy.as_bytes()).into_object(), |
|
484 | PyBytes::new(py, copy.as_bytes()).into_object(), | |
@@ -476,10 +493,13 b' py_class!(pub class DirstateMap |py| {' | |||||
476 | ) -> PyResult<PyObject> { |
|
493 | ) -> PyResult<PyObject> { | |
477 | let key = key.extract::<PyBytes>(py)?; |
|
494 | let key = key.extract::<PyBytes>(py)?; | |
478 | let value = value.extract::<PyBytes>(py)?; |
|
495 | let value = value.extract::<PyBytes>(py)?; | |
479 | self.inner(py).borrow_mut().copy_map_insert( |
|
496 | self.inner(py) | |
480 | HgPathBuf::from_bytes(key.data(py)), |
|
497 | .borrow_mut() | |
481 | HgPathBuf::from_bytes(value.data(py)), |
|
498 | .copy_map_insert( | |
482 | ); |
|
499 | HgPathBuf::from_bytes(key.data(py)), | |
|
500 | HgPathBuf::from_bytes(value.data(py)), | |||
|
501 | ) | |||
|
502 | .map_err(|e| v2_error(py, e))?; | |||
483 | Ok(py.None()) |
|
503 | Ok(py.None()) | |
484 | } |
|
504 | } | |
485 | def copymappop( |
|
505 | def copymappop( | |
@@ -492,6 +512,7 b' py_class!(pub class DirstateMap |py| {' | |||||
492 | .inner(py) |
|
512 | .inner(py) | |
493 | .borrow_mut() |
|
513 | .borrow_mut() | |
494 | .copy_map_remove(HgPath::new(key.data(py))) |
|
514 | .copy_map_remove(HgPath::new(key.data(py))) | |
|
515 | .map_err(|e| v2_error(py, e))? | |||
495 | { |
|
516 | { | |
496 | Some(_) => Ok(None), |
|
517 | Some(_) => Ok(None), | |
497 | None => Ok(default), |
|
518 | None => Ok(default), | |
@@ -525,15 +546,16 b' impl DirstateMap {' | |||||
525 | } |
|
546 | } | |
526 | fn translate_key( |
|
547 | fn translate_key( | |
527 | py: Python, |
|
548 | py: Python, | |
528 | res: (&HgPath, DirstateEntry), |
|
549 | res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>, | |
529 | ) -> PyResult<Option<PyBytes>> { |
|
550 | ) -> PyResult<Option<PyBytes>> { | |
530 | Ok(Some(PyBytes::new(py, res.0.as_bytes()))) |
|
551 | let (f, _entry) = res.map_err(|e| v2_error(py, e))?; | |
|
552 | Ok(Some(PyBytes::new(py, f.as_bytes()))) | |||
531 | } |
|
553 | } | |
532 | fn translate_key_value( |
|
554 | fn translate_key_value( | |
533 | py: Python, |
|
555 | py: Python, | |
534 | res: (&HgPath, DirstateEntry), |
|
556 | res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>, | |
535 | ) -> PyResult<Option<(PyBytes, PyObject)>> { |
|
557 | ) -> PyResult<Option<(PyBytes, PyObject)>> { | |
536 | let (f, entry) = res; |
|
558 | let (f, entry) = res.map_err(|e| v2_error(py, e))?; | |
537 | Ok(Some(( |
|
559 | Ok(Some(( | |
538 | PyBytes::new(py, f.as_bytes()), |
|
560 | PyBytes::new(py, f.as_bytes()), | |
539 | make_dirstate_tuple(py, &entry)?, |
|
561 | make_dirstate_tuple(py, &entry)?, | |
@@ -562,3 +584,7 b' fn extract_node_id(py: Python, obj: &PyO' | |||||
562 | Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())), |
|
584 | Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())), | |
563 | } |
|
585 | } | |
564 | } |
|
586 | } | |
|
587 | ||||
|
588 | pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr { | |||
|
589 | PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2") | |||
|
590 | } |
@@ -1,12 +1,12 b'' | |||||
1 | use crate::dirstate::owning::OwningDirstateMap; |
|
1 | use crate::dirstate::owning::OwningDirstateMap; | |
2 | use hg::dirstate::parsers::Timestamp; |
|
2 | use hg::dirstate::parsers::Timestamp; | |
3 | use hg::dirstate_tree::dispatch::DirstateMapMethods; |
|
3 | use hg::dirstate_tree::dispatch::DirstateMapMethods; | |
|
4 | use hg::dirstate_tree::on_disk::DirstateV2ParseError; | |||
4 | use hg::matchers::Matcher; |
|
5 | use hg::matchers::Matcher; | |
5 | use hg::utils::hg_path::{HgPath, HgPathBuf}; |
|
6 | use hg::utils::hg_path::{HgPath, HgPathBuf}; | |
6 | use hg::CopyMapIter; |
|
7 | use hg::CopyMapIter; | |
7 | use hg::DirstateEntry; |
|
8 | use hg::DirstateEntry; | |
8 | use hg::DirstateError; |
|
9 | use hg::DirstateError; | |
9 | use hg::DirstateMapError; |
|
|||
10 | use hg::DirstateParents; |
|
10 | use hg::DirstateParents; | |
11 | use hg::DirstateStatus; |
|
11 | use hg::DirstateStatus; | |
12 | use hg::EntryState; |
|
12 | use hg::EntryState; | |
@@ -26,7 +26,7 b' impl DirstateMapMethods for OwningDirsta' | |||||
26 | filename: &HgPath, |
|
26 | filename: &HgPath, | |
27 | old_state: EntryState, |
|
27 | old_state: EntryState, | |
28 | entry: DirstateEntry, |
|
28 | entry: DirstateEntry, | |
29 |
) -> Result<(), Dirstate |
|
29 | ) -> Result<(), DirstateError> { | |
30 | self.get_mut().add_file(filename, old_state, entry) |
|
30 | self.get_mut().add_file(filename, old_state, entry) | |
31 | } |
|
31 | } | |
32 |
|
32 | |||
@@ -35,7 +35,7 b' impl DirstateMapMethods for OwningDirsta' | |||||
35 | filename: &HgPath, |
|
35 | filename: &HgPath, | |
36 | old_state: EntryState, |
|
36 | old_state: EntryState, | |
37 | size: i32, |
|
37 | size: i32, | |
38 |
) -> Result<(), Dirstate |
|
38 | ) -> Result<(), DirstateError> { | |
39 | self.get_mut().remove_file(filename, old_state, size) |
|
39 | self.get_mut().remove_file(filename, old_state, size) | |
40 | } |
|
40 | } | |
41 |
|
41 | |||
@@ -43,15 +43,22 b' impl DirstateMapMethods for OwningDirsta' | |||||
43 | &mut self, |
|
43 | &mut self, | |
44 | filename: &HgPath, |
|
44 | filename: &HgPath, | |
45 | old_state: EntryState, |
|
45 | old_state: EntryState, | |
46 |
) -> Result<bool, Dirstate |
|
46 | ) -> Result<bool, DirstateError> { | |
47 | self.get_mut().drop_file(filename, old_state) |
|
47 | self.get_mut().drop_file(filename, old_state) | |
48 | } |
|
48 | } | |
49 |
|
49 | |||
50 | fn clear_ambiguous_times(&mut self, filenames: Vec<HgPathBuf>, now: i32) { |
|
50 | fn clear_ambiguous_times( | |
|
51 | &mut self, | |||
|
52 | filenames: Vec<HgPathBuf>, | |||
|
53 | now: i32, | |||
|
54 | ) -> Result<(), DirstateV2ParseError> { | |||
51 | self.get_mut().clear_ambiguous_times(filenames, now) |
|
55 | self.get_mut().clear_ambiguous_times(filenames, now) | |
52 | } |
|
56 | } | |
53 |
|
57 | |||
54 |
fn non_normal_entries_contains( |
|
58 | fn non_normal_entries_contains( | |
|
59 | &mut self, | |||
|
60 | key: &HgPath, | |||
|
61 | ) -> Result<bool, DirstateV2ParseError> { | |||
55 | self.get_mut().non_normal_entries_contains(key) |
|
62 | self.get_mut().non_normal_entries_contains(key) | |
56 | } |
|
63 | } | |
57 |
|
64 | |||
@@ -61,7 +68,8 b' impl DirstateMapMethods for OwningDirsta' | |||||
61 |
|
68 | |||
62 | fn non_normal_or_other_parent_paths( |
|
69 | fn non_normal_or_other_parent_paths( | |
63 | &mut self, |
|
70 | &mut self, | |
64 |
) -> Box<dyn Iterator<Item = &HgPath> + '_> |
|
71 | ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_> | |
|
72 | { | |||
65 | self.get_mut().non_normal_or_other_parent_paths() |
|
73 | self.get_mut().non_normal_or_other_parent_paths() | |
66 | } |
|
74 | } | |
67 |
|
75 | |||
@@ -71,33 +79,36 b' impl DirstateMapMethods for OwningDirsta' | |||||
71 |
|
79 | |||
72 | fn iter_non_normal_paths( |
|
80 | fn iter_non_normal_paths( | |
73 | &mut self, |
|
81 | &mut self, | |
74 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
82 | ) -> Box< | |
|
83 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
84 | > { | |||
75 | self.get_mut().iter_non_normal_paths() |
|
85 | self.get_mut().iter_non_normal_paths() | |
76 | } |
|
86 | } | |
77 |
|
87 | |||
78 | fn iter_non_normal_paths_panic( |
|
88 | fn iter_non_normal_paths_panic( | |
79 | &self, |
|
89 | &self, | |
80 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
90 | ) -> Box< | |
|
91 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
92 | > { | |||
81 | self.get().iter_non_normal_paths_panic() |
|
93 | self.get().iter_non_normal_paths_panic() | |
82 | } |
|
94 | } | |
83 |
|
95 | |||
84 | fn iter_other_parent_paths( |
|
96 | fn iter_other_parent_paths( | |
85 | &mut self, |
|
97 | &mut self, | |
86 | ) -> Box<dyn Iterator<Item = &HgPath> + Send + '_> { |
|
98 | ) -> Box< | |
|
99 | dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_, | |||
|
100 | > { | |||
87 | self.get_mut().iter_other_parent_paths() |
|
101 | self.get_mut().iter_other_parent_paths() | |
88 | } |
|
102 | } | |
89 |
|
103 | |||
90 | fn has_tracked_dir( |
|
104 | fn has_tracked_dir( | |
91 | &mut self, |
|
105 | &mut self, | |
92 | directory: &HgPath, |
|
106 | directory: &HgPath, | |
93 |
) -> Result<bool, Dirstate |
|
107 | ) -> Result<bool, DirstateError> { | |
94 | self.get_mut().has_tracked_dir(directory) |
|
108 | self.get_mut().has_tracked_dir(directory) | |
95 | } |
|
109 | } | |
96 |
|
110 | |||
97 | fn has_dir( |
|
111 | fn has_dir(&mut self, directory: &HgPath) -> Result<bool, DirstateError> { | |
98 | &mut self, |
|
|||
99 | directory: &HgPath, |
|
|||
100 | ) -> Result<bool, DirstateMapError> { |
|
|||
101 | self.get_mut().has_dir(directory) |
|
112 | self.get_mut().has_dir(directory) | |
102 | } |
|
113 | } | |
103 |
|
114 | |||
@@ -117,11 +128,11 b' impl DirstateMapMethods for OwningDirsta' | |||||
117 | self.get_mut().pack_v2(parents, now) |
|
128 | self.get_mut().pack_v2(parents, now) | |
118 | } |
|
129 | } | |
119 |
|
130 | |||
120 |
fn set_all_dirs(&mut self) -> Result<(), Dirstate |
|
131 | fn set_all_dirs(&mut self) -> Result<(), DirstateError> { | |
121 | self.get_mut().set_all_dirs() |
|
132 | self.get_mut().set_all_dirs() | |
122 | } |
|
133 | } | |
123 |
|
134 | |||
124 |
fn set_dirs(&mut self) -> Result<(), Dirstate |
|
135 | fn set_dirs(&mut self) -> Result<(), DirstateError> { | |
125 | self.get_mut().set_dirs() |
|
136 | self.get_mut().set_dirs() | |
126 | } |
|
137 | } | |
127 |
|
138 | |||
@@ -145,15 +156,24 b' impl DirstateMapMethods for OwningDirsta' | |||||
145 | self.get().copy_map_iter() |
|
156 | self.get().copy_map_iter() | |
146 | } |
|
157 | } | |
147 |
|
158 | |||
148 |
fn copy_map_contains_key( |
|
159 | fn copy_map_contains_key( | |
|
160 | &self, | |||
|
161 | key: &HgPath, | |||
|
162 | ) -> Result<bool, DirstateV2ParseError> { | |||
149 | self.get().copy_map_contains_key(key) |
|
163 | self.get().copy_map_contains_key(key) | |
150 | } |
|
164 | } | |
151 |
|
165 | |||
152 | fn copy_map_get(&self, key: &HgPath) -> Option<&HgPath> { |
|
166 | fn copy_map_get( | |
|
167 | &self, | |||
|
168 | key: &HgPath, | |||
|
169 | ) -> Result<Option<&HgPath>, DirstateV2ParseError> { | |||
153 | self.get().copy_map_get(key) |
|
170 | self.get().copy_map_get(key) | |
154 | } |
|
171 | } | |
155 |
|
172 | |||
156 | fn copy_map_remove(&mut self, key: &HgPath) -> Option<HgPathBuf> { |
|
173 | fn copy_map_remove( | |
|
174 | &mut self, | |||
|
175 | key: &HgPath, | |||
|
176 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | |||
157 | self.get_mut().copy_map_remove(key) |
|
177 | self.get_mut().copy_map_remove(key) | |
158 | } |
|
178 | } | |
159 |
|
179 | |||
@@ -161,7 +181,7 b' impl DirstateMapMethods for OwningDirsta' | |||||
161 | &mut self, |
|
181 | &mut self, | |
162 | key: HgPathBuf, |
|
182 | key: HgPathBuf, | |
163 | value: HgPathBuf, |
|
183 | value: HgPathBuf, | |
164 | ) -> Option<HgPathBuf> { |
|
184 | ) -> Result<Option<HgPathBuf>, DirstateV2ParseError> { | |
165 | self.get_mut().copy_map_insert(key, value) |
|
185 | self.get_mut().copy_map_insert(key, value) | |
166 | } |
|
186 | } | |
167 |
|
187 | |||
@@ -169,11 +189,17 b' impl DirstateMapMethods for OwningDirsta' | |||||
169 | self.get().len() |
|
189 | self.get().len() | |
170 | } |
|
190 | } | |
171 |
|
191 | |||
172 | fn contains_key(&self, key: &HgPath) -> bool { |
|
192 | fn contains_key( | |
|
193 | &self, | |||
|
194 | key: &HgPath, | |||
|
195 | ) -> Result<bool, DirstateV2ParseError> { | |||
173 | self.get().contains_key(key) |
|
196 | self.get().contains_key(key) | |
174 | } |
|
197 | } | |
175 |
|
198 | |||
176 | fn get(&self, key: &HgPath) -> Option<DirstateEntry> { |
|
199 | fn get( | |
|
200 | &self, | |||
|
201 | key: &HgPath, | |||
|
202 | ) -> Result<Option<DirstateEntry>, DirstateV2ParseError> { | |||
177 | self.get().get(key) |
|
203 | self.get().get(key) | |
178 | } |
|
204 | } | |
179 |
|
205 |
@@ -11,7 +11,9 b' use cpython::{' | |||||
11 | UnsafePyLeaked, |
|
11 | UnsafePyLeaked, | |
12 | }; |
|
12 | }; | |
13 |
|
13 | |||
|
14 | use crate::dirstate::dirstate_map::v2_error; | |||
14 | use crate::dirstate::DirstateMap; |
|
15 | use crate::dirstate::DirstateMap; | |
|
16 | use hg::dirstate_tree::on_disk::DirstateV2ParseError; | |||
15 | use hg::utils::hg_path::HgPath; |
|
17 | use hg::utils::hg_path::HgPath; | |
16 | use std::cell::RefCell; |
|
18 | use std::cell::RefCell; | |
17 |
|
19 | |||
@@ -54,13 +56,18 b' impl NonNormalEntries {' | |||||
54 | Ok(true) |
|
56 | Ok(true) | |
55 | } |
|
57 | } | |
56 |
|
58 | |||
57 | fn translate_key(py: Python, key: &HgPath) -> PyResult<Option<PyBytes>> { |
|
59 | fn translate_key( | |
|
60 | py: Python, | |||
|
61 | key: Result<&HgPath, DirstateV2ParseError>, | |||
|
62 | ) -> PyResult<Option<PyBytes>> { | |||
|
63 | let key = key.map_err(|e| v2_error(py, e))?; | |||
58 | Ok(Some(PyBytes::new(py, key.as_bytes()))) |
|
64 | Ok(Some(PyBytes::new(py, key.as_bytes()))) | |
59 | } |
|
65 | } | |
60 | } |
|
66 | } | |
61 |
|
67 | |||
62 | type NonNormalEntriesIter<'a> = |
|
68 | type NonNormalEntriesIter<'a> = Box< | |
63 |
|
|
69 | dyn Iterator<Item = Result<&'a HgPath, DirstateV2ParseError>> + Send + 'a, | |
|
70 | >; | |||
64 |
|
71 | |||
65 | py_shared_iterator!( |
|
72 | py_shared_iterator!( | |
66 | NonNormalEntriesIterator, |
|
73 | NonNormalEntriesIterator, |
General Comments 0
You need to be logged in to leave comments.
Login now