117 symbols = filesetlang.symbols |
117 symbols = filesetlang.symbols |
118 |
118 |
119 predicate = registrar.filesetpredicate(symbols) |
119 predicate = registrar.filesetpredicate(symbols) |
120 |
120 |
121 |
121 |
122 @predicate('modified()', callstatus=True, weight=_WEIGHT_STATUS) |
122 @predicate(b'modified()', callstatus=True, weight=_WEIGHT_STATUS) |
123 def modified(mctx, x): |
123 def modified(mctx, x): |
124 """File that is modified according to :hg:`status`. |
124 """File that is modified according to :hg:`status`. |
125 """ |
125 """ |
126 # i18n: "modified" is a keyword |
126 # i18n: "modified" is a keyword |
127 getargs(x, 0, 0, _("modified takes no arguments")) |
127 getargs(x, 0, 0, _(b"modified takes no arguments")) |
128 s = set(mctx.status().modified) |
128 s = set(mctx.status().modified) |
129 return mctx.predicate(s.__contains__, predrepr='modified') |
129 return mctx.predicate(s.__contains__, predrepr=b'modified') |
130 |
130 |
131 |
131 |
132 @predicate('added()', callstatus=True, weight=_WEIGHT_STATUS) |
132 @predicate(b'added()', callstatus=True, weight=_WEIGHT_STATUS) |
133 def added(mctx, x): |
133 def added(mctx, x): |
134 """File that is added according to :hg:`status`. |
134 """File that is added according to :hg:`status`. |
135 """ |
135 """ |
136 # i18n: "added" is a keyword |
136 # i18n: "added" is a keyword |
137 getargs(x, 0, 0, _("added takes no arguments")) |
137 getargs(x, 0, 0, _(b"added takes no arguments")) |
138 s = set(mctx.status().added) |
138 s = set(mctx.status().added) |
139 return mctx.predicate(s.__contains__, predrepr='added') |
139 return mctx.predicate(s.__contains__, predrepr=b'added') |
140 |
140 |
141 |
141 |
142 @predicate('removed()', callstatus=True, weight=_WEIGHT_STATUS) |
142 @predicate(b'removed()', callstatus=True, weight=_WEIGHT_STATUS) |
143 def removed(mctx, x): |
143 def removed(mctx, x): |
144 """File that is removed according to :hg:`status`. |
144 """File that is removed according to :hg:`status`. |
145 """ |
145 """ |
146 # i18n: "removed" is a keyword |
146 # i18n: "removed" is a keyword |
147 getargs(x, 0, 0, _("removed takes no arguments")) |
147 getargs(x, 0, 0, _(b"removed takes no arguments")) |
148 s = set(mctx.status().removed) |
148 s = set(mctx.status().removed) |
149 return mctx.predicate(s.__contains__, predrepr='removed') |
149 return mctx.predicate(s.__contains__, predrepr=b'removed') |
150 |
150 |
151 |
151 |
152 @predicate('deleted()', callstatus=True, weight=_WEIGHT_STATUS) |
152 @predicate(b'deleted()', callstatus=True, weight=_WEIGHT_STATUS) |
153 def deleted(mctx, x): |
153 def deleted(mctx, x): |
154 """Alias for ``missing()``. |
154 """Alias for ``missing()``. |
155 """ |
155 """ |
156 # i18n: "deleted" is a keyword |
156 # i18n: "deleted" is a keyword |
157 getargs(x, 0, 0, _("deleted takes no arguments")) |
157 getargs(x, 0, 0, _(b"deleted takes no arguments")) |
158 s = set(mctx.status().deleted) |
158 s = set(mctx.status().deleted) |
159 return mctx.predicate(s.__contains__, predrepr='deleted') |
159 return mctx.predicate(s.__contains__, predrepr=b'deleted') |
160 |
160 |
161 |
161 |
162 @predicate('missing()', callstatus=True, weight=_WEIGHT_STATUS) |
162 @predicate(b'missing()', callstatus=True, weight=_WEIGHT_STATUS) |
163 def missing(mctx, x): |
163 def missing(mctx, x): |
164 """File that is missing according to :hg:`status`. |
164 """File that is missing according to :hg:`status`. |
165 """ |
165 """ |
166 # i18n: "missing" is a keyword |
166 # i18n: "missing" is a keyword |
167 getargs(x, 0, 0, _("missing takes no arguments")) |
167 getargs(x, 0, 0, _(b"missing takes no arguments")) |
168 s = set(mctx.status().deleted) |
168 s = set(mctx.status().deleted) |
169 return mctx.predicate(s.__contains__, predrepr='deleted') |
169 return mctx.predicate(s.__contains__, predrepr=b'deleted') |
170 |
170 |
171 |
171 |
172 @predicate('unknown()', callstatus=True, weight=_WEIGHT_STATUS_THOROUGH) |
172 @predicate(b'unknown()', callstatus=True, weight=_WEIGHT_STATUS_THOROUGH) |
173 def unknown(mctx, x): |
173 def unknown(mctx, x): |
174 """File that is unknown according to :hg:`status`.""" |
174 """File that is unknown according to :hg:`status`.""" |
175 # i18n: "unknown" is a keyword |
175 # i18n: "unknown" is a keyword |
176 getargs(x, 0, 0, _("unknown takes no arguments")) |
176 getargs(x, 0, 0, _(b"unknown takes no arguments")) |
177 s = set(mctx.status().unknown) |
177 s = set(mctx.status().unknown) |
178 return mctx.predicate(s.__contains__, predrepr='unknown') |
178 return mctx.predicate(s.__contains__, predrepr=b'unknown') |
179 |
179 |
180 |
180 |
181 @predicate('ignored()', callstatus=True, weight=_WEIGHT_STATUS_THOROUGH) |
181 @predicate(b'ignored()', callstatus=True, weight=_WEIGHT_STATUS_THOROUGH) |
182 def ignored(mctx, x): |
182 def ignored(mctx, x): |
183 """File that is ignored according to :hg:`status`.""" |
183 """File that is ignored according to :hg:`status`.""" |
184 # i18n: "ignored" is a keyword |
184 # i18n: "ignored" is a keyword |
185 getargs(x, 0, 0, _("ignored takes no arguments")) |
185 getargs(x, 0, 0, _(b"ignored takes no arguments")) |
186 s = set(mctx.status().ignored) |
186 s = set(mctx.status().ignored) |
187 return mctx.predicate(s.__contains__, predrepr='ignored') |
187 return mctx.predicate(s.__contains__, predrepr=b'ignored') |
188 |
188 |
189 |
189 |
190 @predicate('clean()', callstatus=True, weight=_WEIGHT_STATUS) |
190 @predicate(b'clean()', callstatus=True, weight=_WEIGHT_STATUS) |
191 def clean(mctx, x): |
191 def clean(mctx, x): |
192 """File that is clean according to :hg:`status`. |
192 """File that is clean according to :hg:`status`. |
193 """ |
193 """ |
194 # i18n: "clean" is a keyword |
194 # i18n: "clean" is a keyword |
195 getargs(x, 0, 0, _("clean takes no arguments")) |
195 getargs(x, 0, 0, _(b"clean takes no arguments")) |
196 s = set(mctx.status().clean) |
196 s = set(mctx.status().clean) |
197 return mctx.predicate(s.__contains__, predrepr='clean') |
197 return mctx.predicate(s.__contains__, predrepr=b'clean') |
198 |
198 |
199 |
199 |
200 @predicate('tracked()') |
200 @predicate(b'tracked()') |
201 def tracked(mctx, x): |
201 def tracked(mctx, x): |
202 """File that is under Mercurial control.""" |
202 """File that is under Mercurial control.""" |
203 # i18n: "tracked" is a keyword |
203 # i18n: "tracked" is a keyword |
204 getargs(x, 0, 0, _("tracked takes no arguments")) |
204 getargs(x, 0, 0, _(b"tracked takes no arguments")) |
205 return mctx.predicate(mctx.ctx.__contains__, predrepr='tracked') |
205 return mctx.predicate(mctx.ctx.__contains__, predrepr=b'tracked') |
206 |
206 |
207 |
207 |
208 @predicate('binary()', weight=_WEIGHT_READ_CONTENTS) |
208 @predicate(b'binary()', weight=_WEIGHT_READ_CONTENTS) |
209 def binary(mctx, x): |
209 def binary(mctx, x): |
210 """File that appears to be binary (contains NUL bytes). |
210 """File that appears to be binary (contains NUL bytes). |
211 """ |
211 """ |
212 # i18n: "binary" is a keyword |
212 # i18n: "binary" is a keyword |
213 getargs(x, 0, 0, _("binary takes no arguments")) |
213 getargs(x, 0, 0, _(b"binary takes no arguments")) |
214 return mctx.fpredicate( |
214 return mctx.fpredicate( |
215 lambda fctx: fctx.isbinary(), predrepr='binary', cache=True |
215 lambda fctx: fctx.isbinary(), predrepr=b'binary', cache=True |
216 ) |
216 ) |
217 |
217 |
218 |
218 |
219 @predicate('exec()') |
219 @predicate(b'exec()') |
220 def exec_(mctx, x): |
220 def exec_(mctx, x): |
221 """File that is marked as executable. |
221 """File that is marked as executable. |
222 """ |
222 """ |
223 # i18n: "exec" is a keyword |
223 # i18n: "exec" is a keyword |
224 getargs(x, 0, 0, _("exec takes no arguments")) |
224 getargs(x, 0, 0, _(b"exec takes no arguments")) |
225 ctx = mctx.ctx |
225 ctx = mctx.ctx |
226 return mctx.predicate(lambda f: ctx.flags(f) == 'x', predrepr='exec') |
226 return mctx.predicate(lambda f: ctx.flags(f) == b'x', predrepr=b'exec') |
227 |
227 |
228 |
228 |
229 @predicate('symlink()') |
229 @predicate(b'symlink()') |
230 def symlink(mctx, x): |
230 def symlink(mctx, x): |
231 """File that is marked as a symlink. |
231 """File that is marked as a symlink. |
232 """ |
232 """ |
233 # i18n: "symlink" is a keyword |
233 # i18n: "symlink" is a keyword |
234 getargs(x, 0, 0, _("symlink takes no arguments")) |
234 getargs(x, 0, 0, _(b"symlink takes no arguments")) |
235 ctx = mctx.ctx |
235 ctx = mctx.ctx |
236 return mctx.predicate(lambda f: ctx.flags(f) == 'l', predrepr='symlink') |
236 return mctx.predicate(lambda f: ctx.flags(f) == b'l', predrepr=b'symlink') |
237 |
237 |
238 |
238 |
239 @predicate('resolved()', weight=_WEIGHT_STATUS) |
239 @predicate(b'resolved()', weight=_WEIGHT_STATUS) |
240 def resolved(mctx, x): |
240 def resolved(mctx, x): |
241 """File that is marked resolved according to :hg:`resolve -l`. |
241 """File that is marked resolved according to :hg:`resolve -l`. |
242 """ |
242 """ |
243 # i18n: "resolved" is a keyword |
243 # i18n: "resolved" is a keyword |
244 getargs(x, 0, 0, _("resolved takes no arguments")) |
244 getargs(x, 0, 0, _(b"resolved takes no arguments")) |
245 if mctx.ctx.rev() is not None: |
245 if mctx.ctx.rev() is not None: |
246 return mctx.never() |
246 return mctx.never() |
247 ms = merge.mergestate.read(mctx.ctx.repo()) |
247 ms = merge.mergestate.read(mctx.ctx.repo()) |
248 return mctx.predicate( |
248 return mctx.predicate( |
249 lambda f: f in ms and ms[f] == 'r', predrepr='resolved' |
249 lambda f: f in ms and ms[f] == b'r', predrepr=b'resolved' |
250 ) |
250 ) |
251 |
251 |
252 |
252 |
253 @predicate('unresolved()', weight=_WEIGHT_STATUS) |
253 @predicate(b'unresolved()', weight=_WEIGHT_STATUS) |
254 def unresolved(mctx, x): |
254 def unresolved(mctx, x): |
255 """File that is marked unresolved according to :hg:`resolve -l`. |
255 """File that is marked unresolved according to :hg:`resolve -l`. |
256 """ |
256 """ |
257 # i18n: "unresolved" is a keyword |
257 # i18n: "unresolved" is a keyword |
258 getargs(x, 0, 0, _("unresolved takes no arguments")) |
258 getargs(x, 0, 0, _(b"unresolved takes no arguments")) |
259 if mctx.ctx.rev() is not None: |
259 if mctx.ctx.rev() is not None: |
260 return mctx.never() |
260 return mctx.never() |
261 ms = merge.mergestate.read(mctx.ctx.repo()) |
261 ms = merge.mergestate.read(mctx.ctx.repo()) |
262 return mctx.predicate( |
262 return mctx.predicate( |
263 lambda f: f in ms and ms[f] == 'u', predrepr='unresolved' |
263 lambda f: f in ms and ms[f] == b'u', predrepr=b'unresolved' |
264 ) |
264 ) |
265 |
265 |
266 |
266 |
267 @predicate('hgignore()', weight=_WEIGHT_STATUS) |
267 @predicate(b'hgignore()', weight=_WEIGHT_STATUS) |
268 def hgignore(mctx, x): |
268 def hgignore(mctx, x): |
269 """File that matches the active .hgignore pattern. |
269 """File that matches the active .hgignore pattern. |
270 """ |
270 """ |
271 # i18n: "hgignore" is a keyword |
271 # i18n: "hgignore" is a keyword |
272 getargs(x, 0, 0, _("hgignore takes no arguments")) |
272 getargs(x, 0, 0, _(b"hgignore takes no arguments")) |
273 return mctx.ctx.repo().dirstate._ignore |
273 return mctx.ctx.repo().dirstate._ignore |
274 |
274 |
275 |
275 |
276 @predicate('portable()', weight=_WEIGHT_CHECK_FILENAME) |
276 @predicate(b'portable()', weight=_WEIGHT_CHECK_FILENAME) |
277 def portable(mctx, x): |
277 def portable(mctx, x): |
278 """File that has a portable name. (This doesn't include filenames with case |
278 """File that has a portable name. (This doesn't include filenames with case |
279 collisions.) |
279 collisions.) |
280 """ |
280 """ |
281 # i18n: "portable" is a keyword |
281 # i18n: "portable" is a keyword |
282 getargs(x, 0, 0, _("portable takes no arguments")) |
282 getargs(x, 0, 0, _(b"portable takes no arguments")) |
283 return mctx.predicate( |
283 return mctx.predicate( |
284 lambda f: util.checkwinfilename(f) is None, predrepr='portable' |
284 lambda f: util.checkwinfilename(f) is None, predrepr=b'portable' |
285 ) |
285 ) |
286 |
286 |
287 |
287 |
288 @predicate('grep(regex)', weight=_WEIGHT_READ_CONTENTS) |
288 @predicate(b'grep(regex)', weight=_WEIGHT_READ_CONTENTS) |
289 def grep(mctx, x): |
289 def grep(mctx, x): |
290 """File contains the given regular expression. |
290 """File contains the given regular expression. |
291 """ |
291 """ |
292 try: |
292 try: |
293 # i18n: "grep" is a keyword |
293 # i18n: "grep" is a keyword |
294 r = re.compile(getstring(x, _("grep requires a pattern"))) |
294 r = re.compile(getstring(x, _(b"grep requires a pattern"))) |
295 except re.error as e: |
295 except re.error as e: |
296 raise error.ParseError( |
296 raise error.ParseError( |
297 _('invalid match pattern: %s') % stringutil.forcebytestr(e) |
297 _(b'invalid match pattern: %s') % stringutil.forcebytestr(e) |
298 ) |
298 ) |
299 return mctx.fpredicate( |
299 return mctx.fpredicate( |
300 lambda fctx: r.search(fctx.data()), |
300 lambda fctx: r.search(fctx.data()), |
301 predrepr=('grep(%r)', r.pattern), |
301 predrepr=(b'grep(%r)', r.pattern), |
302 cache=True, |
302 cache=True, |
303 ) |
303 ) |
304 |
304 |
305 |
305 |
306 def _sizetomax(s): |
306 def _sizetomax(s): |
309 for k, v in util._sizeunits: |
309 for k, v in util._sizeunits: |
310 if s.endswith(k): |
310 if s.endswith(k): |
311 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1 |
311 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1 |
312 n = s[: -len(k)] |
312 n = s[: -len(k)] |
313 inc = 1.0 |
313 inc = 1.0 |
314 if "." in n: |
314 if b"." in n: |
315 inc /= 10 ** len(n.split(".")[1]) |
315 inc /= 10 ** len(n.split(b".")[1]) |
316 return int((float(n) + inc) * v) - 1 |
316 return int((float(n) + inc) * v) - 1 |
317 # no extension, this is a precise value |
317 # no extension, this is a precise value |
318 return int(s) |
318 return int(s) |
319 except ValueError: |
319 except ValueError: |
320 raise error.ParseError(_("couldn't parse size: %s") % s) |
320 raise error.ParseError(_(b"couldn't parse size: %s") % s) |
321 |
321 |
322 |
322 |
323 def sizematcher(expr): |
323 def sizematcher(expr): |
324 """Return a function(size) -> bool from the ``size()`` expression""" |
324 """Return a function(size) -> bool from the ``size()`` expression""" |
325 expr = expr.strip() |
325 expr = expr.strip() |
326 if '-' in expr: # do we have a range? |
326 if b'-' in expr: # do we have a range? |
327 a, b = expr.split('-', 1) |
327 a, b = expr.split(b'-', 1) |
328 a = util.sizetoint(a) |
328 a = util.sizetoint(a) |
329 b = util.sizetoint(b) |
329 b = util.sizetoint(b) |
330 return lambda x: x >= a and x <= b |
330 return lambda x: x >= a and x <= b |
331 elif expr.startswith("<="): |
331 elif expr.startswith(b"<="): |
332 a = util.sizetoint(expr[2:]) |
332 a = util.sizetoint(expr[2:]) |
333 return lambda x: x <= a |
333 return lambda x: x <= a |
334 elif expr.startswith("<"): |
334 elif expr.startswith(b"<"): |
335 a = util.sizetoint(expr[1:]) |
335 a = util.sizetoint(expr[1:]) |
336 return lambda x: x < a |
336 return lambda x: x < a |
337 elif expr.startswith(">="): |
337 elif expr.startswith(b">="): |
338 a = util.sizetoint(expr[2:]) |
338 a = util.sizetoint(expr[2:]) |
339 return lambda x: x >= a |
339 return lambda x: x >= a |
340 elif expr.startswith(">"): |
340 elif expr.startswith(b">"): |
341 a = util.sizetoint(expr[1:]) |
341 a = util.sizetoint(expr[1:]) |
342 return lambda x: x > a |
342 return lambda x: x > a |
343 else: |
343 else: |
344 a = util.sizetoint(expr) |
344 a = util.sizetoint(expr) |
345 b = _sizetomax(expr) |
345 b = _sizetomax(expr) |
346 return lambda x: x >= a and x <= b |
346 return lambda x: x >= a and x <= b |
347 |
347 |
348 |
348 |
349 @predicate('size(expression)', weight=_WEIGHT_STATUS) |
349 @predicate(b'size(expression)', weight=_WEIGHT_STATUS) |
350 def size(mctx, x): |
350 def size(mctx, x): |
351 """File size matches the given expression. Examples: |
351 """File size matches the given expression. Examples: |
352 |
352 |
353 - size('1k') - files from 1024 to 2047 bytes |
353 - size('1k') - files from 1024 to 2047 bytes |
354 - size('< 20k') - files less than 20480 bytes |
354 - size('< 20k') - files less than 20480 bytes |
355 - size('>= .5MB') - files at least 524288 bytes |
355 - size('>= .5MB') - files at least 524288 bytes |
356 - size('4k - 1MB') - files from 4096 bytes to 1048576 bytes |
356 - size('4k - 1MB') - files from 4096 bytes to 1048576 bytes |
357 """ |
357 """ |
358 # i18n: "size" is a keyword |
358 # i18n: "size" is a keyword |
359 expr = getstring(x, _("size requires an expression")) |
359 expr = getstring(x, _(b"size requires an expression")) |
360 m = sizematcher(expr) |
360 m = sizematcher(expr) |
361 return mctx.fpredicate( |
361 return mctx.fpredicate( |
362 lambda fctx: m(fctx.size()), predrepr=('size(%r)', expr), cache=True |
362 lambda fctx: m(fctx.size()), predrepr=(b'size(%r)', expr), cache=True |
363 ) |
363 ) |
364 |
364 |
365 |
365 |
366 @predicate('encoding(name)', weight=_WEIGHT_READ_CONTENTS) |
366 @predicate(b'encoding(name)', weight=_WEIGHT_READ_CONTENTS) |
367 def encoding(mctx, x): |
367 def encoding(mctx, x): |
368 """File can be successfully decoded with the given character |
368 """File can be successfully decoded with the given character |
369 encoding. May not be useful for encodings other than ASCII and |
369 encoding. May not be useful for encodings other than ASCII and |
370 UTF-8. |
370 UTF-8. |
371 """ |
371 """ |
372 |
372 |
373 # i18n: "encoding" is a keyword |
373 # i18n: "encoding" is a keyword |
374 enc = getstring(x, _("encoding requires an encoding name")) |
374 enc = getstring(x, _(b"encoding requires an encoding name")) |
375 |
375 |
376 def encp(fctx): |
376 def encp(fctx): |
377 d = fctx.data() |
377 d = fctx.data() |
378 try: |
378 try: |
379 d.decode(pycompat.sysstr(enc)) |
379 d.decode(pycompat.sysstr(enc)) |
380 return True |
380 return True |
381 except LookupError: |
381 except LookupError: |
382 raise error.Abort(_("unknown encoding '%s'") % enc) |
382 raise error.Abort(_(b"unknown encoding '%s'") % enc) |
383 except UnicodeDecodeError: |
383 except UnicodeDecodeError: |
384 return False |
384 return False |
385 |
385 |
386 return mctx.fpredicate(encp, predrepr=('encoding(%r)', enc), cache=True) |
386 return mctx.fpredicate(encp, predrepr=(b'encoding(%r)', enc), cache=True) |
387 |
387 |
388 |
388 |
389 @predicate('eol(style)', weight=_WEIGHT_READ_CONTENTS) |
389 @predicate(b'eol(style)', weight=_WEIGHT_READ_CONTENTS) |
390 def eol(mctx, x): |
390 def eol(mctx, x): |
391 """File contains newlines of the given style (dos, unix, mac). Binary |
391 """File contains newlines of the given style (dos, unix, mac). Binary |
392 files are excluded, files with mixed line endings match multiple |
392 files are excluded, files with mixed line endings match multiple |
393 styles. |
393 styles. |
394 """ |
394 """ |
395 |
395 |
396 # i18n: "eol" is a keyword |
396 # i18n: "eol" is a keyword |
397 enc = getstring(x, _("eol requires a style name")) |
397 enc = getstring(x, _(b"eol requires a style name")) |
398 |
398 |
399 def eolp(fctx): |
399 def eolp(fctx): |
400 if fctx.isbinary(): |
400 if fctx.isbinary(): |
401 return False |
401 return False |
402 d = fctx.data() |
402 d = fctx.data() |
403 if (enc == 'dos' or enc == 'win') and '\r\n' in d: |
403 if (enc == b'dos' or enc == b'win') and b'\r\n' in d: |
404 return True |
404 return True |
405 elif enc == 'unix' and re.search('(?<!\r)\n', d): |
405 elif enc == b'unix' and re.search(b'(?<!\r)\n', d): |
406 return True |
406 return True |
407 elif enc == 'mac' and re.search('\r(?!\n)', d): |
407 elif enc == b'mac' and re.search(b'\r(?!\n)', d): |
408 return True |
408 return True |
409 return False |
409 return False |
410 |
410 |
411 return mctx.fpredicate(eolp, predrepr=('eol(%r)', enc), cache=True) |
411 return mctx.fpredicate(eolp, predrepr=(b'eol(%r)', enc), cache=True) |
412 |
412 |
413 |
413 |
414 @predicate('copied()') |
414 @predicate(b'copied()') |
415 def copied(mctx, x): |
415 def copied(mctx, x): |
416 """File that is recorded as being copied. |
416 """File that is recorded as being copied. |
417 """ |
417 """ |
418 # i18n: "copied" is a keyword |
418 # i18n: "copied" is a keyword |
419 getargs(x, 0, 0, _("copied takes no arguments")) |
419 getargs(x, 0, 0, _(b"copied takes no arguments")) |
420 |
420 |
421 def copiedp(fctx): |
421 def copiedp(fctx): |
422 p = fctx.parents() |
422 p = fctx.parents() |
423 return p and p[0].path() != fctx.path() |
423 return p and p[0].path() != fctx.path() |
424 |
424 |
425 return mctx.fpredicate(copiedp, predrepr='copied', cache=True) |
425 return mctx.fpredicate(copiedp, predrepr=b'copied', cache=True) |
426 |
426 |
427 |
427 |
428 @predicate('revs(revs, pattern)', weight=_WEIGHT_STATUS) |
428 @predicate(b'revs(revs, pattern)', weight=_WEIGHT_STATUS) |
429 def revs(mctx, x): |
429 def revs(mctx, x): |
430 """Evaluate set in the specified revisions. If the revset match multiple |
430 """Evaluate set in the specified revisions. If the revset match multiple |
431 revs, this will return file matching pattern in any of the revision. |
431 revs, this will return file matching pattern in any of the revision. |
432 """ |
432 """ |
433 # i18n: "revs" is a keyword |
433 # i18n: "revs" is a keyword |
434 r, x = getargs(x, 2, 2, _("revs takes two arguments")) |
434 r, x = getargs(x, 2, 2, _(b"revs takes two arguments")) |
435 # i18n: "revs" is a keyword |
435 # i18n: "revs" is a keyword |
436 revspec = getstring(r, _("first argument to revs must be a revision")) |
436 revspec = getstring(r, _(b"first argument to revs must be a revision")) |
437 repo = mctx.ctx.repo() |
437 repo = mctx.ctx.repo() |
438 revs = scmutil.revrange(repo, [revspec]) |
438 revs = scmutil.revrange(repo, [revspec]) |
439 |
439 |
440 matchers = [] |
440 matchers = [] |
441 for r in revs: |
441 for r in revs: |
447 if len(matchers) == 1: |
447 if len(matchers) == 1: |
448 return matchers[0] |
448 return matchers[0] |
449 return matchmod.unionmatcher(matchers) |
449 return matchmod.unionmatcher(matchers) |
450 |
450 |
451 |
451 |
452 @predicate('status(base, rev, pattern)', weight=_WEIGHT_STATUS) |
452 @predicate(b'status(base, rev, pattern)', weight=_WEIGHT_STATUS) |
453 def status(mctx, x): |
453 def status(mctx, x): |
454 """Evaluate predicate using status change between ``base`` and |
454 """Evaluate predicate using status change between ``base`` and |
455 ``rev``. Examples: |
455 ``rev``. Examples: |
456 |
456 |
457 - ``status(3, 7, added())`` - matches files added from "3" to "7" |
457 - ``status(3, 7, added())`` - matches files added from "3" to "7" |
458 """ |
458 """ |
459 repo = mctx.ctx.repo() |
459 repo = mctx.ctx.repo() |
460 # i18n: "status" is a keyword |
460 # i18n: "status" is a keyword |
461 b, r, x = getargs(x, 3, 3, _("status takes three arguments")) |
461 b, r, x = getargs(x, 3, 3, _(b"status takes three arguments")) |
462 # i18n: "status" is a keyword |
462 # i18n: "status" is a keyword |
463 baseerr = _("first argument to status must be a revision") |
463 baseerr = _(b"first argument to status must be a revision") |
464 baserevspec = getstring(b, baseerr) |
464 baserevspec = getstring(b, baseerr) |
465 if not baserevspec: |
465 if not baserevspec: |
466 raise error.ParseError(baseerr) |
466 raise error.ParseError(baseerr) |
467 reverr = _("second argument to status must be a revision") |
467 reverr = _(b"second argument to status must be a revision") |
468 revspec = getstring(r, reverr) |
468 revspec = getstring(r, reverr) |
469 if not revspec: |
469 if not revspec: |
470 raise error.ParseError(reverr) |
470 raise error.ParseError(reverr) |
471 basectx, ctx = scmutil.revpair(repo, [baserevspec, revspec]) |
471 basectx, ctx = scmutil.revpair(repo, [baserevspec, revspec]) |
472 mc = mctx.switch(basectx, ctx) |
472 mc = mctx.switch(basectx, ctx) |
473 return getmatch(mc, x) |
473 return getmatch(mc, x) |
474 |
474 |
475 |
475 |
476 @predicate('subrepo([pattern])') |
476 @predicate(b'subrepo([pattern])') |
477 def subrepo(mctx, x): |
477 def subrepo(mctx, x): |
478 """Subrepositories whose paths match the given pattern. |
478 """Subrepositories whose paths match the given pattern. |
479 """ |
479 """ |
480 # i18n: "subrepo" is a keyword |
480 # i18n: "subrepo" is a keyword |
481 getargs(x, 0, 1, _("subrepo takes at most one argument")) |
481 getargs(x, 0, 1, _(b"subrepo takes at most one argument")) |
482 ctx = mctx.ctx |
482 ctx = mctx.ctx |
483 sstate = ctx.substate |
483 sstate = ctx.substate |
484 if x: |
484 if x: |
485 pat = getpattern( |
485 pat = getpattern( |
486 x, |
486 x, |
487 matchmod.allpatternkinds, |
487 matchmod.allpatternkinds, |
488 # i18n: "subrepo" is a keyword |
488 # i18n: "subrepo" is a keyword |
489 _("subrepo requires a pattern or no arguments"), |
489 _(b"subrepo requires a pattern or no arguments"), |
490 ) |
490 ) |
491 fast = not matchmod.patkind(pat) |
491 fast = not matchmod.patkind(pat) |
492 if fast: |
492 if fast: |
493 |
493 |
494 def m(s): |
494 def m(s): |
495 return s == pat |
495 return s == pat |
496 |
496 |
497 else: |
497 else: |
498 m = matchmod.match(ctx.repo().root, '', [pat], ctx=ctx) |
498 m = matchmod.match(ctx.repo().root, b'', [pat], ctx=ctx) |
499 return mctx.predicate( |
499 return mctx.predicate( |
500 lambda f: f in sstate and m(f), predrepr=('subrepo(%r)', pat) |
500 lambda f: f in sstate and m(f), predrepr=(b'subrepo(%r)', pat) |
501 ) |
501 ) |
502 else: |
502 else: |
503 return mctx.predicate(sstate.__contains__, predrepr='subrepo') |
503 return mctx.predicate(sstate.__contains__, predrepr=b'subrepo') |
504 |
504 |
505 |
505 |
506 methods = { |
506 methods = { |
507 'withstatus': getmatchwithstatus, |
507 b'withstatus': getmatchwithstatus, |
508 'string': stringmatch, |
508 b'string': stringmatch, |
509 'symbol': stringmatch, |
509 b'symbol': stringmatch, |
510 'kindpat': kindpatmatch, |
510 b'kindpat': kindpatmatch, |
511 'patterns': patternsmatch, |
511 b'patterns': patternsmatch, |
512 'and': andmatch, |
512 b'and': andmatch, |
513 'or': ormatch, |
513 b'or': ormatch, |
514 'minus': minusmatch, |
514 b'minus': minusmatch, |
515 'list': listmatch, |
515 b'list': listmatch, |
516 'not': notmatch, |
516 b'not': notmatch, |
517 'func': func, |
517 b'func': func, |
518 } |
518 } |
519 |
519 |
520 |
520 |
521 class matchctx(object): |
521 class matchctx(object): |
522 def __init__(self, basectx, ctx, badfn=None): |
522 def __init__(self, basectx, ctx, badfn=None): |