# HG changeset patch # User Eamonn Kent # Date 1512614269 28800 # Node ID c67fb3bfe3a1a43d38e1dffc8c7cdc301029f80f # Parent 73abb81ccb28d8fe5b3fcf9944c3afdd7f61ae33 fsmonitor: fsmonitor should send wlock notifications to watchman The fsmonitor extension should send state-enter and state-leave notifications to watchman when the wlock is acquired/release, respectively. This will allow watchman and watchman subscribers to customize behavior based on whether source control operations are occurring. Test Plan: Tested checkout, update and working copy changes with extension enabled. Differential Revision: https://phab.mercurial-scm.org/D1612 diff -r 73abb81ccb28 -r c67fb3bfe3a1 hgext/fsmonitor/__init__.py --- a/hgext/fsmonitor/__init__.py Wed Dec 06 18:37:49 2017 -0800 +++ b/hgext/fsmonitor/__init__.py Wed Dec 06 18:37:49 2017 -0800 @@ -161,6 +161,9 @@ configitem('fsmonitor', 'blacklistusers', default=list, ) +configitem('experimental', 'fsmonitor.transaction_notify', + default=False, +) # This extension is incompatible with the following blacklisted extensions # and will disable itself when encountering one of these: @@ -656,14 +659,18 @@ self.enter() def enter(self): - # We explicitly need to take a lock here, before we proceed to update - # watchman about the update operation, so that we don't race with - # some other actor. merge.update is going to take the wlock almost - # immediately anyway, so this is effectively extending the lock - # around a couple of short sanity checks. + # Make sure we have a wlock prior to sending notifications to watchman. + # We don't want to race with other actors. In the update case, + # merge.update is going to take the wlock almost immediately. We are + # effectively extending the lock around several short sanity checks. if self.oldnode is None: self.oldnode = self.repo['.'].node() - self._lock = self.repo.wlock() + + if self.repo.currentwlock() is None: + if util.safehasattr(self.repo, 'wlocknostateupdate'): + self._lock = self.repo.wlocknostateupdate() + else: + self._lock = self.repo.wlock() self.need_leave = self._state( 'state-enter', hex(self.oldnode)) @@ -784,4 +791,34 @@ orig = super(fsmonitorrepo, self).status return overridestatus(orig, self, *args, **kwargs) + def wlocknostateupdate(self, *args, **kwargs): + return super(fsmonitorrepo, self).wlock(*args, **kwargs) + + def wlock(self, *args, **kwargs): + l = super(fsmonitorrepo, self).wlock(*args, **kwargs) + if not ui.configbool( + "experimental", "fsmonitor.transaction_notify"): + return l + if l.held != 1: + return l + origrelease = l.releasefn + + def staterelease(): + if origrelease: + origrelease() + if l.stateupdate: + l.stateupdate.exit() + l.stateupdate = None + + try: + l.stateupdate = None + l.stateupdate = state_update(self, name="hg.transaction") + l.stateupdate.enter() + l.releasefn = staterelease + except Exception as e: + # Swallow any errors; fire and forget + self.ui.log( + 'watchman', 'Exception in state update %s\n', e) + return l + repo.__class__ = fsmonitorrepo