Mercurial > hg
annotate mercurial/revset.py @ 12592:f2937d6492c5 stable
url: verify correctness of https server certificates (issue2407)
Pythons SSL module verifies that certificates received for HTTPS are valid
according to the specified cacerts, but it doesn't verify that the certificate
is for the host we connect to.
We now explicitly verify that the commonName in the received certificate
matches the requested hostname and is valid for the time being.
This is a minimal patch where we try to fail to the safe side, but we do still
rely on Python's SSL functionality and do not try to implement the standards
fully and correctly. CRLs and subjectAltName are not handled and proxies
haven't been considered.
This change might break connections to some sites if cacerts is specified and
the certificates (by our definition) isn't correct. The workaround is to
disable cacerts which in most cases isn't much worse than it was before with
cacerts.
author | Mads Kiilerich <mads@kiilerich.com> |
---|---|
date | Fri, 01 Oct 2010 00:46:59 +0200 |
parents | 40c40c6f20b8 |
children | 11db6fa2961e f314723f36f5 |
rev | line source |
---|---|
11275 | 1 # revset.py - revision set queries for mercurial |
2 # | |
3 # Copyright 2010 Matt Mackall <mpm@selenic.com> | |
4 # | |
5 # This software may be used and distributed according to the terms of the | |
6 # GNU General Public License version 2 or any later version. | |
7 | |
8 import re | |
11301
3d0591a66118
move discovery methods from localrepo into new discovery module
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
11293
diff
changeset
|
9 import parser, util, error, discovery |
11275 | 10 import match as _match |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
11 from i18n import _ |
11275 | 12 |
13 elements = { | |
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")), | |
15 "-": (19, ("negate", 19), ("minus", 19)), | |
11278
7df88cdf47fd
revset: add support for prefix and suffix versions of : and ::
Matt Mackall <mpm@selenic.com>
parents:
11275
diff
changeset
|
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17), |
7df88cdf47fd
revset: add support for prefix and suffix versions of : and ::
Matt Mackall <mpm@selenic.com>
parents:
11275
diff
changeset
|
17 ("dagrangepost", 17)), |
7df88cdf47fd
revset: add support for prefix and suffix versions of : and ::
Matt Mackall <mpm@selenic.com>
parents:
11275
diff
changeset
|
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17), |
7df88cdf47fd
revset: add support for prefix and suffix versions of : and ::
Matt Mackall <mpm@selenic.com>
parents:
11275
diff
changeset
|
19 ("dagrangepost", 17)), |
7df88cdf47fd
revset: add support for prefix and suffix versions of : and ::
Matt Mackall <mpm@selenic.com>
parents:
11275
diff
changeset
|
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)), |
11275 | 21 "not": (10, ("not", 10)), |
22 "!": (10, ("not", 10)), | |
23 "and": (5, None, ("and", 5)), | |
24 "&": (5, None, ("and", 5)), | |
25 "or": (4, None, ("or", 4)), | |
26 "|": (4, None, ("or", 4)), | |
27 "+": (4, None, ("or", 4)), | |
28 ",": (2, None, ("list", 2)), | |
29 ")": (0, None, None), | |
30 "symbol": (0, ("symbol",), None), | |
31 "string": (0, ("string",), None), | |
32 "end": (0, None, None), | |
33 } | |
34 | |
35 keywords = set(['and', 'or', 'not']) | |
36 | |
37 def tokenize(program): | |
38 pos, l = 0, len(program) | |
39 while pos < l: | |
40 c = program[pos] | |
41 if c.isspace(): # skip inter-token whitespace | |
42 pass | |
11278
7df88cdf47fd
revset: add support for prefix and suffix versions of : and ::
Matt Mackall <mpm@selenic.com>
parents:
11275
diff
changeset
|
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
44 yield ('::', None, pos) |
11278
7df88cdf47fd
revset: add support for prefix and suffix versions of : and ::
Matt Mackall <mpm@selenic.com>
parents:
11275
diff
changeset
|
45 pos += 1 # skip ahead |
11275 | 46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
47 yield ('..', None, pos) |
11275 | 48 pos += 1 # skip ahead |
11278
7df88cdf47fd
revset: add support for prefix and suffix versions of : and ::
Matt Mackall <mpm@selenic.com>
parents:
11275
diff
changeset
|
49 elif c in "():,-|&+!": # handle simple operators |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
50 yield (c, None, pos) |
11275 | 51 elif c in '"\'': # handle quoted strings |
52 pos += 1 | |
53 s = pos | |
54 while pos < l: # find closing quote | |
55 d = program[pos] | |
56 if d == '\\': # skip over escaped characters | |
57 pos += 2 | |
58 continue | |
59 if d == c: | |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
60 yield ('string', program[s:pos].decode('string-escape'), s) |
11275 | 61 break |
62 pos += 1 | |
63 else: | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
64 raise error.ParseError(_("unterminated string"), s) |
11404
37cbedbeae96
revset: allow extended characters in symbols
Matt Mackall <mpm@selenic.com>
parents:
11385
diff
changeset
|
65 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword |
11275 | 66 s = pos |
67 pos += 1 | |
68 while pos < l: # find end of symbol | |
69 d = program[pos] | |
11404
37cbedbeae96
revset: allow extended characters in symbols
Matt Mackall <mpm@selenic.com>
parents:
11385
diff
changeset
|
70 if not (d.isalnum() or d in "._" or ord(d) > 127): |
11275 | 71 break |
72 if d == '.' and program[pos - 1] == '.': # special case for .. | |
73 pos -= 1 | |
74 break | |
75 pos += 1 | |
76 sym = program[s:pos] | |
77 if sym in keywords: # operator keywords | |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
78 yield (sym, None, s) |
11275 | 79 else: |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
80 yield ('symbol', sym, s) |
11275 | 81 pos -= 1 |
82 else: | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
83 raise error.ParseError(_("syntax error"), pos) |
11275 | 84 pos += 1 |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
85 yield ('end', None, pos) |
11275 | 86 |
87 # helpers | |
88 | |
89 def getstring(x, err): | |
11406
42408cd43f55
revset: fix up contains/getstring when no args passed
Matt Mackall <mpm@selenic.com>
parents:
11404
diff
changeset
|
90 if x and (x[0] == 'string' or x[0] == 'symbol'): |
11275 | 91 return x[1] |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
92 raise error.ParseError(err) |
11275 | 93 |
94 def getlist(x): | |
95 if not x: | |
96 return [] | |
97 if x[0] == 'list': | |
98 return getlist(x[1]) + [x[2]] | |
99 return [x] | |
100 | |
11339
744d5b73f776
revset: improve filter argument handling
Matt Mackall <mpm@selenic.com>
parents:
11304
diff
changeset
|
101 def getargs(x, min, max, err): |
11275 | 102 l = getlist(x) |
11339
744d5b73f776
revset: improve filter argument handling
Matt Mackall <mpm@selenic.com>
parents:
11304
diff
changeset
|
103 if len(l) < min or len(l) > max: |
11289
4215ce511134
revset: raise ParseError exceptions
Matt Mackall <mpm@selenic.com>
parents:
11284
diff
changeset
|
104 raise error.ParseError(err) |
11275 | 105 return l |
106 | |
107 def getset(repo, subset, x): | |
108 if not x: | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
109 raise error.ParseError(_("missing argument")) |
11275 | 110 return methods[x[0]](repo, subset, *x[1:]) |
111 | |
112 # operator methods | |
113 | |
114 def stringset(repo, subset, x): | |
115 x = repo[x].rev() | |
11282 | 116 if x == -1 and len(subset) == len(repo): |
117 return [-1] | |
11275 | 118 if x in subset: |
119 return [x] | |
120 return [] | |
121 | |
122 def symbolset(repo, subset, x): | |
123 if x in symbols: | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
124 raise error.ParseError(_("can't use %s here") % x) |
11275 | 125 return stringset(repo, subset, x) |
126 | |
127 def rangeset(repo, subset, x, y): | |
11456
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
128 m = getset(repo, subset, x) |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
129 if not m: |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
130 m = getset(repo, range(len(repo)), x) |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
131 |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
132 n = getset(repo, subset, y) |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
133 if not n: |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
134 n = getset(repo, range(len(repo)), y) |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
135 |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
136 if not m or not n: |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
137 return [] |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
138 m, n = m[0], n[-1] |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
139 |
11275 | 140 if m < n: |
11456
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
141 r = range(m, n + 1) |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
142 else: |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
143 r = range(m, n - 1, -1) |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
144 s = set(subset) |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
145 return [x for x in r if x in s] |
11275 | 146 |
147 def andset(repo, subset, x, y): | |
148 return getset(repo, getset(repo, subset, x), y) | |
149 | |
150 def orset(repo, subset, x, y): | |
151 s = set(getset(repo, subset, x)) | |
152 s |= set(getset(repo, [r for r in subset if r not in s], y)) | |
153 return [r for r in subset if r in s] | |
154 | |
155 def notset(repo, subset, x): | |
156 s = set(getset(repo, subset, x)) | |
157 return [r for r in subset if r not in s] | |
158 | |
159 def listset(repo, subset, a, b): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
160 raise error.ParseError(_("can't use a list in this context")) |
11275 | 161 |
162 def func(repo, subset, a, b): | |
163 if a[0] == 'symbol' and a[1] in symbols: | |
164 return symbols[a[1]](repo, subset, b) | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
165 raise error.ParseError(_("not a function: %s") % a[1]) |
11275 | 166 |
167 # functions | |
168 | |
169 def p1(repo, subset, x): | |
170 ps = set() | |
171 cl = repo.changelog | |
172 for r in getset(repo, subset, x): | |
173 ps.add(cl.parentrevs(r)[0]) | |
174 return [r for r in subset if r in ps] | |
175 | |
176 def p2(repo, subset, x): | |
177 ps = set() | |
178 cl = repo.changelog | |
179 for r in getset(repo, subset, x): | |
180 ps.add(cl.parentrevs(r)[1]) | |
181 return [r for r in subset if r in ps] | |
182 | |
183 def parents(repo, subset, x): | |
184 ps = set() | |
185 cl = repo.changelog | |
186 for r in getset(repo, subset, x): | |
187 ps.update(cl.parentrevs(r)) | |
188 return [r for r in subset if r in ps] | |
189 | |
190 def maxrev(repo, subset, x): | |
191 s = getset(repo, subset, x) | |
192 if s: | |
193 m = max(s) | |
194 if m in subset: | |
195 return [m] | |
196 return [] | |
197 | |
198 def limit(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
199 l = getargs(x, 2, 2, _("limit wants two arguments")) |
11275 | 200 try: |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
201 lim = int(getstring(l[1], _("limit wants a number"))) |
11275 | 202 except ValueError: |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
203 raise error.ParseError(_("limit expects a number")) |
11275 | 204 return getset(repo, subset, l[0])[:lim] |
205 | |
206 def children(repo, subset, x): | |
207 cs = set() | |
208 cl = repo.changelog | |
209 s = set(getset(repo, subset, x)) | |
210 for r in xrange(0, len(repo)): | |
211 for p in cl.parentrevs(r): | |
212 if p in s: | |
213 cs.add(r) | |
214 return [r for r in subset if r in cs] | |
215 | |
216 def branch(repo, subset, x): | |
217 s = getset(repo, range(len(repo)), x) | |
218 b = set() | |
219 for r in s: | |
220 b.add(repo[r].branch()) | |
221 s = set(s) | |
222 return [r for r in subset if r in s or repo[r].branch() in b] | |
223 | |
224 def ancestor(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
225 l = getargs(x, 2, 2, _("ancestor wants two arguments")) |
11650
ebaf117c2642
revset: fix ancestor subset handling (issue2298)
Matt Mackall <mpm@selenic.com>
parents:
11467
diff
changeset
|
226 r = range(len(repo)) |
ebaf117c2642
revset: fix ancestor subset handling (issue2298)
Matt Mackall <mpm@selenic.com>
parents:
11467
diff
changeset
|
227 a = getset(repo, r, l[0]) |
ebaf117c2642
revset: fix ancestor subset handling (issue2298)
Matt Mackall <mpm@selenic.com>
parents:
11467
diff
changeset
|
228 b = getset(repo, r, l[1]) |
ebaf117c2642
revset: fix ancestor subset handling (issue2298)
Matt Mackall <mpm@selenic.com>
parents:
11467
diff
changeset
|
229 if len(a) != 1 or len(b) != 1: |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
230 raise error.ParseError(_("ancestor arguments must be single revisions")) |
11650
ebaf117c2642
revset: fix ancestor subset handling (issue2298)
Matt Mackall <mpm@selenic.com>
parents:
11467
diff
changeset
|
231 an = [repo[a[0]].ancestor(repo[b[0]]).rev()] |
ebaf117c2642
revset: fix ancestor subset handling (issue2298)
Matt Mackall <mpm@selenic.com>
parents:
11467
diff
changeset
|
232 |
ebaf117c2642
revset: fix ancestor subset handling (issue2298)
Matt Mackall <mpm@selenic.com>
parents:
11467
diff
changeset
|
233 return [r for r in an if r in subset] |
11275 | 234 |
235 def ancestors(repo, subset, x): | |
236 args = getset(repo, range(len(repo)), x) | |
11456
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
237 if not args: |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
238 return [] |
11275 | 239 s = set(repo.changelog.ancestors(*args)) | set(args) |
240 return [r for r in subset if r in s] | |
241 | |
242 def descendants(repo, subset, x): | |
243 args = getset(repo, range(len(repo)), x) | |
11456
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
244 if not args: |
88abbb046e66
revset: deal with empty sets in range endpoints
Matt Mackall <mpm@selenic.com>
parents:
11446
diff
changeset
|
245 return [] |
11275 | 246 s = set(repo.changelog.descendants(*args)) | set(args) |
247 return [r for r in subset if r in s] | |
248 | |
249 def follow(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
250 getargs(x, 0, 0, _("follow takes no arguments")) |
11275 | 251 p = repo['.'].rev() |
252 s = set(repo.changelog.ancestors(p)) | set([p]) | |
253 return [r for r in subset if r in s] | |
254 | |
255 def date(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
256 ds = getstring(x, _("date wants a string")) |
11275 | 257 dm = util.matchdate(ds) |
258 return [r for r in subset if dm(repo[r].date()[0])] | |
259 | |
260 def keyword(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
261 kw = getstring(x, _("keyword wants a string")).lower() |
11275 | 262 l = [] |
263 for r in subset: | |
264 c = repo[r] | |
265 t = " ".join(c.files() + [c.user(), c.description()]) | |
266 if kw in t.lower(): | |
267 l.append(r) | |
268 return l | |
269 | |
270 def grep(repo, subset, x): | |
12320
40c40c6f20b8
revset: handle re.compile() errors in grep()
Brodie Rao <brodie@bitheap.org>
parents:
11882
diff
changeset
|
271 try: |
40c40c6f20b8
revset: handle re.compile() errors in grep()
Brodie Rao <brodie@bitheap.org>
parents:
11882
diff
changeset
|
272 gr = re.compile(getstring(x, _("grep wants a string"))) |
40c40c6f20b8
revset: handle re.compile() errors in grep()
Brodie Rao <brodie@bitheap.org>
parents:
11882
diff
changeset
|
273 except re.error, e: |
40c40c6f20b8
revset: handle re.compile() errors in grep()
Brodie Rao <brodie@bitheap.org>
parents:
11882
diff
changeset
|
274 raise error.ParseError(_('invalid match pattern: %s') % e) |
11275 | 275 l = [] |
276 for r in subset: | |
277 c = repo[r] | |
278 for e in c.files() + [c.user(), c.description()]: | |
279 if gr.search(e): | |
280 l.append(r) | |
281 continue | |
282 return l | |
283 | |
284 def author(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
285 n = getstring(x, _("author wants a string")).lower() |
11275 | 286 return [r for r in subset if n in repo[r].user().lower()] |
287 | |
288 def hasfile(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
289 pat = getstring(x, _("file wants a pattern")) |
11275 | 290 m = _match.match(repo.root, repo.getcwd(), [pat]) |
291 s = [] | |
292 for r in subset: | |
293 for f in repo[r].files(): | |
294 if m(f): | |
295 s.append(r) | |
296 continue | |
297 return s | |
298 | |
299 def contains(repo, subset, x): | |
11406
42408cd43f55
revset: fix up contains/getstring when no args passed
Matt Mackall <mpm@selenic.com>
parents:
11404
diff
changeset
|
300 pat = getstring(x, _("contains wants a pattern")) |
11275 | 301 m = _match.match(repo.root, repo.getcwd(), [pat]) |
302 s = [] | |
303 if m.files() == [pat]: | |
304 for r in subset: | |
305 if pat in repo[r]: | |
306 s.append(r) | |
307 continue | |
308 else: | |
309 for r in subset: | |
310 for f in repo[r].manifest(): | |
311 if m(f): | |
312 s.append(r) | |
313 continue | |
314 return s | |
315 | |
316 def checkstatus(repo, subset, pat, field): | |
317 m = _match.match(repo.root, repo.getcwd(), [pat]) | |
318 s = [] | |
319 fast = (m.files() == [pat]) | |
320 for r in subset: | |
321 c = repo[r] | |
322 if fast: | |
323 if pat not in c.files(): | |
324 continue | |
325 else: | |
326 for f in c.files(): | |
327 if m(f): | |
328 break | |
329 else: | |
330 continue | |
331 files = repo.status(c.p1().node(), c.node())[field] | |
332 if fast: | |
333 if pat in files: | |
334 s.append(r) | |
335 continue | |
336 else: | |
337 for f in files: | |
338 if m(f): | |
339 s.append(r) | |
340 continue | |
341 return s | |
342 | |
343 def modifies(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
344 pat = getstring(x, _("modifies wants a pattern")) |
11275 | 345 return checkstatus(repo, subset, pat, 0) |
346 | |
347 def adds(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
348 pat = getstring(x, _("adds wants a pattern")) |
11275 | 349 return checkstatus(repo, subset, pat, 1) |
350 | |
351 def removes(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
352 pat = getstring(x, _("removes wants a pattern")) |
11275 | 353 return checkstatus(repo, subset, pat, 2) |
354 | |
355 def merge(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
356 getargs(x, 0, 0, _("merge takes no arguments")) |
11275 | 357 cl = repo.changelog |
358 return [r for r in subset if cl.parentrevs(r)[1] != -1] | |
359 | |
360 def closed(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
361 getargs(x, 0, 0, _("closed takes no arguments")) |
11349
cf8a9154a362
revset: fix call to ctx.extra() in closed()
Georg Brandl <georg@python.org>
parents:
11339
diff
changeset
|
362 return [r for r in subset if repo[r].extra().get('close')] |
11275 | 363 |
364 def head(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
365 getargs(x, 0, 0, _("head takes no arguments")) |
11275 | 366 hs = set() |
367 for b, ls in repo.branchmap().iteritems(): | |
368 hs.update(repo[h].rev() for h in ls) | |
369 return [r for r in subset if r in hs] | |
370 | |
371 def reverse(repo, subset, x): | |
372 l = getset(repo, subset, x) | |
373 l.reverse() | |
374 return l | |
375 | |
376 def sort(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
377 l = getargs(x, 1, 2, _("sort wants one or two arguments")) |
11275 | 378 keys = "rev" |
379 if len(l) == 2: | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
380 keys = getstring(l[1], _("sort spec must be a string")) |
11275 | 381 |
382 s = l[0] | |
383 keys = keys.split() | |
384 l = [] | |
385 def invert(s): | |
386 return "".join(chr(255 - ord(c)) for c in s) | |
387 for r in getset(repo, subset, s): | |
388 c = repo[r] | |
389 e = [] | |
390 for k in keys: | |
391 if k == 'rev': | |
392 e.append(r) | |
393 elif k == '-rev': | |
394 e.append(-r) | |
395 elif k == 'branch': | |
396 e.append(c.branch()) | |
397 elif k == '-branch': | |
398 e.append(invert(c.branch())) | |
399 elif k == 'desc': | |
400 e.append(c.description()) | |
401 elif k == '-desc': | |
402 e.append(invert(c.description())) | |
403 elif k in 'user author': | |
404 e.append(c.user()) | |
405 elif k in '-user -author': | |
406 e.append(invert(c.user())) | |
407 elif k == 'date': | |
408 e.append(c.date()[0]) | |
409 elif k == '-date': | |
410 e.append(-c.date()[0]) | |
411 else: | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
412 raise error.ParseError(_("unknown sort key %r") % k) |
11275 | 413 e.append(r) |
414 l.append(e) | |
415 l.sort() | |
416 return [e[-1] for e in l] | |
417 | |
418 def getall(repo, subset, x): | |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
419 getargs(x, 0, 0, _("all takes no arguments")) |
11275 | 420 return subset |
421 | |
422 def heads(repo, subset, x): | |
423 s = getset(repo, subset, x) | |
424 ps = set(parents(repo, subset, x)) | |
425 return [r for r in s if r not in ps] | |
426 | |
427 def roots(repo, subset, x): | |
428 s = getset(repo, subset, x) | |
429 cs = set(children(repo, subset, x)) | |
430 return [r for r in s if r not in cs] | |
431 | |
432 def outgoing(repo, subset, x): | |
11293
0e5ce2325795
revset: delay import of hg to avoid start-up import loops
Matt Mackall <mpm@selenic.com>
parents:
11289
diff
changeset
|
433 import hg # avoid start-up nasties |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
434 l = getargs(x, 0, 1, _("outgoing wants a repository path")) |
11882
b75dea24e296
revset: fix outgoing argument handling
Wagner Bruna <wbruna@softwareexpress.com.br>
parents:
11650
diff
changeset
|
435 dest = l and getstring(l[0], _("outgoing wants a repository path")) or '' |
11275 | 436 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default') |
437 dest, branches = hg.parseurl(dest) | |
438 other = hg.repository(hg.remoteui(repo, {}), dest) | |
439 repo.ui.pushbuffer() | |
11301
3d0591a66118
move discovery methods from localrepo into new discovery module
Dirkjan Ochtman <dirkjan@ochtman.nl>
parents:
11293
diff
changeset
|
440 o = discovery.findoutgoing(repo, other) |
11275 | 441 repo.ui.popbuffer() |
442 cl = repo.changelog | |
443 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, None)[0]]) | |
444 return [r for r in subset if r in o] | |
445 | |
11280
a5eb0bf7e158
revset: add tagged predicate
Matt Mackall <mpm@selenic.com>
parents:
11279
diff
changeset
|
446 def tagged(repo, subset, x): |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
447 getargs(x, 0, 0, _("tagged takes no arguments")) |
11280
a5eb0bf7e158
revset: add tagged predicate
Matt Mackall <mpm@selenic.com>
parents:
11279
diff
changeset
|
448 cl = repo.changelog |
a5eb0bf7e158
revset: add tagged predicate
Matt Mackall <mpm@selenic.com>
parents:
11279
diff
changeset
|
449 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip']) |
a5eb0bf7e158
revset: add tagged predicate
Matt Mackall <mpm@selenic.com>
parents:
11279
diff
changeset
|
450 return [r for r in subset if r in s] |
a5eb0bf7e158
revset: add tagged predicate
Matt Mackall <mpm@selenic.com>
parents:
11279
diff
changeset
|
451 |
11275 | 452 symbols = { |
11284
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
453 "adds": adds, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
454 "all": getall, |
11275 | 455 "ancestor": ancestor, |
456 "ancestors": ancestors, | |
11284
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
457 "author": author, |
11275 | 458 "branch": branch, |
11284
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
459 "children": children, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
460 "closed": closed, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
461 "contains": contains, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
462 "date": date, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
463 "descendants": descendants, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
464 "file": hasfile, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
465 "follow": follow, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
466 "grep": grep, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
467 "head": head, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
468 "heads": heads, |
11275 | 469 "keyword": keyword, |
11284
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
470 "limit": limit, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
471 "max": maxrev, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
472 "merge": merge, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
473 "modifies": modifies, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
474 "outgoing": outgoing, |
11275 | 475 "p1": p1, |
476 "p2": p2, | |
477 "parents": parents, | |
11284
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
478 "removes": removes, |
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
479 "reverse": reverse, |
11275 | 480 "roots": roots, |
11284
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
481 "sort": sort, |
11280
a5eb0bf7e158
revset: add tagged predicate
Matt Mackall <mpm@selenic.com>
parents:
11279
diff
changeset
|
482 "tagged": tagged, |
11284
0b5c2e82aeb5
revset: sort the predicate list
Matt Mackall <mpm@selenic.com>
parents:
11283
diff
changeset
|
483 "user": author, |
11275 | 484 } |
485 | |
486 methods = { | |
487 "range": rangeset, | |
488 "string": stringset, | |
489 "symbol": symbolset, | |
490 "and": andset, | |
491 "or": orset, | |
492 "not": notset, | |
493 "list": listset, | |
494 "func": func, | |
495 } | |
496 | |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
497 def optimize(x, small): |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
498 if x == None: |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
499 return 0, x |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
500 |
11275 | 501 smallbonus = 1 |
502 if small: | |
503 smallbonus = .5 | |
504 | |
505 op = x[0] | |
11283
a6356b2695a3
revset: fix - handling in the optimizer
Matt Mackall <mpm@selenic.com>
parents:
11282
diff
changeset
|
506 if op == 'minus': |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
507 return optimize(('and', x[1], ('not', x[2])), small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
508 elif op == 'dagrange': |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
509 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]), |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
510 ('func', ('symbol', 'ancestors'), x[2])), small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
511 elif op == 'dagrangepre': |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
512 return optimize(('func', ('symbol', 'ancestors'), x[1]), small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
513 elif op == 'dagrangepost': |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
514 return optimize(('func', ('symbol', 'descendants'), x[1]), small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
515 elif op == 'rangepre': |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
516 return optimize(('range', ('string', '0'), x[1]), small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
517 elif op == 'rangepost': |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
518 return optimize(('range', x[1], ('string', 'tip')), small) |
11467
6b836d5c8c9e
revset: make negate work for sort specs
Matt Mackall <mpm@selenic.com>
parents:
11456
diff
changeset
|
519 elif op == 'negate': |
6b836d5c8c9e
revset: make negate work for sort specs
Matt Mackall <mpm@selenic.com>
parents:
11456
diff
changeset
|
520 return optimize(('string', |
6b836d5c8c9e
revset: make negate work for sort specs
Matt Mackall <mpm@selenic.com>
parents:
11456
diff
changeset
|
521 '-' + getstring(x[1], _("can't negate that"))), small) |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
522 elif op in 'string symbol negate': |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
523 return smallbonus, x # single revisions are small |
11275 | 524 elif op == 'and' or op == 'dagrange': |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
525 wa, ta = optimize(x[1], True) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
526 wb, tb = optimize(x[2], True) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
527 w = min(wa, wb) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
528 if wa > wb: |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
529 return w, (op, tb, ta) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
530 return w, (op, ta, tb) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
531 elif op == 'or': |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
532 wa, ta = optimize(x[1], False) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
533 wb, tb = optimize(x[2], False) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
534 if wb < wa: |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
535 wb, wa = wa, wb |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
536 return max(wa, wb), (op, ta, tb) |
11275 | 537 elif op == 'not': |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
538 o = optimize(x[1], not small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
539 return o[0], (op, o[1]) |
11275 | 540 elif op == 'group': |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
541 return optimize(x[1], small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
542 elif op in 'range list': |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
543 wa, ta = optimize(x[1], small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
544 wb, tb = optimize(x[2], small) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
545 return wa + wb, (op, ta, tb) |
11275 | 546 elif op == 'func': |
11383
de544774ebea
revset: all your error messages are belong to _
Martin Geisler <mg@lazybytes.net>
parents:
11349
diff
changeset
|
547 f = getstring(x[1], _("not a symbol")) |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
548 wa, ta = optimize(x[2], small) |
11275 | 549 if f in "grep date user author keyword branch file": |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
550 w = 10 # slow |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
551 elif f in "modifies adds removes outgoing": |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
552 w = 30 # slower |
11275 | 553 elif f == "contains": |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
554 w = 100 # very slow |
11275 | 555 elif f == "ancestor": |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
556 w = 1 * smallbonus |
11275 | 557 elif f == "reverse limit": |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
558 w = 0 |
11275 | 559 elif f in "sort": |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
560 w = 10 # assume most sorts look at changelog |
11275 | 561 else: |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
562 w = 1 |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
563 return w + wa, (op, x[1], ta) |
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
564 return 1, x |
11275 | 565 |
566 parse = parser.parser(tokenize, elements).parse | |
567 | |
568 def match(spec): | |
11385
e5a2134c083b
revset: nicer exception for empty queries
Matt Mackall <mpm@selenic.com>
parents:
11383
diff
changeset
|
569 if not spec: |
e5a2134c083b
revset: nicer exception for empty queries
Matt Mackall <mpm@selenic.com>
parents:
11383
diff
changeset
|
570 raise error.ParseError(_("empty query")) |
11275 | 571 tree = parse(spec) |
11279
62ccf4cd6e7f
revset: optimize the parse tree directly
Matt Mackall <mpm@selenic.com>
parents:
11278
diff
changeset
|
572 weight, tree = optimize(tree, True) |
11275 | 573 def mfunc(repo, subset): |
574 return getset(repo, subset, tree) | |
575 return mfunc |