# HG changeset patch # User Valentin Gatien-Baron # Date 1589754825 14400 # Node ID 708ad5cf5e5a7666ec6619829a68c6ef8d4cb3e0 # Parent 8d552701806d537bffe741b6ecebc4bbe7226329 grep: grep the working copy faster `hg grep qqqq` in the mercurial repo: before: 0,859s after: 0,233s `hg grep somethingwithnomatch` in mozilla-central: before: 51s after: 19s This is probably also a tiny bug fix, because the code was looking up a node for filename `pfn` on a filelog for filename `fn`, which are most of the time the same filename, but don't have to be. Ignoring performance and the bug fix, the code should have the same behavior. Differential Revision: https://phab.mercurial-scm.org/D8545 diff -r 8d552701806d -r 708ad5cf5e5a mercurial/commands.py --- a/mercurial/commands.py Sun May 17 13:10:54 2020 -0400 +++ b/mercurial/commands.py Sun May 17 18:33:45 2020 -0400 @@ -3578,18 +3578,27 @@ getrenamed = scmutil.getrenamedfn(repo) - def get_file_content(filename, filelog, filenode, context, revision): - try: - content = filelog.read(filenode) - except error.WdirUnsupported: - content = context[filename].data() - except error.CensoredNodeError: - content = None - ui.warn( - _(b'cannot search in censored file: %(filename)s:%(revnum)s\n') - % {b'filename': filename, b'revnum': pycompat.bytestr(revision)} - ) - return content + def readfile(ctx, fn): + rev = ctx.rev() + if rev is None: + fctx = ctx[fn] + try: + return fctx.data() + except IOError as e: + if e.errno != errno.ENOENT: + raise + else: + flog = getfile(fn) + fnode = ctx.filenode(fn) + try: + return flog.read(fnode) + except error.CensoredNodeError: + ui.warn( + _( + b'cannot search in censored file: %(filename)s:%(revnum)s\n' + ) + % {b'filename': fn, b'revnum': pycompat.bytestr(rev),} + ) def prep(ctx, fns): rev = ctx.rev() @@ -3600,10 +3609,10 @@ matches.setdefault(parent, {}) files = revfiles.setdefault(rev, []) for fn in fns: - flog = getfile(fn) - try: - fnode = ctx.filenode(fn) - except error.LookupError: + # fn might not exist in the revision (could be a file removed by the + # revision). We could check `fn not in ctx` even when rev is None, + # but it's less racy to protect againt that in readfile. + if rev is not None and fn not in ctx: continue copy = None @@ -3618,20 +3627,12 @@ files.append(fn) if fn not in matches[rev]: - content = get_file_content(fn, flog, fnode, ctx, rev) - grepbody(fn, rev, content) + grepbody(fn, rev, readfile(ctx, fn)) if diff: pfn = copy or fn - if pfn not in matches[parent]: - try: - pfnode = pctx.filenode(pfn) - pcontent = get_file_content( - pfn, flog, pfnode, pctx, parent - ) - grepbody(pfn, parent, pcontent) - except error.LookupError: - pass + if pfn not in matches[parent] and pfn in pctx: + grepbody(pfn, parent, readfile(pctx, pfn)) ui.pager(b'grep') fm = ui.formatter(b'grep', opts)