Show More
@@ -45,7 +45,6 b' from . import (' | |||||
45 | help, |
|
45 | help, | |
46 | hg, |
|
46 | hg, | |
47 | logcmdutil, |
|
47 | logcmdutil, | |
48 | match as matchmod, |
|
|||
49 | merge as mergemod, |
|
48 | merge as mergemod, | |
50 | mergestate as mergestatemod, |
|
49 | mergestate as mergestatemod, | |
51 | narrowspec, |
|
50 | narrowspec, | |
@@ -3371,6 +3370,7 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
3371 | """ |
|
3370 | """ | |
3372 | opts = pycompat.byteskwargs(opts) |
|
3371 | opts = pycompat.byteskwargs(opts) | |
3373 | diff = opts.get(b'all') or opts.get(b'diff') |
|
3372 | diff = opts.get(b'all') or opts.get(b'diff') | |
|
3373 | follow = opts.get(b'follow') | |||
3374 | if diff and opts.get(b'all_files'): |
|
3374 | if diff and opts.get(b'all_files'): | |
3375 | raise error.Abort(_(b'--diff and --all-files are mutually exclusive')) |
|
3375 | raise error.Abort(_(b'--diff and --all-files are mutually exclusive')) | |
3376 | if opts.get(b'all_files') is None and not diff: |
|
3376 | if opts.get(b'all_files') is None and not diff: | |
@@ -3398,7 +3398,9 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
3398 | if opts.get(b'print0'): |
|
3398 | if opts.get(b'print0'): | |
3399 | sep = eol = b'\0' |
|
3399 | sep = eol = b'\0' | |
3400 |
|
3400 | |||
3401 |
searcher = grepmod.grepsearcher( |
|
3401 | searcher = grepmod.grepsearcher( | |
|
3402 | ui, repo, regexp, all_files=all_files, diff=diff, follow=follow | |||
|
3403 | ) | |||
3402 |
|
3404 | |||
3403 | getfile = searcher._getfile |
|
3405 | getfile = searcher._getfile | |
3404 | matches = searcher._matches |
|
3406 | matches = searcher._matches | |
@@ -3515,58 +3517,6 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
3515 | skip = searcher._skip |
|
3517 | skip = searcher._skip | |
3516 | revfiles = searcher._revfiles |
|
3518 | revfiles = searcher._revfiles | |
3517 | found = False |
|
3519 | found = False | |
3518 | follow = opts.get(b'follow') |
|
|||
3519 |
|
||||
3520 | getrenamed = searcher._getrenamed |
|
|||
3521 |
|
||||
3522 | def prep(ctx, fmatch): |
|
|||
3523 | rev = ctx.rev() |
|
|||
3524 | pctx = ctx.p1() |
|
|||
3525 | matches.setdefault(rev, {}) |
|
|||
3526 | if diff: |
|
|||
3527 | parent = pctx.rev() |
|
|||
3528 | matches.setdefault(parent, {}) |
|
|||
3529 | files = revfiles.setdefault(rev, []) |
|
|||
3530 | if rev is None: |
|
|||
3531 | # in `hg grep pattern`, 2/3 of the time is spent is spent in |
|
|||
3532 | # pathauditor checks without this in mozilla-central |
|
|||
3533 | contextmanager = repo.wvfs.audit.cached |
|
|||
3534 | else: |
|
|||
3535 | contextmanager = util.nullcontextmanager |
|
|||
3536 | with contextmanager(): |
|
|||
3537 | # TODO: maybe better to warn missing files? |
|
|||
3538 | if all_files: |
|
|||
3539 | fmatch = matchmod.badmatch(fmatch, lambda f, msg: None) |
|
|||
3540 | filenames = ctx.matches(fmatch) |
|
|||
3541 | else: |
|
|||
3542 | filenames = (f for f in ctx.files() if fmatch(f)) |
|
|||
3543 | for fn in filenames: |
|
|||
3544 | # fn might not exist in the revision (could be a file removed by |
|
|||
3545 | # the revision). We could check `fn not in ctx` even when rev is |
|
|||
3546 | # None, but it's less racy to protect againt that in readfile. |
|
|||
3547 | if rev is not None and fn not in ctx: |
|
|||
3548 | continue |
|
|||
3549 |
|
||||
3550 | copy = None |
|
|||
3551 | if follow: |
|
|||
3552 | copy = getrenamed(fn, rev) |
|
|||
3553 | if copy: |
|
|||
3554 | copies.setdefault(rev, {})[fn] = copy |
|
|||
3555 | if fn in skip: |
|
|||
3556 | skip.add(copy) |
|
|||
3557 | if fn in skip: |
|
|||
3558 | continue |
|
|||
3559 | files.append(fn) |
|
|||
3560 |
|
||||
3561 | if fn not in matches[rev]: |
|
|||
3562 | searcher._grepbody(fn, rev, searcher._readfile(ctx, fn)) |
|
|||
3563 |
|
||||
3564 | if diff: |
|
|||
3565 | pfn = copy or fn |
|
|||
3566 | if pfn not in matches[parent] and pfn in pctx: |
|
|||
3567 | searcher._grepbody( |
|
|||
3568 | pfn, parent, searcher._readfile(pctx, pfn) |
|
|||
3569 | ) |
|
|||
3570 |
|
3520 | |||
3571 | wopts = logcmdutil.walkopts( |
|
3521 | wopts = logcmdutil.walkopts( | |
3572 | pats=pats, |
|
3522 | pats=pats, | |
@@ -3582,7 +3532,9 b' def grep(ui, repo, pattern, *pats, **opt' | |||||
3582 |
|
3532 | |||
3583 | ui.pager(b'grep') |
|
3533 | ui.pager(b'grep') | |
3584 | fm = ui.formatter(b'grep', opts) |
|
3534 | fm = ui.formatter(b'grep', opts) | |
3585 |
for ctx in cmdutil.walkchangerevs( |
|
3535 | for ctx in cmdutil.walkchangerevs( | |
|
3536 | repo, revs, makefilematcher, searcher._prep | |||
|
3537 | ): | |||
3586 | rev = ctx.rev() |
|
3538 | rev = ctx.rev() | |
3587 | parent = ctx.p1().rev() |
|
3539 | parent = ctx.p1().rev() | |
3588 | for fn in sorted(revfiles.get(rev, [])): |
|
3540 | for fn in sorted(revfiles.get(rev, [])): |
@@ -14,6 +14,7 b' from .i18n import _' | |||||
14 |
|
14 | |||
15 | from . import ( |
|
15 | from . import ( | |
16 | error, |
|
16 | error, | |
|
17 | match as matchmod, | |||
17 | pycompat, |
|
18 | pycompat, | |
18 | scmutil, |
|
19 | scmutil, | |
19 | util, |
|
20 | util, | |
@@ -80,12 +81,23 b' def difflinestates(a, b):' | |||||
80 |
|
81 | |||
81 |
|
82 | |||
82 | class grepsearcher(object): |
|
83 | class grepsearcher(object): | |
83 |
"""Search files and revisions for lines matching the given pattern |
|
84 | """Search files and revisions for lines matching the given pattern | |
84 |
|
|
85 | ||
85 | def __init__(self, ui, repo, regexp): |
|
86 | Options: | |
|
87 | - all_files to search unchanged files at that revision. | |||
|
88 | - diff to search files in the parent revision so diffs can be generated. | |||
|
89 | - follow to skip files across copies and renames. | |||
|
90 | """ | |||
|
91 | ||||
|
92 | def __init__( | |||
|
93 | self, ui, repo, regexp, all_files=False, diff=False, follow=False | |||
|
94 | ): | |||
86 | self._ui = ui |
|
95 | self._ui = ui | |
87 | self._repo = repo |
|
96 | self._repo = repo | |
88 | self._regexp = regexp |
|
97 | self._regexp = regexp | |
|
98 | self._all_files = all_files | |||
|
99 | self._diff = diff | |||
|
100 | self._follow = follow | |||
89 |
|
101 | |||
90 | self._getfile = util.lrucachefunc(repo.file) |
|
102 | self._getfile = util.lrucachefunc(repo.file) | |
91 | self._getrenamed = scmutil.getrenamedfn(repo) |
|
103 | self._getrenamed = scmutil.getrenamedfn(repo) | |
@@ -127,3 +139,50 b' class grepsearcher(object):' | |||||
127 | ) |
|
139 | ) | |
128 | % {b'filename': fn, b'revnum': pycompat.bytestr(rev)} |
|
140 | % {b'filename': fn, b'revnum': pycompat.bytestr(rev)} | |
129 | ) |
|
141 | ) | |
|
142 | ||||
|
143 | def _prep(self, ctx, fmatch): | |||
|
144 | rev = ctx.rev() | |||
|
145 | pctx = ctx.p1() | |||
|
146 | self._matches.setdefault(rev, {}) | |||
|
147 | if self._diff: | |||
|
148 | parent = pctx.rev() | |||
|
149 | self._matches.setdefault(parent, {}) | |||
|
150 | files = self._revfiles.setdefault(rev, []) | |||
|
151 | if rev is None: | |||
|
152 | # in `hg grep pattern`, 2/3 of the time is spent is spent in | |||
|
153 | # pathauditor checks without this in mozilla-central | |||
|
154 | contextmanager = self._repo.wvfs.audit.cached | |||
|
155 | else: | |||
|
156 | contextmanager = util.nullcontextmanager | |||
|
157 | with contextmanager(): | |||
|
158 | # TODO: maybe better to warn missing files? | |||
|
159 | if self._all_files: | |||
|
160 | fmatch = matchmod.badmatch(fmatch, lambda f, msg: None) | |||
|
161 | filenames = ctx.matches(fmatch) | |||
|
162 | else: | |||
|
163 | filenames = (f for f in ctx.files() if fmatch(f)) | |||
|
164 | for fn in filenames: | |||
|
165 | # fn might not exist in the revision (could be a file removed by | |||
|
166 | # the revision). We could check `fn not in ctx` even when rev is | |||
|
167 | # None, but it's less racy to protect againt that in readfile. | |||
|
168 | if rev is not None and fn not in ctx: | |||
|
169 | continue | |||
|
170 | ||||
|
171 | copy = None | |||
|
172 | if self._follow: | |||
|
173 | copy = self._getrenamed(fn, rev) | |||
|
174 | if copy: | |||
|
175 | self._copies.setdefault(rev, {})[fn] = copy | |||
|
176 | if fn in self._skip: | |||
|
177 | self._skip.add(copy) | |||
|
178 | if fn in self._skip: | |||
|
179 | continue | |||
|
180 | files.append(fn) | |||
|
181 | ||||
|
182 | if fn not in self._matches[rev]: | |||
|
183 | self._grepbody(fn, rev, self._readfile(ctx, fn)) | |||
|
184 | ||||
|
185 | if self._diff: | |||
|
186 | pfn = copy or fn | |||
|
187 | if pfn not in self._matches[parent] and pfn in pctx: | |||
|
188 | self._grepbody(pfn, parent, self._readfile(pctx, pfn)) |
General Comments 0
You need to be logged in to leave comments.
Login now