Mercurial > public > mercurial-scm > hg
comparison mercurial/grep.py @ 45700:c694b1841a5e
grep: move prep() to grepsearcher class
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Wed, 09 Sep 2020 16:18:26 +0900 |
parents | 888e633f0c1c |
children | c10c87c8fe79 |
comparison
equal
deleted
inserted
replaced
45699:888e633f0c1c | 45700:c694b1841a5e |
---|---|
12 | 12 |
13 from .i18n import _ | 13 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, |
20 ) | 21 ) |
21 | 22 |
78 for i in pycompat.xrange(blo, bhi): | 79 for i in pycompat.xrange(blo, bhi): |
79 yield (b'+', b[i]) | 80 yield (b'+', b[i]) |
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) |
92 | 104 |
93 self._matches = {} | 105 self._matches = {} |
125 b'cannot search in censored file: ' | 137 b'cannot search in censored file: ' |
126 b'%(filename)s:%(revnum)s\n' | 138 b'%(filename)s:%(revnum)s\n' |
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)) |