##// 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 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, fsmonitorstate, watchmanclient):
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._fsmonitorstate, repo._watchmanclient)
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, partial):
613 self.repo = repo
614 self.node = node
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('state-enter')
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 = 'ok' if type_ is None else 'failed'
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': 'hg.update',
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(), repo['.'].node(),
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