##// END OF EJS Templates
rust: fix file folding map...
Dan Villiom Podlaski Christiansen -
r46844:5bae4bc9 default
parent child Browse files
Show More
@@ -1,546 +1,546 b''
1 1 // dirstate_map.rs
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 use crate::revlog::node::NULL_NODE_ID;
9 9 use crate::{
10 10 dirstate::{parsers::PARENT_SIZE, EntryState, SIZE_FROM_OTHER_PARENT},
11 11 pack_dirstate, parse_dirstate,
12 12 utils::{
13 13 files::normalize_case,
14 14 hg_path::{HgPath, HgPathBuf},
15 15 },
16 16 CopyMap, DirsMultiset, DirstateEntry, DirstateError, DirstateMapError,
17 17 DirstateParents, DirstateParseError, FastHashMap, StateMap,
18 18 };
19 19 use micro_timer::timed;
20 20 use std::collections::HashSet;
21 21 use std::convert::TryInto;
22 22 use std::iter::FromIterator;
23 23 use std::ops::Deref;
24 24 use std::time::Duration;
25 25
26 26 pub type FileFoldMap = FastHashMap<HgPathBuf, HgPathBuf>;
27 27
28 28 const MTIME_UNSET: i32 = -1;
29 29
30 30 #[derive(Default)]
31 31 pub struct DirstateMap {
32 32 state_map: StateMap,
33 33 pub copy_map: CopyMap,
34 34 file_fold_map: Option<FileFoldMap>,
35 35 pub dirs: Option<DirsMultiset>,
36 36 pub all_dirs: Option<DirsMultiset>,
37 37 non_normal_set: Option<HashSet<HgPathBuf>>,
38 38 other_parent_set: Option<HashSet<HgPathBuf>>,
39 39 parents: Option<DirstateParents>,
40 40 dirty_parents: bool,
41 41 }
42 42
43 43 /// Should only really be used in python interface code, for clarity
44 44 impl Deref for DirstateMap {
45 45 type Target = StateMap;
46 46
47 47 fn deref(&self) -> &Self::Target {
48 48 &self.state_map
49 49 }
50 50 }
51 51
52 52 impl FromIterator<(HgPathBuf, DirstateEntry)> for DirstateMap {
53 53 fn from_iter<I: IntoIterator<Item = (HgPathBuf, DirstateEntry)>>(
54 54 iter: I,
55 55 ) -> Self {
56 56 Self {
57 57 state_map: iter.into_iter().collect(),
58 58 ..Self::default()
59 59 }
60 60 }
61 61 }
62 62
63 63 impl DirstateMap {
64 64 pub fn new() -> Self {
65 65 Self::default()
66 66 }
67 67
68 68 pub fn clear(&mut self) {
69 69 self.state_map = StateMap::default();
70 70 self.copy_map.clear();
71 71 self.file_fold_map = None;
72 72 self.non_normal_set = None;
73 73 self.other_parent_set = None;
74 74 self.set_parents(&DirstateParents {
75 75 p1: NULL_NODE_ID,
76 76 p2: NULL_NODE_ID,
77 77 })
78 78 }
79 79
80 80 /// Add a tracked file to the dirstate
81 81 pub fn add_file(
82 82 &mut self,
83 83 filename: &HgPath,
84 84 old_state: EntryState,
85 85 entry: DirstateEntry,
86 86 ) -> Result<(), DirstateMapError> {
87 87 if old_state == EntryState::Unknown || old_state == EntryState::Removed
88 88 {
89 89 if let Some(ref mut dirs) = self.dirs {
90 90 dirs.add_path(filename)?;
91 91 }
92 92 }
93 93 if old_state == EntryState::Unknown {
94 94 if let Some(ref mut all_dirs) = self.all_dirs {
95 95 all_dirs.add_path(filename)?;
96 96 }
97 97 }
98 98 self.state_map.insert(filename.to_owned(), entry.to_owned());
99 99
100 100 if entry.state != EntryState::Normal || entry.mtime == MTIME_UNSET {
101 101 self.get_non_normal_other_parent_entries()
102 102 .0
103 103 .insert(filename.to_owned());
104 104 }
105 105
106 106 if entry.size == SIZE_FROM_OTHER_PARENT {
107 107 self.get_non_normal_other_parent_entries()
108 108 .1
109 109 .insert(filename.to_owned());
110 110 }
111 111 Ok(())
112 112 }
113 113
114 114 /// Mark a file as removed in the dirstate.
115 115 ///
116 116 /// The `size` parameter is used to store sentinel values that indicate
117 117 /// the file's previous state. In the future, we should refactor this
118 118 /// to be more explicit about what that state is.
119 119 pub fn remove_file(
120 120 &mut self,
121 121 filename: &HgPath,
122 122 old_state: EntryState,
123 123 size: i32,
124 124 ) -> Result<(), DirstateMapError> {
125 125 if old_state != EntryState::Unknown && old_state != EntryState::Removed
126 126 {
127 127 if let Some(ref mut dirs) = self.dirs {
128 128 dirs.delete_path(filename)?;
129 129 }
130 130 }
131 131 if old_state == EntryState::Unknown {
132 132 if let Some(ref mut all_dirs) = self.all_dirs {
133 133 all_dirs.add_path(filename)?;
134 134 }
135 135 }
136 136
137 137 if let Some(ref mut file_fold_map) = self.file_fold_map {
138 138 file_fold_map.remove(&normalize_case(filename));
139 139 }
140 140 self.state_map.insert(
141 141 filename.to_owned(),
142 142 DirstateEntry {
143 143 state: EntryState::Removed,
144 144 mode: 0,
145 145 size,
146 146 mtime: 0,
147 147 },
148 148 );
149 149 self.get_non_normal_other_parent_entries()
150 150 .0
151 151 .insert(filename.to_owned());
152 152 Ok(())
153 153 }
154 154
155 155 /// Remove a file from the dirstate.
156 156 /// Returns `true` if the file was previously recorded.
157 157 pub fn drop_file(
158 158 &mut self,
159 159 filename: &HgPath,
160 160 old_state: EntryState,
161 161 ) -> Result<bool, DirstateMapError> {
162 162 let exists = self.state_map.remove(filename).is_some();
163 163
164 164 if exists {
165 165 if old_state != EntryState::Removed {
166 166 if let Some(ref mut dirs) = self.dirs {
167 167 dirs.delete_path(filename)?;
168 168 }
169 169 }
170 170 if let Some(ref mut all_dirs) = self.all_dirs {
171 171 all_dirs.delete_path(filename)?;
172 172 }
173 173 }
174 174 if let Some(ref mut file_fold_map) = self.file_fold_map {
175 175 file_fold_map.remove(&normalize_case(filename));
176 176 }
177 177 self.get_non_normal_other_parent_entries()
178 178 .0
179 179 .remove(filename);
180 180
181 181 Ok(exists)
182 182 }
183 183
184 184 pub fn clear_ambiguous_times(
185 185 &mut self,
186 186 filenames: Vec<HgPathBuf>,
187 187 now: i32,
188 188 ) {
189 189 for filename in filenames {
190 190 let mut changed = false;
191 191 if let Some(entry) = self.state_map.get_mut(&filename) {
192 192 if entry.state == EntryState::Normal && entry.mtime == now {
193 193 changed = true;
194 194 *entry = DirstateEntry {
195 195 mtime: MTIME_UNSET,
196 196 ..*entry
197 197 };
198 198 }
199 199 }
200 200 if changed {
201 201 self.get_non_normal_other_parent_entries()
202 202 .0
203 203 .insert(filename.to_owned());
204 204 }
205 205 }
206 206 }
207 207
208 208 pub fn non_normal_entries_remove(
209 209 &mut self,
210 210 key: impl AsRef<HgPath>,
211 211 ) -> bool {
212 212 self.get_non_normal_other_parent_entries()
213 213 .0
214 214 .remove(key.as_ref())
215 215 }
216 216 pub fn non_normal_entries_union(
217 217 &mut self,
218 218 other: HashSet<HgPathBuf>,
219 219 ) -> Vec<HgPathBuf> {
220 220 self.get_non_normal_other_parent_entries()
221 221 .0
222 222 .union(&other)
223 223 .map(ToOwned::to_owned)
224 224 .collect()
225 225 }
226 226
227 227 pub fn get_non_normal_other_parent_entries(
228 228 &mut self,
229 229 ) -> (&mut HashSet<HgPathBuf>, &mut HashSet<HgPathBuf>) {
230 230 self.set_non_normal_other_parent_entries(false);
231 231 (
232 232 self.non_normal_set.as_mut().unwrap(),
233 233 self.other_parent_set.as_mut().unwrap(),
234 234 )
235 235 }
236 236
237 237 /// Useful to get immutable references to those sets in contexts where
238 238 /// you only have an immutable reference to the `DirstateMap`, like when
239 239 /// sharing references with Python.
240 240 ///
241 241 /// TODO, get rid of this along with the other "setter/getter" stuff when
242 242 /// a nice typestate plan is defined.
243 243 ///
244 244 /// # Panics
245 245 ///
246 246 /// Will panic if either set is `None`.
247 247 pub fn get_non_normal_other_parent_entries_panic(
248 248 &self,
249 249 ) -> (&HashSet<HgPathBuf>, &HashSet<HgPathBuf>) {
250 250 (
251 251 self.non_normal_set.as_ref().unwrap(),
252 252 self.other_parent_set.as_ref().unwrap(),
253 253 )
254 254 }
255 255
256 256 #[cfg(not(feature = "dirstate-tree"))]
257 257 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
258 258 if !force
259 259 && self.non_normal_set.is_some()
260 260 && self.other_parent_set.is_some()
261 261 {
262 262 return;
263 263 }
264 264 let mut non_normal = HashSet::new();
265 265 let mut other_parent = HashSet::new();
266 266
267 267 for (
268 268 filename,
269 269 DirstateEntry {
270 270 state, size, mtime, ..
271 271 },
272 272 ) in self.state_map.iter()
273 273 {
274 274 if *state != EntryState::Normal || *mtime == MTIME_UNSET {
275 275 non_normal.insert(filename.to_owned());
276 276 }
277 277 if *state == EntryState::Normal && *size == SIZE_FROM_OTHER_PARENT
278 278 {
279 279 other_parent.insert(filename.to_owned());
280 280 }
281 281 }
282 282 self.non_normal_set = Some(non_normal);
283 283 self.other_parent_set = Some(other_parent);
284 284 }
285 285 #[cfg(feature = "dirstate-tree")]
286 286 pub fn set_non_normal_other_parent_entries(&mut self, force: bool) {
287 287 if !force
288 288 && self.non_normal_set.is_some()
289 289 && self.other_parent_set.is_some()
290 290 {
291 291 return;
292 292 }
293 293 let mut non_normal = HashSet::new();
294 294 let mut other_parent = HashSet::new();
295 295
296 296 for (
297 297 filename,
298 298 DirstateEntry {
299 299 state, size, mtime, ..
300 300 },
301 301 ) in self.state_map.iter()
302 302 {
303 303 if state != EntryState::Normal || mtime == MTIME_UNSET {
304 304 non_normal.insert(filename.to_owned());
305 305 }
306 306 if state == EntryState::Normal && size == SIZE_FROM_OTHER_PARENT {
307 307 other_parent.insert(filename.to_owned());
308 308 }
309 309 }
310 310 self.non_normal_set = Some(non_normal);
311 311 self.other_parent_set = Some(other_parent);
312 312 }
313 313
314 314 /// Both of these setters and their uses appear to be the simplest way to
315 315 /// emulate a Python lazy property, but it is ugly and unidiomatic.
316 316 /// TODO One day, rewriting this struct using the typestate might be a
317 317 /// good idea.
318 318 pub fn set_all_dirs(&mut self) -> Result<(), DirstateMapError> {
319 319 if self.all_dirs.is_none() {
320 320 self.all_dirs =
321 321 Some(DirsMultiset::from_dirstate(&self.state_map, None)?);
322 322 }
323 323 Ok(())
324 324 }
325 325
326 326 pub fn set_dirs(&mut self) -> Result<(), DirstateMapError> {
327 327 if self.dirs.is_none() {
328 328 self.dirs = Some(DirsMultiset::from_dirstate(
329 329 &self.state_map,
330 330 Some(EntryState::Removed),
331 331 )?);
332 332 }
333 333 Ok(())
334 334 }
335 335
336 336 pub fn has_tracked_dir(
337 337 &mut self,
338 338 directory: &HgPath,
339 339 ) -> Result<bool, DirstateMapError> {
340 340 self.set_dirs()?;
341 341 Ok(self.dirs.as_ref().unwrap().contains(directory))
342 342 }
343 343
344 344 pub fn has_dir(
345 345 &mut self,
346 346 directory: &HgPath,
347 347 ) -> Result<bool, DirstateMapError> {
348 348 self.set_all_dirs()?;
349 349 Ok(self.all_dirs.as_ref().unwrap().contains(directory))
350 350 }
351 351
352 352 pub fn parents(
353 353 &mut self,
354 354 file_contents: &[u8],
355 355 ) -> Result<&DirstateParents, DirstateError> {
356 356 if let Some(ref parents) = self.parents {
357 357 return Ok(parents);
358 358 }
359 359 let parents;
360 360 if file_contents.len() == PARENT_SIZE * 2 {
361 361 parents = DirstateParents {
362 362 p1: file_contents[..PARENT_SIZE].try_into().unwrap(),
363 363 p2: file_contents[PARENT_SIZE..PARENT_SIZE * 2]
364 364 .try_into()
365 365 .unwrap(),
366 366 };
367 367 } else if file_contents.is_empty() {
368 368 parents = DirstateParents {
369 369 p1: NULL_NODE_ID,
370 370 p2: NULL_NODE_ID,
371 371 };
372 372 } else {
373 373 return Err(DirstateError::Parse(DirstateParseError::Damaged));
374 374 }
375 375
376 376 self.parents = Some(parents);
377 377 Ok(self.parents.as_ref().unwrap())
378 378 }
379 379
380 380 pub fn set_parents(&mut self, parents: &DirstateParents) {
381 381 self.parents = Some(parents.clone());
382 382 self.dirty_parents = true;
383 383 }
384 384
385 385 #[timed]
386 386 pub fn read(
387 387 &mut self,
388 388 file_contents: &[u8],
389 389 ) -> Result<Option<DirstateParents>, DirstateError> {
390 390 if file_contents.is_empty() {
391 391 return Ok(None);
392 392 }
393 393
394 394 let (parents, entries, copies) = parse_dirstate(file_contents)?;
395 395 self.state_map.extend(
396 396 entries
397 397 .into_iter()
398 398 .map(|(path, entry)| (path.to_owned(), entry)),
399 399 );
400 400 self.copy_map.extend(
401 401 copies
402 402 .into_iter()
403 403 .map(|(path, copy)| (path.to_owned(), copy.to_owned())),
404 404 );
405 405
406 406 if !self.dirty_parents {
407 407 self.set_parents(&parents);
408 408 }
409 409
410 410 Ok(Some(parents))
411 411 }
412 412
413 413 pub fn pack(
414 414 &mut self,
415 415 parents: DirstateParents,
416 416 now: Duration,
417 417 ) -> Result<Vec<u8>, DirstateError> {
418 418 let packed =
419 419 pack_dirstate(&mut self.state_map, &self.copy_map, parents, now)?;
420 420
421 421 self.dirty_parents = false;
422 422
423 423 self.set_non_normal_other_parent_entries(true);
424 424 Ok(packed)
425 425 }
426 426 #[cfg(not(feature = "dirstate-tree"))]
427 427 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
428 428 if let Some(ref file_fold_map) = self.file_fold_map {
429 429 return file_fold_map;
430 430 }
431 431 let mut new_file_fold_map = FileFoldMap::default();
432 432
433 433 for (filename, DirstateEntry { state, .. }) in self.state_map.iter() {
434 if *state == EntryState::Removed {
434 if *state != EntryState::Removed {
435 435 new_file_fold_map
436 436 .insert(normalize_case(&filename), filename.to_owned());
437 437 }
438 438 }
439 439 self.file_fold_map = Some(new_file_fold_map);
440 440 self.file_fold_map.as_ref().unwrap()
441 441 }
442 442 #[cfg(feature = "dirstate-tree")]
443 443 pub fn build_file_fold_map(&mut self) -> &FileFoldMap {
444 444 if let Some(ref file_fold_map) = self.file_fold_map {
445 445 return file_fold_map;
446 446 }
447 447 let mut new_file_fold_map = FileFoldMap::default();
448 448
449 449 for (filename, DirstateEntry { state, .. }) in self.state_map.iter() {
450 if state == EntryState::Removed {
450 if state != EntryState::Removed {
451 451 new_file_fold_map
452 452 .insert(normalize_case(&filename), filename.to_owned());
453 453 }
454 454 }
455 455 self.file_fold_map = Some(new_file_fold_map);
456 456 self.file_fold_map.as_ref().unwrap()
457 457 }
458 458 }
459 459
460 460 #[cfg(test)]
461 461 mod tests {
462 462 use super::*;
463 463
464 464 #[test]
465 465 fn test_dirs_multiset() {
466 466 let mut map = DirstateMap::new();
467 467 assert!(map.dirs.is_none());
468 468 assert!(map.all_dirs.is_none());
469 469
470 470 assert_eq!(map.has_dir(HgPath::new(b"nope")).unwrap(), false);
471 471 assert!(map.all_dirs.is_some());
472 472 assert!(map.dirs.is_none());
473 473
474 474 assert_eq!(map.has_tracked_dir(HgPath::new(b"nope")).unwrap(), false);
475 475 assert!(map.dirs.is_some());
476 476 }
477 477
478 478 #[test]
479 479 fn test_add_file() {
480 480 let mut map = DirstateMap::new();
481 481
482 482 assert_eq!(0, map.len());
483 483
484 484 map.add_file(
485 485 HgPath::new(b"meh"),
486 486 EntryState::Normal,
487 487 DirstateEntry {
488 488 state: EntryState::Normal,
489 489 mode: 1337,
490 490 mtime: 1337,
491 491 size: 1337,
492 492 },
493 493 )
494 494 .unwrap();
495 495
496 496 assert_eq!(1, map.len());
497 497 assert_eq!(0, map.get_non_normal_other_parent_entries().0.len());
498 498 assert_eq!(0, map.get_non_normal_other_parent_entries().1.len());
499 499 }
500 500
501 501 #[test]
502 502 fn test_non_normal_other_parent_entries() {
503 503 let mut map: DirstateMap = [
504 504 (b"f1", (EntryState::Removed, 1337, 1337, 1337)),
505 505 (b"f2", (EntryState::Normal, 1337, 1337, -1)),
506 506 (b"f3", (EntryState::Normal, 1337, 1337, 1337)),
507 507 (b"f4", (EntryState::Normal, 1337, -2, 1337)),
508 508 (b"f5", (EntryState::Added, 1337, 1337, 1337)),
509 509 (b"f6", (EntryState::Added, 1337, 1337, -1)),
510 510 (b"f7", (EntryState::Merged, 1337, 1337, -1)),
511 511 (b"f8", (EntryState::Merged, 1337, 1337, 1337)),
512 512 (b"f9", (EntryState::Merged, 1337, -2, 1337)),
513 513 (b"fa", (EntryState::Added, 1337, -2, 1337)),
514 514 (b"fb", (EntryState::Removed, 1337, -2, 1337)),
515 515 ]
516 516 .iter()
517 517 .map(|(fname, (state, mode, size, mtime))| {
518 518 (
519 519 HgPathBuf::from_bytes(fname.as_ref()),
520 520 DirstateEntry {
521 521 state: *state,
522 522 mode: *mode,
523 523 size: *size,
524 524 mtime: *mtime,
525 525 },
526 526 )
527 527 })
528 528 .collect();
529 529
530 530 let mut non_normal = [
531 531 b"f1", b"f2", b"f5", b"f6", b"f7", b"f8", b"f9", b"fa", b"fb",
532 532 ]
533 533 .iter()
534 534 .map(|x| HgPathBuf::from_bytes(x.as_ref()))
535 535 .collect();
536 536
537 537 let mut other_parent = HashSet::new();
538 538 other_parent.insert(HgPathBuf::from_bytes(b"f4"));
539 539 let entries = map.get_non_normal_other_parent_entries();
540 540
541 541 assert_eq!(
542 542 (&mut non_normal, &mut other_parent),
543 543 (entries.0, entries.1)
544 544 );
545 545 }
546 546 }
@@ -1,610 +1,610 b''
1 1 // dirstate_map.rs
2 2 //
3 3 // Copyright 2019 Raphaël Gomès <rgomes@octobus.net>
4 4 //
5 5 // This software may be used and distributed according to the terms of the
6 6 // GNU General Public License version 2 or any later version.
7 7
8 8 //! Bindings for the `hg::dirstate::dirstate_map` file provided by the
9 9 //! `hg-core` package.
10 10
11 11 use std::cell::{Ref, RefCell};
12 12 use std::convert::TryInto;
13 13 use std::time::Duration;
14 14
15 15 use cpython::{
16 16 exc, ObjectProtocol, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList,
17 17 PyObject, PyResult, PyString, PyTuple, Python, PythonObject, ToPyObject,
18 18 UnsafePyLeaked,
19 19 };
20 20
21 21 use crate::{
22 22 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
23 23 dirstate::non_normal_entries::{
24 24 NonNormalEntries, NonNormalEntriesIterator,
25 25 },
26 26 dirstate::{dirs_multiset::Dirs, make_dirstate_tuple},
27 27 };
28 28 use hg::{
29 29 utils::hg_path::{HgPath, HgPathBuf},
30 30 DirsMultiset, DirstateEntry, DirstateMap as RustDirstateMap,
31 31 DirstateMapError, DirstateParents, DirstateParseError, EntryState,
32 32 StateMapIter, PARENT_SIZE,
33 33 };
34 34
35 35 // TODO
36 36 // This object needs to share references to multiple members of its Rust
37 37 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
38 38 // Right now `CopyMap` is done, but it needs to have an explicit reference
39 39 // to `RustDirstateMap` which itself needs to have an encapsulation for
40 40 // every method in `CopyMap` (copymapcopy, etc.).
41 41 // This is ugly and hard to maintain.
42 42 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
43 43 // `py_class!` is already implemented and does not mention
44 44 // `RustDirstateMap`, rightfully so.
45 45 // All attributes also have to have a separate refcount data attribute for
46 46 // leaks, with all methods that go along for reference sharing.
47 47 py_class!(pub class DirstateMap |py| {
48 48 @shared data inner: RustDirstateMap;
49 49
50 50 def __new__(_cls, _root: PyObject) -> PyResult<Self> {
51 51 let inner = RustDirstateMap::default();
52 52 Self::create_instance(py, inner)
53 53 }
54 54
55 55 def clear(&self) -> PyResult<PyObject> {
56 56 self.inner(py).borrow_mut().clear();
57 57 Ok(py.None())
58 58 }
59 59
60 60 def get(
61 61 &self,
62 62 key: PyObject,
63 63 default: Option<PyObject> = None
64 64 ) -> PyResult<Option<PyObject>> {
65 65 let key = key.extract::<PyBytes>(py)?;
66 66 match self.inner(py).borrow().get(HgPath::new(key.data(py))) {
67 67 Some(entry) => {
68 68 Ok(Some(make_dirstate_tuple(py, entry)?))
69 69 },
70 70 None => Ok(default)
71 71 }
72 72 }
73 73
74 74 def addfile(
75 75 &self,
76 76 f: PyObject,
77 77 oldstate: PyObject,
78 78 state: PyObject,
79 79 mode: PyObject,
80 80 size: PyObject,
81 81 mtime: PyObject
82 82 ) -> PyResult<PyObject> {
83 83 self.inner(py).borrow_mut().add_file(
84 84 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
85 85 oldstate.extract::<PyBytes>(py)?.data(py)[0]
86 86 .try_into()
87 87 .map_err(|e: DirstateParseError| {
88 88 PyErr::new::<exc::ValueError, _>(py, e.to_string())
89 89 })?,
90 90 DirstateEntry {
91 91 state: state.extract::<PyBytes>(py)?.data(py)[0]
92 92 .try_into()
93 93 .map_err(|e: DirstateParseError| {
94 94 PyErr::new::<exc::ValueError, _>(py, e.to_string())
95 95 })?,
96 96 mode: mode.extract(py)?,
97 97 size: size.extract(py)?,
98 98 mtime: mtime.extract(py)?,
99 99 },
100 100 ).and(Ok(py.None())).or_else(|e: DirstateMapError| {
101 101 Err(PyErr::new::<exc::ValueError, _>(py, e.to_string()))
102 102 })
103 103 }
104 104
105 105 def removefile(
106 106 &self,
107 107 f: PyObject,
108 108 oldstate: PyObject,
109 109 size: PyObject
110 110 ) -> PyResult<PyObject> {
111 111 self.inner(py).borrow_mut()
112 112 .remove_file(
113 113 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
114 114 oldstate.extract::<PyBytes>(py)?.data(py)[0]
115 115 .try_into()
116 116 .map_err(|e: DirstateParseError| {
117 117 PyErr::new::<exc::ValueError, _>(py, e.to_string())
118 118 })?,
119 119 size.extract(py)?,
120 120 )
121 121 .or_else(|_| {
122 122 Err(PyErr::new::<exc::OSError, _>(
123 123 py,
124 124 "Dirstate error".to_string(),
125 125 ))
126 126 })?;
127 127 Ok(py.None())
128 128 }
129 129
130 130 def dropfile(
131 131 &self,
132 132 f: PyObject,
133 133 oldstate: PyObject
134 134 ) -> PyResult<PyBool> {
135 135 self.inner(py).borrow_mut()
136 136 .drop_file(
137 137 HgPath::new(f.extract::<PyBytes>(py)?.data(py)),
138 138 oldstate.extract::<PyBytes>(py)?.data(py)[0]
139 139 .try_into()
140 140 .map_err(|e: DirstateParseError| {
141 141 PyErr::new::<exc::ValueError, _>(py, e.to_string())
142 142 })?,
143 143 )
144 144 .and_then(|b| Ok(b.to_py_object(py)))
145 145 .or_else(|e| {
146 146 Err(PyErr::new::<exc::OSError, _>(
147 147 py,
148 148 format!("Dirstate error: {}", e.to_string()),
149 149 ))
150 150 })
151 151 }
152 152
153 153 def clearambiguoustimes(
154 154 &self,
155 155 files: PyObject,
156 156 now: PyObject
157 157 ) -> PyResult<PyObject> {
158 158 let files: PyResult<Vec<HgPathBuf>> = files
159 159 .iter(py)?
160 160 .map(|filename| {
161 161 Ok(HgPathBuf::from_bytes(
162 162 filename?.extract::<PyBytes>(py)?.data(py),
163 163 ))
164 164 })
165 165 .collect();
166 166 self.inner(py).borrow_mut()
167 167 .clear_ambiguous_times(files?, now.extract(py)?);
168 168 Ok(py.None())
169 169 }
170 170
171 171 def other_parent_entries(&self) -> PyResult<PyObject> {
172 172 let mut inner_shared = self.inner(py).borrow_mut();
173 173 let (_, other_parent) =
174 174 inner_shared.get_non_normal_other_parent_entries();
175 175
176 176 let locals = PyDict::new(py);
177 177 locals.set_item(
178 178 py,
179 179 "other_parent",
180 180 other_parent
181 181 .iter()
182 182 .map(|v| PyBytes::new(py, v.as_bytes()))
183 183 .collect::<Vec<PyBytes>>()
184 184 .to_py_object(py),
185 185 )?;
186 186
187 187 py.eval("set(other_parent)", None, Some(&locals))
188 188 }
189 189
190 190 def non_normal_entries(&self) -> PyResult<NonNormalEntries> {
191 191 NonNormalEntries::from_inner(py, self.clone_ref(py))
192 192 }
193 193
194 194 def non_normal_entries_contains(&self, key: PyObject) -> PyResult<bool> {
195 195 let key = key.extract::<PyBytes>(py)?;
196 196 Ok(self
197 197 .inner(py)
198 198 .borrow_mut()
199 199 .get_non_normal_other_parent_entries().0
200 200 .contains(HgPath::new(key.data(py))))
201 201 }
202 202
203 203 def non_normal_entries_display(&self) -> PyResult<PyString> {
204 204 Ok(
205 205 PyString::new(
206 206 py,
207 207 &format!(
208 208 "NonNormalEntries: {:?}",
209 209 self
210 210 .inner(py)
211 211 .borrow_mut()
212 212 .get_non_normal_other_parent_entries().0
213 213 .iter().map(|o| o))
214 214 )
215 215 )
216 216 }
217 217
218 218 def non_normal_entries_remove(&self, key: PyObject) -> PyResult<PyObject> {
219 219 let key = key.extract::<PyBytes>(py)?;
220 220 self
221 221 .inner(py)
222 222 .borrow_mut()
223 223 .non_normal_entries_remove(HgPath::new(key.data(py)));
224 224 Ok(py.None())
225 225 }
226 226
227 227 def non_normal_entries_union(&self, other: PyObject) -> PyResult<PyList> {
228 228 let other: PyResult<_> = other.iter(py)?
229 229 .map(|f| {
230 230 Ok(HgPathBuf::from_bytes(
231 231 f?.extract::<PyBytes>(py)?.data(py),
232 232 ))
233 233 })
234 234 .collect();
235 235
236 236 let res = self
237 237 .inner(py)
238 238 .borrow_mut()
239 239 .non_normal_entries_union(other?);
240 240
241 241 let ret = PyList::new(py, &[]);
242 242 for filename in res.iter() {
243 243 let as_pystring = PyBytes::new(py, filename.as_bytes());
244 244 ret.append(py, as_pystring.into_object());
245 245 }
246 246 Ok(ret)
247 247 }
248 248
249 249 def non_normal_entries_iter(&self) -> PyResult<NonNormalEntriesIterator> {
250 250 // Make sure the sets are defined before we no longer have a mutable
251 251 // reference to the dmap.
252 252 self.inner(py)
253 253 .borrow_mut()
254 254 .set_non_normal_other_parent_entries(false);
255 255
256 256 let leaked_ref = self.inner(py).leak_immutable();
257 257
258 258 NonNormalEntriesIterator::from_inner(py, unsafe {
259 259 leaked_ref.map(py, |o| {
260 260 o.get_non_normal_other_parent_entries_panic().0.iter()
261 261 })
262 262 })
263 263 }
264 264
265 265 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
266 266 let d = d.extract::<PyBytes>(py)?;
267 267 Ok(self.inner(py).borrow_mut()
268 268 .has_tracked_dir(HgPath::new(d.data(py)))
269 269 .map_err(|e| {
270 270 PyErr::new::<exc::ValueError, _>(py, e.to_string())
271 271 })?
272 272 .to_py_object(py))
273 273 }
274 274
275 275 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
276 276 let d = d.extract::<PyBytes>(py)?;
277 277 Ok(self.inner(py).borrow_mut()
278 278 .has_dir(HgPath::new(d.data(py)))
279 279 .map_err(|e| {
280 280 PyErr::new::<exc::ValueError, _>(py, e.to_string())
281 281 })?
282 282 .to_py_object(py))
283 283 }
284 284
285 285 def parents(&self, st: PyObject) -> PyResult<PyTuple> {
286 286 self.inner(py).borrow_mut()
287 287 .parents(st.extract::<PyBytes>(py)?.data(py))
288 288 .and_then(|d| {
289 289 Ok((PyBytes::new(py, &d.p1), PyBytes::new(py, &d.p2))
290 290 .to_py_object(py))
291 291 })
292 292 .or_else(|_| {
293 293 Err(PyErr::new::<exc::OSError, _>(
294 294 py,
295 295 "Dirstate error".to_string(),
296 296 ))
297 297 })
298 298 }
299 299
300 300 def setparents(&self, p1: PyObject, p2: PyObject) -> PyResult<PyObject> {
301 301 let p1 = extract_node_id(py, &p1)?;
302 302 let p2 = extract_node_id(py, &p2)?;
303 303
304 304 self.inner(py).borrow_mut()
305 305 .set_parents(&DirstateParents { p1, p2 });
306 306 Ok(py.None())
307 307 }
308 308
309 309 def read(&self, st: PyObject) -> PyResult<Option<PyObject>> {
310 310 match self.inner(py).borrow_mut()
311 311 .read(st.extract::<PyBytes>(py)?.data(py))
312 312 {
313 313 Ok(Some(parents)) => Ok(Some(
314 314 (PyBytes::new(py, &parents.p1), PyBytes::new(py, &parents.p2))
315 315 .to_py_object(py)
316 316 .into_object(),
317 317 )),
318 318 Ok(None) => Ok(Some(py.None())),
319 319 Err(_) => Err(PyErr::new::<exc::OSError, _>(
320 320 py,
321 321 "Dirstate error".to_string(),
322 322 )),
323 323 }
324 324 }
325 325 def write(
326 326 &self,
327 327 p1: PyObject,
328 328 p2: PyObject,
329 329 now: PyObject
330 330 ) -> PyResult<PyBytes> {
331 331 let now = Duration::new(now.extract(py)?, 0);
332 332 let parents = DirstateParents {
333 333 p1: extract_node_id(py, &p1)?,
334 334 p2: extract_node_id(py, &p2)?,
335 335 };
336 336
337 337 match self.inner(py).borrow_mut().pack(parents, now) {
338 338 Ok(packed) => Ok(PyBytes::new(py, &packed)),
339 339 Err(_) => Err(PyErr::new::<exc::OSError, _>(
340 340 py,
341 341 "Dirstate error".to_string(),
342 342 )),
343 343 }
344 344 }
345 345
346 346 def filefoldmapasdict(&self) -> PyResult<PyDict> {
347 347 let dict = PyDict::new(py);
348 348 for (key, value) in
349 349 self.inner(py).borrow_mut().build_file_fold_map().iter()
350 350 {
351 351 dict.set_item(
352 352 py,
353 key.as_bytes().to_vec(),
354 value.as_bytes().to_vec(),
353 PyBytes::new(py, key.as_bytes()).into_object(),
354 PyBytes::new(py, value.as_bytes()).into_object(),
355 355 )?;
356 356 }
357 357 Ok(dict)
358 358 }
359 359
360 360 def __len__(&self) -> PyResult<usize> {
361 361 Ok(self.inner(py).borrow().len())
362 362 }
363 363
364 364 def __contains__(&self, key: PyObject) -> PyResult<bool> {
365 365 let key = key.extract::<PyBytes>(py)?;
366 366 Ok(self.inner(py).borrow().contains_key(HgPath::new(key.data(py))))
367 367 }
368 368
369 369 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
370 370 let key = key.extract::<PyBytes>(py)?;
371 371 let key = HgPath::new(key.data(py));
372 372 match self.inner(py).borrow().get(key) {
373 373 Some(entry) => {
374 374 Ok(make_dirstate_tuple(py, entry)?)
375 375 },
376 376 None => Err(PyErr::new::<exc::KeyError, _>(
377 377 py,
378 378 String::from_utf8_lossy(key.as_bytes()),
379 379 )),
380 380 }
381 381 }
382 382
383 383 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
384 384 let leaked_ref = self.inner(py).leak_immutable();
385 385 DirstateMapKeysIterator::from_inner(
386 386 py,
387 387 unsafe { leaked_ref.map(py, |o| o.iter()) },
388 388 )
389 389 }
390 390
391 391 def items(&self) -> PyResult<DirstateMapItemsIterator> {
392 392 let leaked_ref = self.inner(py).leak_immutable();
393 393 DirstateMapItemsIterator::from_inner(
394 394 py,
395 395 unsafe { leaked_ref.map(py, |o| o.iter()) },
396 396 )
397 397 }
398 398
399 399 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
400 400 let leaked_ref = self.inner(py).leak_immutable();
401 401 DirstateMapKeysIterator::from_inner(
402 402 py,
403 403 unsafe { leaked_ref.map(py, |o| o.iter()) },
404 404 )
405 405 }
406 406
407 407 def getdirs(&self) -> PyResult<Dirs> {
408 408 // TODO don't copy, share the reference
409 409 self.inner(py).borrow_mut().set_dirs()
410 410 .map_err(|e| {
411 411 PyErr::new::<exc::ValueError, _>(py, e.to_string())
412 412 })?;
413 413 Dirs::from_inner(
414 414 py,
415 415 DirsMultiset::from_dirstate(
416 416 &self.inner(py).borrow(),
417 417 Some(EntryState::Removed),
418 418 )
419 419 .map_err(|e| {
420 420 PyErr::new::<exc::ValueError, _>(py, e.to_string())
421 421 })?,
422 422 )
423 423 }
424 424 def getalldirs(&self) -> PyResult<Dirs> {
425 425 // TODO don't copy, share the reference
426 426 self.inner(py).borrow_mut().set_all_dirs()
427 427 .map_err(|e| {
428 428 PyErr::new::<exc::ValueError, _>(py, e.to_string())
429 429 })?;
430 430 Dirs::from_inner(
431 431 py,
432 432 DirsMultiset::from_dirstate(
433 433 &self.inner(py).borrow(),
434 434 None,
435 435 ).map_err(|e| {
436 436 PyErr::new::<exc::ValueError, _>(py, e.to_string())
437 437 })?,
438 438 )
439 439 }
440 440
441 441 // TODO all copymap* methods, see docstring above
442 442 def copymapcopy(&self) -> PyResult<PyDict> {
443 443 let dict = PyDict::new(py);
444 444 for (key, value) in self.inner(py).borrow().copy_map.iter() {
445 445 dict.set_item(
446 446 py,
447 447 PyBytes::new(py, key.as_bytes()),
448 448 PyBytes::new(py, value.as_bytes()),
449 449 )?;
450 450 }
451 451 Ok(dict)
452 452 }
453 453
454 454 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
455 455 let key = key.extract::<PyBytes>(py)?;
456 456 match self.inner(py).borrow().copy_map.get(HgPath::new(key.data(py))) {
457 457 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
458 458 None => Err(PyErr::new::<exc::KeyError, _>(
459 459 py,
460 460 String::from_utf8_lossy(key.data(py)),
461 461 )),
462 462 }
463 463 }
464 464 def copymap(&self) -> PyResult<CopyMap> {
465 465 CopyMap::from_inner(py, self.clone_ref(py))
466 466 }
467 467
468 468 def copymaplen(&self) -> PyResult<usize> {
469 469 Ok(self.inner(py).borrow().copy_map.len())
470 470 }
471 471 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
472 472 let key = key.extract::<PyBytes>(py)?;
473 473 Ok(self
474 474 .inner(py)
475 475 .borrow()
476 476 .copy_map
477 477 .contains_key(HgPath::new(key.data(py))))
478 478 }
479 479 def copymapget(
480 480 &self,
481 481 key: PyObject,
482 482 default: Option<PyObject>
483 483 ) -> PyResult<Option<PyObject>> {
484 484 let key = key.extract::<PyBytes>(py)?;
485 485 match self
486 486 .inner(py)
487 487 .borrow()
488 488 .copy_map
489 489 .get(HgPath::new(key.data(py)))
490 490 {
491 491 Some(copy) => Ok(Some(
492 492 PyBytes::new(py, copy.as_bytes()).into_object(),
493 493 )),
494 494 None => Ok(default),
495 495 }
496 496 }
497 497 def copymapsetitem(
498 498 &self,
499 499 key: PyObject,
500 500 value: PyObject
501 501 ) -> PyResult<PyObject> {
502 502 let key = key.extract::<PyBytes>(py)?;
503 503 let value = value.extract::<PyBytes>(py)?;
504 504 self.inner(py).borrow_mut().copy_map.insert(
505 505 HgPathBuf::from_bytes(key.data(py)),
506 506 HgPathBuf::from_bytes(value.data(py)),
507 507 );
508 508 Ok(py.None())
509 509 }
510 510 def copymappop(
511 511 &self,
512 512 key: PyObject,
513 513 default: Option<PyObject>
514 514 ) -> PyResult<Option<PyObject>> {
515 515 let key = key.extract::<PyBytes>(py)?;
516 516 match self
517 517 .inner(py)
518 518 .borrow_mut()
519 519 .copy_map
520 520 .remove(HgPath::new(key.data(py)))
521 521 {
522 522 Some(_) => Ok(None),
523 523 None => Ok(default),
524 524 }
525 525 }
526 526
527 527 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
528 528 let leaked_ref = self.inner(py).leak_immutable();
529 529 CopyMapKeysIterator::from_inner(
530 530 py,
531 531 unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) },
532 532 )
533 533 }
534 534
535 535 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
536 536 let leaked_ref = self.inner(py).leak_immutable();
537 537 CopyMapItemsIterator::from_inner(
538 538 py,
539 539 unsafe { leaked_ref.map(py, |o| o.copy_map.iter()) },
540 540 )
541 541 }
542 542
543 543 });
544 544
545 545 impl DirstateMap {
546 546 pub fn get_inner<'a>(
547 547 &'a self,
548 548 py: Python<'a>,
549 549 ) -> Ref<'a, RustDirstateMap> {
550 550 self.inner(py).borrow()
551 551 }
552 552 #[cfg(not(feature = "dirstate-tree"))]
553 553 fn translate_key(
554 554 py: Python,
555 555 res: (&HgPathBuf, &DirstateEntry),
556 556 ) -> PyResult<Option<PyBytes>> {
557 557 Ok(Some(PyBytes::new(py, res.0.as_bytes())))
558 558 }
559 559 #[cfg(not(feature = "dirstate-tree"))]
560 560 fn translate_key_value(
561 561 py: Python,
562 562 res: (&HgPathBuf, &DirstateEntry),
563 563 ) -> PyResult<Option<(PyBytes, PyObject)>> {
564 564 let (f, entry) = res;
565 565 Ok(Some((
566 566 PyBytes::new(py, f.as_bytes()),
567 567 make_dirstate_tuple(py, &entry)?,
568 568 )))
569 569 }
570 570 #[cfg(feature = "dirstate-tree")]
571 571 fn translate_key(
572 572 py: Python,
573 573 res: (HgPathBuf, DirstateEntry),
574 574 ) -> PyResult<Option<PyBytes>> {
575 575 Ok(Some(PyBytes::new(py, res.0.as_bytes())))
576 576 }
577 577 #[cfg(feature = "dirstate-tree")]
578 578 fn translate_key_value(
579 579 py: Python,
580 580 res: (HgPathBuf, DirstateEntry),
581 581 ) -> PyResult<Option<(PyBytes, PyObject)>> {
582 582 let (f, entry) = res;
583 583 Ok(Some((
584 584 PyBytes::new(py, f.as_bytes()),
585 585 make_dirstate_tuple(py, &entry)?,
586 586 )))
587 587 }
588 588 }
589 589
590 590 py_shared_iterator!(
591 591 DirstateMapKeysIterator,
592 592 UnsafePyLeaked<StateMapIter<'static>>,
593 593 DirstateMap::translate_key,
594 594 Option<PyBytes>
595 595 );
596 596
597 597 py_shared_iterator!(
598 598 DirstateMapItemsIterator,
599 599 UnsafePyLeaked<StateMapIter<'static>>,
600 600 DirstateMap::translate_key_value,
601 601 Option<(PyBytes, PyObject)>
602 602 );
603 603
604 604 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<[u8; PARENT_SIZE]> {
605 605 let bytes = obj.extract::<PyBytes>(py)?;
606 606 match bytes.data(py).try_into() {
607 607 Ok(s) => Ok(s),
608 608 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
609 609 }
610 610 }
General Comments 0
You need to be logged in to leave comments. Login now