128 self._parentwriters = 0 |
128 self._parentwriters = 0 |
129 self._filename = b'dirstate' |
129 self._filename = b'dirstate' |
130 self._pendingfilename = b'%s.pending' % self._filename |
130 self._pendingfilename = b'%s.pending' % self._filename |
131 self._plchangecallbacks = {} |
131 self._plchangecallbacks = {} |
132 self._origpl = None |
132 self._origpl = None |
133 self._updatedfiles = set() |
|
134 self._mapcls = dirstatemap.dirstatemap |
133 self._mapcls = dirstatemap.dirstatemap |
135 # Access and cache cwd early, so we don't access it for the first time |
134 # Access and cache cwd early, so we don't access it for the first time |
136 # after a working-copy update caused it to not exist (accessing it then |
135 # after a working-copy update caused it to not exist (accessing it then |
137 # raises an exception). |
136 # raises an exception). |
138 self._cwd |
137 self._cwd |
444 for a in ("_map", "_branch", "_ignore"): |
442 for a in ("_map", "_branch", "_ignore"): |
445 if a in self.__dict__: |
443 if a in self.__dict__: |
446 delattr(self, a) |
444 delattr(self, a) |
447 self._lastnormaltime = 0 |
445 self._lastnormaltime = 0 |
448 self._dirty = False |
446 self._dirty = False |
449 self._updatedfiles.clear() |
|
450 self._parentwriters = 0 |
447 self._parentwriters = 0 |
451 self._origpl = None |
448 self._origpl = None |
452 |
449 |
453 def copy(self, source, dest): |
450 def copy(self, source, dest): |
454 """Mark dest as a copy of source. Unmark dest if source is None.""" |
451 """Mark dest as a copy of source. Unmark dest if source is None.""" |
455 if source == dest: |
452 if source == dest: |
456 return |
453 return |
457 self._dirty = True |
454 self._dirty = True |
458 if source is not None: |
455 if source is not None: |
459 self._map.copymap[dest] = source |
456 self._map.copymap[dest] = source |
460 self._updatedfiles.add(source) |
457 else: |
461 self._updatedfiles.add(dest) |
458 self._map.copymap.pop(dest, None) |
462 elif self._map.copymap.pop(dest, None): |
|
463 self._updatedfiles.add(dest) |
|
464 |
459 |
465 def copied(self, file): |
460 def copied(self, file): |
466 return self._map.copymap.get(file, None) |
461 return self._map.copymap.get(file, None) |
467 |
462 |
468 def copies(self): |
463 def copies(self): |
476 example by a command like `hg add X`. |
471 example by a command like `hg add X`. |
477 |
472 |
478 return True the file was previously untracked, False otherwise. |
473 return True the file was previously untracked, False otherwise. |
479 """ |
474 """ |
480 self._dirty = True |
475 self._dirty = True |
481 self._updatedfiles.add(filename) |
|
482 entry = self._map.get(filename) |
476 entry = self._map.get(filename) |
483 if entry is None or not entry.tracked: |
477 if entry is None or not entry.tracked: |
484 self._check_new_tracked_filename(filename) |
478 self._check_new_tracked_filename(filename) |
485 return self._map.set_tracked(filename) |
479 return self._map.set_tracked(filename) |
486 |
480 |
494 return True the file was previously tracked, False otherwise. |
488 return True the file was previously tracked, False otherwise. |
495 """ |
489 """ |
496 ret = self._map.set_untracked(filename) |
490 ret = self._map.set_untracked(filename) |
497 if ret: |
491 if ret: |
498 self._dirty = True |
492 self._dirty = True |
499 self._updatedfiles.add(filename) |
|
500 return ret |
493 return ret |
501 |
494 |
502 @requires_no_parents_change |
495 @requires_no_parents_change |
503 def set_clean(self, filename, parentfiledata=None): |
496 def set_clean(self, filename, parentfiledata=None): |
504 """record that the current state of the file on disk is known to be clean""" |
497 """record that the current state of the file on disk is known to be clean""" |
505 self._dirty = True |
498 self._dirty = True |
506 self._updatedfiles.add(filename) |
|
507 if parentfiledata: |
499 if parentfiledata: |
508 (mode, size, mtime) = parentfiledata |
500 (mode, size, mtime) = parentfiledata |
509 else: |
501 else: |
510 (mode, size, mtime) = self._get_filedata(filename) |
502 (mode, size, mtime) = self._get_filedata(filename) |
511 if not self._map[filename].tracked: |
503 if not self._map[filename].tracked: |
519 |
511 |
520 @requires_no_parents_change |
512 @requires_no_parents_change |
521 def set_possibly_dirty(self, filename): |
513 def set_possibly_dirty(self, filename): |
522 """record that the current state of the file on disk is unknown""" |
514 """record that the current state of the file on disk is unknown""" |
523 self._dirty = True |
515 self._dirty = True |
524 self._updatedfiles.add(filename) |
|
525 self._map.set_possibly_dirty(filename) |
516 self._map.set_possibly_dirty(filename) |
526 |
517 |
527 @requires_parents_change |
518 @requires_parents_change |
528 def update_file_p1( |
519 def update_file_p1( |
529 self, |
520 self, |
554 elif not (p1_tracked or wc_tracked): |
545 elif not (p1_tracked or wc_tracked): |
555 # the file is no longer relevant to anyone |
546 # the file is no longer relevant to anyone |
556 if self._map.get(filename) is not None: |
547 if self._map.get(filename) is not None: |
557 self._map.reset_state(filename) |
548 self._map.reset_state(filename) |
558 self._dirty = True |
549 self._dirty = True |
559 self._updatedfiles.add(filename) |
|
560 elif (not p1_tracked) and wc_tracked: |
550 elif (not p1_tracked) and wc_tracked: |
561 if entry is not None and entry.added: |
551 if entry is not None and entry.added: |
562 return # avoid dropping copy information (maybe?) |
552 return # avoid dropping copy information (maybe?) |
563 elif p1_tracked and not wc_tracked: |
553 elif p1_tracked and not wc_tracked: |
564 pass |
554 pass |
570 # compared to the overall update process calling this. |
560 # compared to the overall update process calling this. |
571 parentfiledata = None |
561 parentfiledata = None |
572 if wc_tracked: |
562 if wc_tracked: |
573 parentfiledata = self._get_filedata(filename) |
563 parentfiledata = self._get_filedata(filename) |
574 |
564 |
575 self._updatedfiles.add(filename) |
|
576 self._map.reset_state( |
565 self._map.reset_state( |
577 filename, |
566 filename, |
578 wc_tracked, |
567 wc_tracked, |
579 p1_tracked, |
568 p1_tracked, |
580 possibly_dirty=possibly_dirty, |
569 possibly_dirty=possibly_dirty, |
620 # note: I do not think we need to double check name clash here since we |
609 # note: I do not think we need to double check name clash here since we |
621 # are in a update/merge case that should already have taken care of |
610 # are in a update/merge case that should already have taken care of |
622 # this. The test agrees |
611 # this. The test agrees |
623 |
612 |
624 self._dirty = True |
613 self._dirty = True |
625 self._updatedfiles.add(filename) |
|
626 |
614 |
627 need_parent_file_data = ( |
615 need_parent_file_data = ( |
628 not (possibly_dirty or clean_p2 or merged) |
616 not (possibly_dirty or clean_p2 or merged) |
629 and wc_tracked |
617 and wc_tracked |
630 and p1_tracked |
618 and p1_tracked |
766 return path |
754 return path |
767 |
755 |
768 def clear(self): |
756 def clear(self): |
769 self._map.clear() |
757 self._map.clear() |
770 self._lastnormaltime = 0 |
758 self._lastnormaltime = 0 |
771 self._updatedfiles.clear() |
|
772 self._dirty = True |
759 self._dirty = True |
773 |
760 |
774 def rebuild(self, parent, allfiles, changedfiles=None): |
761 def rebuild(self, parent, allfiles, changedfiles=None): |
775 if changedfiles is None: |
762 if changedfiles is None: |
776 # Rebuild entire dirstate |
763 # Rebuild entire dirstate |
836 # See also the wiki page below for detail: |
821 # See also the wiki page below for detail: |
837 # https://www.mercurial-scm.org/wiki/DirstateTransactionPlan |
822 # https://www.mercurial-scm.org/wiki/DirstateTransactionPlan |
838 |
823 |
839 # record when mtime start to be ambiguous |
824 # record when mtime start to be ambiguous |
840 now = _getfsnow(self._opener) |
825 now = _getfsnow(self._opener) |
841 |
|
842 # emulate that all 'dirstate.normal' results are written out |
|
843 self._updatedfiles.clear() |
|
844 |
826 |
845 # delay writing in-memory changes out |
827 # delay writing in-memory changes out |
846 tr.addfilegenerator( |
828 tr.addfilegenerator( |
847 b'dirstate', |
829 b'dirstate', |
848 (self._filename,), |
830 (self._filename,), |