##// END OF EJS Templates
rust: start plugging the dirstate tree behind a feature gate...
Raphaël Gomès -
r46185:496537c9 default
parent child Browse files
Show More
@@ -38,8 +38,15 b' pub struct DirstateEntry {'
38 38 /// merge.
39 39 pub const SIZE_FROM_OTHER_PARENT: i32 = -2;
40 40
41 #[cfg(not(feature = "dirstate-tree"))]
41 42 pub type StateMap = FastHashMap<HgPathBuf, DirstateEntry>;
43 #[cfg(not(feature = "dirstate-tree"))]
42 44 pub type StateMapIter<'a> = hash_map::Iter<'a, HgPathBuf, DirstateEntry>;
45
46 #[cfg(feature = "dirstate-tree")]
47 pub type StateMap = dirstate_tree::tree::Tree;
48 #[cfg(feature = "dirstate-tree")]
49 pub type StateMapIter<'a> = dirstate_tree::iter::Iter<'a>;
43 50 pub type CopyMap = FastHashMap<HgPathBuf, HgPathBuf>;
44 51 pub type CopyMapIter<'a> = hash_map::Iter<'a, HgPathBuf, HgPathBuf>;
45 52
@@ -14,7 +14,7 b' use crate::{'
14 14 files,
15 15 hg_path::{HgPath, HgPathBuf, HgPathError},
16 16 },
17 DirstateEntry, DirstateMapError, FastHashMap,
17 DirstateEntry, DirstateMapError, FastHashMap, StateMap,
18 18 };
19 19 use std::collections::{hash_map, hash_map::Entry, HashMap, HashSet};
20 20
@@ -30,15 +30,15 b' impl DirsMultiset {'
30 30 /// Initializes the multiset from a dirstate.
31 31 ///
32 32 /// If `skip_state` is provided, skips dirstate entries with equal state.
33 #[cfg(not(feature = "dirstate-tree"))]
33 34 pub fn from_dirstate(
34 dirstate: &FastHashMap<HgPathBuf, DirstateEntry>,
35 dirstate: &StateMap,
35 36 skip_state: Option<EntryState>,
36 37 ) -> Result<Self, DirstateMapError> {
37 38 let mut multiset = DirsMultiset {
38 39 inner: FastHashMap::default(),
39 40 };
40
41 for (filename, DirstateEntry { state, .. }) in dirstate {
41 for (filename, DirstateEntry { state, .. }) in dirstate.iter() {
42 42 // This `if` is optimized out of the loop
43 43 if let Some(skip) = skip_state {
44 44 if skip != *state {
@@ -51,6 +51,30 b' impl DirsMultiset {'
51 51
52 52 Ok(multiset)
53 53 }
54 /// Initializes the multiset from a dirstate.
55 ///
56 /// If `skip_state` is provided, skips dirstate entries with equal state.
57 #[cfg(feature = "dirstate-tree")]
58 pub fn from_dirstate(
59 dirstate: &StateMap,
60 skip_state: Option<EntryState>,
61 ) -> Result<Self, DirstateMapError> {
62 let mut multiset = DirsMultiset {
63 inner: FastHashMap::default(),
64 };
65 for (filename, DirstateEntry { state, .. }) in dirstate.iter() {
66 // This `if` is optimized out of the loop
67 if let Some(skip) = skip_state {
68 if skip != state {
69 multiset.add_path(filename)?;
70 }
71 } else {
72 multiset.add_path(filename)?;
73 }
74 }
75
76 Ok(multiset)
77 }
54 78
55 79 /// Initializes the multiset from a manifest.
56 80 pub fn from_manifest(
@@ -332,8 +356,8 b' mod tests {'
332 356 };
333 357 assert_eq!(expected, new);
334 358
335 let new = DirsMultiset::from_dirstate(&FastHashMap::default(), None)
336 .unwrap();
359 let new =
360 DirsMultiset::from_dirstate(&StateMap::default(), None).unwrap();
337 361 let expected = DirsMultiset {
338 362 inner: FastHashMap::default(),
339 363 };
@@ -357,7 +381,7 b' mod tests {'
357 381 };
358 382 assert_eq!(expected, new);
359 383
360 let input_map = ["a/", "b/", "a/c", "a/d/"]
384 let input_map = ["b/x", "a/c", "a/d/x"]
361 385 .iter()
362 386 .map(|f| {
363 387 (
@@ -371,7 +395,7 b' mod tests {'
371 395 )
372 396 })
373 397 .collect();
374 let expected_inner = [("", 2), ("a", 3), ("b", 1), ("a/d", 1)]
398 let expected_inner = [("", 2), ("a", 2), ("b", 1), ("a/d", 1)]
375 399 .iter()
376 400 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
377 401 .collect();
@@ -387,9 +411,9 b' mod tests {'
387 411 fn test_dirsmultiset_new_skip() {
388 412 let input_map = [
389 413 ("a/", EntryState::Normal),
390 ("a/b/", EntryState::Normal),
414 ("a/b", EntryState::Normal),
391 415 ("a/c", EntryState::Removed),
392 ("a/d/", EntryState::Merged),
416 ("a/d", EntryState::Merged),
393 417 ]
394 418 .iter()
395 419 .map(|(f, state)| {
@@ -406,7 +430,7 b' mod tests {'
406 430 .collect();
407 431
408 432 // "a" incremented with "a/c" and "a/d/"
409 let expected_inner = [("", 1), ("a", 2), ("a/d", 1)]
433 let expected_inner = [("", 1), ("a", 2)]
410 434 .iter()
411 435 .map(|(k, v)| (HgPathBuf::from_bytes(k.as_bytes()), *v))
412 436 .collect();
@@ -16,7 +16,6 b' use crate::{'
16 16 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
17 17 DirstateParents, DirstateParseError, FastHashMap, StateMap,
18 18 };
19 use core::borrow::Borrow;
20 19 use micro_timer::timed;
21 20 use std::collections::HashSet;
22 21 use std::convert::TryInto;
@@ -67,7 +66,7 b' impl DirstateMap {'
67 66 }
68 67
69 68 pub fn clear(&mut self) {
70 self.state_map.clear();
69 self.state_map = StateMap::default();
71 70 self.copy_map.clear();
72 71 self.file_fold_map = None;
73 72 self.non_normal_set = None;
@@ -189,18 +188,15 b' impl DirstateMap {'
189 188 ) {
190 189 for filename in filenames {
191 190 let mut changed = false;
192 self.state_map
193 .entry(filename.to_owned())
194 .and_modify(|entry| {
195 if entry.state == EntryState::Normal && entry.mtime == now
196 {
197 changed = true;
198 *entry = DirstateEntry {
199 mtime: MTIME_UNSET,
200 ..*entry
201 };
202 }
203 });
191 if let Some(entry) = self.state_map.get_mut(&filename) {
192 if entry.state == EntryState::Normal && entry.mtime == now {
193 changed = true;
194 *entry = DirstateEntry {
195 mtime: MTIME_UNSET,
196 ..*entry
197 };
198 }
199 }
204 200 if changed {
205 201 self.get_non_normal_other_parent_entries()
206 202 .0
@@ -257,6 +253,7 b' impl DirstateMap {'
257 253 )
258 254 }
259 255
256 #[cfg(not(feature = "dirstate-tree"))]
260 257 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
261 258 if !force
262 259 && self.non_normal_set.is_some()
@@ -285,6 +282,34 b' impl DirstateMap {'
285 282 self.non_normal_set = Some(non_normal);
286 283 self.other_parent_set = Some(other_parent);
287 284 }
285 #[cfg(feature = "dirstate-tree")]
286 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
287 if !force
288 && self.non_normal_set.is_some()
289 && self.other_parent_set.is_some()
290 {
291 return;
292 }
293 let mut non_normal = HashSet::new();
294 let mut other_parent = HashSet::new();
295
296 for (
297 filename,
298 DirstateEntry {
299 state, size, mtime, ..
300 },
301 ) in self.state_map.iter()
302 {
303 if state != EntryState::Normal || mtime == MTIME_UNSET {
304 non_normal.insert(filename.to_owned());
305 }
306 if state == EntryState::Normal && size == SIZE_FROM_OTHER_PARENT {
307 other_parent.insert(filename.to_owned());
308 }
309 }
310 self.non_normal_set = Some(non_normal);
311 self.other_parent_set = Some(other_parent);
312 }
288 313
289 314 /// Both of these setters and their uses appear to be the simplest way to
290 315 /// emulate a Python lazy property, but it is ugly and unidiomatic.
@@ -398,17 +423,33 b' impl DirstateMap {'
398 423 self.set_non_normal_other_parent_entries(true);
399 424 Ok(packed)
400 425 }
401
426 #[cfg(not(feature = "dirstate-tree"))]
402 427 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
403 428 if let Some(ref file_fold_map) = self.file_fold_map {
404 429 return file_fold_map;
405 430 }
406 431 let mut new_file_fold_map = FileFoldMap::default();
407 for (filename, DirstateEntry { state, .. }) in self.state_map.borrow()
408 {
432
433 for (filename, DirstateEntry { state, .. }) in self.state_map.iter() {
409 434 if *state == EntryState::Removed {
410 435 new_file_fold_map
411 .insert(normalize_case(filename), filename.to_owned());
436 .insert(normalize_case(&filename), filename.to_owned());
437 }
438 }
439 self.file_fold_map = Some(new_file_fold_map);
440 self.file_fold_map.as_ref().unwrap()
441 }
442 #[cfg(feature = "dirstate-tree")]
443 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
444 if let Some(ref file_fold_map) = self.file_fold_map {
445 return file_fold_map;
446 }
447 let mut new_file_fold_map = FileFoldMap::default();
448
449 for (filename, DirstateEntry { state, .. }) in self.state_map.iter() {
450 if state == EntryState::Removed {
451 new_file_fold_map
452 .insert(normalize_case(&filename), filename.to_owned());
412 453 }
413 454 }
414 455 self.file_fold_map = Some(new_file_fold_map);
@@ -80,11 +80,11 b' pub fn parse_dirstate('
80 80 ));
81 81 curr_pos = curr_pos + MIN_ENTRY_SIZE + (path_len);
82 82 }
83
84 83 Ok((parents, entries, copies))
85 84 }
86 85
87 86 /// `now` is the duration in seconds since the Unix epoch
87 #[cfg(not(feature = "dirstate-tree"))]
88 88 pub fn pack_dirstate(
89 89 state_map: &mut StateMap,
90 90 copy_map: &CopyMap,
@@ -156,15 +156,89 b' pub fn pack_dirstate('
156 156
157 157 Ok(packed)
158 158 }
159 /// `now` is the duration in seconds since the Unix epoch
160 #[cfg(feature = "dirstate-tree")]
161 pub fn pack_dirstate(
162 state_map: &mut StateMap,
163 copy_map: &CopyMap,
164 parents: DirstateParents,
165 now: Duration,
166 ) -> Result<Vec<u8>, DirstatePackError> {
167 // TODO move away from i32 before 2038.
168 let now: i32 = now.as_secs().try_into().expect("time overflow");
169
170 let expected_size: usize = state_map
171 .iter()
172 .map(|(filename, _)| {
173 let mut length = MIN_ENTRY_SIZE + filename.len();
174 if let Some(copy) = copy_map.get(&filename) {
175 length += copy.len() + 1;
176 }
177 length
178 })
179 .sum();
180 let expected_size = expected_size + PARENT_SIZE * 2;
181
182 let mut packed = Vec::with_capacity(expected_size);
183 let mut new_state_map = vec![];
184
185 packed.extend(&parents.p1);
186 packed.extend(&parents.p2);
187
188 for (filename, entry) in state_map.iter() {
189 let new_filename = filename.to_owned();
190 let mut new_mtime: i32 = entry.mtime;
191 if entry.state == EntryState::Normal && entry.mtime == now {
192 // The file was last modified "simultaneously" with the current
193 // write to dirstate (i.e. within the same second for file-
194 // systems with a granularity of 1 sec). This commonly happens
195 // for at least a couple of files on 'update'.
196 // The user could change the file without changing its size
197 // within the same second. Invalidate the file's mtime in
198 // dirstate, forcing future 'status' calls to compare the
199 // contents of the file if the size is the same. This prevents
200 // mistakenly treating such files as clean.
201 new_mtime = -1;
202 new_state_map.push((
203 filename.to_owned(),
204 DirstateEntry {
205 mtime: new_mtime,
206 ..entry
207 },
208 ));
209 }
210 let mut new_filename = new_filename.into_vec();
211 if let Some(copy) = copy_map.get(&filename) {
212 new_filename.push(b'\0');
213 new_filename.extend(copy.bytes());
214 }
215
216 packed.write_u8(entry.state.into())?;
217 packed.write_i32::<BigEndian>(entry.mode)?;
218 packed.write_i32::<BigEndian>(entry.size)?;
219 packed.write_i32::<BigEndian>(new_mtime)?;
220 packed.write_i32::<BigEndian>(new_filename.len() as i32)?;
221 packed.extend(new_filename)
222 }
223
224 if packed.len() != expected_size {
225 return Err(DirstatePackError::BadSize(expected_size, packed.len()));
226 }
227
228 state_map.extend(new_state_map);
229
230 Ok(packed)
231 }
159 232
160 233 #[cfg(test)]
161 234 mod tests {
162 235 use super::*;
163 236 use crate::{utils::hg_path::HgPathBuf, FastHashMap};
237 use pretty_assertions::assert_eq;
164 238
165 239 #[test]
166 240 fn test_pack_dirstate_empty() {
167 let mut state_map: StateMap = FastHashMap::default();
241 let mut state_map = StateMap::default();
168 242 let copymap = FastHashMap::default();
169 243 let parents = DirstateParents {
170 244 p1: *b"12345678910111213141",
@@ -9,6 +9,10 b''
9 9 //! It is currently missing a lot of functionality compared to the Python one
10 10 //! and will only be triggered in narrow cases.
11 11
12 #[cfg(feature = "dirstate-tree")]
13 use crate::dirstate::dirstate_tree::iter::StatusShortcut;
14 #[cfg(not(feature = "dirstate-tree"))]
15 use crate::utils::path_auditor::PathAuditor;
12 16 use crate::{
13 17 dirstate::SIZE_FROM_OTHER_PARENT,
14 18 filepatterns::PatternFileWarning,
@@ -19,7 +23,6 b' use crate::{'
19 23 hg_path_to_path_buf, os_string_to_hg_path_buf, HgPath, HgPathBuf,
20 24 HgPathError,
21 25 },
22 path_auditor::PathAuditor,
23 26 },
24 27 CopyMap, DirstateEntry, DirstateMap, EntryState, FastHashMap,
25 28 PatternError,
@@ -701,12 +704,131 b' where'
701 704 })
702 705 }
703 706
707 /// Add the files in the dirstate to the results.
708 ///
709 /// This takes a mutable reference to the results to account for the
710 /// `extend` in timings
711 #[cfg(feature = "dirstate-tree")]
712 #[timed]
713 pub fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) {
714 results.par_extend(
715 self.dmap
716 .fs_iter(self.root_dir.clone())
717 .par_bridge()
718 .filter(|(path, _)| self.matcher.matches(path))
719 .flat_map(move |(filename, shortcut)| {
720 let entry = match shortcut {
721 StatusShortcut::Entry(e) => e,
722 StatusShortcut::Dispatch(d) => {
723 return Ok((Cow::Owned(filename), d))
724 }
725 };
726 let filename_as_path = hg_path_to_path_buf(&filename)?;
727 let meta = self
728 .root_dir
729 .join(filename_as_path)
730 .symlink_metadata();
731
732 match meta {
733 Ok(ref m)
734 if !(m.file_type().is_file()
735 || m.file_type().is_symlink()) =>
736 {
737 Ok((
738 Cow::Owned(filename),
739 dispatch_missing(entry.state),
740 ))
741 }
742 Ok(m) => {
743 let dispatch = dispatch_found(
744 &filename,
745 entry,
746 HgMetadata::from_metadata(m),
747 &self.dmap.copy_map,
748 self.options,
749 );
750 Ok((Cow::Owned(filename), dispatch))
751 }
752 Err(ref e)
753 if e.kind() == ErrorKind::NotFound
754 || e.raw_os_error() == Some(20) =>
755 {
756 // Rust does not yet have an `ErrorKind` for
757 // `NotADirectory` (errno 20)
758 // It happens if the dirstate contains `foo/bar`
759 // and foo is not a
760 // directory
761 Ok((
762 Cow::Owned(filename),
763 dispatch_missing(entry.state),
764 ))
765 }
766 Err(e) => Err(e),
767 }
768 }),
769 );
770 }
771
772 /// Add the files in the dirstate to the results.
773 ///
774 /// This takes a mutable reference to the results to account for the
775 /// `extend` in timings
776 #[cfg(not(feature = "dirstate-tree"))]
777 #[timed]
778 pub fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) {
779 results.par_extend(self.dmap.par_iter().flat_map(
780 move |(filename, entry)| {
781 let filename: &HgPath = filename;
782 let filename_as_path = hg_path_to_path_buf(filename)?;
783 let meta =
784 self.root_dir.join(filename_as_path).symlink_metadata();
785 match meta {
786 Ok(ref m)
787 if !(m.file_type().is_file()
788 || m.file_type().is_symlink()) =>
789 {
790 Ok((
791 Cow::Borrowed(filename),
792 dispatch_missing(entry.state),
793 ))
794 }
795 Ok(m) => Ok((
796 Cow::Borrowed(filename),
797 dispatch_found(
798 filename,
799 *entry,
800 HgMetadata::from_metadata(m),
801 &self.dmap.copy_map,
802 self.options,
803 ),
804 )),
805 Err(ref e)
806 if e.kind() == ErrorKind::NotFound
807 || e.raw_os_error() == Some(20) =>
808 {
809 // Rust does not yet have an `ErrorKind` for
810 // `NotADirectory` (errno 20)
811 // It happens if the dirstate contains `foo/bar`
812 // and foo is not a
813 // directory
814 Ok((
815 Cow::Borrowed(filename),
816 dispatch_missing(entry.state),
817 ))
818 }
819 Err(e) => Err(e),
820 }
821 },
822 ));
823 }
824
704 825 /// Checks all files that are in the dirstate but were not found during the
705 826 /// working directory traversal. This means that the rest must
706 827 /// be either ignored, under a symlink or under a new nested repo.
707 828 ///
708 829 /// This takes a mutable reference to the results to account for the
709 830 /// `extend` in timings
831 #[cfg(not(feature = "dirstate-tree"))]
710 832 #[timed]
711 833 pub fn handle_unknowns(
712 834 &self,
@@ -781,59 +903,6 b' where'
781 903
782 904 Ok(())
783 905 }
784
785 /// Add the files in the dirstate to the results.
786 ///
787 /// This takes a mutable reference to the results to account for the
788 /// `extend` in timings
789 #[timed]
790 pub fn extend_from_dmap(&self, results: &mut Vec<DispatchedPath<'a>>) {
791 results.par_extend(self.dmap.par_iter().flat_map(
792 move |(filename, entry)| {
793 let filename: &HgPath = filename;
794 let filename_as_path = hg_path_to_path_buf(filename)?;
795 let meta =
796 self.root_dir.join(filename_as_path).symlink_metadata();
797
798 match meta {
799 Ok(ref m)
800 if !(m.file_type().is_file()
801 || m.file_type().is_symlink()) =>
802 {
803 Ok((
804 Cow::Borrowed(filename),
805 dispatch_missing(entry.state),
806 ))
807 }
808 Ok(m) => Ok((
809 Cow::Borrowed(filename),
810 dispatch_found(
811 filename,
812 *entry,
813 HgMetadata::from_metadata(m),
814 &self.dmap.copy_map,
815 self.options,
816 ),
817 )),
818 Err(ref e)
819 if e.kind() == ErrorKind::NotFound
820 || e.raw_os_error() == Some(20) =>
821 {
822 // Rust does not yet have an `ErrorKind` for
823 // `NotADirectory` (errno 20)
824 // It happens if the dirstate contains `foo/bar`
825 // and foo is not a
826 // directory
827 Ok((
828 Cow::Borrowed(filename),
829 dispatch_missing(entry.state),
830 ))
831 }
832 Err(e) => Err(e),
833 }
834 },
835 ));
836 }
837 906 }
838 907
839 908 #[timed]
@@ -14,6 +14,66 b' use crate::{DirstateStatus, StatusError}'
14 14 /// files.
15 15 pub type LookupAndStatus<'a> = (Vec<HgPathCow<'a>>, DirstateStatus<'a>);
16 16
17 #[cfg(feature = "dirstate-tree")]
18 impl<'a, M: Matcher + Sync> Status<'a, M> {
19 pub(crate) fn run(&self) -> Result<LookupAndStatus<'a>, StatusError> {
20 let (traversed_sender, traversed_receiver) =
21 crossbeam::channel::unbounded();
22
23 // Step 1: check the files explicitly mentioned by the user
24 let (work, mut results) = self.walk_explicit(traversed_sender.clone());
25
26 // Step 2: Check files in the dirstate
27 if !self.matcher.is_exact() {
28 self.extend_from_dmap(&mut results);
29 }
30 // Step 3: Check the working directory if listing unknowns
31 if !work.is_empty() {
32 // Hashmaps are quite a bit slower to build than vecs, so only
33 // build it if needed.
34 let mut old_results = None;
35
36 // Step 2: recursively check the working directory for changes if
37 // needed
38 for (dir, dispatch) in work {
39 match dispatch {
40 Dispatch::Directory { was_file } => {
41 if was_file {
42 results.push((dir.to_owned(), Dispatch::Removed));
43 }
44 if self.options.list_ignored
45 || self.options.list_unknown
46 && !self.dir_ignore(&dir)
47 {
48 if old_results.is_none() {
49 old_results =
50 Some(results.iter().cloned().collect());
51 }
52 self.traverse(
53 &dir,
54 old_results
55 .as_ref()
56 .expect("old results should exist"),
57 &mut results,
58 traversed_sender.clone(),
59 )?;
60 }
61 }
62 _ => {
63 unreachable!("There can only be directories in `work`")
64 }
65 }
66 }
67 }
68
69 drop(traversed_sender);
70 let traversed = traversed_receiver.into_iter().collect();
71
72 Ok(build_response(results, traversed))
73 }
74 }
75
76 #[cfg(not(feature = "dirstate-tree"))]
17 77 impl<'a, M: Matcher + Sync> Status<'a, M> {
18 78 pub(crate) fn run(&self) -> Result<LookupAndStatus<'a>, StatusError> {
19 79 let (traversed_sender, traversed_receiver) =
@@ -142,10 +142,10 b' py_class!(pub class DirstateMap |py| {'
142 142 })?,
143 143 )
144 144 .and_then(|b| Ok(b.to_py_object(py)))
145 .or_else(|_| {
145 .or_else(|e| {
146 146 Err(PyErr::new::<exc::OSError, _>(
147 147 py,
148 "Dirstate error".to_string(),
148 format!("Dirstate error: {}", e.to_string()),
149 149 ))
150 150 })
151 151 }
@@ -549,12 +549,14 b' impl DirstateMap {'
549 549 ) -> Ref<'a, RustDirstateMap> {
550 550 self.inner(py).borrow()
551 551 }
552 #[cfg(not(feature = "dirstate-tree"))]
552 553 fn translate_key(
553 554 py: Python,
554 555 res: (&HgPathBuf, &DirstateEntry),
555 556 ) -> PyResult<Option<PyBytes>> {
556 557 Ok(Some(PyBytes::new(py, res.0.as_bytes())))
557 558 }
559 #[cfg(not(feature = "dirstate-tree"))]
558 560 fn translate_key_value(
559 561 py: Python,
560 562 res: (&HgPathBuf, &DirstateEntry),
@@ -562,7 +564,25 b' impl DirstateMap {'
562 564 let (f, entry) = res;
563 565 Ok(Some((
564 566 PyBytes::new(py, f.as_bytes()),
565 make_dirstate_tuple(py, entry)?,
567 make_dirstate_tuple(py, &entry)?,
568 )))
569 }
570 #[cfg(feature = "dirstate-tree")]
571 fn translate_key(
572 py: Python,
573 res: (HgPathBuf, DirstateEntry),
574 ) -> PyResult<Option<PyBytes>> {
575 Ok(Some(PyBytes::new(py, res.0.as_bytes())))
576 }
577 #[cfg(feature = "dirstate-tree")]
578 fn translate_key_value(
579 py: Python,
580 res: (HgPathBuf, DirstateEntry),
581 ) -> PyResult<Option<(PyBytes, PyObject)>> {
582 let (f, entry) = res;
583 Ok(Some((
584 PyBytes::new(py, f.as_bytes()),
585 make_dirstate_tuple(py, &entry)?,
566 586 )))
567 587 }
568 588 }
@@ -159,7 +159,7 b' pub fn status_wrapper('
159 159 .collect();
160 160
161 161 let files = files?;
162 let matcher = FileMatcher::new(&files)
162 let matcher = FileMatcher::new(files.as_ref())
163 163 .map_err(|e| PyErr::new::<ValueError, _>(py, e.to_string()))?;
164 164 let ((lookup, status_res), warnings) = status(
165 165 &dmap,
@@ -119,11 +119,11 b' fn pack_dirstate_wrapper('
119 119 Duration::from_secs(now.as_object().extract::<u64>(py)?),
120 120 ) {
121 121 Ok(packed) => {
122 for (filename, entry) in &dirstate_map {
122 for (filename, entry) in dirstate_map.iter() {
123 123 dmap.set_item(
124 124 py,
125 125 PyBytes::new(py, filename.as_bytes()),
126 make_dirstate_tuple(py, entry)?,
126 make_dirstate_tuple(py, &entry)?,
127 127 )?;
128 128 }
129 129 Ok(PyBytes::new(py, &packed))
General Comments 0
You need to be logged in to leave comments. Login now