36 getstring = filesetlang.getstring |
34 getstring = filesetlang.getstring |
37 _getkindpat = filesetlang.getkindpat |
35 _getkindpat = filesetlang.getkindpat |
38 getpattern = filesetlang.getpattern |
36 getpattern = filesetlang.getpattern |
39 getargs = filesetlang.getargs |
37 getargs = filesetlang.getargs |
40 |
38 |
|
39 |
41 def getmatch(mctx, x): |
40 def getmatch(mctx, x): |
42 if not x: |
41 if not x: |
43 raise error.ParseError(_("missing argument")) |
42 raise error.ParseError(_("missing argument")) |
44 return methods[x[0]](mctx, *x[1:]) |
43 return methods[x[0]](mctx, *x[1:]) |
45 |
44 |
|
45 |
46 def getmatchwithstatus(mctx, x, hint): |
46 def getmatchwithstatus(mctx, x, hint): |
47 keys = set(getstring(hint, 'status hint must be a string').split()) |
47 keys = set(getstring(hint, 'status hint must be a string').split()) |
48 return getmatch(mctx.withstatus(keys), x) |
48 return getmatch(mctx.withstatus(keys), x) |
49 |
49 |
|
50 |
50 def stringmatch(mctx, x): |
51 def stringmatch(mctx, x): |
51 return mctx.matcher([x]) |
52 return mctx.matcher([x]) |
52 |
53 |
|
54 |
53 def kindpatmatch(mctx, x, y): |
55 def kindpatmatch(mctx, x, y): |
54 return stringmatch(mctx, _getkindpat(x, y, matchmod.allpatternkinds, |
56 return stringmatch( |
55 _("pattern must be a string"))) |
57 mctx, |
|
58 _getkindpat( |
|
59 x, y, matchmod.allpatternkinds, _("pattern must be a string") |
|
60 ), |
|
61 ) |
|
62 |
56 |
63 |
57 def patternsmatch(mctx, *xs): |
64 def patternsmatch(mctx, *xs): |
58 allkinds = matchmod.allpatternkinds |
65 allkinds = matchmod.allpatternkinds |
59 patterns = [getpattern(x, allkinds, _("pattern must be a string")) |
66 patterns = [ |
60 for x in xs] |
67 getpattern(x, allkinds, _("pattern must be a string")) for x in xs |
|
68 ] |
61 return mctx.matcher(patterns) |
69 return mctx.matcher(patterns) |
|
70 |
62 |
71 |
63 def andmatch(mctx, x, y): |
72 def andmatch(mctx, x, y): |
64 xm = getmatch(mctx, x) |
73 xm = getmatch(mctx, x) |
65 ym = getmatch(mctx.narrowed(xm), y) |
74 ym = getmatch(mctx.narrowed(xm), y) |
66 return matchmod.intersectmatchers(xm, ym) |
75 return matchmod.intersectmatchers(xm, ym) |
67 |
76 |
|
77 |
68 def ormatch(mctx, *xs): |
78 def ormatch(mctx, *xs): |
69 ms = [getmatch(mctx, x) for x in xs] |
79 ms = [getmatch(mctx, x) for x in xs] |
70 return matchmod.unionmatcher(ms) |
80 return matchmod.unionmatcher(ms) |
71 |
81 |
|
82 |
72 def notmatch(mctx, x): |
83 def notmatch(mctx, x): |
73 m = getmatch(mctx, x) |
84 m = getmatch(mctx, x) |
74 return mctx.predicate(lambda f: not m(f), predrepr=('<not %r>', m)) |
85 return mctx.predicate(lambda f: not m(f), predrepr=('<not %r>', m)) |
|
86 |
75 |
87 |
76 def minusmatch(mctx, x, y): |
88 def minusmatch(mctx, x, y): |
77 xm = getmatch(mctx, x) |
89 xm = getmatch(mctx, x) |
78 ym = getmatch(mctx.narrowed(xm), y) |
90 ym = getmatch(mctx.narrowed(xm), y) |
79 return matchmod.differencematcher(xm, ym) |
91 return matchmod.differencematcher(xm, ym) |
80 |
92 |
|
93 |
81 def listmatch(mctx, *xs): |
94 def listmatch(mctx, *xs): |
82 raise error.ParseError(_("can't use a list in this context"), |
95 raise error.ParseError( |
83 hint=_('see \'hg help "filesets.x or y"\'')) |
96 _("can't use a list in this context"), |
|
97 hint=_('see \'hg help "filesets.x or y"\''), |
|
98 ) |
|
99 |
84 |
100 |
85 def func(mctx, a, b): |
101 def func(mctx, a, b): |
86 funcname = getsymbol(a) |
102 funcname = getsymbol(a) |
87 if funcname in symbols: |
103 if funcname in symbols: |
88 return symbols[funcname](mctx, b) |
104 return symbols[funcname](mctx, b) |
89 |
105 |
90 keep = lambda fn: getattr(fn, '__doc__', None) is not None |
106 keep = lambda fn: getattr(fn, '__doc__', None) is not None |
91 |
107 |
92 syms = [s for (s, fn) in symbols.items() if keep(fn)] |
108 syms = [s for (s, fn) in symbols.items() if keep(fn)] |
93 raise error.UnknownIdentifier(funcname, syms) |
109 raise error.UnknownIdentifier(funcname, syms) |
|
110 |
94 |
111 |
95 # symbols are callable like: |
112 # symbols are callable like: |
96 # fun(mctx, x) |
113 # fun(mctx, x) |
97 # with: |
114 # with: |
98 # mctx - current matchctx instance |
115 # mctx - current matchctx instance |
99 # x - argument in tree form |
116 # x - argument in tree form |
100 symbols = filesetlang.symbols |
117 symbols = filesetlang.symbols |
101 |
118 |
102 predicate = registrar.filesetpredicate(symbols) |
119 predicate = registrar.filesetpredicate(symbols) |
103 |
120 |
|
121 |
104 @predicate('modified()', callstatus=True, weight=_WEIGHT_STATUS) |
122 @predicate('modified()', callstatus=True, weight=_WEIGHT_STATUS) |
105 def modified(mctx, x): |
123 def modified(mctx, x): |
106 """File that is modified according to :hg:`status`. |
124 """File that is modified according to :hg:`status`. |
107 """ |
125 """ |
108 # i18n: "modified" is a keyword |
126 # i18n: "modified" is a keyword |
109 getargs(x, 0, 0, _("modified takes no arguments")) |
127 getargs(x, 0, 0, _("modified takes no arguments")) |
110 s = set(mctx.status().modified) |
128 s = set(mctx.status().modified) |
111 return mctx.predicate(s.__contains__, predrepr='modified') |
129 return mctx.predicate(s.__contains__, predrepr='modified') |
112 |
130 |
|
131 |
113 @predicate('added()', callstatus=True, weight=_WEIGHT_STATUS) |
132 @predicate('added()', callstatus=True, weight=_WEIGHT_STATUS) |
114 def added(mctx, x): |
133 def added(mctx, x): |
115 """File that is added according to :hg:`status`. |
134 """File that is added according to :hg:`status`. |
116 """ |
135 """ |
117 # i18n: "added" is a keyword |
136 # i18n: "added" is a keyword |
118 getargs(x, 0, 0, _("added takes no arguments")) |
137 getargs(x, 0, 0, _("added takes no arguments")) |
119 s = set(mctx.status().added) |
138 s = set(mctx.status().added) |
120 return mctx.predicate(s.__contains__, predrepr='added') |
139 return mctx.predicate(s.__contains__, predrepr='added') |
121 |
140 |
|
141 |
122 @predicate('removed()', callstatus=True, weight=_WEIGHT_STATUS) |
142 @predicate('removed()', callstatus=True, weight=_WEIGHT_STATUS) |
123 def removed(mctx, x): |
143 def removed(mctx, x): |
124 """File that is removed according to :hg:`status`. |
144 """File that is removed according to :hg:`status`. |
125 """ |
145 """ |
126 # i18n: "removed" is a keyword |
146 # i18n: "removed" is a keyword |
127 getargs(x, 0, 0, _("removed takes no arguments")) |
147 getargs(x, 0, 0, _("removed takes no arguments")) |
128 s = set(mctx.status().removed) |
148 s = set(mctx.status().removed) |
129 return mctx.predicate(s.__contains__, predrepr='removed') |
149 return mctx.predicate(s.__contains__, predrepr='removed') |
130 |
150 |
|
151 |
131 @predicate('deleted()', callstatus=True, weight=_WEIGHT_STATUS) |
152 @predicate('deleted()', callstatus=True, weight=_WEIGHT_STATUS) |
132 def deleted(mctx, x): |
153 def deleted(mctx, x): |
133 """Alias for ``missing()``. |
154 """Alias for ``missing()``. |
134 """ |
155 """ |
135 # i18n: "deleted" is a keyword |
156 # i18n: "deleted" is a keyword |
136 getargs(x, 0, 0, _("deleted takes no arguments")) |
157 getargs(x, 0, 0, _("deleted takes no arguments")) |
137 s = set(mctx.status().deleted) |
158 s = set(mctx.status().deleted) |
138 return mctx.predicate(s.__contains__, predrepr='deleted') |
159 return mctx.predicate(s.__contains__, predrepr='deleted') |
139 |
160 |
|
161 |
140 @predicate('missing()', callstatus=True, weight=_WEIGHT_STATUS) |
162 @predicate('missing()', callstatus=True, weight=_WEIGHT_STATUS) |
141 def missing(mctx, x): |
163 def missing(mctx, x): |
142 """File that is missing according to :hg:`status`. |
164 """File that is missing according to :hg:`status`. |
143 """ |
165 """ |
144 # i18n: "missing" is a keyword |
166 # i18n: "missing" is a keyword |
145 getargs(x, 0, 0, _("missing takes no arguments")) |
167 getargs(x, 0, 0, _("missing takes no arguments")) |
146 s = set(mctx.status().deleted) |
168 s = set(mctx.status().deleted) |
147 return mctx.predicate(s.__contains__, predrepr='deleted') |
169 return mctx.predicate(s.__contains__, predrepr='deleted') |
|
170 |
148 |
171 |
149 @predicate('unknown()', callstatus=True, weight=_WEIGHT_STATUS_THOROUGH) |
172 @predicate('unknown()', callstatus=True, weight=_WEIGHT_STATUS_THOROUGH) |
150 def unknown(mctx, x): |
173 def unknown(mctx, x): |
151 """File that is unknown according to :hg:`status`.""" |
174 """File that is unknown according to :hg:`status`.""" |
152 # i18n: "unknown" is a keyword |
175 # i18n: "unknown" is a keyword |
153 getargs(x, 0, 0, _("unknown takes no arguments")) |
176 getargs(x, 0, 0, _("unknown takes no arguments")) |
154 s = set(mctx.status().unknown) |
177 s = set(mctx.status().unknown) |
155 return mctx.predicate(s.__contains__, predrepr='unknown') |
178 return mctx.predicate(s.__contains__, predrepr='unknown') |
156 |
179 |
|
180 |
157 @predicate('ignored()', callstatus=True, weight=_WEIGHT_STATUS_THOROUGH) |
181 @predicate('ignored()', callstatus=True, weight=_WEIGHT_STATUS_THOROUGH) |
158 def ignored(mctx, x): |
182 def ignored(mctx, x): |
159 """File that is ignored according to :hg:`status`.""" |
183 """File that is ignored according to :hg:`status`.""" |
160 # i18n: "ignored" is a keyword |
184 # i18n: "ignored" is a keyword |
161 getargs(x, 0, 0, _("ignored takes no arguments")) |
185 getargs(x, 0, 0, _("ignored takes no arguments")) |
162 s = set(mctx.status().ignored) |
186 s = set(mctx.status().ignored) |
163 return mctx.predicate(s.__contains__, predrepr='ignored') |
187 return mctx.predicate(s.__contains__, predrepr='ignored') |
164 |
188 |
|
189 |
165 @predicate('clean()', callstatus=True, weight=_WEIGHT_STATUS) |
190 @predicate('clean()', callstatus=True, weight=_WEIGHT_STATUS) |
166 def clean(mctx, x): |
191 def clean(mctx, x): |
167 """File that is clean according to :hg:`status`. |
192 """File that is clean according to :hg:`status`. |
168 """ |
193 """ |
169 # i18n: "clean" is a keyword |
194 # i18n: "clean" is a keyword |
170 getargs(x, 0, 0, _("clean takes no arguments")) |
195 getargs(x, 0, 0, _("clean takes no arguments")) |
171 s = set(mctx.status().clean) |
196 s = set(mctx.status().clean) |
172 return mctx.predicate(s.__contains__, predrepr='clean') |
197 return mctx.predicate(s.__contains__, predrepr='clean') |
|
198 |
173 |
199 |
174 @predicate('tracked()') |
200 @predicate('tracked()') |
175 def tracked(mctx, x): |
201 def tracked(mctx, x): |
176 """File that is under Mercurial control.""" |
202 """File that is under Mercurial control.""" |
177 # i18n: "tracked" is a keyword |
203 # i18n: "tracked" is a keyword |
178 getargs(x, 0, 0, _("tracked takes no arguments")) |
204 getargs(x, 0, 0, _("tracked takes no arguments")) |
179 return mctx.predicate(mctx.ctx.__contains__, predrepr='tracked') |
205 return mctx.predicate(mctx.ctx.__contains__, predrepr='tracked') |
180 |
206 |
|
207 |
181 @predicate('binary()', weight=_WEIGHT_READ_CONTENTS) |
208 @predicate('binary()', weight=_WEIGHT_READ_CONTENTS) |
182 def binary(mctx, x): |
209 def binary(mctx, x): |
183 """File that appears to be binary (contains NUL bytes). |
210 """File that appears to be binary (contains NUL bytes). |
184 """ |
211 """ |
185 # i18n: "binary" is a keyword |
212 # i18n: "binary" is a keyword |
186 getargs(x, 0, 0, _("binary takes no arguments")) |
213 getargs(x, 0, 0, _("binary takes no arguments")) |
187 return mctx.fpredicate(lambda fctx: fctx.isbinary(), |
214 return mctx.fpredicate( |
188 predrepr='binary', cache=True) |
215 lambda fctx: fctx.isbinary(), predrepr='binary', cache=True |
|
216 ) |
|
217 |
189 |
218 |
190 @predicate('exec()') |
219 @predicate('exec()') |
191 def exec_(mctx, x): |
220 def exec_(mctx, x): |
192 """File that is marked as executable. |
221 """File that is marked as executable. |
193 """ |
222 """ |
194 # i18n: "exec" is a keyword |
223 # i18n: "exec" is a keyword |
195 getargs(x, 0, 0, _("exec takes no arguments")) |
224 getargs(x, 0, 0, _("exec takes no arguments")) |
196 ctx = mctx.ctx |
225 ctx = mctx.ctx |
197 return mctx.predicate(lambda f: ctx.flags(f) == 'x', predrepr='exec') |
226 return mctx.predicate(lambda f: ctx.flags(f) == 'x', predrepr='exec') |
198 |
227 |
|
228 |
199 @predicate('symlink()') |
229 @predicate('symlink()') |
200 def symlink(mctx, x): |
230 def symlink(mctx, x): |
201 """File that is marked as a symlink. |
231 """File that is marked as a symlink. |
202 """ |
232 """ |
203 # i18n: "symlink" is a keyword |
233 # i18n: "symlink" is a keyword |
204 getargs(x, 0, 0, _("symlink takes no arguments")) |
234 getargs(x, 0, 0, _("symlink takes no arguments")) |
205 ctx = mctx.ctx |
235 ctx = mctx.ctx |
206 return mctx.predicate(lambda f: ctx.flags(f) == 'l', predrepr='symlink') |
236 return mctx.predicate(lambda f: ctx.flags(f) == 'l', predrepr='symlink') |
|
237 |
207 |
238 |
208 @predicate('resolved()', weight=_WEIGHT_STATUS) |
239 @predicate('resolved()', weight=_WEIGHT_STATUS) |
209 def resolved(mctx, x): |
240 def resolved(mctx, x): |
210 """File that is marked resolved according to :hg:`resolve -l`. |
241 """File that is marked resolved according to :hg:`resolve -l`. |
211 """ |
242 """ |
212 # i18n: "resolved" is a keyword |
243 # i18n: "resolved" is a keyword |
213 getargs(x, 0, 0, _("resolved takes no arguments")) |
244 getargs(x, 0, 0, _("resolved takes no arguments")) |
214 if mctx.ctx.rev() is not None: |
245 if mctx.ctx.rev() is not None: |
215 return mctx.never() |
246 return mctx.never() |
216 ms = merge.mergestate.read(mctx.ctx.repo()) |
247 ms = merge.mergestate.read(mctx.ctx.repo()) |
217 return mctx.predicate(lambda f: f in ms and ms[f] == 'r', |
248 return mctx.predicate( |
218 predrepr='resolved') |
249 lambda f: f in ms and ms[f] == 'r', predrepr='resolved' |
|
250 ) |
|
251 |
219 |
252 |
220 @predicate('unresolved()', weight=_WEIGHT_STATUS) |
253 @predicate('unresolved()', weight=_WEIGHT_STATUS) |
221 def unresolved(mctx, x): |
254 def unresolved(mctx, x): |
222 """File that is marked unresolved according to :hg:`resolve -l`. |
255 """File that is marked unresolved according to :hg:`resolve -l`. |
223 """ |
256 """ |
224 # i18n: "unresolved" is a keyword |
257 # i18n: "unresolved" is a keyword |
225 getargs(x, 0, 0, _("unresolved takes no arguments")) |
258 getargs(x, 0, 0, _("unresolved takes no arguments")) |
226 if mctx.ctx.rev() is not None: |
259 if mctx.ctx.rev() is not None: |
227 return mctx.never() |
260 return mctx.never() |
228 ms = merge.mergestate.read(mctx.ctx.repo()) |
261 ms = merge.mergestate.read(mctx.ctx.repo()) |
229 return mctx.predicate(lambda f: f in ms and ms[f] == 'u', |
262 return mctx.predicate( |
230 predrepr='unresolved') |
263 lambda f: f in ms and ms[f] == 'u', predrepr='unresolved' |
|
264 ) |
|
265 |
231 |
266 |
232 @predicate('hgignore()', weight=_WEIGHT_STATUS) |
267 @predicate('hgignore()', weight=_WEIGHT_STATUS) |
233 def hgignore(mctx, x): |
268 def hgignore(mctx, x): |
234 """File that matches the active .hgignore pattern. |
269 """File that matches the active .hgignore pattern. |
235 """ |
270 """ |
236 # i18n: "hgignore" is a keyword |
271 # i18n: "hgignore" is a keyword |
237 getargs(x, 0, 0, _("hgignore takes no arguments")) |
272 getargs(x, 0, 0, _("hgignore takes no arguments")) |
238 return mctx.ctx.repo().dirstate._ignore |
273 return mctx.ctx.repo().dirstate._ignore |
|
274 |
239 |
275 |
240 @predicate('portable()', weight=_WEIGHT_CHECK_FILENAME) |
276 @predicate('portable()', weight=_WEIGHT_CHECK_FILENAME) |
241 def portable(mctx, x): |
277 def portable(mctx, x): |
242 """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 |
243 collisions.) |
279 collisions.) |
244 """ |
280 """ |
245 # i18n: "portable" is a keyword |
281 # i18n: "portable" is a keyword |
246 getargs(x, 0, 0, _("portable takes no arguments")) |
282 getargs(x, 0, 0, _("portable takes no arguments")) |
247 return mctx.predicate(lambda f: util.checkwinfilename(f) is None, |
283 return mctx.predicate( |
248 predrepr='portable') |
284 lambda f: util.checkwinfilename(f) is None, predrepr='portable' |
|
285 ) |
|
286 |
249 |
287 |
250 @predicate('grep(regex)', weight=_WEIGHT_READ_CONTENTS) |
288 @predicate('grep(regex)', weight=_WEIGHT_READ_CONTENTS) |
251 def grep(mctx, x): |
289 def grep(mctx, x): |
252 """File contains the given regular expression. |
290 """File contains the given regular expression. |
253 """ |
291 """ |
254 try: |
292 try: |
255 # i18n: "grep" is a keyword |
293 # i18n: "grep" is a keyword |
256 r = re.compile(getstring(x, _("grep requires a pattern"))) |
294 r = re.compile(getstring(x, _("grep requires a pattern"))) |
257 except re.error as e: |
295 except re.error as e: |
258 raise error.ParseError(_('invalid match pattern: %s') % |
296 raise error.ParseError( |
259 stringutil.forcebytestr(e)) |
297 _('invalid match pattern: %s') % stringutil.forcebytestr(e) |
260 return mctx.fpredicate(lambda fctx: r.search(fctx.data()), |
298 ) |
261 predrepr=('grep(%r)', r.pattern), cache=True) |
299 return mctx.fpredicate( |
|
300 lambda fctx: r.search(fctx.data()), |
|
301 predrepr=('grep(%r)', r.pattern), |
|
302 cache=True, |
|
303 ) |
|
304 |
262 |
305 |
263 def _sizetomax(s): |
306 def _sizetomax(s): |
264 try: |
307 try: |
265 s = s.strip().lower() |
308 s = s.strip().lower() |
266 for k, v in util._sizeunits: |
309 for k, v in util._sizeunits: |
267 if s.endswith(k): |
310 if s.endswith(k): |
268 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1 |
311 # max(4k) = 5k - 1, max(4.5k) = 4.6k - 1 |
269 n = s[:-len(k)] |
312 n = s[: -len(k)] |
270 inc = 1.0 |
313 inc = 1.0 |
271 if "." in n: |
314 if "." in n: |
272 inc /= 10 ** len(n.split(".")[1]) |
315 inc /= 10 ** len(n.split(".")[1]) |
273 return int((float(n) + inc) * v) - 1 |
316 return int((float(n) + inc) * v) - 1 |
274 # no extension, this is a precise value |
317 # no extension, this is a precise value |
275 return int(s) |
318 return int(s) |
276 except ValueError: |
319 except ValueError: |
277 raise error.ParseError(_("couldn't parse size: %s") % s) |
320 raise error.ParseError(_("couldn't parse size: %s") % s) |
278 |
321 |
|
322 |
279 def sizematcher(expr): |
323 def sizematcher(expr): |
280 """Return a function(size) -> bool from the ``size()`` expression""" |
324 """Return a function(size) -> bool from the ``size()`` expression""" |
281 expr = expr.strip() |
325 expr = expr.strip() |
282 if '-' in expr: # do we have a range? |
326 if '-' in expr: # do we have a range? |
283 a, b = expr.split('-', 1) |
327 a, b = expr.split('-', 1) |
284 a = util.sizetoint(a) |
328 a = util.sizetoint(a) |
285 b = util.sizetoint(b) |
329 b = util.sizetoint(b) |
286 return lambda x: x >= a and x <= b |
330 return lambda x: x >= a and x <= b |
287 elif expr.startswith("<="): |
331 elif expr.startswith("<="): |