hgext/fsmonitor/watchmanclient.py
author Augie Fackler <augie@google.com>
Sun, 06 Oct 2019 09:45:02 -0400
changeset 43076 2372284d9457
parent 42650 ab1900323b1d
child 43077 687b865b95ad
permissions -rw-r--r--
formatting: blacken the codebase This is using my patch to black (https://github.com/psf/black/pull/826) so we don't un-wrap collection literals. Done with: hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**"' | xargs black -S # skip-blame mass-reformatting only # no-check-commit reformats foo_bar functions Differential Revision: https://phab.mercurial-scm.org/D6971

# 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.

from __future__ import absolute_import

import getpass

from mercurial import util

from . import pywatchman


class Unavailable(Exception):
    def __init__(self, msg, warn=True, invalidate=False):
        self.msg = msg
        self.warn = warn
        if self.msg == 'timed out waiting for response':
            self.warn = False
        self.invalidate = invalidate

    def __str__(self):
        if self.warn:
            return 'warning: Watchman unavailable: %s' % self.msg
        else:
            return 'Watchman unavailable: %s' % self.msg


class WatchmanNoRoot(Unavailable):
    def __init__(self, root, msg):
        self.root = root
        super(WatchmanNoRoot, self).__init__(msg)


class client(object):
    def __init__(self, ui, root, timeout=1.0):
        err = None
        if not self._user:
            err = "couldn't get user"
            warn = True
        if self._user in ui.configlist('fsmonitor', 'blacklistusers'):
            err = 'user %s in blacklist' % self._user
            warn = False

        if err:
            raise Unavailable(err, warn)

        self._timeout = timeout
        self._watchmanclient = None
        self._root = root
        self._ui = ui
        self._firsttime = True

    def settimeout(self, timeout):
        self._timeout = timeout
        if self._watchmanclient is not None:
            self._watchmanclient.setTimeout(timeout)

    def getcurrentclock(self):
        result = self.command('clock')
        if not util.safehasattr(result, 'clock'):
            raise Unavailable(
                'clock result is missing clock value', invalidate=True
            )
        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
                watchman_exe = self._ui.configpath('fsmonitor', 'watchman_exe')
                self._watchmanclient = pywatchman.client(
                    timeout=self._timeout,
                    useImmutableBser=True,
                    watchman_exe=watchman_exe,
                )
            return self._watchmanclient.query(*watchmanargs)
        except pywatchman.CommandError as ex:
            if 'unable to resolve root' in ex.msg:
                raise WatchmanNoRoot(self._root, ex.msg)
            raise Unavailable(ex.msg)
        except pywatchman.WatchmanError as ex:
            raise Unavailable(str(ex))

    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
                self._command('watch')
                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