##// END OF EJS Templates
fsmonitor: add new watchman notifications to fsmonitor extension...
Eamonn Kent -
r34566:4aa57627 default
parent child Browse files
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, fsmonitorstate, watchmanclient):
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._fsmonitorstate, repo._watchmanclient)
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, partial):
632 def __init__(self, repo, name, oldnode=None, newnode=None, distance=None,
613 self.repo = repo
633 partial=False):
614 self.node = node
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('state-enter')
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 = 'ok' if type_ is None else 'failed'
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': 'hg.update',
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(), repo['.'].node(),
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