##// END OF EJS Templates
rust-hg-cpython: remove use of `EntryState`...
Raphaël Gomès -
r50026:a1fce500 default
parent child Browse files
Show More
@@ -1,544 +1,544
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::{RefCell, RefMut};
12 12 use std::convert::TryInto;
13 13
14 14 use cpython::{
15 15 exc, PyBool, PyBytes, PyClone, PyDict, PyErr, PyList, PyNone, PyObject,
16 16 PyResult, Python, PythonObject, ToPyObject, UnsafePyLeaked,
17 17 };
18 18 use hg::dirstate::{ParentFileData, TruncatedTimestamp};
19 19
20 20 use crate::{
21 21 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
22 22 dirstate::item::DirstateItem,
23 23 pybytes_deref::PyBytesDeref,
24 24 };
25 25 use hg::{
26 26 dirstate::StateMapIter, dirstate_tree::on_disk::DirstateV2ParseError,
27 27 dirstate_tree::owning::OwningDirstateMap, revlog::Node,
28 28 utils::files::normalize_case, utils::hg_path::HgPath, DirstateEntry,
29 DirstateError, DirstateParents, EntryState,
29 DirstateError, DirstateParents,
30 30 };
31 31
32 32 // TODO
33 33 // This object needs to share references to multiple members of its Rust
34 34 // inner struct, namely `copy_map`, `dirs` and `all_dirs`.
35 35 // Right now `CopyMap` is done, but it needs to have an explicit reference
36 36 // to `RustDirstateMap` which itself needs to have an encapsulation for
37 37 // every method in `CopyMap` (copymapcopy, etc.).
38 38 // This is ugly and hard to maintain.
39 39 // The same logic applies to `dirs` and `all_dirs`, however the `Dirs`
40 40 // `py_class!` is already implemented and does not mention
41 41 // `RustDirstateMap`, rightfully so.
42 42 // All attributes also have to have a separate refcount data attribute for
43 43 // leaks, with all methods that go along for reference sharing.
44 44 py_class!(pub class DirstateMap |py| {
45 45 @shared data inner: OwningDirstateMap;
46 46
47 47 /// Returns a `(dirstate_map, parents)` tuple
48 48 @staticmethod
49 49 def new_v1(
50 50 on_disk: PyBytes,
51 51 ) -> PyResult<PyObject> {
52 52 let on_disk = PyBytesDeref::new(py, on_disk);
53 53 let (map, parents) = OwningDirstateMap::new_v1(on_disk)
54 54 .map_err(|e| dirstate_error(py, e))?;
55 55 let map = Self::create_instance(py, map)?;
56 56 let p1 = PyBytes::new(py, parents.p1.as_bytes());
57 57 let p2 = PyBytes::new(py, parents.p2.as_bytes());
58 58 let parents = (p1, p2);
59 59 Ok((map, parents).to_py_object(py).into_object())
60 60 }
61 61
62 62 /// Returns a DirstateMap
63 63 @staticmethod
64 64 def new_v2(
65 65 on_disk: PyBytes,
66 66 data_size: usize,
67 67 tree_metadata: PyBytes,
68 68 ) -> PyResult<PyObject> {
69 69 let dirstate_error = |e: DirstateError| {
70 70 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
71 71 };
72 72 let on_disk = PyBytesDeref::new(py, on_disk);
73 73 let map = OwningDirstateMap::new_v2(
74 74 on_disk, data_size, tree_metadata.data(py),
75 75 ).map_err(dirstate_error)?;
76 76 let map = Self::create_instance(py, map)?;
77 77 Ok(map.into_object())
78 78 }
79 79
80 80 def clear(&self) -> PyResult<PyObject> {
81 81 self.inner(py).borrow_mut().clear();
82 82 Ok(py.None())
83 83 }
84 84
85 85 def get(
86 86 &self,
87 87 key: PyObject,
88 88 default: Option<PyObject> = None
89 89 ) -> PyResult<Option<PyObject>> {
90 90 let key = key.extract::<PyBytes>(py)?;
91 91 match self
92 92 .inner(py)
93 93 .borrow()
94 94 .get(HgPath::new(key.data(py)))
95 95 .map_err(|e| v2_error(py, e))?
96 96 {
97 97 Some(entry) => {
98 98 Ok(Some(DirstateItem::new_as_pyobject(py, entry)?))
99 99 },
100 100 None => Ok(default)
101 101 }
102 102 }
103 103
104 104 def set_tracked(&self, f: PyObject) -> PyResult<PyBool> {
105 105 let bytes = f.extract::<PyBytes>(py)?;
106 106 let path = HgPath::new(bytes.data(py));
107 107 let res = self.inner(py).borrow_mut().set_tracked(path);
108 108 let was_tracked = res.or_else(|_| {
109 109 Err(PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))
110 110 })?;
111 111 Ok(was_tracked.to_py_object(py))
112 112 }
113 113
114 114 def set_untracked(&self, f: PyObject) -> PyResult<PyBool> {
115 115 let bytes = f.extract::<PyBytes>(py)?;
116 116 let path = HgPath::new(bytes.data(py));
117 117 let res = self.inner(py).borrow_mut().set_untracked(path);
118 118 let was_tracked = res.or_else(|_| {
119 119 Err(PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))
120 120 })?;
121 121 Ok(was_tracked.to_py_object(py))
122 122 }
123 123
124 124 def set_clean(
125 125 &self,
126 126 f: PyObject,
127 127 mode: u32,
128 128 size: u32,
129 129 mtime: (i64, u32, bool)
130 130 ) -> PyResult<PyNone> {
131 131 let (mtime_s, mtime_ns, second_ambiguous) = mtime;
132 132 let timestamp = TruncatedTimestamp::new_truncate(
133 133 mtime_s, mtime_ns, second_ambiguous
134 134 );
135 135 let bytes = f.extract::<PyBytes>(py)?;
136 136 let path = HgPath::new(bytes.data(py));
137 137 let res = self.inner(py).borrow_mut().set_clean(
138 138 path, mode, size, timestamp,
139 139 );
140 140 res.or_else(|_| {
141 141 Err(PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))
142 142 })?;
143 143 Ok(PyNone)
144 144 }
145 145
146 146 def set_possibly_dirty(&self, f: PyObject) -> PyResult<PyNone> {
147 147 let bytes = f.extract::<PyBytes>(py)?;
148 148 let path = HgPath::new(bytes.data(py));
149 149 let res = self.inner(py).borrow_mut().set_possibly_dirty(path);
150 150 res.or_else(|_| {
151 151 Err(PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))
152 152 })?;
153 153 Ok(PyNone)
154 154 }
155 155
156 156 def reset_state(
157 157 &self,
158 158 f: PyObject,
159 159 wc_tracked: bool,
160 160 p1_tracked: bool,
161 161 p2_info: bool,
162 162 has_meaningful_mtime: bool,
163 163 parentfiledata: Option<(u32, u32, Option<(i64, u32, bool)>)>,
164 164 ) -> PyResult<PyNone> {
165 165 let mut has_meaningful_mtime = has_meaningful_mtime;
166 166 let parent_file_data = match parentfiledata {
167 167 None => {
168 168 has_meaningful_mtime = false;
169 169 None
170 170 },
171 171 Some(data) => {
172 172 let (mode, size, mtime_info) = data;
173 173 let mtime = if let Some(mtime_info) = mtime_info {
174 174 let (mtime_s, mtime_ns, second_ambiguous) = mtime_info;
175 175 let timestamp = TruncatedTimestamp::new_truncate(
176 176 mtime_s, mtime_ns, second_ambiguous
177 177 );
178 178 Some(timestamp)
179 179 } else {
180 180 has_meaningful_mtime = false;
181 181 None
182 182 };
183 183 Some(ParentFileData {
184 184 mode_size: Some((mode, size)),
185 185 mtime,
186 186 })
187 187 }
188 188 };
189 189 let bytes = f.extract::<PyBytes>(py)?;
190 190 let path = HgPath::new(bytes.data(py));
191 191 let res = self.inner(py).borrow_mut().reset_state(
192 192 path,
193 193 wc_tracked,
194 194 p1_tracked,
195 195 p2_info,
196 196 has_meaningful_mtime,
197 197 parent_file_data,
198 198 );
199 199 res.or_else(|_| {
200 200 Err(PyErr::new::<exc::OSError, _>(py, "Dirstate error".to_string()))
201 201 })?;
202 202 Ok(PyNone)
203 203 }
204 204
205 205 def hastrackeddir(&self, d: PyObject) -> PyResult<PyBool> {
206 206 let d = d.extract::<PyBytes>(py)?;
207 207 Ok(self.inner(py).borrow_mut()
208 208 .has_tracked_dir(HgPath::new(d.data(py)))
209 209 .map_err(|e| {
210 210 PyErr::new::<exc::ValueError, _>(py, e.to_string())
211 211 })?
212 212 .to_py_object(py))
213 213 }
214 214
215 215 def hasdir(&self, d: PyObject) -> PyResult<PyBool> {
216 216 let d = d.extract::<PyBytes>(py)?;
217 217 Ok(self.inner(py).borrow_mut()
218 218 .has_dir(HgPath::new(d.data(py)))
219 219 .map_err(|e| {
220 220 PyErr::new::<exc::ValueError, _>(py, e.to_string())
221 221 })?
222 222 .to_py_object(py))
223 223 }
224 224
225 225 def write_v1(
226 226 &self,
227 227 p1: PyObject,
228 228 p2: PyObject,
229 229 ) -> PyResult<PyBytes> {
230 230 let inner = self.inner(py).borrow();
231 231 let parents = DirstateParents {
232 232 p1: extract_node_id(py, &p1)?,
233 233 p2: extract_node_id(py, &p2)?,
234 234 };
235 235 let result = inner.pack_v1(parents);
236 236 match result {
237 237 Ok(packed) => Ok(PyBytes::new(py, &packed)),
238 238 Err(_) => Err(PyErr::new::<exc::OSError, _>(
239 239 py,
240 240 "Dirstate error".to_string(),
241 241 )),
242 242 }
243 243 }
244 244
245 245 /// Returns new data together with whether that data should be appended to
246 246 /// the existing data file whose content is at `self.on_disk` (True),
247 247 /// instead of written to a new data file (False).
248 248 def write_v2(
249 249 &self,
250 250 can_append: bool,
251 251 ) -> PyResult<PyObject> {
252 252 let inner = self.inner(py).borrow();
253 253 let result = inner.pack_v2(can_append);
254 254 match result {
255 255 Ok((packed, tree_metadata, append)) => {
256 256 let packed = PyBytes::new(py, &packed);
257 257 let tree_metadata = PyBytes::new(py, tree_metadata.as_bytes());
258 258 let tuple = (packed, tree_metadata, append);
259 259 Ok(tuple.to_py_object(py).into_object())
260 260 },
261 261 Err(_) => Err(PyErr::new::<exc::OSError, _>(
262 262 py,
263 263 "Dirstate error".to_string(),
264 264 )),
265 265 }
266 266 }
267 267
268 268 def filefoldmapasdict(&self) -> PyResult<PyDict> {
269 269 let dict = PyDict::new(py);
270 270 for item in self.inner(py).borrow_mut().iter() {
271 271 let (path, entry) = item.map_err(|e| v2_error(py, e))?;
272 if entry.state() != EntryState::Removed {
272 if !entry.removed() {
273 273 let key = normalize_case(path);
274 274 let value = path;
275 275 dict.set_item(
276 276 py,
277 277 PyBytes::new(py, key.as_bytes()).into_object(),
278 278 PyBytes::new(py, value.as_bytes()).into_object(),
279 279 )?;
280 280 }
281 281 }
282 282 Ok(dict)
283 283 }
284 284
285 285 def __len__(&self) -> PyResult<usize> {
286 286 Ok(self.inner(py).borrow().len())
287 287 }
288 288
289 289 def __contains__(&self, key: PyObject) -> PyResult<bool> {
290 290 let key = key.extract::<PyBytes>(py)?;
291 291 self.inner(py)
292 292 .borrow()
293 293 .contains_key(HgPath::new(key.data(py)))
294 294 .map_err(|e| v2_error(py, e))
295 295 }
296 296
297 297 def __getitem__(&self, key: PyObject) -> PyResult<PyObject> {
298 298 let key = key.extract::<PyBytes>(py)?;
299 299 let key = HgPath::new(key.data(py));
300 300 match self
301 301 .inner(py)
302 302 .borrow()
303 303 .get(key)
304 304 .map_err(|e| v2_error(py, e))?
305 305 {
306 306 Some(entry) => {
307 307 Ok(DirstateItem::new_as_pyobject(py, entry)?)
308 308 },
309 309 None => Err(PyErr::new::<exc::KeyError, _>(
310 310 py,
311 311 String::from_utf8_lossy(key.as_bytes()),
312 312 )),
313 313 }
314 314 }
315 315
316 316 def keys(&self) -> PyResult<DirstateMapKeysIterator> {
317 317 let leaked_ref = self.inner(py).leak_immutable();
318 318 DirstateMapKeysIterator::from_inner(
319 319 py,
320 320 unsafe { leaked_ref.map(py, |o| o.iter()) },
321 321 )
322 322 }
323 323
324 324 def items(&self) -> PyResult<DirstateMapItemsIterator> {
325 325 let leaked_ref = self.inner(py).leak_immutable();
326 326 DirstateMapItemsIterator::from_inner(
327 327 py,
328 328 unsafe { leaked_ref.map(py, |o| o.iter()) },
329 329 )
330 330 }
331 331
332 332 def __iter__(&self) -> PyResult<DirstateMapKeysIterator> {
333 333 let leaked_ref = self.inner(py).leak_immutable();
334 334 DirstateMapKeysIterator::from_inner(
335 335 py,
336 336 unsafe { leaked_ref.map(py, |o| o.iter()) },
337 337 )
338 338 }
339 339
340 340 // TODO all copymap* methods, see docstring above
341 341 def copymapcopy(&self) -> PyResult<PyDict> {
342 342 let dict = PyDict::new(py);
343 343 for item in self.inner(py).borrow().copy_map_iter() {
344 344 let (key, value) = item.map_err(|e| v2_error(py, e))?;
345 345 dict.set_item(
346 346 py,
347 347 PyBytes::new(py, key.as_bytes()),
348 348 PyBytes::new(py, value.as_bytes()),
349 349 )?;
350 350 }
351 351 Ok(dict)
352 352 }
353 353
354 354 def copymapgetitem(&self, key: PyObject) -> PyResult<PyBytes> {
355 355 let key = key.extract::<PyBytes>(py)?;
356 356 match self
357 357 .inner(py)
358 358 .borrow()
359 359 .copy_map_get(HgPath::new(key.data(py)))
360 360 .map_err(|e| v2_error(py, e))?
361 361 {
362 362 Some(copy) => Ok(PyBytes::new(py, copy.as_bytes())),
363 363 None => Err(PyErr::new::<exc::KeyError, _>(
364 364 py,
365 365 String::from_utf8_lossy(key.data(py)),
366 366 )),
367 367 }
368 368 }
369 369 def copymap(&self) -> PyResult<CopyMap> {
370 370 CopyMap::from_inner(py, self.clone_ref(py))
371 371 }
372 372
373 373 def copymaplen(&self) -> PyResult<usize> {
374 374 Ok(self.inner(py).borrow().copy_map_len())
375 375 }
376 376 def copymapcontains(&self, key: PyObject) -> PyResult<bool> {
377 377 let key = key.extract::<PyBytes>(py)?;
378 378 self.inner(py)
379 379 .borrow()
380 380 .copy_map_contains_key(HgPath::new(key.data(py)))
381 381 .map_err(|e| v2_error(py, e))
382 382 }
383 383 def copymapget(
384 384 &self,
385 385 key: PyObject,
386 386 default: Option<PyObject>
387 387 ) -> PyResult<Option<PyObject>> {
388 388 let key = key.extract::<PyBytes>(py)?;
389 389 match self
390 390 .inner(py)
391 391 .borrow()
392 392 .copy_map_get(HgPath::new(key.data(py)))
393 393 .map_err(|e| v2_error(py, e))?
394 394 {
395 395 Some(copy) => Ok(Some(
396 396 PyBytes::new(py, copy.as_bytes()).into_object(),
397 397 )),
398 398 None => Ok(default),
399 399 }
400 400 }
401 401 def copymapsetitem(
402 402 &self,
403 403 key: PyObject,
404 404 value: PyObject
405 405 ) -> PyResult<PyObject> {
406 406 let key = key.extract::<PyBytes>(py)?;
407 407 let value = value.extract::<PyBytes>(py)?;
408 408 self.inner(py)
409 409 .borrow_mut()
410 410 .copy_map_insert(
411 411 HgPath::new(key.data(py)),
412 412 HgPath::new(value.data(py)),
413 413 )
414 414 .map_err(|e| v2_error(py, e))?;
415 415 Ok(py.None())
416 416 }
417 417 def copymappop(
418 418 &self,
419 419 key: PyObject,
420 420 default: Option<PyObject>
421 421 ) -> PyResult<Option<PyObject>> {
422 422 let key = key.extract::<PyBytes>(py)?;
423 423 match self
424 424 .inner(py)
425 425 .borrow_mut()
426 426 .copy_map_remove(HgPath::new(key.data(py)))
427 427 .map_err(|e| v2_error(py, e))?
428 428 {
429 429 Some(copy) => Ok(Some(
430 430 PyBytes::new(py, copy.as_bytes()).into_object(),
431 431 )),
432 432 None => Ok(default),
433 433 }
434 434 }
435 435
436 436 def copymapiter(&self) -> PyResult<CopyMapKeysIterator> {
437 437 let leaked_ref = self.inner(py).leak_immutable();
438 438 CopyMapKeysIterator::from_inner(
439 439 py,
440 440 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
441 441 )
442 442 }
443 443
444 444 def copymapitemsiter(&self) -> PyResult<CopyMapItemsIterator> {
445 445 let leaked_ref = self.inner(py).leak_immutable();
446 446 CopyMapItemsIterator::from_inner(
447 447 py,
448 448 unsafe { leaked_ref.map(py, |o| o.copy_map_iter()) },
449 449 )
450 450 }
451 451
452 452 def tracked_dirs(&self) -> PyResult<PyList> {
453 453 let dirs = PyList::new(py, &[]);
454 454 for path in self.inner(py).borrow_mut().iter_tracked_dirs()
455 455 .map_err(|e |dirstate_error(py, e))?
456 456 {
457 457 let path = path.map_err(|e| v2_error(py, e))?;
458 458 let path = PyBytes::new(py, path.as_bytes());
459 459 dirs.append(py, path.into_object())
460 460 }
461 461 Ok(dirs)
462 462 }
463 463
464 464 def setparents_fixup(&self) -> PyResult<PyDict> {
465 465 let dict = PyDict::new(py);
466 466 let copies = self.inner(py).borrow_mut().setparents_fixup();
467 467 for (key, value) in copies.map_err(|e| v2_error(py, e))? {
468 468 dict.set_item(
469 469 py,
470 470 PyBytes::new(py, key.as_bytes()),
471 471 PyBytes::new(py, value.as_bytes()),
472 472 )?;
473 473 }
474 474 Ok(dict)
475 475 }
476 476
477 477 def debug_iter(&self, all: bool) -> PyResult<PyList> {
478 478 let dirs = PyList::new(py, &[]);
479 479 for item in self.inner(py).borrow().debug_iter(all) {
480 480 let (path, (state, mode, size, mtime)) =
481 481 item.map_err(|e| v2_error(py, e))?;
482 482 let path = PyBytes::new(py, path.as_bytes());
483 483 let item = (path, state, mode, size, mtime);
484 484 dirs.append(py, item.to_py_object(py).into_object())
485 485 }
486 486 Ok(dirs)
487 487 }
488 488 });
489 489
490 490 impl DirstateMap {
491 491 pub fn get_inner_mut<'a>(
492 492 &'a self,
493 493 py: Python<'a>,
494 494 ) -> RefMut<'a, OwningDirstateMap> {
495 495 self.inner(py).borrow_mut()
496 496 }
497 497 fn translate_key(
498 498 py: Python,
499 499 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
500 500 ) -> PyResult<Option<PyBytes>> {
501 501 let (f, _entry) = res.map_err(|e| v2_error(py, e))?;
502 502 Ok(Some(PyBytes::new(py, f.as_bytes())))
503 503 }
504 504 fn translate_key_value(
505 505 py: Python,
506 506 res: Result<(&HgPath, DirstateEntry), DirstateV2ParseError>,
507 507 ) -> PyResult<Option<(PyBytes, PyObject)>> {
508 508 let (f, entry) = res.map_err(|e| v2_error(py, e))?;
509 509 Ok(Some((
510 510 PyBytes::new(py, f.as_bytes()),
511 511 DirstateItem::new_as_pyobject(py, entry)?,
512 512 )))
513 513 }
514 514 }
515 515
516 516 py_shared_iterator!(
517 517 DirstateMapKeysIterator,
518 518 UnsafePyLeaked<StateMapIter<'static>>,
519 519 DirstateMap::translate_key,
520 520 Option<PyBytes>
521 521 );
522 522
523 523 py_shared_iterator!(
524 524 DirstateMapItemsIterator,
525 525 UnsafePyLeaked<StateMapIter<'static>>,
526 526 DirstateMap::translate_key_value,
527 527 Option<(PyBytes, PyObject)>
528 528 );
529 529
530 530 fn extract_node_id(py: Python, obj: &PyObject) -> PyResult<Node> {
531 531 let bytes = obj.extract::<PyBytes>(py)?;
532 532 match bytes.data(py).try_into() {
533 533 Ok(s) => Ok(s),
534 534 Err(e) => Err(PyErr::new::<exc::ValueError, _>(py, e.to_string())),
535 535 }
536 536 }
537 537
538 538 pub(super) fn v2_error(py: Python<'_>, _: DirstateV2ParseError) -> PyErr {
539 539 PyErr::new::<exc::ValueError, _>(py, "corrupted dirstate-v2")
540 540 }
541 541
542 542 fn dirstate_error(py: Python<'_>, e: DirstateError) -> PyErr {
543 543 PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e))
544 544 }
General Comments 0
You need to be logged in to leave comments. Login now