Show More
@@ -96,8 +96,14 b' import hashlib' | |||||
96 | import os |
|
96 | import os | |
97 | import stat |
|
97 | import stat | |
98 | import sys |
|
98 | import sys | |
|
99 | import weakref | |||
99 |
|
100 | |||
100 | from mercurial.i18n import _ |
|
101 | from mercurial.i18n import _ | |
|
102 | from mercurial.node import ( | |||
|
103 | hex, | |||
|
104 | nullid, | |||
|
105 | ) | |||
|
106 | ||||
101 | from mercurial import ( |
|
107 | from mercurial import ( | |
102 | context, |
|
108 | context, | |
103 | encoding, |
|
109 | encoding, | |
@@ -555,11 +561,12 b' class poststatus(object):' | |||||
555 |
|
561 | |||
556 | def makedirstate(repo, dirstate): |
|
562 | def makedirstate(repo, dirstate): | |
557 | class fsmonitordirstate(dirstate.__class__): |
|
563 | class fsmonitordirstate(dirstate.__class__): | |
558 |
def _fsmonitorinit(self, |
|
564 | def _fsmonitorinit(self, repo): | |
559 | # _fsmonitordisable is used in paranoid mode |
|
565 | # _fsmonitordisable is used in paranoid mode | |
560 | self._fsmonitordisable = False |
|
566 | self._fsmonitordisable = False | |
561 | self._fsmonitorstate = fsmonitorstate |
|
567 | self._fsmonitorstate = repo._fsmonitorstate | |
562 | self._watchmanclient = watchmanclient |
|
568 | self._watchmanclient = repo._watchmanclient | |
|
569 | self._repo = weakref.proxy(repo) | |||
563 |
|
570 | |||
564 | def walk(self, *args, **kwargs): |
|
571 | def walk(self, *args, **kwargs): | |
565 | orig = super(fsmonitordirstate, self).walk |
|
572 | orig = super(fsmonitordirstate, self).walk | |
@@ -575,8 +582,16 b' def makedirstate(repo, dirstate):' | |||||
575 | self._fsmonitorstate.invalidate() |
|
582 | self._fsmonitorstate.invalidate() | |
576 | return super(fsmonitordirstate, self).invalidate(*args, **kwargs) |
|
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 | dirstate.__class__ = fsmonitordirstate |
|
593 | dirstate.__class__ = fsmonitordirstate | |
579 |
dirstate._fsmonitorinit(repo |
|
594 | dirstate._fsmonitorinit(repo) | |
580 |
|
595 | |||
581 | def wrapdirstate(orig, self): |
|
596 | def wrapdirstate(orig, self): | |
582 | ds = orig(self) |
|
597 | ds = orig(self) | |
@@ -607,47 +622,74 b' def wrapsymlink(orig, source, link_name)' | |||||
607 |
|
622 | |||
608 | class state_update(object): |
|
623 | class state_update(object): | |
609 | ''' This context manager is responsible for dispatching the state-enter |
|
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, |
|
632 | def __init__(self, repo, name, oldnode=None, newnode=None, distance=None, | |
613 | self.repo = repo |
|
633 | partial=False): | |
614 |
self. |
|
634 | self.repo = repo.unfiltered() | |
|
635 | self.name = name | |||
|
636 | self.oldnode = oldnode | |||
|
637 | self.newnode = newnode | |||
615 | self.distance = distance |
|
638 | self.distance = distance | |
616 | self.partial = partial |
|
639 | self.partial = partial | |
617 | self._lock = None |
|
640 | self._lock = None | |
618 | self.need_leave = False |
|
641 | self.need_leave = False | |
619 |
|
642 | |||
620 | def __enter__(self): |
|
643 | def __enter__(self): | |
|
644 | self.enter() | |||
|
645 | ||||
|
646 | def enter(self): | |||
621 | # We explicitly need to take a lock here, before we proceed to update |
|
647 | # We explicitly need to take a lock here, before we proceed to update | |
622 | # watchman about the update operation, so that we don't race with |
|
648 | # watchman about the update operation, so that we don't race with | |
623 | # some other actor. merge.update is going to take the wlock almost |
|
649 | # some other actor. merge.update is going to take the wlock almost | |
624 | # immediately anyway, so this is effectively extending the lock |
|
650 | # immediately anyway, so this is effectively extending the lock | |
625 | # around a couple of short sanity checks. |
|
651 | # around a couple of short sanity checks. | |
|
652 | if self.oldnode is None: | |||
|
653 | self.oldnode = self.repo['.'].node() | |||
626 | self._lock = self.repo.wlock() |
|
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 | return self |
|
658 | return self | |
629 |
|
659 | |||
630 | def __exit__(self, type_, value, tb): |
|
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 | try: |
|
665 | try: | |
632 | if self.need_leave: |
|
666 | if self.need_leave: | |
633 |
status = ' |
|
667 | status = 'failed' if abort else 'ok' | |
634 | self._state('state-leave', status=status) |
|
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 | finally: |
|
677 | finally: | |
|
678 | self.need_leave = False | |||
636 | if self._lock: |
|
679 | if self._lock: | |
637 | self._lock.release() |
|
680 | self._lock.release() | |
638 |
|
681 | |||
639 | def _state(self, cmd, status='ok'): |
|
682 | def _state(self, cmd, commithash, status='ok'): | |
640 | if not util.safehasattr(self.repo, '_watchmanclient'): |
|
683 | if not util.safehasattr(self.repo, '_watchmanclient'): | |
641 | return False |
|
684 | return False | |
642 | try: |
|
685 | try: | |
643 | commithash = self.repo[self.node].hex() |
|
|||
644 | self.repo._watchmanclient.command(cmd, { |
|
686 | self.repo._watchmanclient.command(cmd, { | |
645 |
'name': |
|
687 | 'name': self.name, | |
646 | 'metadata': { |
|
688 | 'metadata': { | |
647 | # the target revision |
|
689 | # the target revision | |
648 | 'rev': commithash, |
|
690 | 'rev': commithash, | |
649 | # approximate number of commits between current and target |
|
691 | # approximate number of commits between current and target | |
650 | 'distance': self.distance, |
|
692 | 'distance': self.distance if self.distance else 0, | |
651 | # success/failure (only really meaningful for state-leave) |
|
693 | # success/failure (only really meaningful for state-leave) | |
652 | 'status': status, |
|
694 | 'status': status, | |
653 | # whether the working copy parent is changing |
|
695 | # whether the working copy parent is changing | |
@@ -677,12 +719,14 b' def wrapupdate(orig, repo, node, branchm' | |||||
677 |
|
719 | |||
678 | distance = 0 |
|
720 | distance = 0 | |
679 | partial = True |
|
721 | partial = True | |
|
722 | oldnode = repo['.'].node() | |||
|
723 | newnode = repo[node].node() | |||
680 | if matcher is None or matcher.always(): |
|
724 | if matcher is None or matcher.always(): | |
681 | partial = False |
|
725 | partial = False | |
682 |
distance = calcdistance(repo.unfiltered(), |
|
726 | distance = calcdistance(repo.unfiltered(), oldnode, newnode) | |
683 | repo[node].node()) |
|
|||
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 | return orig( |
|
730 | return orig( | |
687 | repo, node, branchmerge, force, ancestor, mergeancestor, |
|
731 | repo, node, branchmerge, force, ancestor, mergeancestor, | |
688 | labels, matcher, **kwargs) |
|
732 | labels, matcher, **kwargs) | |
@@ -728,4 +772,32 b' def reposetup(ui, repo):' | |||||
728 | orig = super(fsmonitorrepo, self).status |
|
772 | orig = super(fsmonitorrepo, self).status | |
729 | return overridestatus(orig, self, *args, **kwargs) |
|
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 | repo.__class__ = fsmonitorrepo |
|
803 | repo.__class__ = fsmonitorrepo |
General Comments 0
You need to be logged in to leave comments.
Login now