Show More
@@ -96,8 +96,14 b' import hashlib' | |||
|
96 | 96 | import os |
|
97 | 97 | import stat |
|
98 | 98 | import sys |
|
99 | import weakref | |
|
99 | 100 | |
|
100 | 101 | from mercurial.i18n import _ |
|
102 | from mercurial.node import ( | |
|
103 | hex, | |
|
104 | nullid, | |
|
105 | ) | |
|
106 | ||
|
101 | 107 | from mercurial import ( |
|
102 | 108 | context, |
|
103 | 109 | encoding, |
@@ -555,11 +561,12 b' class poststatus(object):' | |||
|
555 | 561 | |
|
556 | 562 | def makedirstate(repo, dirstate): |
|
557 | 563 | class fsmonitordirstate(dirstate.__class__): |
|
558 |
def _fsmonitorinit(self, |
|
|
564 | def _fsmonitorinit(self, repo): | |
|
559 | 565 | # _fsmonitordisable is used in paranoid mode |
|
560 | 566 | self._fsmonitordisable = False |
|
561 | self._fsmonitorstate = fsmonitorstate | |
|
562 | self._watchmanclient = watchmanclient | |
|
567 | self._fsmonitorstate = repo._fsmonitorstate | |
|
568 | self._watchmanclient = repo._watchmanclient | |
|
569 | self._repo = weakref.proxy(repo) | |
|
563 | 570 | |
|
564 | 571 | def walk(self, *args, **kwargs): |
|
565 | 572 | orig = super(fsmonitordirstate, self).walk |
@@ -575,8 +582,16 b' def makedirstate(repo, dirstate):' | |||
|
575 | 582 | self._fsmonitorstate.invalidate() |
|
576 | 583 | return super(fsmonitordirstate, self).invalidate(*args, **kwargs) |
|
577 | 584 | |
|
585 | if dirstate._ui.configbool( | |
|
586 | "experimental", "fsmonitor.wc_change_notify"): | |
|
587 | def setparents(self, p1, p2=nullid): | |
|
588 | with state_update(self._repo, name="hg.wc_change", | |
|
589 | oldnode=self._pl[0], newnode=p1, | |
|
590 | partial=False): | |
|
591 | return super(fsmonitordirstate, self).setparents(p1, p2) | |
|
592 | ||
|
578 | 593 | dirstate.__class__ = fsmonitordirstate |
|
579 |
dirstate._fsmonitorinit(repo |
|
|
594 | dirstate._fsmonitorinit(repo) | |
|
580 | 595 | |
|
581 | 596 | def wrapdirstate(orig, self): |
|
582 | 597 | ds = orig(self) |
@@ -607,47 +622,74 b' def wrapsymlink(orig, source, link_name)' | |||
|
607 | 622 | |
|
608 | 623 | class state_update(object): |
|
609 | 624 | ''' This context manager is responsible for dispatching the state-enter |
|
610 |
and state-leave signals to the watchman service |
|
|
625 | and state-leave signals to the watchman service. The enter and leave | |
|
626 | methods can be invoked manually (for scenarios where context manager | |
|
627 | semantics are not possible). If parameters oldnode and newnode are None, | |
|
628 | they will be populated based on current working copy in enter and | |
|
629 | leave, respectively. Similarly, if the distance is none, it will be | |
|
630 | calculated based on the oldnode and newnode in the leave method.''' | |
|
611 | 631 | |
|
612 |
def __init__(self, repo, node, distance, |
|
|
613 | self.repo = repo | |
|
614 |
self. |
|
|
632 | def __init__(self, repo, name, oldnode=None, newnode=None, distance=None, | |
|
633 | partial=False): | |
|
634 | self.repo = repo.unfiltered() | |
|
635 | self.name = name | |
|
636 | self.oldnode = oldnode | |
|
637 | self.newnode = newnode | |
|
615 | 638 | self.distance = distance |
|
616 | 639 | self.partial = partial |
|
617 | 640 | self._lock = None |
|
618 | 641 | self.need_leave = False |
|
619 | 642 | |
|
620 | 643 | def __enter__(self): |
|
644 | self.enter() | |
|
645 | ||
|
646 | def enter(self): | |
|
621 | 647 | # We explicitly need to take a lock here, before we proceed to update |
|
622 | 648 | # watchman about the update operation, so that we don't race with |
|
623 | 649 | # some other actor. merge.update is going to take the wlock almost |
|
624 | 650 | # immediately anyway, so this is effectively extending the lock |
|
625 | 651 | # around a couple of short sanity checks. |
|
652 | if self.oldnode is None: | |
|
653 | self.oldnode = self.repo['.'].node() | |
|
626 | 654 | self._lock = self.repo.wlock() |
|
627 |
self.need_leave = self._state( |
|
|
655 | self.need_leave = self._state( | |
|
656 | 'state-enter', | |
|
657 | hex(self.oldnode)) | |
|
628 | 658 | return self |
|
629 | 659 | |
|
630 | 660 | def __exit__(self, type_, value, tb): |
|
661 | abort = True if type_ else False | |
|
662 | self.exit(abort=abort) | |
|
663 | ||
|
664 | def exit(self, abort=False): | |
|
631 | 665 | try: |
|
632 | 666 | if self.need_leave: |
|
633 |
status = ' |
|
|
634 | self._state('state-leave', status=status) | |
|
667 | status = 'failed' if abort else 'ok' | |
|
668 | if self.newnode is None: | |
|
669 | self.newnode = self.repo['.'].node() | |
|
670 | if self.distance is None: | |
|
671 | self.distance = calcdistance( | |
|
672 | self.repo, self.oldnode, self.newnode) | |
|
673 | self._state( | |
|
674 | 'state-leave', | |
|
675 | hex(self.newnode), | |
|
676 | status=status) | |
|
635 | 677 | finally: |
|
678 | self.need_leave = False | |
|
636 | 679 | if self._lock: |
|
637 | 680 | self._lock.release() |
|
638 | 681 | |
|
639 | def _state(self, cmd, status='ok'): | |
|
682 | def _state(self, cmd, commithash, status='ok'): | |
|
640 | 683 | if not util.safehasattr(self.repo, '_watchmanclient'): |
|
641 | 684 | return False |
|
642 | 685 | try: |
|
643 | commithash = self.repo[self.node].hex() | |
|
644 | 686 | self.repo._watchmanclient.command(cmd, { |
|
645 |
'name': |
|
|
687 | 'name': self.name, | |
|
646 | 688 | 'metadata': { |
|
647 | 689 | # the target revision |
|
648 | 690 | 'rev': commithash, |
|
649 | 691 | # approximate number of commits between current and target |
|
650 | 'distance': self.distance, | |
|
692 | 'distance': self.distance if self.distance else 0, | |
|
651 | 693 | # success/failure (only really meaningful for state-leave) |
|
652 | 694 | 'status': status, |
|
653 | 695 | # whether the working copy parent is changing |
@@ -677,12 +719,14 b' def wrapupdate(orig, repo, node, branchm' | |||
|
677 | 719 | |
|
678 | 720 | distance = 0 |
|
679 | 721 | partial = True |
|
722 | oldnode = repo['.'].node() | |
|
723 | newnode = repo[node].node() | |
|
680 | 724 | if matcher is None or matcher.always(): |
|
681 | 725 | partial = False |
|
682 |
distance = calcdistance(repo.unfiltered(), |
|
|
683 | repo[node].node()) | |
|
726 | distance = calcdistance(repo.unfiltered(), oldnode, newnode) | |
|
684 | 727 | |
|
685 | with state_update(repo, node, distance, partial): | |
|
728 | with state_update(repo, name="hg.update", oldnode=oldnode, newnode=newnode, | |
|
729 | distance=distance, partial=partial): | |
|
686 | 730 | return orig( |
|
687 | 731 | repo, node, branchmerge, force, ancestor, mergeancestor, |
|
688 | 732 | labels, matcher, **kwargs) |
@@ -728,4 +772,32 b' def reposetup(ui, repo):' | |||
|
728 | 772 | orig = super(fsmonitorrepo, self).status |
|
729 | 773 | return overridestatus(orig, self, *args, **kwargs) |
|
730 | 774 | |
|
775 | if ui.configbool("experimental", "fsmonitor.transaction_notify"): | |
|
776 | def transaction(self, *args, **kwargs): | |
|
777 | tr = super(fsmonitorrepo, self).transaction( | |
|
778 | *args, **kwargs) | |
|
779 | if tr.count != 1: | |
|
780 | return tr | |
|
781 | stateupdate = state_update(self, name="hg.transaction") | |
|
782 | stateupdate.enter() | |
|
783 | ||
|
784 | class fsmonitortrans(tr.__class__): | |
|
785 | def _abort(self): | |
|
786 | try: | |
|
787 | result = super(fsmonitortrans, self)._abort() | |
|
788 | finally: | |
|
789 | stateupdate.exit(abort=True) | |
|
790 | return result | |
|
791 | ||
|
792 | def close(self): | |
|
793 | try: | |
|
794 | result = super(fsmonitortrans, self).close() | |
|
795 | finally: | |
|
796 | if self.count == 0: | |
|
797 | stateupdate.exit() | |
|
798 | return result | |
|
799 | ||
|
800 | tr.__class__ = fsmonitortrans | |
|
801 | return tr | |
|
802 | ||
|
731 | 803 | repo.__class__ = fsmonitorrepo |
General Comments 0
You need to be logged in to leave comments.
Login now