def wrapped(self, *args, **kwargs): retrylog = self.retrylog or noop funcname = fn.__name__ i = 0 while i < self.numattempts: if i > 0: retrylog('re-attempting (n=%d) %s\n' % (i, funcname)) self.markforrefresh() i += 1 try: return fn(self, *args, **kwargs) except KeyError: if i == self.numattempts: # retries exhausted retrylog( 'retries exhausted in %s, raising KeyError\n' % pycompat.sysbytes(funcname)) raise
def messageid(ctx, domain, messageidseed): if domain and messageidseed: host = domain else: host = encoding.strtolocal(socket.getfqdn()) if messageidseed: messagehash = hashlib.sha512(ctx.hex() + messageidseed) messageid = b'<hg.%s@%s>' % ( pycompat.sysbytes(messagehash.hexdigest()[:64]), host, ) else: messageid = b'<hg.%s.%d.%d@%s>' % ( ctx, int(time.time()), hash(ctx.repo().root), host, ) return encoding.strfromlocal(messageid)
def rawstorefiledata_cache_fn(repo, proto, cacher, **args): # Only cache if we request changelog + manifestlog with no path filter. # Caching is hard and restricting what is cached is safer. if set(args.get('files', [])) != {'changelog', 'manifestlog'}: return None if args.get('pathfilter'): return None state = { b'globalversion': wireprotov2server.GLOBAL_CACHE_VERSION, b'localversion': 'moz0', b'command': b'rawstorefiledata', # TODO this needs to change when we support different wire protocol # versions. b'mediatype': wireprotov2server.FRAMINGTYPE, b'version': wireprotov2server.HTTP_WIREPROTO_V2, b'repo': repo.root, } # Hashing the entire changelog could take a while, since it can be # dozens or hundreds of megabytes. As a proxy, we hash the first few # bytes of the changelog (to pull in revlog flags) and the DAG heads # in the changelog. cl = repo.unfiltered().changelog with cl.opener(cl.indexfile, 'rb') as fh: state[b'changeloghead'] = fh.read(32768) state[b'changelogheads'] = cl.heads() cacher.adjustcachekeystate(state) hasher = hashlib.sha1() for chunk in cborutil.streamencode(state): hasher.update(chunk) return pycompat.sysbytes(hasher.hexdigest())
def fwarn(f, msg): self._ui.warn(b'%s: %s\n' % ( self.pathto(f), pycompat.sysbytes(msg), )) return False
def __init__(self, startclock): self._startclock = pycompat.sysbytes(startclock)
def overridewalk(orig, self, match, subrepos, unknown, ignored, full=True): """Replacement for dirstate.walk, hooking into Watchman. Whenever full is False, ignored is False, and the Watchman client is available, use Watchman combined with saved state to possibly return only a subset of files.""" def bail(reason): self._ui.debug(b'fsmonitor: fallback to core status, %s\n' % reason) return orig(match, subrepos, unknown, ignored, full=True) if full: return bail(b'full rewalk requested') if ignored: return bail(b'listing ignored files') if not self._watchmanclient.available(): return bail(b'client unavailable') state = self._fsmonitorstate clock, ignorehash, notefiles = state.get() if not clock: if state.walk_on_invalidate: return bail(b'no clock') # Initial NULL clock value, see # https://facebook.github.io/watchman/docs/clockspec.html clock = b'c:0:0' notefiles = [] ignore = self._ignore dirignore = self._dirignore if unknown: if _hashignore(ignore) != ignorehash and clock != b'c:0:0': # ignore list changed -- can't rely on Watchman state any more if state.walk_on_invalidate: return bail(b'ignore rules changed') notefiles = [] clock = b'c:0:0' else: # always ignore ignore = util.always dirignore = util.always matchfn = match.matchfn matchalways = match.always() dmap = self._map if util.safehasattr(dmap, b'_map'): # for better performance, directly access the inner dirstate map if the # standard dirstate implementation is in use. dmap = dmap._map nonnormalset = self._map.nonnormalset copymap = self._map.copymap getkind = stat.S_IFMT dirkind = stat.S_IFDIR regkind = stat.S_IFREG lnkkind = stat.S_IFLNK join = self._join normcase = util.normcase fresh_instance = False exact = skipstep3 = False if match.isexact(): # match.exact exact = True dirignore = util.always # skip step 2 elif match.prefix(): # match.match, no patterns skipstep3 = True if not exact and self._checkcase: # note that even though we could receive directory entries, we're only # interested in checking if a file with the same name exists. So only # normalize files if possible. normalize = self._normalizefile skipstep3 = False else: normalize = None # step 1: find all explicit files results, work, dirsnotfound = self._walkexplicit(match, subrepos) skipstep3 = skipstep3 and not (work or dirsnotfound) work = [d for d in work if not dirignore(d[0])] if not work and (exact or skipstep3): for s in subrepos: del results[s] del results[b'.hg'] return results # step 2: query Watchman try: # Use the user-configured timeout for the query. # Add a little slack over the top of the user query to allow for # overheads while transferring the data self._watchmanclient.settimeout(state.timeout + 0.1) result = self._watchmanclient.command( b'query', { b'fields': [b'mode', b'mtime', b'size', b'exists', b'name'], b'since': clock, b'expression': [ b'not', [ b'anyof', [b'dirname', b'.hg'], [b'name', b'.hg', b'wholename'], ], ], b'sync_timeout': int(state.timeout * 1000), b'empty_on_fresh_instance': state.walk_on_invalidate, }, ) except Exception as ex: _handleunavailable(self._ui, state, ex) self._watchmanclient.clearconnection() return bail(b'exception during run') else: # We need to propagate the last observed clock up so that we # can use it for our next query state.setlastclock(pycompat.sysbytes(result[b'clock'])) if result[b'is_fresh_instance']: if state.walk_on_invalidate: state.invalidate() return bail(b'fresh instance') fresh_instance = True # Ignore any prior noteable files from the state info notefiles = [] # for file paths which require normalization and we encounter a case # collision, we store our own foldmap if normalize: foldmap = {normcase(k): k for k in results} switch_slashes = pycompat.ossep == b'\\' # The order of the results is, strictly speaking, undefined. # For case changes on a case insensitive filesystem we may receive # two entries, one with exists=True and another with exists=False. # The exists=True entries in the same response should be interpreted # as being happens-after the exists=False entries due to the way that # Watchman tracks files. We use this property to reconcile deletes # for name case changes. for entry in result[b'files']: fname = entry[b'name'] # Watchman always give us a str. Normalize to bytes on Python 3 # using Watchman's encoding, if needed. if not isinstance(fname, bytes): fname = fname.encode(_watchmanencoding) if _fixencoding: fname = _watchmantofsencoding(fname) if switch_slashes: fname = fname.replace(b'\\', b'/') if normalize: normed = normcase(fname) fname = normalize(fname, True, True) foldmap[normed] = fname fmode = entry[b'mode'] fexists = entry[b'exists'] kind = getkind(fmode) if b'/.hg/' in fname or fname.endswith(b'/.hg'): return bail(b'nested-repo-detected') if not fexists: # if marked as deleted and we don't already have a change # record, mark it as deleted. If we already have an entry # for fname then it was either part of walkexplicit or was # an earlier result that was a case change if (fname not in results and fname in dmap and (matchalways or matchfn(fname))): results[fname] = None elif kind == dirkind: if fname in dmap and (matchalways or matchfn(fname)): results[fname] = None elif kind == regkind or kind == lnkkind: if fname in dmap: if matchalways or matchfn(fname): results[fname] = entry elif (matchalways or matchfn(fname)) and not ignore(fname): results[fname] = entry elif fname in dmap and (matchalways or matchfn(fname)): results[fname] = None # step 3: query notable files we don't already know about # XXX try not to iterate over the entire dmap if normalize: # any notable files that have changed case will already be handled # above, so just check membership in the foldmap notefiles = { normalize(f, True, True) for f in notefiles if normcase(f) not in foldmap } visit = { f for f in notefiles if (f not in results and matchfn(f) and (f in dmap or not ignore(f))) } if not fresh_instance: if matchalways: visit.update(f for f in nonnormalset if f not in results) visit.update(f for f in copymap if f not in results) else: visit.update(f for f in nonnormalset if f not in results and matchfn(f)) visit.update(f for f in copymap if f not in results and matchfn(f)) else: if matchalways: visit.update(f for f, st in pycompat.iteritems(dmap) if f not in results) visit.update(f for f in copymap if f not in results) else: visit.update(f for f, st in pycompat.iteritems(dmap) if f not in results and matchfn(f)) visit.update(f for f in copymap if f not in results and matchfn(f)) audit = pathutil.pathauditor(self._root, cached=True).check auditpass = [f for f in visit if audit(f)] auditpass.sort() auditfail = visit.difference(auditpass) for f in auditfail: results[f] = None nf = iter(auditpass) for st in util.statfiles([join(f) for f in auditpass]): f = next(nf) if st or f in dmap: results[f] = st for s in subrepos: del results[s] del results[b'.hg'] return results
def show(ui, repo, view=None, template=None): """show various repository information A requested view of repository data is displayed. If no view is requested, the list of available views is shown and the command aborts. .. note:: There are no backwards compatibility guarantees for the output of this command. Output may change in any future Mercurial release. Consumers wanting stable command output should specify a template via ``-T/--template``. List of available views: """ if ui.plain() and not template: hint = _('invoke with -T/--template to control output format') raise error.Abort(_('must specify a template in plain mode'), hint=hint) views = showview._table if not view: ui.pager('show') # TODO consider using formatter here so available views can be # rendered to custom format. ui.write(_('available views:\n')) ui.write('\n') for name, func in sorted(views.items()): ui.write(('%s\n') % pycompat.sysbytes(func.__doc__)) ui.write('\n') raise error.Abort(_('no view requested'), hint=_('use "hg show VIEW" to choose a view')) # TODO use same logic as dispatch to perform prefix matching. if view not in views: raise error.Abort(_('unknown view: %s') % view, hint=_('run "hg show" to see available views')) template = template or 'show' fn = views[view] ui.pager('show') if fn._fmtopic: fmtopic = 'show%s' % fn._fmtopic with ui.formatter(fmtopic, {'template': template}) as fm: return fn(ui, repo, fm) elif fn._csettopic: ref = 'show%s' % fn._csettopic spec = formatter.lookuptemplate(ui, ref, template) displayer = logcmdutil.changesettemplater(ui, repo, spec, buffered=True) return fn(ui, repo, displayer) else: return fn(ui, repo)
def sysbytes(s): # 5.2 does not check this if isinstance(s, str): return pycompat.sysbytes(s) else: return s