watchmanclient.py
128 lines
| 3.8 KiB
| text/x-python
|
PythonLexer
|
r28433 | # watchmanclient.py - Watchman client for the fsmonitor extension | ||
# | ||||
# Copyright 2013-2016 Facebook, Inc. | ||||
# | ||||
# This software may be used and distributed according to the terms of the | ||||
# GNU General Public License version 2 or any later version. | ||||
import getpass | ||||
|
r43716 | from mercurial import ( | ||
encoding, | ||||
util, | ||||
) | ||||
from mercurial.utils import ( | ||||
procutil, | ||||
stringutil, | ||||
) | ||||
|
r28433 | |||
from . import pywatchman | ||||
|
r43346 | |||
|
r28433 | class Unavailable(Exception): | ||
def __init__(self, msg, warn=True, invalidate=False): | ||||
self.msg = msg | ||||
self.warn = warn | ||||
|
r43347 | if self.msg == b'timed out waiting for response': | ||
|
r28433 | self.warn = False | ||
self.invalidate = invalidate | ||||
|
r43716 | def __bytes__(self): | ||
|
r28433 | if self.warn: | ||
|
r43347 | return b'warning: Watchman unavailable: %s' % self.msg | ||
|
r28433 | else: | ||
|
r43347 | return b'Watchman unavailable: %s' % self.msg | ||
|
r28433 | |||
|
r43716 | __str__ = encoding.strmethod(__bytes__) | ||
|
r43346 | |||
|
r28433 | class WatchmanNoRoot(Unavailable): | ||
def __init__(self, root, msg): | ||||
self.root = root | ||||
super(WatchmanNoRoot, self).__init__(msg) | ||||
|
r43346 | |||
|
r28433 | class client(object): | ||
|
r42877 | def __init__(self, ui, root, timeout=1.0): | ||
|
r28433 | err = None | ||
if not self._user: | ||||
|
r43347 | err = b"couldn't get user" | ||
|
r28433 | warn = True | ||
|
r43347 | if self._user in ui.configlist(b'fsmonitor', b'blacklistusers'): | ||
err = b'user %s in blacklist' % self._user | ||||
|
r28433 | warn = False | ||
if err: | ||||
raise Unavailable(err, warn) | ||||
self._timeout = timeout | ||||
self._watchmanclient = None | ||||
|
r42877 | self._root = root | ||
self._ui = ui | ||||
|
r28433 | self._firsttime = True | ||
def settimeout(self, timeout): | ||||
self._timeout = timeout | ||||
if self._watchmanclient is not None: | ||||
self._watchmanclient.setTimeout(timeout) | ||||
def getcurrentclock(self): | ||||
|
r43347 | result = self.command(b'clock') | ||
|
r43385 | if not util.safehasattr(result, 'clock'): | ||
|
r43346 | raise Unavailable( | ||
|
r43347 | b'clock result is missing clock value', invalidate=True | ||
|
r43346 | ) | ||
|
r28433 | return result.clock | ||
def clearconnection(self): | ||||
self._watchmanclient = None | ||||
def available(self): | ||||
return self._watchmanclient is not None or self._firsttime | ||||
@util.propertycache | ||||
def _user(self): | ||||
try: | ||||
return getpass.getuser() | ||||
except KeyError: | ||||
# couldn't figure out our user | ||||
return None | ||||
def _command(self, *args): | ||||
watchmanargs = (args[0], self._root) + args[1:] | ||||
try: | ||||
if self._watchmanclient is None: | ||||
self._firsttime = False | ||||
|
r43347 | watchman_exe = self._ui.configpath( | ||
b'fsmonitor', b'watchman_exe' | ||||
) | ||||
|
r28433 | self._watchmanclient = pywatchman.client( | ||
timeout=self._timeout, | ||||
|
r42134 | useImmutableBser=True, | ||
|
r43703 | binpath=procutil.tonativestr(watchman_exe), | ||
|
r43346 | ) | ||
|
r28433 | return self._watchmanclient.query(*watchmanargs) | ||
except pywatchman.CommandError as ex: | ||||
|
r44531 | if 'unable to resolve root' in ex.msg: | ||
|
r43716 | raise WatchmanNoRoot( | ||
self._root, stringutil.forcebytestr(ex.msg) | ||||
) | ||||
|
r44531 | raise Unavailable(stringutil.forcebytestr(ex.msg)) | ||
|
r28433 | except pywatchman.WatchmanError as ex: | ||
|
r43716 | raise Unavailable(stringutil.forcebytestr(ex)) | ||
|
r28433 | |||
def command(self, *args): | ||||
try: | ||||
try: | ||||
return self._command(*args) | ||||
except WatchmanNoRoot: | ||||
# this 'watch' command can also raise a WatchmanNoRoot if | ||||
# watchman refuses to accept this root | ||||
|
r43347 | self._command(b'watch') | ||
|
r28433 | return self._command(*args) | ||
except Unavailable: | ||||
# this is in an outer scope to catch Unavailable form any of the | ||||
# above _command calls | ||||
self._watchmanclient = None | ||||
raise | ||||