##// END OF EJS Templates
fsmonitor: hook up state-enter, state-leave signals...
Martijn Pieters -
r28443:49d65663 default
parent child Browse files
Show More
@@ -99,6 +99,7 b' from mercurial import ('
99 context,
99 context,
100 extensions,
100 extensions,
101 localrepo,
101 localrepo,
102 merge,
102 pathutil,
103 pathutil,
103 scmutil,
104 scmutil,
104 util,
105 util,
@@ -547,6 +548,8 b' def extsetup(ui):'
547 # An assist for avoiding the dangling-symlink fsevents bug
548 # An assist for avoiding the dangling-symlink fsevents bug
548 extensions.wrapfunction(os, 'symlink', wrapsymlink)
549 extensions.wrapfunction(os, 'symlink', wrapsymlink)
549
550
551 extensions.wrapfunction(merge, 'update', wrapupdate)
552
550 def wrapsymlink(orig, source, link_name):
553 def wrapsymlink(orig, source, link_name):
551 ''' if we create a dangling symlink, also touch the parent dir
554 ''' if we create a dangling symlink, also touch the parent dir
552 to encourage fsevents notifications to work more correctly '''
555 to encourage fsevents notifications to work more correctly '''
@@ -558,6 +561,71 b' def wrapsymlink(orig, source, link_name)'
558 except OSError:
561 except OSError:
559 pass
562 pass
560
563
564 class state_update(object):
565 ''' This context mananger is responsible for dispatching the state-enter
566 and state-leave signals to the watchman service '''
567
568 def __init__(self, repo, node, distance, partial):
569 self.repo = repo
570 self.node = node
571 self.distance = distance
572 self.partial = partial
573
574 def __enter__(self):
575 self._state('state-enter')
576 return self
577
578 def __exit__(self, type_, value, tb):
579 status = 'ok' if type_ is None else 'failed'
580 self._state('state-leave', status=status)
581
582 def _state(self, cmd, status='ok'):
583 if not util.safehasattr(self.repo, '_watchmanclient'):
584 return
585 try:
586 commithash = self.repo[self.node].hex()
587 self.repo._watchmanclient.command(cmd, {
588 'name': 'hg.update',
589 'metadata': {
590 # the target revision
591 'rev': commithash,
592 # approximate number of commits between current and target
593 'distance': self.distance,
594 # success/failure (only really meaningful for state-leave)
595 'status': status,
596 # whether the working copy parent is changing
597 'partial': self.partial,
598 }})
599 except Exception as e:
600 # Swallow any errors; fire and forget
601 self.repo.ui.log(
602 'watchman', 'Exception %s while running %s\n', e, cmd)
603
604 # Bracket working copy updates with calls to the watchman state-enter
605 # and state-leave commands. This allows clients to perform more intelligent
606 # settling during bulk file change scenarios
607 # https://facebook.github.io/watchman/docs/cmd/subscribe.html#advanced-settling
608 def wrapupdate(orig, repo, node, branchmerge, force, ancestor=None,
609 mergeancestor=False, labels=None, matcher=None, **kwargs):
610
611 distance = 0
612 partial = True
613 if matcher is None or matcher.always():
614 partial = False
615 wc = repo[None]
616 parents = wc.parents()
617 if len(parents) == 2:
618 anc = repo.changelog.ancestor(parents[0].node(), parents[1].node())
619 ancrev = repo[anc].rev()
620 distance = abs(repo[node].rev() - ancrev)
621 elif len(parents) == 1:
622 distance = abs(repo[node].rev() - parents[0].rev())
623
624 with state_update(repo, node, distance, partial):
625 return orig(
626 repo, node, branchmerge, force, ancestor, mergeancestor,
627 labels, matcher, *kwargs)
628
561 def reposetup(ui, repo):
629 def reposetup(ui, repo):
562 # We don't work with largefiles or inotify
630 # We don't work with largefiles or inotify
563 exts = extensions.enabled()
631 exts = extensions.enabled()
General Comments 0
You need to be logged in to leave comments. Login now