##// END OF EJS Templates
dirstate: remove need_delay logic...
Raphaël Gomès -
r49215:2b5d1618 default draft
parent child Browse files
Show More
@@ -320,21 +320,6 b' static PyObject *dirstate_item_v1_mtime('
320 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
320 return PyInt_FromLong(dirstate_item_c_v1_mtime(self));
321 };
321 };
322
322
323 static PyObject *dirstate_item_need_delay(dirstateItemObject *self,
324 PyObject *now)
325 {
326 int now_s;
327 int now_ns;
328 if (!PyArg_ParseTuple(now, "ii", &now_s, &now_ns)) {
329 return NULL;
330 }
331 if (dirstate_item_c_v1_state(self) == 'n' && self->mtime_s == now_s) {
332 Py_RETURN_TRUE;
333 } else {
334 Py_RETURN_FALSE;
335 }
336 };
337
338 static PyObject *dirstate_item_mtime_likely_equal_to(dirstateItemObject *self,
323 static PyObject *dirstate_item_mtime_likely_equal_to(dirstateItemObject *self,
339 PyObject *other)
324 PyObject *other)
340 {
325 {
@@ -548,8 +533,6 b' static PyMethodDef dirstate_item_methods'
548 "return a \"size\" suitable for v1 serialization"},
533 "return a \"size\" suitable for v1 serialization"},
549 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
534 {"v1_mtime", (PyCFunction)dirstate_item_v1_mtime, METH_NOARGS,
550 "return a \"mtime\" suitable for v1 serialization"},
535 "return a \"mtime\" suitable for v1 serialization"},
551 {"need_delay", (PyCFunction)dirstate_item_need_delay, METH_O,
552 "True if the stored mtime would be ambiguous with the current time"},
553 {"mtime_likely_equal_to", (PyCFunction)dirstate_item_mtime_likely_equal_to,
536 {"mtime_likely_equal_to", (PyCFunction)dirstate_item_mtime_likely_equal_to,
554 METH_O, "True if the stored mtime is likely equal to the given mtime"},
537 METH_O, "True if the stored mtime is likely equal to the given mtime"},
555 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
538 {"from_v1_data", (PyCFunction)dirstate_item_from_v1_meth,
@@ -922,12 +905,9 b' static PyObject *pack_dirstate(PyObject '
922 Py_ssize_t nbytes, pos, l;
905 Py_ssize_t nbytes, pos, l;
923 PyObject *k, *v = NULL, *pn;
906 PyObject *k, *v = NULL, *pn;
924 char *p, *s;
907 char *p, *s;
925 int now_s;
926 int now_ns;
927
908
928 if (!PyArg_ParseTuple(args, "O!O!O!(ii):pack_dirstate", &PyDict_Type,
909 if (!PyArg_ParseTuple(args, "O!O!O!:pack_dirstate", &PyDict_Type, &map,
929 &map, &PyDict_Type, &copymap, &PyTuple_Type, &pl,
910 &PyDict_Type, &copymap, &PyTuple_Type, &pl)) {
930 &now_s, &now_ns)) {
931 return NULL;
911 return NULL;
932 }
912 }
933
913
@@ -996,21 +976,6 b' static PyObject *pack_dirstate(PyObject '
996 mode = dirstate_item_c_v1_mode(tuple);
976 mode = dirstate_item_c_v1_mode(tuple);
997 size = dirstate_item_c_v1_size(tuple);
977 size = dirstate_item_c_v1_size(tuple);
998 mtime = dirstate_item_c_v1_mtime(tuple);
978 mtime = dirstate_item_c_v1_mtime(tuple);
999 if (state == 'n' && tuple->mtime_s == now_s) {
1000 /* See pure/parsers.py:pack_dirstate for why we do
1001 * this. */
1002 mtime = -1;
1003 mtime_unset = (PyObject *)dirstate_item_from_v1_data(
1004 state, mode, size, mtime);
1005 if (!mtime_unset) {
1006 goto bail;
1007 }
1008 if (PyDict_SetItem(map, k, mtime_unset) == -1) {
1009 goto bail;
1010 }
1011 Py_DECREF(mtime_unset);
1012 mtime_unset = NULL;
1013 }
1014 *p++ = state;
979 *p++ = state;
1015 putbe32((uint32_t)mode, p);
980 putbe32((uint32_t)mode, p);
1016 putbe32((uint32_t)size, p + 4);
981 putbe32((uint32_t)size, p + 4);
@@ -779,25 +779,6 b' class dirstate(object):'
779 # filesystem's notion of 'now'
779 # filesystem's notion of 'now'
780 now = timestamp.mtime_of(util.fstat(st))
780 now = timestamp.mtime_of(util.fstat(st))
781
781
782 # enough 'delaywrite' prevents 'pack_dirstate' from dropping
783 # timestamp of each entries in dirstate, because of 'now > mtime'
784 delaywrite = self._ui.configint(b'debug', b'dirstate.delaywrite')
785 if delaywrite > 0:
786 # do we have any files to delay for?
787 for f, e in pycompat.iteritems(self._map):
788 if e.need_delay(now):
789 import time # to avoid useless import
790
791 # rather than sleep n seconds, sleep until the next
792 # multiple of n seconds
793 clock = time.time()
794 start = int(clock) - (int(clock) % delaywrite)
795 end = start + delaywrite
796 time.sleep(end - clock)
797 # trust our estimate that the end is near now
798 now = timestamp.timestamp((end, 0))
799 break
800
801 self._map.write(tr, st, now)
782 self._map.write(tr, st, now)
802 self._dirty = False
783 self._dirty = False
803
784
@@ -446,11 +446,11 b' class dirstatemap(_dirstatemapcommon):'
446
446
447 def write(self, tr, st, now):
447 def write(self, tr, st, now):
448 if self._use_dirstate_v2:
448 if self._use_dirstate_v2:
449 packed, meta = v2.pack_dirstate(self._map, self.copymap, now)
449 packed, meta = v2.pack_dirstate(self._map, self.copymap)
450 self.write_v2_no_append(tr, st, meta, packed)
450 self.write_v2_no_append(tr, st, meta, packed)
451 else:
451 else:
452 packed = parsers.pack_dirstate(
452 packed = parsers.pack_dirstate(
453 self._map, self.copymap, self.parents(), now
453 self._map, self.copymap, self.parents()
454 )
454 )
455 st.write(packed)
455 st.write(packed)
456 st.close()
456 st.close()
@@ -658,7 +658,7 b' if rustmod is not None:'
658 def write(self, tr, st, now):
658 def write(self, tr, st, now):
659 if not self._use_dirstate_v2:
659 if not self._use_dirstate_v2:
660 p1, p2 = self.parents()
660 p1, p2 = self.parents()
661 packed = self._map.write_v1(p1, p2, now)
661 packed = self._map.write_v1(p1, p2)
662 st.write(packed)
662 st.write(packed)
663 st.close()
663 st.close()
664 self._dirtyparents = False
664 self._dirtyparents = False
@@ -666,7 +666,7 b' if rustmod is not None:'
666
666
667 # We can only append to an existing data file if there is one
667 # We can only append to an existing data file if there is one
668 can_append = self.docket.uuid is not None
668 can_append = self.docket.uuid is not None
669 packed, meta, append = self._map.write_v2(now, can_append)
669 packed, meta, append = self._map.write_v2(can_append)
670 if append:
670 if append:
671 docket = self.docket
671 docket = self.docket
672 data_filename = docket.data_filename()
672 data_filename = docket.data_filename()
@@ -174,12 +174,10 b' class Node(object):'
174 )
174 )
175
175
176
176
177 def pack_dirstate(map, copy_map, now):
177 def pack_dirstate(map, copy_map):
178 """
178 """
179 Pack `map` and `copy_map` into the dirstate v2 binary format and return
179 Pack `map` and `copy_map` into the dirstate v2 binary format and return
180 the bytearray.
180 the bytearray.
181 `now` is a timestamp of the current filesystem time used to detect race
182 conditions in writing the dirstate to disk, see inline comment.
183
181
184 The on-disk format expects a tree-like structure where the leaves are
182 The on-disk format expects a tree-like structure where the leaves are
185 written first (and sorted per-directory), going up levels until the root
183 written first (and sorted per-directory), going up levels until the root
@@ -284,17 +282,6 b' def pack_dirstate(map, copy_map, now):'
284 stack.append(current_node)
282 stack.append(current_node)
285
283
286 for index, (path, entry) in enumerate(sorted_map, 1):
284 for index, (path, entry) in enumerate(sorted_map, 1):
287 if entry.need_delay(now):
288 # The file was last modified "simultaneously" with the current
289 # write to dirstate (i.e. within the same second for file-
290 # systems with a granularity of 1 sec). This commonly happens
291 # for at least a couple of files on 'update'.
292 # The user could change the file without changing its size
293 # within the same second. Invalidate the file's mtime in
294 # dirstate, forcing future 'status' calls to compare the
295 # contents of the file if the size is the same. This prevents
296 # mistakenly treating such files as clean.
297 entry.set_possibly_dirty()
298 nodes_with_entry_count += 1
285 nodes_with_entry_count += 1
299 if path in copy_map:
286 if path in copy_map:
300 nodes_with_copy_source_count += 1
287 nodes_with_copy_source_count += 1
@@ -536,10 +536,6 b' class DirstateItem(object):'
536 else:
536 else:
537 return self._mtime_s
537 return self._mtime_s
538
538
539 def need_delay(self, now):
540 """True if the stored mtime would be ambiguous with the current time"""
541 return self.v1_state() == b'n' and self._mtime_s == now[0]
542
543
539
544 def gettype(q):
540 def gettype(q):
545 return int(q & 0xFFFF)
541 return int(q & 0xFFFF)
@@ -905,23 +901,11 b' def parse_dirstate(dmap, copymap, st):'
905 return parents
901 return parents
906
902
907
903
908 def pack_dirstate(dmap, copymap, pl, now):
904 def pack_dirstate(dmap, copymap, pl):
909 cs = stringio()
905 cs = stringio()
910 write = cs.write
906 write = cs.write
911 write(b"".join(pl))
907 write(b"".join(pl))
912 for f, e in pycompat.iteritems(dmap):
908 for f, e in pycompat.iteritems(dmap):
913 if e.need_delay(now):
914 # The file was last modified "simultaneously" with the current
915 # write to dirstate (i.e. within the same second for file-
916 # systems with a granularity of 1 sec). This commonly happens
917 # for at least a couple of files on 'update'.
918 # The user could change the file without changing its size
919 # within the same second. Invalidate the file's mtime in
920 # dirstate, forcing future 'status' calls to compare the
921 # contents of the file if the size is the same. This prevents
922 # mistakenly treating such files as clean.
923 e.set_possibly_dirty()
924
925 if f in copymap:
909 if f in copymap:
926 f = b"%s\0%s" % (f, copymap[f])
910 f = b"%s\0%s" % (f, copymap[f])
927 e = _pack(
911 e = _pack(
@@ -590,16 +590,6 b' impl DirstateEntry {'
590 pub fn debug_tuple(&self) -> (u8, i32, i32, i32) {
590 pub fn debug_tuple(&self) -> (u8, i32, i32, i32) {
591 (self.state().into(), self.mode(), self.size(), self.mtime())
591 (self.state().into(), self.mode(), self.size(), self.mtime())
592 }
592 }
593
594 /// True if the stored mtime would be ambiguous with the current time
595 pub fn need_delay(&self, now: TruncatedTimestamp) -> bool {
596 if let Some(mtime) = self.mtime {
597 self.state() == EntryState::Normal
598 && mtime.truncated_seconds() == now.truncated_seconds()
599 } else {
600 false
601 }
602 }
603 }
593 }
604
594
605 impl EntryState {
595 impl EntryState {
@@ -677,25 +677,6 b" impl<'on_disk> DirstateMap<'on_disk> {"
677 })
677 })
678 }
678 }
679
679
680 fn clear_known_ambiguous_mtimes(
681 &mut self,
682 paths: &[impl AsRef<HgPath>],
683 ) -> Result<(), DirstateV2ParseError> {
684 for path in paths {
685 if let Some(node) = Self::get_node_mut(
686 self.on_disk,
687 &mut self.unreachable_bytes,
688 &mut self.root,
689 path.as_ref(),
690 )? {
691 if let NodeData::Entry(entry) = &mut node.data {
692 entry.set_possibly_dirty();
693 }
694 }
695 }
696 Ok(())
697 }
698
699 fn count_dropped_path(unreachable_bytes: &mut u32, path: &Cow<HgPath>) {
680 fn count_dropped_path(unreachable_bytes: &mut u32, path: &Cow<HgPath>) {
700 if let Cow::Borrowed(path) = path {
681 if let Cow::Borrowed(path) = path {
701 *unreachable_bytes += path.len() as u32
682 *unreachable_bytes += path.len() as u32
@@ -930,29 +911,20 b' impl OwningDirstateMap {'
930 pub fn pack_v1(
911 pub fn pack_v1(
931 &mut self,
912 &mut self,
932 parents: DirstateParents,
913 parents: DirstateParents,
933 now: TruncatedTimestamp,
934 ) -> Result<Vec<u8>, DirstateError> {
914 ) -> Result<Vec<u8>, DirstateError> {
935 let map = self.get_map_mut();
915 let map = self.get_map_mut();
936 let mut ambiguous_mtimes = Vec::new();
937 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
916 // Optizimation (to be measured?): pre-compute size to avoid `Vec`
938 // reallocations
917 // reallocations
939 let mut size = parents.as_bytes().len();
918 let mut size = parents.as_bytes().len();
940 for node in map.iter_nodes() {
919 for node in map.iter_nodes() {
941 let node = node?;
920 let node = node?;
942 if let Some(entry) = node.entry()? {
921 if node.entry()?.is_some() {
943 size += packed_entry_size(
922 size += packed_entry_size(
944 node.full_path(map.on_disk)?,
923 node.full_path(map.on_disk)?,
945 node.copy_source(map.on_disk)?,
924 node.copy_source(map.on_disk)?,
946 );
925 );
947 if entry.need_delay(now) {
948 ambiguous_mtimes.push(
949 node.full_path_borrowed(map.on_disk)?
950 .detach_from_tree(),
951 )
952 }
953 }
926 }
954 }
927 }
955 map.clear_known_ambiguous_mtimes(&ambiguous_mtimes)?;
956
928
957 let mut packed = Vec::with_capacity(size);
929 let mut packed = Vec::with_capacity(size);
958 packed.extend(parents.as_bytes());
930 packed.extend(parents.as_bytes());
@@ -978,26 +950,9 b' impl OwningDirstateMap {'
978 #[timed]
950 #[timed]
979 pub fn pack_v2(
951 pub fn pack_v2(
980 &mut self,
952 &mut self,
981 now: TruncatedTimestamp,
982 can_append: bool,
953 can_append: bool,
983 ) -> Result<(Vec<u8>, Vec<u8>, bool), DirstateError> {
954 ) -> Result<(Vec<u8>, Vec<u8>, bool), DirstateError> {
984 let map = self.get_map_mut();
955 let map = self.get_map_mut();
985 let mut paths = Vec::new();
986 for node in map.iter_nodes() {
987 let node = node?;
988 if let Some(entry) = node.entry()? {
989 if entry.need_delay(now) {
990 paths.push(
991 node.full_path_borrowed(map.on_disk)?
992 .detach_from_tree(),
993 )
994 }
995 }
996 }
997 // Borrow of `self` ends here since we collect cloned paths
998
999 map.clear_known_ambiguous_mtimes(&paths)?;
1000
1001 on_disk::write(map, can_append)
956 on_disk::write(map, can_append)
1002 }
957 }
1003
958
@@ -18,7 +18,7 b' use cpython::{'
18
18
19 use crate::{
19 use crate::{
20 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
20 dirstate::copymap::{CopyMap, CopyMapItemsIterator, CopyMapKeysIterator},
21 dirstate::item::{timestamp, DirstateItem},
21 dirstate::item::DirstateItem,
22 pybytes_deref::PyBytesDeref,
22 pybytes_deref::PyBytesDeref,
23 };
23 };
24 use hg::{
24 use hg::{
@@ -194,16 +194,13 b' py_class!(pub class DirstateMap |py| {'
194 &self,
194 &self,
195 p1: PyObject,
195 p1: PyObject,
196 p2: PyObject,
196 p2: PyObject,
197 now: (u32, u32)
198 ) -> PyResult<PyBytes> {
197 ) -> PyResult<PyBytes> {
199 let now = timestamp(py, now)?;
200
201 let mut inner = self.inner(py).borrow_mut();
198 let mut inner = self.inner(py).borrow_mut();
202 let parents = DirstateParents {
199 let parents = DirstateParents {
203 p1: extract_node_id(py, &p1)?,
200 p1: extract_node_id(py, &p1)?,
204 p2: extract_node_id(py, &p2)?,
201 p2: extract_node_id(py, &p2)?,
205 };
202 };
206 let result = inner.pack_v1(parents, now);
203 let result = inner.pack_v1(parents);
207 match result {
204 match result {
208 Ok(packed) => Ok(PyBytes::new(py, &packed)),
205 Ok(packed) => Ok(PyBytes::new(py, &packed)),
209 Err(_) => Err(PyErr::new::<exc::OSError, _>(
206 Err(_) => Err(PyErr::new::<exc::OSError, _>(
@@ -218,13 +215,10 b' py_class!(pub class DirstateMap |py| {'
218 /// instead of written to a new data file (False).
215 /// instead of written to a new data file (False).
219 def write_v2(
216 def write_v2(
220 &self,
217 &self,
221 now: (u32, u32),
222 can_append: bool,
218 can_append: bool,
223 ) -> PyResult<PyObject> {
219 ) -> PyResult<PyObject> {
224 let now = timestamp(py, now)?;
225
226 let mut inner = self.inner(py).borrow_mut();
220 let mut inner = self.inner(py).borrow_mut();
227 let result = inner.pack_v2(now, can_append);
221 let result = inner.pack_v2(can_append);
228 match result {
222 match result {
229 Ok((packed, tree_metadata, append)) => {
223 Ok((packed, tree_metadata, append)) => {
230 let packed = PyBytes::new(py, &packed);
224 let packed = PyBytes::new(py, &packed);
@@ -194,11 +194,6 b' py_class!(pub class DirstateItem |py| {'
194 Ok(mtime)
194 Ok(mtime)
195 }
195 }
196
196
197 def need_delay(&self, now: (u32, u32)) -> PyResult<bool> {
198 let now = timestamp(py, now)?;
199 Ok(self.entry(py).get().need_delay(now))
200 }
201
202 def mtime_likely_equal_to(&self, other: (u32, u32)) -> PyResult<bool> {
197 def mtime_likely_equal_to(&self, other: (u32, u32)) -> PyResult<bool> {
203 if let Some(mtime) = self.entry(py).get().truncated_mtime() {
198 if let Some(mtime) = self.entry(py).get().truncated_mtime() {
204 Ok(mtime.likely_equal(timestamp(py, other)?))
199 Ok(mtime.likely_equal(timestamp(py, other)?))
@@ -37,14 +37,8 b" parsers = policy.importmod('parsers')"
37 has_rust_dirstate = policy.importrust('dirstate') is not None
37 has_rust_dirstate = policy.importrust('dirstate') is not None
38
38
39
39
40 def pack_dirstate(fakenow, orig, dmap, copymap, pl, now):
40 def pack_dirstate(orig, dmap, copymap, pl):
41 # execute what original parsers.pack_dirstate should do actually
41 return orig(dmap, copymap, pl)
42 # for consistency
43 for f, e in dmap.items():
44 if e.need_delay(now):
45 e.set_possibly_dirty()
46
47 return orig(dmap, copymap, pl, fakenow)
48
42
49
43
50 def fakewrite(ui, func):
44 def fakewrite(ui, func):
@@ -67,19 +61,19 b' def fakewrite(ui, func):'
67 # The Rust implementation does not use public parse/pack dirstate
61 # The Rust implementation does not use public parse/pack dirstate
68 # to prevent conversion round-trips
62 # to prevent conversion round-trips
69 orig_dirstatemap_write = dirstatemapmod.dirstatemap.write
63 orig_dirstatemap_write = dirstatemapmod.dirstatemap.write
70 wrapper = lambda self, tr, st, now: orig_dirstatemap_write(
64 wrapper = lambda self, tr, st: orig_dirstatemap_write(self, tr, st)
71 self, tr, st, fakenow
72 )
73 dirstatemapmod.dirstatemap.write = wrapper
65 dirstatemapmod.dirstatemap.write = wrapper
74
66
75 orig_get_fs_now = timestamp.get_fs_now
67 orig_get_fs_now = timestamp.get_fs_now
76 wrapper = lambda *args: pack_dirstate(fakenow, orig_pack_dirstate, *args)
68 wrapper = lambda *args: pack_dirstate(orig_pack_dirstate, *args)
77
69
78 orig_module = parsers
70 orig_module = parsers
79 orig_pack_dirstate = parsers.pack_dirstate
71 orig_pack_dirstate = parsers.pack_dirstate
80
72
81 orig_module.pack_dirstate = wrapper
73 orig_module.pack_dirstate = wrapper
82 timestamp.get_fs_now = lambda *args: fakenow
74 timestamp.get_fs_now = (
75 lambda *args: fakenow
76 ) # XXX useless for this purpose now
83 try:
77 try:
84 return func()
78 return func()
85 finally:
79 finally:
@@ -349,6 +349,10 b' Test that updated files are treated as "'
349 aren't changed), even if none of mode, size and timestamp of them
349 aren't changed), even if none of mode, size and timestamp of them
350 isn't changed on the filesystem (see also issue4583).
350 isn't changed on the filesystem (see also issue4583).
351
351
352 This test is now "best effort" as the mechanism to prevent such race are
353 getting better, it get more complicated to test a specific scenario that would
354 trigger it. If you see flakyness here, there is a race.
355
352 $ cat > $TESTTMP/abort.py <<EOF
356 $ cat > $TESTTMP/abort.py <<EOF
353 > from __future__ import absolute_import
357 > from __future__ import absolute_import
354 > # emulate aborting before "recordupdates()". in this case, files
358 > # emulate aborting before "recordupdates()". in this case, files
@@ -365,13 +369,6 b" isn't changed on the filesystem (see als"
365 > extensions.wrapfunction(merge, "applyupdates", applyupdates)
369 > extensions.wrapfunction(merge, "applyupdates", applyupdates)
366 > EOF
370 > EOF
367
371
368 $ cat >> .hg/hgrc <<EOF
369 > [fakedirstatewritetime]
370 > # emulate invoking dirstate.write() via repo.status()
371 > # at 2000-01-01 00:00
372 > fakenow = 200001010000
373 > EOF
374
375 (file gotten from other revision)
372 (file gotten from other revision)
376
373
377 $ hg update -q -C 2
374 $ hg update -q -C 2
@@ -381,12 +378,8 b" isn't changed on the filesystem (see als"
381 $ hg update -q -C 3
378 $ hg update -q -C 3
382 $ cat b
379 $ cat b
383 This is file b1
380 This is file b1
384 $ touch -t 200001010000 b
385 $ hg debugrebuildstate
386
387 $ cat >> .hg/hgrc <<EOF
381 $ cat >> .hg/hgrc <<EOF
388 > [extensions]
382 > [extensions]
389 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
390 > abort = $TESTTMP/abort.py
383 > abort = $TESTTMP/abort.py
391 > EOF
384 > EOF
392 $ hg merge 5
385 $ hg merge 5
@@ -394,13 +387,11 b" isn't changed on the filesystem (see als"
394 [255]
387 [255]
395 $ cat >> .hg/hgrc <<EOF
388 $ cat >> .hg/hgrc <<EOF
396 > [extensions]
389 > [extensions]
397 > fakedirstatewritetime = !
398 > abort = !
390 > abort = !
399 > EOF
391 > EOF
400
392
401 $ cat b
393 $ cat b
402 THIS IS FILE B5
394 THIS IS FILE B5
403 $ touch -t 200001010000 b
404 $ hg status -A b
395 $ hg status -A b
405 M b
396 M b
406
397
@@ -413,12 +404,10 b" isn't changed on the filesystem (see als"
413
404
414 $ cat b
405 $ cat b
415 this is file b6
406 this is file b6
416 $ touch -t 200001010000 b
407 $ hg status
417 $ hg debugrebuildstate
418
408
419 $ cat >> .hg/hgrc <<EOF
409 $ cat >> .hg/hgrc <<EOF
420 > [extensions]
410 > [extensions]
421 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
422 > abort = $TESTTMP/abort.py
411 > abort = $TESTTMP/abort.py
423 > EOF
412 > EOF
424 $ hg merge --tool internal:other 5
413 $ hg merge --tool internal:other 5
@@ -426,13 +415,11 b" isn't changed on the filesystem (see als"
426 [255]
415 [255]
427 $ cat >> .hg/hgrc <<EOF
416 $ cat >> .hg/hgrc <<EOF
428 > [extensions]
417 > [extensions]
429 > fakedirstatewritetime = !
430 > abort = !
418 > abort = !
431 > EOF
419 > EOF
432
420
433 $ cat b
421 $ cat b
434 THIS IS FILE B5
422 THIS IS FILE B5
435 $ touch -t 200001010000 b
436 $ hg status -A b
423 $ hg status -A b
437 M b
424 M b
438
425
@@ -1021,37 +1021,21 b' Issue1977: multirepo push should fail if'
1021
1021
1022 test if untracked file is not overwritten
1022 test if untracked file is not overwritten
1023
1023
1024 (this also tests that updated .hgsubstate is treated as "modified",
1024 (this tests also has a change to update .hgsubstate and merge it within the
1025 when 'merge.update()' is aborted before 'merge.recordupdates()', even
1025 same second. It should mark is are modified , even if none of mode, size and
1026 if none of mode, size and timestamp of it isn't changed on the
1026 timestamp of it isn't changed on the filesystem (see also issue4583))
1027 filesystem (see also issue4583))
1028
1027
1029 $ echo issue3276_ok > repo/s/b
1028 $ echo issue3276_ok > repo/s/b
1030 $ hg -R repo2 push -f -q
1029 $ hg -R repo2 push -f -q
1031 $ touch -t 200001010000 repo/.hgsubstate
1032
1030
1033 $ cat >> repo/.hg/hgrc <<EOF
1034 > [fakedirstatewritetime]
1035 > # emulate invoking dirstate.write() via repo.status()
1036 > # at 2000-01-01 00:00
1037 > fakenow = 200001010000
1038 >
1039 > [extensions]
1040 > fakedirstatewritetime = $TESTDIR/fakedirstatewritetime.py
1041 > EOF
1042 $ hg -R repo update
1031 $ hg -R repo update
1043 b: untracked file differs
1032 b: untracked file differs
1044 abort: untracked files in working directory differ from files in requested revision (in subrepository "s")
1033 abort: untracked files in working directory differ from files in requested revision (in subrepository "s")
1045 [255]
1034 [255]
1046 $ cat >> repo/.hg/hgrc <<EOF
1047 > [extensions]
1048 > fakedirstatewritetime = !
1049 > EOF
1050
1035
1051 $ cat repo/s/b
1036 $ cat repo/s/b
1052 issue3276_ok
1037 issue3276_ok
1053 $ rm repo/s/b
1038 $ rm repo/s/b
1054 $ touch -t 200001010000 repo/.hgsubstate
1055 $ hg -R repo revert --all
1039 $ hg -R repo revert --all
1056 reverting repo/.hgsubstate
1040 reverting repo/.hgsubstate
1057 reverting subrepo s
1041 reverting subrepo s
General Comments 0
You need to be logged in to leave comments. Login now