Mercurial > hg
view hgext/fsmonitor/watchmanclient.py @ 35506:fa865878a849
lfs: show a friendly message when pushing lfs to a server without lfs enabled
Upfront disclaimer: I don't know anything about the wire protocol, and this was
pretty much cargo-culted from largefiles, and then clonebundles, since it seems
more modern. I was surprised that exchange.push() will ensure all of the proper
requirements when exchanging between two local repos, but doesn't care when one
is remote.
All this new capability marker does is inform the client that the extension is
enabled remotely. It may or may not contain commits with external blobs.
Open issues:
- largefiles uses 'largefiles=serve' for its capability. Someday I hope to
be able to push lfs blobs to an `hg serve` instance. That will probably
require a distinct capability. Should it change to '=serve' then? Or just
add an 'lfs-serve' capability then?
- The flip side of this is more complicated. It looks like largefiles adds an
'lheads' command for the client to signal to the server that the extension
is loaded. That is then converted to 'heads' and sent through the normal
wire protocol plumbing. A client using the 'heads' command directly is
kicked out with a message indicating that the largefiles extension must be
loaded. We could do similar with 'lfsheads', but then a repo with both
largefiles and lfs blobs can't be pushed over the wire. Hopefully somebody
with more wire protocol experience can think of something else. I see
'x-hgarg-1' on some commands in the tests, but not on heads, and didn't dig
any further.
author | Matt Harbison <matt_harbison@yahoo.com> |
---|---|
date | Sat, 23 Dec 2017 17:49:12 -0500 |
parents | b0a0f7b9ed90 |
children | 57264906a996 |
line wrap: on
line source
# 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, repo, timeout=1.0): err = None if not self._user: err = "couldn't get user" warn = True if self._user in repo.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 = repo.root self._ui = repo.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 self._watchmanclient = pywatchman.client( timeout=self._timeout, useImmutableBser=True) 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