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