##// END OF EJS Templates
dirstate: drop all logic around the "non-normal" sets...
marmoute -
r48875:060cd909 default
parent child Browse files
Show More
@@ -661,24 +661,6 b' static PyObject *dirstate_item_get_remov'
661 }
661 }
662 };
662 };
663
663
664 static PyObject *dm_nonnormal(dirstateItemObject *self)
665 {
666 if ((dirstate_item_c_v1_state(self) != 'n') ||
667 (dirstate_item_c_v1_mtime(self) == ambiguous_time)) {
668 Py_RETURN_TRUE;
669 } else {
670 Py_RETURN_FALSE;
671 }
672 };
673 static PyObject *dm_otherparent(dirstateItemObject *self)
674 {
675 if (dirstate_item_c_v1_mtime(self) == dirstate_v1_from_p2) {
676 Py_RETURN_TRUE;
677 } else {
678 Py_RETURN_FALSE;
679 }
680 };
681
682 static PyGetSetDef dirstate_item_getset[] = {
664 static PyGetSetDef dirstate_item_getset[] = {
683 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
665 {"mode", (getter)dirstate_item_get_mode, NULL, "mode", NULL},
684 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
666 {"size", (getter)dirstate_item_get_size, NULL, "size", NULL},
@@ -693,8 +675,6 b' static PyGetSetDef dirstate_item_getset['
693 "from_p2_removed", NULL},
675 "from_p2_removed", NULL},
694 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
676 {"from_p2", (getter)dirstate_item_get_from_p2, NULL, "from_p2", NULL},
695 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
677 {"removed", (getter)dirstate_item_get_removed, NULL, "removed", NULL},
696 {"dm_nonnormal", (getter)dm_nonnormal, NULL, "dm_nonnormal", NULL},
697 {"dm_otherparent", (getter)dm_otherparent, NULL, "dm_otherparent", NULL},
698 {NULL} /* Sentinel */
678 {NULL} /* Sentinel */
699 };
679 };
700
680
@@ -831,70 +811,6 b' quit:'
831 }
811 }
832
812
833 /*
813 /*
834 * Build a set of non-normal and other parent entries from the dirstate dmap
835 */
836 static PyObject *nonnormalotherparententries(PyObject *self, PyObject *args)
837 {
838 PyObject *dmap, *fname, *v;
839 PyObject *nonnset = NULL, *otherpset = NULL, *result = NULL;
840 Py_ssize_t pos;
841
842 if (!PyArg_ParseTuple(args, "O!:nonnormalentries", &PyDict_Type,
843 &dmap)) {
844 goto bail;
845 }
846
847 nonnset = PySet_New(NULL);
848 if (nonnset == NULL) {
849 goto bail;
850 }
851
852 otherpset = PySet_New(NULL);
853 if (otherpset == NULL) {
854 goto bail;
855 }
856
857 pos = 0;
858 while (PyDict_Next(dmap, &pos, &fname, &v)) {
859 dirstateItemObject *t;
860 if (!dirstate_tuple_check(v)) {
861 PyErr_SetString(PyExc_TypeError,
862 "expected a dirstate tuple");
863 goto bail;
864 }
865 t = (dirstateItemObject *)v;
866
867 if (dirstate_item_c_from_p2(t)) {
868 if (PySet_Add(otherpset, fname) == -1) {
869 goto bail;
870 }
871 }
872 if (!(t->flags & dirstate_flag_wc_tracked) ||
873 !(t->flags &
874 (dirstate_flag_p1_tracked | dirstate_flag_p2_tracked)) ||
875 (t->flags &
876 (dirstate_flag_possibly_dirty | dirstate_flag_merged))) {
877 if (PySet_Add(nonnset, fname) == -1) {
878 goto bail;
879 }
880 }
881 }
882
883 result = Py_BuildValue("(OO)", nonnset, otherpset);
884 if (result == NULL) {
885 goto bail;
886 }
887 Py_DECREF(nonnset);
888 Py_DECREF(otherpset);
889 return result;
890 bail:
891 Py_XDECREF(nonnset);
892 Py_XDECREF(otherpset);
893 Py_XDECREF(result);
894 return NULL;
895 }
896
897 /*
898 * Efficiently pack a dirstate object into its on-disk format.
814 * Efficiently pack a dirstate object into its on-disk format.
899 */
815 */
900 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
816 static PyObject *pack_dirstate(PyObject *self, PyObject *args)
@@ -1226,9 +1142,6 b' PyObject *parse_index2(PyObject *self, P'
1226
1142
1227 static PyMethodDef methods[] = {
1143 static PyMethodDef methods[] = {
1228 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1144 {"pack_dirstate", pack_dirstate, METH_VARARGS, "pack a dirstate\n"},
1229 {"nonnormalotherparententries", nonnormalotherparententries, METH_VARARGS,
1230 "create a set containing non-normal and other parent entries of given "
1231 "dirstate\n"},
1232 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1145 {"parse_dirstate", parse_dirstate, METH_VARARGS, "parse a dirstate\n"},
1233 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1146 {"parse_index2", (PyCFunction)parse_index2, METH_VARARGS | METH_KEYWORDS,
1234 "parse a revlog index\n"},
1147 "parse a revlog index\n"},
@@ -62,12 +62,6 b' class dirstatemap(object):'
62
62
63 The dirstate also provides the following views onto the state:
63 The dirstate also provides the following views onto the state:
64
64
65 - `nonnormalset` is a set of the filenames that have state other
66 than 'normal', or are normal but have an mtime of -1 ('normallookup').
67
68 - `otherparentset` is a set of the filenames that are marked as coming
69 from the second parent when the dirstate is currently being merged.
70
71 - `filefoldmap` is a dict mapping normalized filenames to the denormalized
65 - `filefoldmap` is a dict mapping normalized filenames to the denormalized
72 form that they appear as in the dirstate.
66 form that they appear as in the dirstate.
73
67
@@ -112,8 +106,6 b' class dirstatemap(object):'
112 util.clearcachedproperty(self, b"_alldirs")
106 util.clearcachedproperty(self, b"_alldirs")
113 util.clearcachedproperty(self, b"filefoldmap")
107 util.clearcachedproperty(self, b"filefoldmap")
114 util.clearcachedproperty(self, b"dirfoldmap")
108 util.clearcachedproperty(self, b"dirfoldmap")
115 util.clearcachedproperty(self, b"nonnormalset")
116 util.clearcachedproperty(self, b"otherparentset")
117
109
118 def items(self):
110 def items(self):
119 return pycompat.iteritems(self._map)
111 return pycompat.iteritems(self._map)
@@ -185,7 +177,6 b' class dirstatemap(object):'
185 size = size & rangemask
177 size = size & rangemask
186 entry.set_clean(mode, size, mtime)
178 entry.set_clean(mode, size, mtime)
187 self.copymap.pop(filename, None)
179 self.copymap.pop(filename, None)
188 self.nonnormalset.discard(filename)
189
180
190 def reset_state(
181 def reset_state(
191 self,
182 self,
@@ -218,7 +209,6 b' class dirstatemap(object):'
218 if not (p1_tracked or p2_tracked or wc_tracked):
209 if not (p1_tracked or p2_tracked or wc_tracked):
219 old_entry = self._map.pop(filename, None)
210 old_entry = self._map.pop(filename, None)
220 self._dirs_decr(filename, old_entry=old_entry)
211 self._dirs_decr(filename, old_entry=old_entry)
221 self.nonnormalset.discard(filename)
222 self.copymap.pop(filename, None)
212 self.copymap.pop(filename, None)
223 return
213 return
224 elif merged:
214 elif merged:
@@ -271,14 +261,6 b' class dirstatemap(object):'
271 possibly_dirty=possibly_dirty,
261 possibly_dirty=possibly_dirty,
272 parentfiledata=parentfiledata,
262 parentfiledata=parentfiledata,
273 )
263 )
274 if entry.dm_nonnormal:
275 self.nonnormalset.add(filename)
276 else:
277 self.nonnormalset.discard(filename)
278 if entry.dm_otherparent:
279 self.otherparentset.add(filename)
280 else:
281 self.otherparentset.discard(filename)
282 self._map[filename] = entry
264 self._map[filename] = entry
283
265
284 def set_tracked(self, filename):
266 def set_tracked(self, filename):
@@ -297,8 +279,6 b' class dirstatemap(object):'
297 parentfiledata=None,
279 parentfiledata=None,
298 )
280 )
299 self._map[filename] = entry
281 self._map[filename] = entry
300 if entry.dm_nonnormal:
301 self.nonnormalset.add(filename)
302 new = True
282 new = True
303 elif not entry.tracked:
283 elif not entry.tracked:
304 self._dirs_incr(filename, entry)
284 self._dirs_incr(filename, entry)
@@ -321,29 +301,11 b' class dirstatemap(object):'
321 if not entry.merged:
301 if not entry.merged:
322 self.copymap.pop(f, None)
302 self.copymap.pop(f, None)
323 if entry.added:
303 if entry.added:
324 self.nonnormalset.discard(f)
325 self._map.pop(f, None)
304 self._map.pop(f, None)
326 else:
305 else:
327 self.nonnormalset.add(f)
328 if entry.from_p2:
329 self.otherparentset.add(f)
330 entry.set_untracked()
306 entry.set_untracked()
331 return True
307 return True
332
308
333 def nonnormalentries(self):
334 '''Compute the nonnormal dirstate entries from the dmap'''
335 try:
336 return parsers.nonnormalotherparententries(self._map)
337 except AttributeError:
338 nonnorm = set()
339 otherparent = set()
340 for fname, e in pycompat.iteritems(self._map):
341 if e.dm_nonnormal:
342 nonnorm.add(fname)
343 if e.from_p2:
344 otherparent.add(fname)
345 return nonnorm, otherparent
346
347 @propertycache
309 @propertycache
348 def filefoldmap(self):
310 def filefoldmap(self):
349 """Returns a dictionary mapping normalized case paths to their
311 """Returns a dictionary mapping normalized case paths to their
@@ -433,13 +395,7 b' class dirstatemap(object):'
433 self._dirtyparents = True
395 self._dirtyparents = True
434 copies = {}
396 copies = {}
435 if fold_p2:
397 if fold_p2:
436 candidatefiles = self.non_normal_or_other_parent_paths()
398 for f, s in pycompat.iteritems(self._map):
437
438 for f in candidatefiles:
439 s = self.get(f)
440 if s is None:
441 continue
442
443 # Discard "merged" markers when moving away from a merge state
399 # Discard "merged" markers when moving away from a merge state
444 if s.merged or s.from_p2:
400 if s.merged or s.from_p2:
445 source = self.copymap.pop(f, None)
401 source = self.copymap.pop(f, None)
@@ -504,22 +460,6 b' class dirstatemap(object):'
504 )
460 )
505 st.close()
461 st.close()
506 self._dirtyparents = False
462 self._dirtyparents = False
507 self.nonnormalset, self.otherparentset = self.nonnormalentries()
508
509 @propertycache
510 def nonnormalset(self):
511 nonnorm, otherparents = self.nonnormalentries()
512 self.otherparentset = otherparents
513 return nonnorm
514
515 @propertycache
516 def otherparentset(self):
517 nonnorm, otherparents = self.nonnormalentries()
518 self.nonnormalset = nonnorm
519 return otherparents
520
521 def non_normal_or_other_parent_paths(self):
522 return self.nonnormalset.union(self.otherparentset)
523
463
524 @propertycache
464 @propertycache
525 def identity(self):
465 def identity(self):
@@ -643,7 +583,6 b' if rustmod is not None:'
643 elif (p1_tracked or p2_tracked) and not wc_tracked:
583 elif (p1_tracked or p2_tracked) and not wc_tracked:
644 # XXX might be merged and removed ?
584 # XXX might be merged and removed ?
645 self[filename] = DirstateItem.from_v1_data(b'r', 0, 0, 0)
585 self[filename] = DirstateItem.from_v1_data(b'r', 0, 0, 0)
646 self.nonnormalset.add(filename)
647 elif clean_p2 and wc_tracked:
586 elif clean_p2 and wc_tracked:
648 if p1_tracked or self.get(filename) is not None:
587 if p1_tracked or self.get(filename) is not None:
649 # XXX the `self.get` call is catching some case in
588 # XXX the `self.get` call is catching some case in
@@ -670,7 +609,6 b' if rustmod is not None:'
670 raise error.ProgrammingError(msg)
609 raise error.ProgrammingError(msg)
671 mode, size, mtime = parentfiledata
610 mode, size, mtime = parentfiledata
672 self.addfile(filename, mode=mode, size=size, mtime=mtime)
611 self.addfile(filename, mode=mode, size=size, mtime=mtime)
673 self.nonnormalset.discard(filename)
674 else:
612 else:
675 assert False, 'unreachable'
613 assert False, 'unreachable'
676
614
@@ -710,9 +648,6 b' if rustmod is not None:'
710 def removefile(self, *args, **kwargs):
648 def removefile(self, *args, **kwargs):
711 return self._rustmap.removefile(*args, **kwargs)
649 return self._rustmap.removefile(*args, **kwargs)
712
650
713 def nonnormalentries(self):
714 return self._rustmap.nonnormalentries()
715
716 def get(self, *args, **kwargs):
651 def get(self, *args, **kwargs):
717 return self._rustmap.get(*args, **kwargs)
652 return self._rustmap.get(*args, **kwargs)
718
653
@@ -790,13 +725,17 b' if rustmod is not None:'
790 self._dirtyparents = True
725 self._dirtyparents = True
791 copies = {}
726 copies = {}
792 if fold_p2:
727 if fold_p2:
793 candidatefiles = self.non_normal_or_other_parent_paths()
728 # Collect into an intermediate list to avoid a `RuntimeError`
794
729 # exception due to mutation during iteration.
795 for f in candidatefiles:
730 # TODO: move this the whole loop to Rust where `iter_mut`
796 s = self.get(f)
731 # enables in-place mutation of elements of a collection while
797 if s is None:
732 # iterating it, without mutating the collection itself.
798 continue
733 candidatefiles = [
799
734 (f, s)
735 for f, s in self._rustmap.items()
736 if s.merged or s.from_p2
737 ]
738 for f, s in candidatefiles:
800 # Discard "merged" markers when moving away from a merge state
739 # Discard "merged" markers when moving away from a merge state
801 if s.merged:
740 if s.merged:
802 source = self.copymap.get(f)
741 source = self.copymap.get(f)
@@ -965,19 +904,6 b' if rustmod is not None:'
965 self._rustmap
904 self._rustmap
966 return self.identity
905 return self.identity
967
906
968 @property
969 def nonnormalset(self):
970 nonnorm = self._rustmap.non_normal_entries()
971 return nonnorm
972
973 @propertycache
974 def otherparentset(self):
975 otherparents = self._rustmap.other_parent_entries()
976 return otherparents
977
978 def non_normal_or_other_parent_paths(self):
979 return self._rustmap.non_normal_or_other_parent_paths()
980
981 @propertycache
907 @propertycache
982 def dirfoldmap(self):
908 def dirfoldmap(self):
983 f = {}
909 f = {}
@@ -361,22 +361,6 b' class DirstateItem(object):'
361 """
361 """
362 return self.removed and self._merged
362 return self.removed and self._merged
363
363
364 @property
365 def dm_nonnormal(self):
366 """True is the entry is non-normal in the dirstatemap sense
367
368 There is no reason for any code, but the dirstatemap one to use this.
369 """
370 return self.v1_state() != b'n' or self.v1_mtime() == AMBIGUOUS_TIME
371
372 @property
373 def dm_otherparent(self):
374 """True is the entry is `otherparent` in the dirstatemap sense
375
376 There is no reason for any code, but the dirstatemap one to use this.
377 """
378 return self.v1_size() == FROM_P2
379
380 def v1_state(self):
364 def v1_state(self):
381 """return a "state" suitable for v1 serialization"""
365 """return a "state" suitable for v1 serialization"""
382 if not (self._p1_tracked or self._p2_tracked or self._wc_tracked):
366 if not (self._p1_tracked or self._p2_tracked or self._wc_tracked):
@@ -6,6 +6,7 b''
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::parsers::Timestamp;
8 use crate::dirstate::parsers::Timestamp;
9 use crate::errors::HgError;
9 use crate::{
10 use crate::{
10 dirstate::EntryState,
11 dirstate::EntryState,
11 dirstate::SIZE_FROM_OTHER_PARENT,
12 dirstate::SIZE_FROM_OTHER_PARENT,
@@ -16,7 +17,6 b' use crate::{'
16 StateMap,
17 StateMap,
17 };
18 };
18 use micro_timer::timed;
19 use micro_timer::timed;
19 use std::collections::HashSet;
20 use std::iter::FromIterator;
20 use std::iter::FromIterator;
21 use std::ops::Deref;
21 use std::ops::Deref;
22
22
@@ -26,8 +26,6 b' pub struct DirstateMap {'
26 pub copy_map: CopyMap,
26 pub copy_map: CopyMap,
27 pub dirs: Option<DirsMultiset>,
27 pub dirs: Option<DirsMultiset>,
28 pub all_dirs: Option<DirsMultiset>,
28 pub all_dirs: Option<DirsMultiset>,
29 non_normal_set: Option<HashSet<HgPathBuf>>,
30 other_parent_set: Option<HashSet<HgPathBuf>>,
31 }
29 }
32
30
33 /// Should only really be used in python interface code, for clarity
31 /// Should only really be used in python interface code, for clarity
@@ -58,8 +56,6 b' impl DirstateMap {'
58 pub fn clear(&mut self) {
56 pub fn clear(&mut self) {
59 self.state_map = StateMap::default();
57 self.state_map = StateMap::default();
60 self.copy_map.clear();
58 self.copy_map.clear();
61 self.non_normal_set = None;
62 self.other_parent_set = None;
63 }
59 }
64
60
65 pub fn set_entry(&mut self, filename: &HgPath, entry: DirstateEntry) {
61 pub fn set_entry(&mut self, filename: &HgPath, entry: DirstateEntry) {
@@ -84,18 +80,6 b' impl DirstateMap {'
84 }
80 }
85 }
81 }
86 self.state_map.insert(filename.to_owned(), entry.to_owned());
82 self.state_map.insert(filename.to_owned(), entry.to_owned());
87
88 if entry.is_non_normal() {
89 self.get_non_normal_other_parent_entries()
90 .0
91 .insert(filename.to_owned());
92 }
93
94 if entry.is_from_other_parent() {
95 self.get_non_normal_other_parent_entries()
96 .1
97 .insert(filename.to_owned());
98 }
99 Ok(())
83 Ok(())
100 }
84 }
101
85
@@ -126,9 +110,6 b' impl DirstateMap {'
126 {
110 {
127 // other parent
111 // other parent
128 size = SIZE_FROM_OTHER_PARENT;
112 size = SIZE_FROM_OTHER_PARENT;
129 self.get_non_normal_other_parent_entries()
130 .1
131 .insert(filename.to_owned());
132 }
113 }
133 }
114 }
134 }
115 }
@@ -148,9 +129,6 b' impl DirstateMap {'
148
129
149 self.state_map
130 self.state_map
150 .insert(filename.to_owned(), DirstateEntry::new_removed(size));
131 .insert(filename.to_owned(), DirstateEntry::new_removed(size));
151 self.get_non_normal_other_parent_entries()
152 .0
153 .insert(filename.to_owned());
154 Ok(())
132 Ok(())
155 }
133 }
156
134
@@ -173,92 +151,11 b' impl DirstateMap {'
173 all_dirs.delete_path(filename)?;
151 all_dirs.delete_path(filename)?;
174 }
152 }
175 }
153 }
176 self.get_non_normal_other_parent_entries()
177 .0
178 .remove(filename);
179
180 self.copy_map.remove(filename);
154 self.copy_map.remove(filename);
181
155
182 Ok(())
156 Ok(())
183 }
157 }
184
158
185 pub fn non_normal_entries_remove(
186 &mut self,
187 key: impl AsRef<HgPath>,
188 ) -> bool {
189 self.get_non_normal_other_parent_entries()
190 .0
191 .remove(key.as_ref())
192 }
193
194 pub fn non_normal_entries_add(&mut self, key: impl AsRef<HgPath>) {
195 self.get_non_normal_other_parent_entries()
196 .0
197 .insert(key.as_ref().into());
198 }
199
200 pub fn non_normal_entries_union(
201 &mut self,
202 other: HashSet<HgPathBuf>,
203 ) -> Vec<HgPathBuf> {
204 self.get_non_normal_other_parent_entries()
205 .0
206 .union(&other)
207 .map(ToOwned::to_owned)
208 .collect()
209 }
210
211 pub fn get_non_normal_other_parent_entries(
212 &mut self,
213 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
214 self.set_non_normal_other_parent_entries(false);
215 (
216 self.non_normal_set.as_mut().unwrap(),
217 self.other_parent_set.as_mut().unwrap(),
218 )
219 }
220
221 /// Useful to get immutable references to those sets in contexts where
222 /// you only have an immutable reference to the `DirstateMap`, like when
223 /// sharing references with Python.
224 ///
225 /// TODO, get rid of this along with the other "setter/getter" stuff when
226 /// a nice typestate plan is defined.
227 ///
228 /// # Panics
229 ///
230 /// Will panic if either set is `None`.
231 pub fn get_non_normal_other_parent_entries_panic(
232 &self,
233 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
234 (
235 self.non_normal_set.as_ref().unwrap(),
236 self.other_parent_set.as_ref().unwrap(),
237 )
238 }
239
240 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
241 if !force
242 && self.non_normal_set.is_some()
243 && self.other_parent_set.is_some()
244 {
245 return;
246 }
247 let mut non_normal = HashSet::new();
248 let mut other_parent = HashSet::new();
249
250 for (filename, entry) in self.state_map.iter() {
251 if entry.is_non_normal() {
252 non_normal.insert(filename.to_owned());
253 }
254 if entry.is_from_other_parent() {
255 other_parent.insert(filename.to_owned());
256 }
257 }
258 self.non_normal_set = Some(non_normal);
259 self.other_parent_set = Some(other_parent);
260 }
261
262 /// Both of these setters and their uses appear to be the simplest way to
159 /// Both of these setters and their uses appear to be the simplest way to
263 /// emulate a Python lazy property, but it is ugly and unidiomatic.
160 /// emulate a Python lazy property, but it is ugly and unidiomatic.
264 /// TODO One day, rewriting this struct using the typestate might be a
161 /// TODO One day, rewriting this struct using the typestate might be a
@@ -326,12 +223,8 b' impl DirstateMap {'
326 &mut self,
223 &mut self,
327 parents: DirstateParents,
224 parents: DirstateParents,
328 now: Timestamp,
225 now: Timestamp,
329 ) -> Result<Vec<u8>, DirstateError> {
226 ) -> Result<Vec<u8>, HgError> {
330 let packed =
227 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)
331 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
332
333 self.set_non_normal_other_parent_entries(true);
334 Ok(packed)
335 }
228 }
336 }
229 }
337
230
@@ -366,49 +259,5 b' mod tests {'
366 .unwrap();
259 .unwrap();
367
260
368 assert_eq!(1, map.len());
261 assert_eq!(1, map.len());
369 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
370 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
371 }
372
373 #[test]
374 fn test_non_normal_other_parent_entries() {
375 let mut map: DirstateMap = [
376 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
377 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
378 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
379 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
380 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
381 (b"f6", (EntryState::Added, 1337, 1337, -1)),
382 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
383 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
384 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
385 (b"fa", (EntryState::Added, 1337, -2, 1337)),
386 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
387 ]
388 .iter()
389 .map(|(fname, (state, mode, size, mtime))| {
390 (
391 HgPathBuf::from_bytes(fname.as_ref()),
392 DirstateEntry::from_v1_data(*state, *mode, *size, *mtime),
393 )
394 })
395 .collect();
396
397 let mut non_normal = [
398 b"f1", b"f2", b"f4", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa",
399 b"fb",
400 ]
401 .iter()
402 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
403 .collect();
404
405 let mut other_parent = HashSet::new();
406 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
407 let entries = map.get_non_normal_other_parent_entries();
408
409 assert_eq!(
410 (&mut non_normal, &mut other_parent),
411 (entries.0, entries.1)
412 );
413 }
262 }
414 }
263 }
@@ -294,11 +294,7 b' impl DirstateEntry {'
294 (self.state().into(), self.mode(), self.size(), self.mtime())
294 (self.state().into(), self.mode(), self.size(), self.mtime())
295 }
295 }
296
296
297 pub fn is_non_normal(&self) -> bool {
297 pub(crate) fn is_from_other_parent(&self) -> bool {
298 self.state() != EntryState::Normal || self.mtime() == MTIME_UNSET
299 }
300
301 pub fn is_from_other_parent(&self) -> bool {
302 self.state() == EntryState::Normal
298 self.state() == EntryState::Normal
303 && self.size() == SIZE_FROM_OTHER_PARENT
299 && self.size() == SIZE_FROM_OTHER_PARENT
304 }
300 }
@@ -701,27 +701,6 b" impl<'on_disk> DirstateMap<'on_disk> {"
701 Ok(())
701 Ok(())
702 }
702 }
703
703
704 /// Return a faillilble iterator of full paths of nodes that have an
705 /// `entry` for which the given `predicate` returns true.
706 ///
707 /// Fallibility means that each iterator item is a `Result`, which may
708 /// indicate a parse error of the on-disk dirstate-v2 format. Such errors
709 /// should only happen if Mercurial is buggy or a repository is corrupted.
710 fn filter_full_paths<'tree>(
711 &'tree self,
712 predicate: impl Fn(&DirstateEntry) -> bool + 'tree,
713 ) -> impl Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + 'tree
714 {
715 filter_map_results(self.iter_nodes(), move |node| {
716 if let Some(entry) = node.entry()? {
717 if predicate(&entry) {
718 return Ok(Some(node.full_path(self.on_disk)?));
719 }
720 }
721 Ok(None)
722 })
723 }
724
725 fn count_dropped_path(unreachable_bytes: &mut u32, path: &Cow<HgPath>) {
704 fn count_dropped_path(unreachable_bytes: &mut u32, path: &Cow<HgPath>) {
726 if let Cow::Borrowed(path) = path {
705 if let Cow::Borrowed(path) = path {
727 *unreachable_bytes += path.len() as u32
706 *unreachable_bytes += path.len() as u32
@@ -917,69 +896,6 b" impl<'on_disk> super::dispatch::Dirstate"
917 Ok(())
896 Ok(())
918 }
897 }
919
898
920 fn non_normal_entries_contains(
921 &mut self,
922 key: &HgPath,
923 ) -> Result<bool, DirstateV2ParseError> {
924 Ok(if let Some(node) = self.get_node(key)? {
925 node.entry()?.map_or(false, |entry| entry.is_non_normal())
926 } else {
927 false
928 })
929 }
930
931 fn non_normal_entries_remove(&mut self, key: &HgPath) -> bool {
932 // Do nothing, this `DirstateMap` does not have a separate "non normal
933 // entries" set that need to be kept up to date.
934 if let Ok(Some(v)) = self.get(key) {
935 return v.is_non_normal();
936 }
937 false
938 }
939
940 fn non_normal_entries_add(&mut self, _key: &HgPath) {
941 // Do nothing, this `DirstateMap` does not have a separate "non normal
942 // entries" set that need to be kept up to date
943 }
944
945 fn non_normal_or_other_parent_paths(
946 &mut self,
947 ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_>
948 {
949 Box::new(self.filter_full_paths(|entry| {
950 entry.is_non_normal() || entry.is_from_other_parent()
951 }))
952 }
953
954 fn set_non_normal_other_parent_entries(&mut self, _force: bool) {
955 // Do nothing, this `DirstateMap` does not have a separate "non normal
956 // entries" and "from other parent" sets that need to be recomputed
957 }
958
959 fn iter_non_normal_paths(
960 &mut self,
961 ) -> Box<
962 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
963 > {
964 self.iter_non_normal_paths_panic()
965 }
966
967 fn iter_non_normal_paths_panic(
968 &self,
969 ) -> Box<
970 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
971 > {
972 Box::new(self.filter_full_paths(|entry| entry.is_non_normal()))
973 }
974
975 fn iter_other_parent_paths(
976 &mut self,
977 ) -> Box<
978 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
979 > {
980 Box::new(self.filter_full_paths(|entry| entry.is_from_other_parent()))
981 }
982
983 fn has_tracked_dir(
899 fn has_tracked_dir(
984 &mut self,
900 &mut self,
985 directory: &HgPath,
901 directory: &HgPath,
@@ -67,82 +67,6 b' pub trait DirstateMapMethods {'
67 filename: &HgPath,
67 filename: &HgPath,
68 ) -> Result<(), DirstateError>;
68 ) -> Result<(), DirstateError>;
69
69
70 /// Return whether the map has an "non-normal" entry for the given
71 /// filename. That is, any entry with a `state` other than
72 /// `EntryState::Normal` or with an ambiguous `mtime`.
73 fn non_normal_entries_contains(
74 &mut self,
75 key: &HgPath,
76 ) -> Result<bool, DirstateV2ParseError>;
77
78 /// Mark the given path as "normal" file. This is only relevant in the flat
79 /// dirstate map where there is a separate `HashSet` that needs to be kept
80 /// up to date.
81 /// Returns whether the key was present in the set.
82 fn non_normal_entries_remove(&mut self, key: &HgPath) -> bool;
83
84 /// Mark the given path as "non-normal" file.
85 /// This is only relevant in the flat dirstate map where there is a
86 /// separate `HashSet` that needs to be kept up to date.
87 fn non_normal_entries_add(&mut self, key: &HgPath);
88
89 /// Return an iterator of paths whose respective entry are either
90 /// "non-normal" (see `non_normal_entries_contains`) or "from other
91 /// parent".
92 ///
93 /// If that information is cached, create the cache as needed.
94 ///
95 /// "From other parent" is defined as `state == Normal && size == -2`.
96 ///
97 /// Because parse errors can happen during iteration, the iterated items
98 /// are `Result`s.
99 fn non_normal_or_other_parent_paths(
100 &mut self,
101 ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_>;
102
103 /// Create the cache for `non_normal_or_other_parent_paths` if needed.
104 ///
105 /// If `force` is true, the cache is re-created even if it already exists.
106 fn set_non_normal_other_parent_entries(&mut self, force: bool);
107
108 /// Return an iterator of paths whose respective entry are "non-normal"
109 /// (see `non_normal_entries_contains`).
110 ///
111 /// If that information is cached, create the cache as needed.
112 ///
113 /// Because parse errors can happen during iteration, the iterated items
114 /// are `Result`s.
115 fn iter_non_normal_paths(
116 &mut self,
117 ) -> Box<
118 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
119 >;
120
121 /// Same as `iter_non_normal_paths`, but takes `&self` instead of `&mut
122 /// self`.
123 ///
124 /// Panics if a cache is necessary but does not exist yet.
125 fn iter_non_normal_paths_panic(
126 &self,
127 ) -> Box<
128 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
129 >;
130
131 /// Return an iterator of paths whose respective entry are "from other
132 /// parent".
133 ///
134 /// If that information is cached, create the cache as needed.
135 ///
136 /// "From other parent" is defined as `state == Normal && size == -2`.
137 ///
138 /// Because parse errors can happen during iteration, the iterated items
139 /// are `Result`s.
140 fn iter_other_parent_paths(
141 &mut self,
142 ) -> Box<
143 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
144 >;
145
146 /// Returns whether the sub-tree rooted at the given directory contains any
70 /// Returns whether the sub-tree rooted at the given directory contains any
147 /// tracked file.
71 /// tracked file.
148 ///
72 ///
@@ -330,66 +254,6 b' impl DirstateMapMethods for DirstateMap '
330 self.drop_entry_and_copy_source(filename)
254 self.drop_entry_and_copy_source(filename)
331 }
255 }
332
256
333 fn non_normal_entries_contains(
334 &mut self,
335 key: &HgPath,
336 ) -> Result<bool, DirstateV2ParseError> {
337 let (non_normal, _other_parent) =
338 self.get_non_normal_other_parent_entries();
339 Ok(non_normal.contains(key))
340 }
341
342 fn non_normal_entries_remove(&mut self, key: &HgPath) -> bool {
343 self.non_normal_entries_remove(key)
344 }
345
346 fn non_normal_entries_add(&mut self, key: &HgPath) {
347 self.non_normal_entries_add(key)
348 }
349
350 fn non_normal_or_other_parent_paths(
351 &mut self,
352 ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_>
353 {
354 let (non_normal, other_parent) =
355 self.get_non_normal_other_parent_entries();
356 Box::new(non_normal.union(other_parent).map(|p| Ok(&**p)))
357 }
358
359 fn set_non_normal_other_parent_entries(&mut self, force: bool) {
360 self.set_non_normal_other_parent_entries(force)
361 }
362
363 fn iter_non_normal_paths(
364 &mut self,
365 ) -> Box<
366 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
367 > {
368 let (non_normal, _other_parent) =
369 self.get_non_normal_other_parent_entries();
370 Box::new(non_normal.iter().map(|p| Ok(&**p)))
371 }
372
373 fn iter_non_normal_paths_panic(
374 &self,
375 ) -> Box<
376 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
377 > {
378 let (non_normal, _other_parent) =
379 self.get_non_normal_other_parent_entries_panic();
380 Box::new(non_normal.iter().map(|p| Ok(&**p)))
381 }
382
383 fn iter_other_parent_paths(
384 &mut self,
385 ) -> Box<
386 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
387 > {
388 let (_non_normal, other_parent) =
389 self.get_non_normal_other_parent_entries();
390 Box::new(other_parent.iter().map(|p| Ok(&**p)))
391 }
392
393 fn has_tracked_dir(
257 fn has_tracked_dir(
394 &mut self,
258 &mut self,
395 directory: &HgPath,
259 directory: &HgPath,
@@ -406,7 +270,7 b' impl DirstateMapMethods for DirstateMap '
406 parents: DirstateParents,
270 parents: DirstateParents,
407 now: Timestamp,
271 now: Timestamp,
408 ) -> Result<Vec<u8>, DirstateError> {
272 ) -> Result<Vec<u8>, DirstateError> {
409 self.pack(parents, now)
273 Ok(self.pack(parents, now)?)
410 }
274 }
411
275
412 fn pack_v2(
276 fn pack_v2(
@@ -51,56 +51,6 b' impl DirstateMapMethods for OwningDirsta'
51 self.get_mut().drop_entry_and_copy_source(filename)
51 self.get_mut().drop_entry_and_copy_source(filename)
52 }
52 }
53
53
54 fn non_normal_entries_contains(
55 &mut self,
56 key: &HgPath,
57 ) -> Result<bool, DirstateV2ParseError> {
58 self.get_mut().non_normal_entries_contains(key)
59 }
60
61 fn non_normal_entries_remove(&mut self, key: &HgPath) -> bool {
62 self.get_mut().non_normal_entries_remove(key)
63 }
64
65 fn non_normal_entries_add(&mut self, key: &HgPath) {
66 self.get_mut().non_normal_entries_add(key)
67 }
68
69 fn non_normal_or_other_parent_paths(
70 &mut self,
71 ) -> Box<dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + '_>
72 {
73 self.get_mut().non_normal_or_other_parent_paths()
74 }
75
76 fn set_non_normal_other_parent_entries(&mut self, force: bool) {
77 self.get_mut().set_non_normal_other_parent_entries(force)
78 }
79
80 fn iter_non_normal_paths(
81 &mut self,
82 ) -> Box<
83 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
84 > {
85 self.get_mut().iter_non_normal_paths()
86 }
87
88 fn iter_non_normal_paths_panic(
89 &self,
90 ) -> Box<
91 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
92 > {
93 self.get().iter_non_normal_paths_panic()
94 }
95
96 fn iter_other_parent_paths(
97 &mut self,
98 ) -> Box<
99 dyn Iterator<Item = Result<&HgPath, DirstateV2ParseError>> + Send + '_,
100 > {
101 self.get_mut().iter_other_parent_paths()
102 }
103
104 fn has_tracked_dir(
54 fn has_tracked_dir(
105 &mut self,
55 &mut self,
106 directory: &HgPath,
56 directory: &HgPath,
@@ -13,7 +13,6 b' mod copymap;'
13 mod dirs_multiset;
13 mod dirs_multiset;
14 mod dirstate_map;
14 mod dirstate_map;
15 mod item;
15 mod item;
16 mod non_normal_entries;
17 mod status;
16 mod status;
18 use self::item::DirstateItem;
17 use self::item::DirstateItem;
19 use crate::{
18 use crate::{
@@ -13,16 +13,12 b' use std::convert::TryInto;'
13
13
14 use cpython::{
14 use cpython::{
15 exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject,
15 exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject,
16 PyResult, PySet, PyString, Python, PythonObject, ToPyObject,
16 PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked,
17 UnsafePyLeaked,
18 };
17 };
19
18
20 use crate::{
19 use crate::{
21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
20 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 dirstate::item::DirstateItem,
21 dirstate::item::DirstateItem,
23 dirstate::non_normal_entries::{
24 NonNormalEntries, NonNormalEntriesIterator,
25 },
26 pybytes_deref::PyBytesDeref,
22 pybytes_deref::PyBytesDeref,
27 };
23 };
28 use hg::{
24 use hg::{
@@ -185,100 +181,6 b' py_class!(pub class DirstateMap |py| {'
185 Ok(PyNone)
181 Ok(PyNone)
186 }
182 }
187
183
188 def other_parent_entries(&self) -> PyResult<PyObject> {
189 let mut inner_shared = self.inner(py).borrow_mut();
190 let set = PySet::empty(py)?;
191 for path in inner_shared.iter_other_parent_paths() {
192 let path = path.map_err(|e| v2_error(py, e))?;
193 set.add(py, PyBytes::new(py, path.as_bytes()))?;
194 }
195 Ok(set.into_object())
196 }
197
198 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
199 NonNormalEntries::from_inner(py, self.clone_ref(py))
200 }
201
202 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
203 let key = key.extract::<PyBytes>(py)?;
204 self.inner(py)
205 .borrow_mut()
206 .non_normal_entries_contains(HgPath::new(key.data(py)))
207 .map_err(|e| v2_error(py, e))
208 }
209
210 def non_normal_entries_display(&self) -> PyResult<PyString> {
211 let mut inner = self.inner(py).borrow_mut();
212 let paths = inner
213 .iter_non_normal_paths()
214 .collect::<Result<Vec<_>, _>>()
215 .map_err(|e| v2_error(py, e))?;
216 let formatted = format!("NonNormalEntries: {}", hg::utils::join_display(paths, ", "));
217 Ok(PyString::new(py, &formatted))
218 }
219
220 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
221 let key = key.extract::<PyBytes>(py)?;
222 let key = key.data(py);
223 let was_present = self
224 .inner(py)
225 .borrow_mut()
226 .non_normal_entries_remove(HgPath::new(key));
227 if !was_present {
228 let msg = String::from_utf8_lossy(key);
229 Err(PyErr::new::<exc::KeyError, _>(py, msg))
230 } else {
231 Ok(py.None())
232 }
233 }
234
235 def non_normal_entries_discard(&self, key: PyObject) -> PyResult<PyObject>
236 {
237 let key = key.extract::<PyBytes>(py)?;
238 self
239 .inner(py)
240 .borrow_mut()
241 .non_normal_entries_remove(HgPath::new(key.data(py)));
242 Ok(py.None())
243 }
244
245 def non_normal_entries_add(&self, key: PyObject) -> PyResult<PyObject> {
246 let key = key.extract::<PyBytes>(py)?;
247 self
248 .inner(py)
249 .borrow_mut()
250 .non_normal_entries_add(HgPath::new(key.data(py)));
251 Ok(py.None())
252 }
253
254 def non_normal_or_other_parent_paths(&self) -> PyResult<PyList> {
255 let mut inner = self.inner(py).borrow_mut();
256
257 let ret = PyList::new(py, &[]);
258 for filename in inner.non_normal_or_other_parent_paths() {
259 let filename = filename.map_err(|e| v2_error(py, e))?;
260 let as_pystring = PyBytes::new(py, filename.as_bytes());
261 ret.append(py, as_pystring.into_object());
262 }
263 Ok(ret)
264 }
265
266 def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> {
267 // Make sure the sets are defined before we no longer have a mutable
268 // reference to the dmap.
269 self.inner(py)
270 .borrow_mut()
271 .set_non_normal_other_parent_entries(false);
272
273 let leaked_ref = self.inner(py).leak_immutable();
274
275 NonNormalEntriesIterator::from_inner(py, unsafe {
276 leaked_ref.map(py, |o| {
277 o.iter_non_normal_paths_panic()
278 })
279 })
280 }
281
282 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
184 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
283 let d = d.extract::<PyBytes>(py)?;
185 let d = d.extract::<PyBytes>(py)?;
284 Ok(self.inner(py).borrow_mut()
186 Ok(self.inner(py).borrow_mut()
@@ -95,16 +95,6 b' py_class!(pub class DirstateItem |py| {'
95 Ok(self.entry(py).get().from_p2_removed())
95 Ok(self.entry(py).get().from_p2_removed())
96 }
96 }
97
97
98 @property
99 def dm_nonnormal(&self) -> PyResult<bool> {
100 Ok(self.entry(py).get().is_non_normal())
101 }
102
103 @property
104 def dm_otherparent(&self) -> PyResult<bool> {
105 Ok(self.entry(py).get().is_from_other_parent())
106 }
107
108 def v1_state(&self) -> PyResult<PyBytes> {
98 def v1_state(&self) -> PyResult<PyBytes> {
109 let (state, _mode, _size, _mtime) = self.entry(py).get().v1_data();
99 let (state, _mode, _size, _mtime) = self.entry(py).get().v1_data();
110 let state_byte: u8 = state.into();
100 let state_byte: u8 = state.into();
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now