Show More
@@ -570,6 +570,12 b' if rustmod is not None:' | |||||
570 | testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file') |
|
570 | testing.wait_on_cfg(self._ui, b'dirstate.pre-read-file') | |
571 | if self._use_dirstate_v2: |
|
571 | if self._use_dirstate_v2: | |
572 | self.docket # load the data if needed |
|
572 | self.docket # load the data if needed | |
|
573 | inode = ( | |||
|
574 | self.identity.stat.st_ino | |||
|
575 | if self.identity is not None | |||
|
576 | and self.identity.stat is not None | |||
|
577 | else None | |||
|
578 | ) | |||
573 | testing.wait_on_cfg(self._ui, b'dirstate.post-docket-read-file') |
|
579 | testing.wait_on_cfg(self._ui, b'dirstate.post-docket-read-file') | |
574 | if not self.docket.uuid: |
|
580 | if not self.docket.uuid: | |
575 | data = b'' |
|
581 | data = b'' | |
@@ -581,12 +587,19 b' if rustmod is not None:' | |||||
581 | self.docket.data_size, |
|
587 | self.docket.data_size, | |
582 | self.docket.tree_metadata, |
|
588 | self.docket.tree_metadata, | |
583 | self.docket.uuid, |
|
589 | self.docket.uuid, | |
|
590 | inode, | |||
584 | ) |
|
591 | ) | |
585 | parents = self.docket.parents |
|
592 | parents = self.docket.parents | |
586 | else: |
|
593 | else: | |
587 | self._set_identity() |
|
594 | self._set_identity() | |
|
595 | inode = ( | |||
|
596 | self.identity.stat.st_ino | |||
|
597 | if self.identity is not None | |||
|
598 | and self.identity.stat is not None | |||
|
599 | else None | |||
|
600 | ) | |||
588 | self._map, parents = rustmod.DirstateMap.new_v1( |
|
601 | self._map, parents = rustmod.DirstateMap.new_v1( | |
589 | self._readdirstatefile() |
|
602 | self._readdirstatefile(), inode | |
590 | ) |
|
603 | ) | |
591 |
|
604 | |||
592 | if parents and not self._dirtyparents: |
|
605 | if parents and not self._dirtyparents: |
@@ -76,6 +76,14 b" pub struct DirstateMap<'on_disk> {" | |||||
76 | /// Can be `None` if using dirstate v1 or if it's a brand new dirstate. |
|
76 | /// Can be `None` if using dirstate v1 or if it's a brand new dirstate. | |
77 | pub(super) old_uuid: Option<Vec<u8>>, |
|
77 | pub(super) old_uuid: Option<Vec<u8>>, | |
78 |
|
78 | |||
|
79 | /// Identity of the dirstate file (for dirstate-v1) or the docket file | |||
|
80 | /// (v2). Used to detect if the file has changed from another process. | |||
|
81 | /// Since it's always written atomically, we can compare the inode to | |||
|
82 | /// check the file identity. | |||
|
83 | /// | |||
|
84 | /// TODO On non-Unix systems, something like hashing is a possibility? | |||
|
85 | pub(super) identity: Option<u64>, | |||
|
86 | ||||
79 | pub(super) dirstate_version: DirstateVersion, |
|
87 | pub(super) dirstate_version: DirstateVersion, | |
80 |
|
88 | |||
81 | /// Controlled by config option `devel.dirstate.v2.data_update_mode` |
|
89 | /// Controlled by config option `devel.dirstate.v2.data_update_mode` | |
@@ -468,6 +476,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
468 | unreachable_bytes: 0, |
|
476 | unreachable_bytes: 0, | |
469 | old_data_size: 0, |
|
477 | old_data_size: 0, | |
470 | old_uuid: None, |
|
478 | old_uuid: None, | |
|
479 | identity: None, | |||
471 | dirstate_version: DirstateVersion::V1, |
|
480 | dirstate_version: DirstateVersion::V1, | |
472 | write_mode: DirstateMapWriteMode::Auto, |
|
481 | write_mode: DirstateMapWriteMode::Auto, | |
473 | } |
|
482 | } | |
@@ -479,9 +488,10 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
479 | data_size: usize, |
|
488 | data_size: usize, | |
480 | metadata: &[u8], |
|
489 | metadata: &[u8], | |
481 | uuid: Vec<u8>, |
|
490 | uuid: Vec<u8>, | |
|
491 | identity: Option<u64>, | |||
482 | ) -> Result<Self, DirstateError> { |
|
492 | ) -> Result<Self, DirstateError> { | |
483 | if let Some(data) = on_disk.get(..data_size) { |
|
493 | if let Some(data) = on_disk.get(..data_size) { | |
484 | Ok(on_disk::read(data, metadata, uuid)?) |
|
494 | Ok(on_disk::read(data, metadata, uuid, identity)?) | |
485 | } else { |
|
495 | } else { | |
486 | Err(DirstateV2ParseError::new("not enough bytes on disk").into()) |
|
496 | Err(DirstateV2ParseError::new("not enough bytes on disk").into()) | |
487 | } |
|
497 | } | |
@@ -490,6 +500,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
490 | #[timed] |
|
500 | #[timed] | |
491 | pub fn new_v1( |
|
501 | pub fn new_v1( | |
492 | on_disk: &'on_disk [u8], |
|
502 | on_disk: &'on_disk [u8], | |
|
503 | identity: Option<u64>, | |||
493 | ) -> Result<(Self, Option<DirstateParents>), DirstateError> { |
|
504 | ) -> Result<(Self, Option<DirstateParents>), DirstateError> { | |
494 | let mut map = Self::empty(on_disk); |
|
505 | let mut map = Self::empty(on_disk); | |
495 | if map.on_disk.is_empty() { |
|
506 | if map.on_disk.is_empty() { | |
@@ -531,6 +542,7 b" impl<'on_disk> DirstateMap<'on_disk> {" | |||||
531 | }, |
|
542 | }, | |
532 | )?; |
|
543 | )?; | |
533 | let parents = Some(parents.clone()); |
|
544 | let parents = Some(parents.clone()); | |
|
545 | map.identity = identity; | |||
534 |
|
546 | |||
535 | Ok((map, parents)) |
|
547 | Ok((map, parents)) | |
536 | } |
|
548 | } | |
@@ -1853,6 +1865,7 b' mod tests {' | |||||
1853 | packed_len, |
|
1865 | packed_len, | |
1854 | metadata.as_bytes(), |
|
1866 | metadata.as_bytes(), | |
1855 | vec![], |
|
1867 | vec![], | |
|
1868 | None, | |||
1856 | )?; |
|
1869 | )?; | |
1857 |
|
1870 | |||
1858 | // Check that everything is accounted for |
|
1871 | // Check that everything is accounted for |
@@ -291,6 +291,7 b" pub(super) fn read<'on_disk>(" | |||||
291 | on_disk: &'on_disk [u8], |
|
291 | on_disk: &'on_disk [u8], | |
292 | metadata: &[u8], |
|
292 | metadata: &[u8], | |
293 | uuid: Vec<u8>, |
|
293 | uuid: Vec<u8>, | |
|
294 | identity: Option<u64>, | |||
294 | ) -> Result<DirstateMap<'on_disk>, DirstateV2ParseError> { |
|
295 | ) -> Result<DirstateMap<'on_disk>, DirstateV2ParseError> { | |
295 | if on_disk.is_empty() { |
|
296 | if on_disk.is_empty() { | |
296 | let mut map = DirstateMap::empty(on_disk); |
|
297 | let mut map = DirstateMap::empty(on_disk); | |
@@ -314,6 +315,7 b" pub(super) fn read<'on_disk>(" | |||||
314 | unreachable_bytes: meta.unreachable_bytes.get(), |
|
315 | unreachable_bytes: meta.unreachable_bytes.get(), | |
315 | old_data_size: on_disk.len(), |
|
316 | old_data_size: on_disk.len(), | |
316 | old_uuid: Some(uuid), |
|
317 | old_uuid: Some(uuid), | |
|
318 | identity, | |||
317 | dirstate_version: DirstateVersion::V2, |
|
319 | dirstate_version: DirstateVersion::V2, | |
318 | write_mode: DirstateMapWriteMode::Auto, |
|
320 | write_mode: DirstateMapWriteMode::Auto, | |
319 | }; |
|
321 | }; |
@@ -31,6 +31,7 b' impl OwningDirstateMap {' | |||||
31 |
|
31 | |||
32 | pub fn new_v1<OnDisk>( |
|
32 | pub fn new_v1<OnDisk>( | |
33 | on_disk: OnDisk, |
|
33 | on_disk: OnDisk, | |
|
34 | identity: Option<u64>, | |||
34 | ) -> Result<(Self, DirstateParents), DirstateError> |
|
35 | ) -> Result<(Self, DirstateParents), DirstateError> | |
35 | where |
|
36 | where | |
36 | OnDisk: Deref<Target = [u8]> + Send + 'static, |
|
37 | OnDisk: Deref<Target = [u8]> + Send + 'static, | |
@@ -42,7 +43,7 b' impl OwningDirstateMap {' | |||||
42 | OwningDirstateMapTryBuilder { |
|
43 | OwningDirstateMapTryBuilder { | |
43 | on_disk, |
|
44 | on_disk, | |
44 | map_builder: |bytes| { |
|
45 | map_builder: |bytes| { | |
45 | DirstateMap::new_v1(&bytes).map(|(dmap, p)| { |
|
46 | DirstateMap::new_v1(&bytes, identity).map(|(dmap, p)| { | |
46 | parents = p.unwrap_or(DirstateParents::NULL); |
|
47 | parents = p.unwrap_or(DirstateParents::NULL); | |
47 | dmap |
|
48 | dmap | |
48 | }) |
|
49 | }) | |
@@ -58,6 +59,7 b' impl OwningDirstateMap {' | |||||
58 | data_size: usize, |
|
59 | data_size: usize, | |
59 | metadata: &[u8], |
|
60 | metadata: &[u8], | |
60 | uuid: Vec<u8>, |
|
61 | uuid: Vec<u8>, | |
|
62 | identity: Option<u64>, | |||
61 | ) -> Result<Self, DirstateError> |
|
63 | ) -> Result<Self, DirstateError> | |
62 | where |
|
64 | where | |
63 | OnDisk: Deref<Target = [u8]> + Send + 'static, |
|
65 | OnDisk: Deref<Target = [u8]> + Send + 'static, | |
@@ -67,7 +69,9 b' impl OwningDirstateMap {' | |||||
67 | OwningDirstateMapTryBuilder { |
|
69 | OwningDirstateMapTryBuilder { | |
68 | on_disk, |
|
70 | on_disk, | |
69 | map_builder: |bytes| { |
|
71 | map_builder: |bytes| { | |
70 |
DirstateMap::new_v2( |
|
72 | DirstateMap::new_v2( | |
|
73 | &bytes, data_size, metadata, uuid, identity, | |||
|
74 | ) | |||
71 | }, |
|
75 | }, | |
72 | } |
|
76 | } | |
73 | .try_build() |
|
77 | .try_build() | |
@@ -92,6 +96,10 b' impl OwningDirstateMap {' | |||||
92 | self.get_map().old_uuid.as_deref() |
|
96 | self.get_map().old_uuid.as_deref() | |
93 | } |
|
97 | } | |
94 |
|
98 | |||
|
99 | pub fn old_identity(&self) -> Option<u64> { | |||
|
100 | self.get_map().identity | |||
|
101 | } | |||
|
102 | ||||
95 | pub fn old_data_size(&self) -> usize { |
|
103 | pub fn old_data_size(&self) -> usize { | |
96 | self.get_map().old_data_size |
|
104 | self.get_map().old_data_size | |
97 | } |
|
105 | } |
@@ -259,6 +259,15 b' impl Repo {' | |||||
259 | .unwrap_or(Vec::new())) |
|
259 | .unwrap_or(Vec::new())) | |
260 | } |
|
260 | } | |
261 |
|
261 | |||
|
262 | fn dirstate_identity(&self) -> Result<Option<u64>, HgError> { | |||
|
263 | use std::os::unix::fs::MetadataExt; | |||
|
264 | Ok(self | |||
|
265 | .hg_vfs() | |||
|
266 | .symlink_metadata("dirstate") | |||
|
267 | .io_not_found_as_none()? | |||
|
268 | .map(|meta| meta.ino())) | |||
|
269 | } | |||
|
270 | ||||
262 | pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> { |
|
271 | pub fn dirstate_parents(&self) -> Result<DirstateParents, HgError> { | |
263 | Ok(*self |
|
272 | Ok(*self | |
264 | .dirstate_parents |
|
273 | .dirstate_parents | |
@@ -284,23 +293,27 b' impl Repo {' | |||||
284 | /// Returns the information read from the dirstate docket necessary to |
|
293 | /// Returns the information read from the dirstate docket necessary to | |
285 | /// check if the data file has been updated/deleted by another process |
|
294 | /// check if the data file has been updated/deleted by another process | |
286 | /// since we last read the dirstate. |
|
295 | /// since we last read the dirstate. | |
287 | /// Namely, the data file uuid and the data size. |
|
296 | /// Namely, the inode, data file uuid and the data size. | |
288 | fn get_dirstate_data_file_integrity( |
|
297 | fn get_dirstate_data_file_integrity( | |
289 | &self, |
|
298 | &self, | |
290 | ) -> Result<(Option<Vec<u8>>, usize), HgError> { |
|
299 | ) -> Result<(Option<u64>, Option<Vec<u8>>, usize), HgError> { | |
291 | assert!( |
|
300 | assert!( | |
292 | self.has_dirstate_v2(), |
|
301 | self.has_dirstate_v2(), | |
293 | "accessing dirstate data file ID without dirstate-v2" |
|
302 | "accessing dirstate data file ID without dirstate-v2" | |
294 | ); |
|
303 | ); | |
|
304 | // Get the identity before the contents since we could have a race | |||
|
305 | // between the two. Having an identity that is too old is fine, but | |||
|
306 | // one that is younger than the content change is bad. | |||
|
307 | let identity = self.dirstate_identity()?; | |||
295 | let dirstate = self.dirstate_file_contents()?; |
|
308 | let dirstate = self.dirstate_file_contents()?; | |
296 | if dirstate.is_empty() { |
|
309 | if dirstate.is_empty() { | |
297 | self.dirstate_parents.set(DirstateParents::NULL); |
|
310 | self.dirstate_parents.set(DirstateParents::NULL); | |
298 | Ok((None, 0)) |
|
311 | Ok((identity, None, 0)) | |
299 | } else { |
|
312 | } else { | |
300 | let docket = |
|
313 | let docket = | |
301 | crate::dirstate_tree::on_disk::read_docket(&dirstate)?; |
|
314 | crate::dirstate_tree::on_disk::read_docket(&dirstate)?; | |
302 | self.dirstate_parents.set(docket.parents()); |
|
315 | self.dirstate_parents.set(docket.parents()); | |
303 | Ok((Some(docket.uuid.to_owned()), docket.data_size())) |
|
316 | Ok((identity, Some(docket.uuid.to_owned()), docket.data_size())) | |
304 | } |
|
317 | } | |
305 | } |
|
318 | } | |
306 |
|
319 | |||
@@ -347,13 +360,16 b' impl Repo {' | |||||
347 | self.config(), |
|
360 | self.config(), | |
348 | "dirstate.pre-read-file", |
|
361 | "dirstate.pre-read-file", | |
349 | ); |
|
362 | ); | |
|
363 | let identity = self.dirstate_identity()?; | |||
350 | let dirstate_file_contents = self.dirstate_file_contents()?; |
|
364 | let dirstate_file_contents = self.dirstate_file_contents()?; | |
351 | return if dirstate_file_contents.is_empty() { |
|
365 | return if dirstate_file_contents.is_empty() { | |
352 | self.dirstate_parents.set(DirstateParents::NULL); |
|
366 | self.dirstate_parents.set(DirstateParents::NULL); | |
353 | Ok(OwningDirstateMap::new_empty(Vec::new())) |
|
367 | Ok(OwningDirstateMap::new_empty(Vec::new())) | |
354 | } else { |
|
368 | } else { | |
355 | let (map, parents) = |
|
369 | let (map, parents) = OwningDirstateMap::new_v1( | |
356 |
|
|
370 | dirstate_file_contents, | |
|
371 | identity, | |||
|
372 | )?; | |||
357 | self.dirstate_parents.set(parents); |
|
373 | self.dirstate_parents.set(parents); | |
358 | Ok(map) |
|
374 | Ok(map) | |
359 | }; |
|
375 | }; | |
@@ -365,6 +381,7 b' impl Repo {' | |||||
365 | ) -> Result<OwningDirstateMap, DirstateError> { |
|
381 | ) -> Result<OwningDirstateMap, DirstateError> { | |
366 | debug_wait_for_file_or_print(self.config(), "dirstate.pre-read-file"); |
|
382 | debug_wait_for_file_or_print(self.config(), "dirstate.pre-read-file"); | |
367 | let dirstate_file_contents = self.dirstate_file_contents()?; |
|
383 | let dirstate_file_contents = self.dirstate_file_contents()?; | |
|
384 | let identity = self.dirstate_identity()?; | |||
368 | if dirstate_file_contents.is_empty() { |
|
385 | if dirstate_file_contents.is_empty() { | |
369 | self.dirstate_parents.set(DirstateParents::NULL); |
|
386 | self.dirstate_parents.set(DirstateParents::NULL); | |
370 | return Ok(OwningDirstateMap::new_empty(Vec::new())); |
|
387 | return Ok(OwningDirstateMap::new_empty(Vec::new())); | |
@@ -410,7 +427,9 b' impl Repo {' | |||||
410 | } |
|
427 | } | |
411 | Err(e) => return Err(e.into()), |
|
428 | Err(e) => return Err(e.into()), | |
412 | }; |
|
429 | }; | |
413 |
OwningDirstateMap::new_v2( |
|
430 | OwningDirstateMap::new_v2( | |
|
431 | contents, data_size, metadata, uuid, identity, | |||
|
432 | ) | |||
414 | } else { |
|
433 | } else { | |
415 | match self |
|
434 | match self | |
416 | .hg_vfs() |
|
435 | .hg_vfs() | |
@@ -418,7 +437,7 b' impl Repo {' | |||||
418 | .io_not_found_as_none() |
|
437 | .io_not_found_as_none() | |
419 | { |
|
438 | { | |
420 | Ok(Some(data_mmap)) => OwningDirstateMap::new_v2( |
|
439 | Ok(Some(data_mmap)) => OwningDirstateMap::new_v2( | |
421 | data_mmap, data_size, metadata, uuid, |
|
440 | data_mmap, data_size, metadata, uuid, identity, | |
422 | ), |
|
441 | ), | |
423 | Ok(None) => { |
|
442 | Ok(None) => { | |
424 | // Race where the data file was deleted right after we |
|
443 | // Race where the data file was deleted right after we | |
@@ -534,12 +553,15 b' impl Repo {' | |||||
534 | // it’s unset |
|
553 | // it’s unset | |
535 | let parents = self.dirstate_parents()?; |
|
554 | let parents = self.dirstate_parents()?; | |
536 | let (packed_dirstate, old_uuid_to_remove) = if self.has_dirstate_v2() { |
|
555 | let (packed_dirstate, old_uuid_to_remove) = if self.has_dirstate_v2() { | |
537 | let (uuid, data_size) = self.get_dirstate_data_file_integrity()?; |
|
556 | let (identity, uuid, data_size) = | |
|
557 | self.get_dirstate_data_file_integrity()?; | |||
|
558 | let identity_changed = identity != map.old_identity(); | |||
538 | let uuid_changed = uuid.as_deref() != map.old_uuid(); |
|
559 | let uuid_changed = uuid.as_deref() != map.old_uuid(); | |
539 | let data_length_changed = data_size != map.old_data_size(); |
|
560 | let data_length_changed = data_size != map.old_data_size(); | |
540 |
|
561 | |||
541 | if uuid_changed || data_length_changed { |
|
562 | if identity_changed || uuid_changed || data_length_changed { | |
542 |
// If uuid or length changed since |
|
563 | // If any of identity, uuid or length have changed since | |
|
564 | // last disk read, don't write. | |||
543 | // This is fine because either we're in a command that doesn't |
|
565 | // This is fine because either we're in a command that doesn't | |
544 | // write anything too important (like `hg status`), or we're in |
|
566 | // write anything too important (like `hg status`), or we're in | |
545 | // `hg add` and we're supposed to have taken the lock before |
|
567 | // `hg add` and we're supposed to have taken the lock before | |
@@ -636,6 +658,22 b' impl Repo {' | |||||
636 |
|
658 | |||
637 | (packed_dirstate, old_uuid) |
|
659 | (packed_dirstate, old_uuid) | |
638 | } else { |
|
660 | } else { | |
|
661 | let identity = self.dirstate_identity()?; | |||
|
662 | if identity != map.old_identity() { | |||
|
663 | // If identity changed since last disk read, don't write. | |||
|
664 | // This is fine because either we're in a command that doesn't | |||
|
665 | // write anything too important (like `hg status`), or we're in | |||
|
666 | // `hg add` and we're supposed to have taken the lock before | |||
|
667 | // reading anyway. | |||
|
668 | // | |||
|
669 | // TODO complain loudly if we've changed anything important | |||
|
670 | // without taking the lock. | |||
|
671 | // (see `hg help config.format.use-dirstate-tracked-hint`) | |||
|
672 | log::debug!( | |||
|
673 | "dirstate has changed since last read, not updating." | |||
|
674 | ); | |||
|
675 | return Ok(()); | |||
|
676 | } | |||
639 | (map.pack_v1(parents)?, None) |
|
677 | (map.pack_v1(parents)?, None) | |
640 | }; |
|
678 | }; | |
641 |
|
679 |
@@ -49,9 +49,10 b' py_class!(pub class DirstateMap |py| {' | |||||
49 | @staticmethod |
|
49 | @staticmethod | |
50 | def new_v1( |
|
50 | def new_v1( | |
51 | on_disk: PyBytes, |
|
51 | on_disk: PyBytes, | |
|
52 | identity: Option<u64>, | |||
52 | ) -> PyResult<PyObject> { |
|
53 | ) -> PyResult<PyObject> { | |
53 | let on_disk = PyBytesDeref::new(py, on_disk); |
|
54 | let on_disk = PyBytesDeref::new(py, on_disk); | |
54 | let (map, parents) = OwningDirstateMap::new_v1(on_disk) |
|
55 | let (map, parents) = OwningDirstateMap::new_v1(on_disk, identity) | |
55 | .map_err(|e| dirstate_error(py, e))?; |
|
56 | .map_err(|e| dirstate_error(py, e))?; | |
56 | let map = Self::create_instance(py, map)?; |
|
57 | let map = Self::create_instance(py, map)?; | |
57 | let p1 = PyBytes::new(py, parents.p1.as_bytes()); |
|
58 | let p1 = PyBytes::new(py, parents.p1.as_bytes()); | |
@@ -67,6 +68,7 b' py_class!(pub class DirstateMap |py| {' | |||||
67 | data_size: usize, |
|
68 | data_size: usize, | |
68 | tree_metadata: PyBytes, |
|
69 | tree_metadata: PyBytes, | |
69 | uuid: PyBytes, |
|
70 | uuid: PyBytes, | |
|
71 | identity: Option<u64>, | |||
70 | ) -> PyResult<PyObject> { |
|
72 | ) -> PyResult<PyObject> { | |
71 | let dirstate_error = |e: DirstateError| { |
|
73 | let dirstate_error = |e: DirstateError| { | |
72 | PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e)) |
|
74 | PyErr::new::<exc::OSError, _>(py, format!("Dirstate error: {:?}", e)) | |
@@ -74,7 +76,11 b' py_class!(pub class DirstateMap |py| {' | |||||
74 | let on_disk = PyBytesDeref::new(py, on_disk); |
|
76 | let on_disk = PyBytesDeref::new(py, on_disk); | |
75 | let uuid = uuid.data(py); |
|
77 | let uuid = uuid.data(py); | |
76 | let map = OwningDirstateMap::new_v2( |
|
78 | let map = OwningDirstateMap::new_v2( | |
77 | on_disk, data_size, tree_metadata.data(py), uuid.to_owned(), |
|
79 | on_disk, | |
|
80 | data_size, | |||
|
81 | tree_metadata.data(py), | |||
|
82 | uuid.to_owned(), | |||
|
83 | identity, | |||
78 | ).map_err(dirstate_error)?; |
|
84 | ).map_err(dirstate_error)?; | |
79 | let map = Self::create_instance(py, map)?; |
|
85 | let map = Self::create_instance(py, map)?; | |
80 | Ok(map.into_object()) |
|
86 | Ok(map.into_object()) |
@@ -242,12 +242,9 b' Add a file' | |||||
242 | The file should in a "added" state |
|
242 | The file should in a "added" state | |
243 |
|
243 | |||
244 | $ hg status |
|
244 | $ hg status | |
245 | A dir/n (no-rhg dirstate-v1 !) |
|
245 | A dir/n | |
246 | A dir/n (no-dirstate-v1 !) |
|
|||
247 | A dir/n (missing-correct-output rhg dirstate-v1 !) |
|
|||
248 | A dir/o |
|
246 | A dir/o | |
249 | R dir/nested/m |
|
247 | R dir/nested/m | |
250 | ? dir/n (known-bad-output rhg dirstate-v1 !) |
|
|||
251 |
? |
|
248 | ? p | |
252 |
? |
|
249 | ? q | |
253 |
|
250 | |||
@@ -289,22 +286,6 b' Add a file and force the data file rewri' | |||||
289 |
|
286 | |||
290 | The parent must change and the status should be clean |
|
287 | The parent must change and the status should be clean | |
291 |
|
288 | |||
292 | # XXX rhg misbehaves here |
|
|||
293 | #if rhg dirstate-v1 |
|
|||
294 | $ hg summary |
|
|||
295 | parent: 1:c349430a1631 |
|
|||
296 | more files to have two commits |
|
|||
297 | branch: default |
|
|||
298 | commit: 1 added, 1 removed, 3 unknown (new branch head) |
|
|||
299 | update: 1 new changesets (update) |
|
|||
300 | phases: 3 draft |
|
|||
301 | $ hg status |
|
|||
302 | A dir/o |
|
|||
303 | R dir/nested/m |
|
|||
304 | ? dir/n |
|
|||
305 | ? p |
|
|||
306 | ? q |
|
|||
307 | #else |
|
|||
308 | $ hg summary |
|
289 | $ hg summary | |
309 | parent: 2:2e3b442a2fd4 tip |
|
290 | parent: 2:2e3b442a2fd4 tip | |
310 | created-during-status |
|
291 | created-during-status | |
@@ -317,7 +298,6 b' The parent must change and the status sh' | |||||
317 | ? dir/n |
|
298 | ? dir/n | |
318 | ? p |
|
299 | ? p | |
319 | ? q |
|
300 | ? q | |
320 | #endif |
|
|||
321 |
|
|
301 | ||
322 | The status process should return a consistent result and not crash. |
|
302 | The status process should return a consistent result and not crash. | |
323 |
|
303 | |||
@@ -416,9 +396,7 b' touch g' | |||||
416 | the first update should be on disk |
|
396 | the first update should be on disk | |
417 |
|
397 | |||
418 | $ hg debugstate --all | grep "g" |
|
398 | $ hg debugstate --all | grep "g" | |
419 |
n 644 0 2000-01-01 00: |
|
399 | n 644 0 2000-01-01 00:25:00 g | |
420 | n 644 0 2000-01-01 00:25:00 g (rhg no-dirstate-v1 !) |
|
|||
421 | n 644 0 2000-01-01 00:25:00 g (no-rhg !) |
|
|||
422 |
|
400 | |||
423 | The status process should return a consistent result and not crash. |
|
401 | The status process should return a consistent result and not crash. | |
424 |
|
402 |
General Comments 0
You need to be logged in to leave comments.
Login now