diff --git a/mercurial/commands.py b/mercurial/commands.py --- a/mercurial/commands.py +++ b/mercurial/commands.py @@ -2469,7 +2469,10 @@ @util.cachefunc def binary(): flog = getfile(fn) - return util.binary(flog.read(ctx.filenode(fn))) + try: + return util.binary(flog.read(ctx.filenode(fn))) + except AttributeError: + return ctx.filectx(fn).isbinary() fieldnamemap = {'filename': 'file', 'linenumber': 'line_number'} if opts.get('all'): @@ -2478,10 +2481,11 @@ iter = [('', l) for l in states] for change, l in iter: fm.startitem() - fm.data(node=fm.hexfunc(ctx.node())) + fm.data(node=fm.hexfunc(scmutil.binnode(ctx))) + showrev = opts.get('all') or opts.get('rev') cols = [ ('filename', fn, True), - ('rev', rev, True), + ('rev', rev, showrev), ('linenumber', l.linenum, opts.get('line_number')), ] if opts.get('all'): @@ -2568,26 +2572,46 @@ ui.pager('grep') fm = ui.formatter('grep', opts) - for ctx in cmdutil.walkchangerevs(repo, match, opts, prep): - rev = ctx.rev() - parent = ctx.p1().rev() - for fn in sorted(revfiles.get(rev, [])): - states = matches[rev][fn] - copy = copies.get(rev, {}).get(fn) - if fn in skip: - if copy: - skip[copy] = True + # This if part handles the default situation,\ + # when nothing is passed in -r or --all + if not (opts.get('rev') or opts.get('all')): + rev = scmutil.revsingle(repo, opts.get('rev'), None).node() + m = scmutil.match(repo[rev], pats, opts, default='relglob') + m.bad = lambda x, y: False + ctx = repo[rev] + ds = ctx.repo().dirstate + + for fn in ctx.matches(m): + if rev is None and ds[fn] == 'r': continue - pstates = matches.get(parent, {}).get(copy or fn, []) - if pstates or states: - r = display(fm, fn, ctx, pstates, states) + data = ctx.filectx(fn).data() + states = [] + for lnum, cstart, cend, line in matchlines(data): + states.append(linestate(line, lnum, cstart, cend)) + if states: + r = display(fm, fn, ctx, [], states) found = found or r - if r and not opts.get('all'): - skip[fn] = True + else : + for ctx in cmdutil.walkchangerevs(repo, match, opts, prep): + rev = ctx.rev() + parent = ctx.p1().rev() + for fn in sorted(revfiles.get(rev, [])): + states = matches[rev][fn] + copy = copies.get(rev, {}).get(fn) + if fn in skip: if copy: skip[copy] = True - del matches[rev] - del revfiles[rev] + continue + pstates = matches.get(parent, {}).get(copy or fn, []) + if pstates or states: + r = display(fm, fn, ctx, pstates, states) + found = found or r + if r and not opts.get('all'): + skip[fn] = True + if copy: + skip[copy] = True + del matches[rev] + del revfiles[rev] fm.end() return not found diff --git a/tests/test-grep.t b/tests/test-grep.t --- a/tests/test-grep.t +++ b/tests/test-grep.t @@ -24,60 +24,60 @@ simple $ hg grep '.*' - port:4:export - port:4:vaportight - port:4:import/export + port:export + port:vaportight + port:import/export $ hg grep port port - port:4:export - port:4:vaportight - port:4:import/export + port:export + port:vaportight + port:import/export simple with color $ hg --config extensions.color= grep --config color.mode=ansi \ > --color=always port port - \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc) - \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc) - \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc) + \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc) + \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc) + \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/ex\x1b[0;31;1mport\x1b[0m (esc) simple templated $ hg grep port \ > -T '{file}:{rev}:{node|short}:{texts % "{if(matched, text|upper, text)}"}\n' - port:4:914fa752cdea:exPORT - port:4:914fa752cdea:vaPORTight - port:4:914fa752cdea:imPORT/exPORT + port::ffffffffffff:exPORT + port::ffffffffffff:vaPORTight + port::ffffffffffff:imPORT/exPORT simple JSON (no "change" field) $ hg grep -Tjson port [ { - "date": [4.0, 0], - "file": "port", - "line_number": 1, - "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c", - "rev": 4, + "date": [0, 0], + "file": "port", + "line_number": 1, + "node": "ffffffffffffffffffffffffffffffffffffffff", + "rev": null, "texts": [{"matched": false, "text": "ex"}, {"matched": true, "text": "port"}], - "user": "spam" - }, - { - "date": [4.0, 0], + "user": "test" + }, + { + "date": [0, 0], "file": "port", "line_number": 2, - "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c", - "rev": 4, + "node": "ffffffffffffffffffffffffffffffffffffffff", + "rev": null, "texts": [{"matched": false, "text": "va"}, {"matched": true, "text": "port"}, {"matched": false, "text": "ight"}], - "user": "spam" - }, - { - "date": [4.0, 0], + "user": "test" + }, + { + "date": [0, 0], "file": "port", "line_number": 3, - "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c", - "rev": 4, + "node": "ffffffffffffffffffffffffffffffffffffffff", + "rev": null, "texts": [{"matched": false, "text": "im"}, {"matched": true, "text": "port"}, {"matched": false, "text": "/ex"}, {"matched": true, "text": "port"}], - "user": "spam" + "user": "test" } ] @@ -86,12 +86,12 @@ $ hg grep -Tjson -l port [ { - "date": [4.0, 0], - "file": "port", - "line_number": 1, - "node": "914fa752cdea87777ac1a8d5c858b0c736218f6c", - "rev": 4, - "user": "spam" + "date": [0, 0], + "file": "port", + "line_number": 1, + "node": "ffffffffffffffffffffffffffffffffffffffff", + "rev": null, + "user": "test" } ] @@ -207,9 +207,9 @@ other $ hg grep -l port port - port:4 + port $ hg grep import port - port:4:import/export + port:import/export $ hg cp port port2 $ hg commit -m 4 -u spam -d '5 0' @@ -217,8 +217,7 @@ follow $ hg grep --traceback -f 'import\n\Z' port2 - port:0:import - + [1] $ echo deport >> port2 $ hg commit -m 5 -u eggs -d '6 0' $ hg grep -f --all -nu port port2 @@ -256,7 +255,7 @@ $ echo blue >> color $ hg ci -m 3 $ hg grep orange - color:3:orange + color:orange $ hg grep --all orange color:3:+:orange color:2:-:orange @@ -265,9 +264,9 @@ test substring match: '^' should only match at the beginning $ hg grep '^.' --config extensions.color= --color debug - [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lack - [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|o]range - [grep.filename|color][grep.sep|:][grep.rev|3][grep.sep|:][grep.match|b]lue + [grep.filename|color][grep.sep|:][grep.match|b]lack + [grep.filename|color][grep.sep|:][grep.match|o]range + [grep.filename|color][grep.sep|:][grep.match|b]lue match in last "line" without newline @@ -275,7 +274,7 @@ $ hg ci -Amnoeol adding noeol $ hg grep loop - noeol:4:no infinite loop + noeol:no infinite loop $ cd .. @@ -292,8 +291,7 @@ $ hg rename color colour $ hg ci -Am rename $ hg grep octarine - colour:1:octarine - color:0:octarine + colour:octarine Used to crash here @@ -340,4 +338,29 @@ $ hg grep "MaCam" --all binfile.bin:0:+: Binary file matches - $ cd .. +Test that grep searches only on working directory + $ cd .. + $ hg init t5 + $ cd t5 + $ echo "mercurial revsets are awesome" > firstfile + $ hg add firstfile + $ hg commit -m 'adds firstfile' + $ hg rm firstfile + $ hg commit -m 'removes firstfile' + $ echo "mercurial revsets are awesome and makes life easier" > secondfile + $ echo "some generic text" > thirdfile + $ hg add secondfile thirdfile + $ hg commit -m 'adds two new files' + $ hg grep 'revsets' + secondfile:mercurial revsets are awesome and makes life easier + $ echo "another generic string" > fourthone + +Search on added but not commit i.e dirty working directory + $ hg add fourthone + $ hg grep "generic" + fourthone:another generic string + thirdfile:some generic text +Search on untracked files | Should fail + $ echo "an apple a day" > genericname + $ hg grep "apple" + [1]