comparison mercurial/commands.py @ 44910:708ad5cf5e5a

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
author Valentin Gatien-Baron <valentin.gatienbaron@gmail.com>
date Sun, 17 May 2020 18:33:45 -0400
parents 8d552701806d
children b7808443ed6a
comparison
equal deleted inserted replaced
44909:8d552701806d 44910:708ad5cf5e5a
3576 found = False 3576 found = False
3577 follow = opts.get(b'follow') 3577 follow = opts.get(b'follow')
3578 3578
3579 getrenamed = scmutil.getrenamedfn(repo) 3579 getrenamed = scmutil.getrenamedfn(repo)
3580 3580
3581 def get_file_content(filename, filelog, filenode, context, revision): 3581 def readfile(ctx, fn):
3582 try: 3582 rev = ctx.rev()
3583 content = filelog.read(filenode) 3583 if rev is None:
3584 except error.WdirUnsupported: 3584 fctx = ctx[fn]
3585 content = context[filename].data() 3585 try:
3586 except error.CensoredNodeError: 3586 return fctx.data()
3587 content = None 3587 except IOError as e:
3588 ui.warn( 3588 if e.errno != errno.ENOENT:
3589 _(b'cannot search in censored file: %(filename)s:%(revnum)s\n') 3589 raise
3590 % {b'filename': filename, b'revnum': pycompat.bytestr(revision)} 3590 else:
3591 ) 3591 flog = getfile(fn)
3592 return content 3592 fnode = ctx.filenode(fn)
3593 try:
3594 return flog.read(fnode)
3595 except error.CensoredNodeError:
3596 ui.warn(
3597 _(
3598 b'cannot search in censored file: %(filename)s:%(revnum)s\n'
3599 )
3600 % {b'filename': fn, b'revnum': pycompat.bytestr(rev),}
3601 )
3593 3602
3594 def prep(ctx, fns): 3603 def prep(ctx, fns):
3595 rev = ctx.rev() 3604 rev = ctx.rev()
3596 pctx = ctx.p1() 3605 pctx = ctx.p1()
3597 matches.setdefault(rev, {}) 3606 matches.setdefault(rev, {})
3598 if diff: 3607 if diff:
3599 parent = pctx.rev() 3608 parent = pctx.rev()
3600 matches.setdefault(parent, {}) 3609 matches.setdefault(parent, {})
3601 files = revfiles.setdefault(rev, []) 3610 files = revfiles.setdefault(rev, [])
3602 for fn in fns: 3611 for fn in fns:
3603 flog = getfile(fn) 3612 # fn might not exist in the revision (could be a file removed by the
3604 try: 3613 # revision). We could check `fn not in ctx` even when rev is None,
3605 fnode = ctx.filenode(fn) 3614 # but it's less racy to protect againt that in readfile.
3606 except error.LookupError: 3615 if rev is not None and fn not in ctx:
3607 continue 3616 continue
3608 3617
3609 copy = None 3618 copy = None
3610 if follow: 3619 if follow:
3611 copy = getrenamed(fn, rev) 3620 copy = getrenamed(fn, rev)
3616 if fn in skip: 3625 if fn in skip:
3617 continue 3626 continue
3618 files.append(fn) 3627 files.append(fn)
3619 3628
3620 if fn not in matches[rev]: 3629 if fn not in matches[rev]:
3621 content = get_file_content(fn, flog, fnode, ctx, rev) 3630 grepbody(fn, rev, readfile(ctx, fn))
3622 grepbody(fn, rev, content)
3623 3631
3624 if diff: 3632 if diff:
3625 pfn = copy or fn 3633 pfn = copy or fn
3626 if pfn not in matches[parent]: 3634 if pfn not in matches[parent] and pfn in pctx:
3627 try: 3635 grepbody(pfn, parent, readfile(pctx, pfn))
3628 pfnode = pctx.filenode(pfn)
3629 pcontent = get_file_content(
3630 pfn, flog, pfnode, pctx, parent
3631 )
3632 grepbody(pfn, parent, pcontent)
3633 except error.LookupError:
3634 pass
3635 3636
3636 ui.pager(b'grep') 3637 ui.pager(b'grep')
3637 fm = ui.formatter(b'grep', opts) 3638 fm = ui.formatter(b'grep', opts)
3638 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep): 3639 for ctx in cmdutil.walkchangerevs(repo, match, opts, prep):
3639 rev = ctx.rev() 3640 rev = ctx.rev()