Beispiel #1
0
 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
Beispiel #2
0
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)
Beispiel #3
0
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())
Beispiel #4
0
 def fwarn(f, msg):
     self._ui.warn(b'%s: %s\n' % (
         self.pathto(f),
         pycompat.sysbytes(msg),
     ))
     return False
Beispiel #5
0
 def __init__(self, startclock):
     self._startclock = pycompat.sysbytes(startclock)
Beispiel #6
0
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
Beispiel #7
0
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)
Beispiel #8
0
def sysbytes(s):
    # 5.2 does not check this
    if isinstance(s, str):
        return pycompat.sysbytes(s)
    else:
        return s