##// END OF EJS Templates
revset: disable subset optimization for parents() and children() (issue2437)...
Wagner Bruna -
r12786:9aae04f4 default
parent child Browse files
Show More
@@ -1,626 +1,626 b''
1 # revset.py - revision set queries for mercurial
1 # revset.py - revision set queries for mercurial
2 #
2 #
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
3 # Copyright 2010 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
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.
6 # GNU General Public License version 2 or any later version.
7
7
8 import re
8 import re
9 import parser, util, error, discovery
9 import parser, util, error, discovery
10 import match as matchmod
10 import match as matchmod
11 from i18n import _
11 from i18n import _
12
12
13 elements = {
13 elements = {
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
14 "(": (20, ("group", 1, ")"), ("func", 1, ")")),
15 "-": (5, ("negate", 19), ("minus", 5)),
15 "-": (5, ("negate", 19), ("minus", 5)),
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
16 "::": (17, ("dagrangepre", 17), ("dagrange", 17),
17 ("dagrangepost", 17)),
17 ("dagrangepost", 17)),
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
18 "..": (17, ("dagrangepre", 17), ("dagrange", 17),
19 ("dagrangepost", 17)),
19 ("dagrangepost", 17)),
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
20 ":": (15, ("rangepre", 15), ("range", 15), ("rangepost", 15)),
21 "not": (10, ("not", 10)),
21 "not": (10, ("not", 10)),
22 "!": (10, ("not", 10)),
22 "!": (10, ("not", 10)),
23 "and": (5, None, ("and", 5)),
23 "and": (5, None, ("and", 5)),
24 "&": (5, None, ("and", 5)),
24 "&": (5, None, ("and", 5)),
25 "or": (4, None, ("or", 4)),
25 "or": (4, None, ("or", 4)),
26 "|": (4, None, ("or", 4)),
26 "|": (4, None, ("or", 4)),
27 "+": (4, None, ("or", 4)),
27 "+": (4, None, ("or", 4)),
28 ",": (2, None, ("list", 2)),
28 ",": (2, None, ("list", 2)),
29 ")": (0, None, None),
29 ")": (0, None, None),
30 "symbol": (0, ("symbol",), None),
30 "symbol": (0, ("symbol",), None),
31 "string": (0, ("string",), None),
31 "string": (0, ("string",), None),
32 "end": (0, None, None),
32 "end": (0, None, None),
33 }
33 }
34
34
35 keywords = set(['and', 'or', 'not'])
35 keywords = set(['and', 'or', 'not'])
36
36
37 def tokenize(program):
37 def tokenize(program):
38 pos, l = 0, len(program)
38 pos, l = 0, len(program)
39 while pos < l:
39 while pos < l:
40 c = program[pos]
40 c = program[pos]
41 if c.isspace(): # skip inter-token whitespace
41 if c.isspace(): # skip inter-token whitespace
42 pass
42 pass
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
43 elif c == ':' and program[pos:pos + 2] == '::': # look ahead carefully
44 yield ('::', None, pos)
44 yield ('::', None, pos)
45 pos += 1 # skip ahead
45 pos += 1 # skip ahead
46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
46 elif c == '.' and program[pos:pos + 2] == '..': # look ahead carefully
47 yield ('..', None, pos)
47 yield ('..', None, pos)
48 pos += 1 # skip ahead
48 pos += 1 # skip ahead
49 elif c in "():,-|&+!": # handle simple operators
49 elif c in "():,-|&+!": # handle simple operators
50 yield (c, None, pos)
50 yield (c, None, pos)
51 elif (c in '"\'' or c == 'r' and
51 elif (c in '"\'' or c == 'r' and
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
53 if c == 'r':
53 if c == 'r':
54 pos += 1
54 pos += 1
55 c = program[pos]
55 c = program[pos]
56 decode = lambda x: x
56 decode = lambda x: x
57 else:
57 else:
58 decode = lambda x: x.decode('string-escape')
58 decode = lambda x: x.decode('string-escape')
59 pos += 1
59 pos += 1
60 s = pos
60 s = pos
61 while pos < l: # find closing quote
61 while pos < l: # find closing quote
62 d = program[pos]
62 d = program[pos]
63 if d == '\\': # skip over escaped characters
63 if d == '\\': # skip over escaped characters
64 pos += 2
64 pos += 2
65 continue
65 continue
66 if d == c:
66 if d == c:
67 yield ('string', decode(program[s:pos]), s)
67 yield ('string', decode(program[s:pos]), s)
68 break
68 break
69 pos += 1
69 pos += 1
70 else:
70 else:
71 raise error.ParseError(_("unterminated string"), s)
71 raise error.ParseError(_("unterminated string"), s)
72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
72 elif c.isalnum() or c in '._' or ord(c) > 127: # gather up a symbol/keyword
73 s = pos
73 s = pos
74 pos += 1
74 pos += 1
75 while pos < l: # find end of symbol
75 while pos < l: # find end of symbol
76 d = program[pos]
76 d = program[pos]
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
78 break
78 break
79 if d == '.' and program[pos - 1] == '.': # special case for ..
79 if d == '.' and program[pos - 1] == '.': # special case for ..
80 pos -= 1
80 pos -= 1
81 break
81 break
82 pos += 1
82 pos += 1
83 sym = program[s:pos]
83 sym = program[s:pos]
84 if sym in keywords: # operator keywords
84 if sym in keywords: # operator keywords
85 yield (sym, None, s)
85 yield (sym, None, s)
86 else:
86 else:
87 yield ('symbol', sym, s)
87 yield ('symbol', sym, s)
88 pos -= 1
88 pos -= 1
89 else:
89 else:
90 raise error.ParseError(_("syntax error"), pos)
90 raise error.ParseError(_("syntax error"), pos)
91 pos += 1
91 pos += 1
92 yield ('end', None, pos)
92 yield ('end', None, pos)
93
93
94 # helpers
94 # helpers
95
95
96 def getstring(x, err):
96 def getstring(x, err):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
98 return x[1]
98 return x[1]
99 raise error.ParseError(err)
99 raise error.ParseError(err)
100
100
101 def getlist(x):
101 def getlist(x):
102 if not x:
102 if not x:
103 return []
103 return []
104 if x[0] == 'list':
104 if x[0] == 'list':
105 return getlist(x[1]) + [x[2]]
105 return getlist(x[1]) + [x[2]]
106 return [x]
106 return [x]
107
107
108 def getargs(x, min, max, err):
108 def getargs(x, min, max, err):
109 l = getlist(x)
109 l = getlist(x)
110 if len(l) < min or len(l) > max:
110 if len(l) < min or len(l) > max:
111 raise error.ParseError(err)
111 raise error.ParseError(err)
112 return l
112 return l
113
113
114 def getset(repo, subset, x):
114 def getset(repo, subset, x):
115 if not x:
115 if not x:
116 raise error.ParseError(_("missing argument"))
116 raise error.ParseError(_("missing argument"))
117 return methods[x[0]](repo, subset, *x[1:])
117 return methods[x[0]](repo, subset, *x[1:])
118
118
119 # operator methods
119 # operator methods
120
120
121 def stringset(repo, subset, x):
121 def stringset(repo, subset, x):
122 x = repo[x].rev()
122 x = repo[x].rev()
123 if x == -1 and len(subset) == len(repo):
123 if x == -1 and len(subset) == len(repo):
124 return [-1]
124 return [-1]
125 if x in subset:
125 if x in subset:
126 return [x]
126 return [x]
127 return []
127 return []
128
128
129 def symbolset(repo, subset, x):
129 def symbolset(repo, subset, x):
130 if x in symbols:
130 if x in symbols:
131 raise error.ParseError(_("can't use %s here") % x)
131 raise error.ParseError(_("can't use %s here") % x)
132 return stringset(repo, subset, x)
132 return stringset(repo, subset, x)
133
133
134 def rangeset(repo, subset, x, y):
134 def rangeset(repo, subset, x, y):
135 m = getset(repo, subset, x)
135 m = getset(repo, subset, x)
136 if not m:
136 if not m:
137 m = getset(repo, range(len(repo)), x)
137 m = getset(repo, range(len(repo)), x)
138
138
139 n = getset(repo, subset, y)
139 n = getset(repo, subset, y)
140 if not n:
140 if not n:
141 n = getset(repo, range(len(repo)), y)
141 n = getset(repo, range(len(repo)), y)
142
142
143 if not m or not n:
143 if not m or not n:
144 return []
144 return []
145 m, n = m[0], n[-1]
145 m, n = m[0], n[-1]
146
146
147 if m < n:
147 if m < n:
148 r = range(m, n + 1)
148 r = range(m, n + 1)
149 else:
149 else:
150 r = range(m, n - 1, -1)
150 r = range(m, n - 1, -1)
151 s = set(subset)
151 s = set(subset)
152 return [x for x in r if x in s]
152 return [x for x in r if x in s]
153
153
154 def andset(repo, subset, x, y):
154 def andset(repo, subset, x, y):
155 return getset(repo, getset(repo, subset, x), y)
155 return getset(repo, getset(repo, subset, x), y)
156
156
157 def orset(repo, subset, x, y):
157 def orset(repo, subset, x, y):
158 s = set(getset(repo, subset, x))
158 s = set(getset(repo, subset, x))
159 s |= set(getset(repo, [r for r in subset if r not in s], y))
159 s |= set(getset(repo, [r for r in subset if r not in s], y))
160 return [r for r in subset if r in s]
160 return [r for r in subset if r in s]
161
161
162 def notset(repo, subset, x):
162 def notset(repo, subset, x):
163 s = set(getset(repo, subset, x))
163 s = set(getset(repo, subset, x))
164 return [r for r in subset if r not in s]
164 return [r for r in subset if r not in s]
165
165
166 def listset(repo, subset, a, b):
166 def listset(repo, subset, a, b):
167 raise error.ParseError(_("can't use a list in this context"))
167 raise error.ParseError(_("can't use a list in this context"))
168
168
169 def func(repo, subset, a, b):
169 def func(repo, subset, a, b):
170 if a[0] == 'symbol' and a[1] in symbols:
170 if a[0] == 'symbol' and a[1] in symbols:
171 return symbols[a[1]](repo, subset, b)
171 return symbols[a[1]](repo, subset, b)
172 raise error.ParseError(_("not a function: %s") % a[1])
172 raise error.ParseError(_("not a function: %s") % a[1])
173
173
174 # functions
174 # functions
175
175
176 def node(repo, subset, x):
176 def node(repo, subset, x):
177 l = getargs(x, 1, 1, _("id requires one argument"))
177 l = getargs(x, 1, 1, _("id requires one argument"))
178 n = getstring(l[0], _("id requires a string"))
178 n = getstring(l[0], _("id requires a string"))
179 if len(n) == 40:
179 if len(n) == 40:
180 rn = repo[n].rev()
180 rn = repo[n].rev()
181 else:
181 else:
182 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
182 rn = repo.changelog.rev(repo.changelog._partialmatch(n))
183 return [r for r in subset if r == rn]
183 return [r for r in subset if r == rn]
184
184
185 def rev(repo, subset, x):
185 def rev(repo, subset, x):
186 l = getargs(x, 1, 1, _("rev requires one argument"))
186 l = getargs(x, 1, 1, _("rev requires one argument"))
187 try:
187 try:
188 l = int(getstring(l[0], _("rev requires a number")))
188 l = int(getstring(l[0], _("rev requires a number")))
189 except ValueError:
189 except ValueError:
190 raise error.ParseError(_("rev expects a number"))
190 raise error.ParseError(_("rev expects a number"))
191 return [r for r in subset if r == l]
191 return [r for r in subset if r == l]
192
192
193 def p1(repo, subset, x):
193 def p1(repo, subset, x):
194 ps = set()
194 ps = set()
195 cl = repo.changelog
195 cl = repo.changelog
196 for r in getset(repo, subset, x):
196 for r in getset(repo, range(len(repo)), x):
197 ps.add(cl.parentrevs(r)[0])
197 ps.add(cl.parentrevs(r)[0])
198 return [r for r in subset if r in ps]
198 return [r for r in subset if r in ps]
199
199
200 def p2(repo, subset, x):
200 def p2(repo, subset, x):
201 ps = set()
201 ps = set()
202 cl = repo.changelog
202 cl = repo.changelog
203 for r in getset(repo, subset, x):
203 for r in getset(repo, range(len(repo)), x):
204 ps.add(cl.parentrevs(r)[1])
204 ps.add(cl.parentrevs(r)[1])
205 return [r for r in subset if r in ps]
205 return [r for r in subset if r in ps]
206
206
207 def parents(repo, subset, x):
207 def parents(repo, subset, x):
208 ps = set()
208 ps = set()
209 cl = repo.changelog
209 cl = repo.changelog
210 for r in getset(repo, subset, x):
210 for r in getset(repo, range(len(repo)), x):
211 ps.update(cl.parentrevs(r))
211 ps.update(cl.parentrevs(r))
212 return [r for r in subset if r in ps]
212 return [r for r in subset if r in ps]
213
213
214 def maxrev(repo, subset, x):
214 def maxrev(repo, subset, x):
215 s = getset(repo, subset, x)
215 s = getset(repo, subset, x)
216 if s:
216 if s:
217 m = max(s)
217 m = max(s)
218 if m in subset:
218 if m in subset:
219 return [m]
219 return [m]
220 return []
220 return []
221
221
222 def minrev(repo, subset, x):
222 def minrev(repo, subset, x):
223 s = getset(repo, subset, x)
223 s = getset(repo, subset, x)
224 if s:
224 if s:
225 m = min(s)
225 m = min(s)
226 if m in subset:
226 if m in subset:
227 return [m]
227 return [m]
228 return []
228 return []
229
229
230 def limit(repo, subset, x):
230 def limit(repo, subset, x):
231 l = getargs(x, 2, 2, _("limit requires two arguments"))
231 l = getargs(x, 2, 2, _("limit requires two arguments"))
232 try:
232 try:
233 lim = int(getstring(l[1], _("limit requires a number")))
233 lim = int(getstring(l[1], _("limit requires a number")))
234 except ValueError:
234 except ValueError:
235 raise error.ParseError(_("limit expects a number"))
235 raise error.ParseError(_("limit expects a number"))
236 return getset(repo, subset, l[0])[:lim]
236 return getset(repo, subset, l[0])[:lim]
237
237
238 def children(repo, subset, x):
238 def children(repo, subset, x):
239 cs = set()
239 cs = set()
240 cl = repo.changelog
240 cl = repo.changelog
241 s = set(getset(repo, subset, x))
241 s = set(getset(repo, range(len(repo)), x))
242 for r in xrange(0, len(repo)):
242 for r in xrange(0, len(repo)):
243 for p in cl.parentrevs(r):
243 for p in cl.parentrevs(r):
244 if p in s:
244 if p in s:
245 cs.add(r)
245 cs.add(r)
246 return [r for r in subset if r in cs]
246 return [r for r in subset if r in cs]
247
247
248 def branch(repo, subset, x):
248 def branch(repo, subset, x):
249 s = getset(repo, range(len(repo)), x)
249 s = getset(repo, range(len(repo)), x)
250 b = set()
250 b = set()
251 for r in s:
251 for r in s:
252 b.add(repo[r].branch())
252 b.add(repo[r].branch())
253 s = set(s)
253 s = set(s)
254 return [r for r in subset if r in s or repo[r].branch() in b]
254 return [r for r in subset if r in s or repo[r].branch() in b]
255
255
256 def ancestor(repo, subset, x):
256 def ancestor(repo, subset, x):
257 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
257 l = getargs(x, 2, 2, _("ancestor requires two arguments"))
258 r = range(len(repo))
258 r = range(len(repo))
259 a = getset(repo, r, l[0])
259 a = getset(repo, r, l[0])
260 b = getset(repo, r, l[1])
260 b = getset(repo, r, l[1])
261 if len(a) != 1 or len(b) != 1:
261 if len(a) != 1 or len(b) != 1:
262 raise error.ParseError(_("ancestor arguments must be single revisions"))
262 raise error.ParseError(_("ancestor arguments must be single revisions"))
263 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
263 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
264
264
265 return [r for r in an if r in subset]
265 return [r for r in an if r in subset]
266
266
267 def ancestors(repo, subset, x):
267 def ancestors(repo, subset, x):
268 args = getset(repo, range(len(repo)), x)
268 args = getset(repo, range(len(repo)), x)
269 if not args:
269 if not args:
270 return []
270 return []
271 s = set(repo.changelog.ancestors(*args)) | set(args)
271 s = set(repo.changelog.ancestors(*args)) | set(args)
272 return [r for r in subset if r in s]
272 return [r for r in subset if r in s]
273
273
274 def descendants(repo, subset, x):
274 def descendants(repo, subset, x):
275 args = getset(repo, range(len(repo)), x)
275 args = getset(repo, range(len(repo)), x)
276 if not args:
276 if not args:
277 return []
277 return []
278 s = set(repo.changelog.descendants(*args)) | set(args)
278 s = set(repo.changelog.descendants(*args)) | set(args)
279 return [r for r in subset if r in s]
279 return [r for r in subset if r in s]
280
280
281 def follow(repo, subset, x):
281 def follow(repo, subset, x):
282 getargs(x, 0, 0, _("follow takes no arguments"))
282 getargs(x, 0, 0, _("follow takes no arguments"))
283 p = repo['.'].rev()
283 p = repo['.'].rev()
284 s = set(repo.changelog.ancestors(p)) | set([p])
284 s = set(repo.changelog.ancestors(p)) | set([p])
285 return [r for r in subset if r in s]
285 return [r for r in subset if r in s]
286
286
287 def date(repo, subset, x):
287 def date(repo, subset, x):
288 ds = getstring(x, _("date requires a string"))
288 ds = getstring(x, _("date requires a string"))
289 dm = util.matchdate(ds)
289 dm = util.matchdate(ds)
290 return [r for r in subset if dm(repo[r].date()[0])]
290 return [r for r in subset if dm(repo[r].date()[0])]
291
291
292 def keyword(repo, subset, x):
292 def keyword(repo, subset, x):
293 kw = getstring(x, _("keyword requires a string")).lower()
293 kw = getstring(x, _("keyword requires a string")).lower()
294 l = []
294 l = []
295 for r in subset:
295 for r in subset:
296 c = repo[r]
296 c = repo[r]
297 t = " ".join(c.files() + [c.user(), c.description()])
297 t = " ".join(c.files() + [c.user(), c.description()])
298 if kw in t.lower():
298 if kw in t.lower():
299 l.append(r)
299 l.append(r)
300 return l
300 return l
301
301
302 def grep(repo, subset, x):
302 def grep(repo, subset, x):
303 try:
303 try:
304 gr = re.compile(getstring(x, _("grep requires a string")))
304 gr = re.compile(getstring(x, _("grep requires a string")))
305 except re.error, e:
305 except re.error, e:
306 raise error.ParseError(_('invalid match pattern: %s') % e)
306 raise error.ParseError(_('invalid match pattern: %s') % e)
307 l = []
307 l = []
308 for r in subset:
308 for r in subset:
309 c = repo[r]
309 c = repo[r]
310 for e in c.files() + [c.user(), c.description()]:
310 for e in c.files() + [c.user(), c.description()]:
311 if gr.search(e):
311 if gr.search(e):
312 l.append(r)
312 l.append(r)
313 continue
313 continue
314 return l
314 return l
315
315
316 def author(repo, subset, x):
316 def author(repo, subset, x):
317 n = getstring(x, _("author requires a string")).lower()
317 n = getstring(x, _("author requires a string")).lower()
318 return [r for r in subset if n in repo[r].user().lower()]
318 return [r for r in subset if n in repo[r].user().lower()]
319
319
320 def hasfile(repo, subset, x):
320 def hasfile(repo, subset, x):
321 pat = getstring(x, _("file requires a pattern"))
321 pat = getstring(x, _("file requires a pattern"))
322 m = matchmod.match(repo.root, repo.getcwd(), [pat])
322 m = matchmod.match(repo.root, repo.getcwd(), [pat])
323 s = []
323 s = []
324 for r in subset:
324 for r in subset:
325 for f in repo[r].files():
325 for f in repo[r].files():
326 if m(f):
326 if m(f):
327 s.append(r)
327 s.append(r)
328 continue
328 continue
329 return s
329 return s
330
330
331 def contains(repo, subset, x):
331 def contains(repo, subset, x):
332 pat = getstring(x, _("contains requires a pattern"))
332 pat = getstring(x, _("contains requires a pattern"))
333 m = matchmod.match(repo.root, repo.getcwd(), [pat])
333 m = matchmod.match(repo.root, repo.getcwd(), [pat])
334 s = []
334 s = []
335 if m.files() == [pat]:
335 if m.files() == [pat]:
336 for r in subset:
336 for r in subset:
337 if pat in repo[r]:
337 if pat in repo[r]:
338 s.append(r)
338 s.append(r)
339 continue
339 continue
340 else:
340 else:
341 for r in subset:
341 for r in subset:
342 for f in repo[r].manifest():
342 for f in repo[r].manifest():
343 if m(f):
343 if m(f):
344 s.append(r)
344 s.append(r)
345 continue
345 continue
346 return s
346 return s
347
347
348 def checkstatus(repo, subset, pat, field):
348 def checkstatus(repo, subset, pat, field):
349 m = matchmod.match(repo.root, repo.getcwd(), [pat])
349 m = matchmod.match(repo.root, repo.getcwd(), [pat])
350 s = []
350 s = []
351 fast = (m.files() == [pat])
351 fast = (m.files() == [pat])
352 for r in subset:
352 for r in subset:
353 c = repo[r]
353 c = repo[r]
354 if fast:
354 if fast:
355 if pat not in c.files():
355 if pat not in c.files():
356 continue
356 continue
357 else:
357 else:
358 for f in c.files():
358 for f in c.files():
359 if m(f):
359 if m(f):
360 break
360 break
361 else:
361 else:
362 continue
362 continue
363 files = repo.status(c.p1().node(), c.node())[field]
363 files = repo.status(c.p1().node(), c.node())[field]
364 if fast:
364 if fast:
365 if pat in files:
365 if pat in files:
366 s.append(r)
366 s.append(r)
367 continue
367 continue
368 else:
368 else:
369 for f in files:
369 for f in files:
370 if m(f):
370 if m(f):
371 s.append(r)
371 s.append(r)
372 continue
372 continue
373 return s
373 return s
374
374
375 def modifies(repo, subset, x):
375 def modifies(repo, subset, x):
376 pat = getstring(x, _("modifies requires a pattern"))
376 pat = getstring(x, _("modifies requires a pattern"))
377 return checkstatus(repo, subset, pat, 0)
377 return checkstatus(repo, subset, pat, 0)
378
378
379 def adds(repo, subset, x):
379 def adds(repo, subset, x):
380 pat = getstring(x, _("adds requires a pattern"))
380 pat = getstring(x, _("adds requires a pattern"))
381 return checkstatus(repo, subset, pat, 1)
381 return checkstatus(repo, subset, pat, 1)
382
382
383 def removes(repo, subset, x):
383 def removes(repo, subset, x):
384 pat = getstring(x, _("removes requires a pattern"))
384 pat = getstring(x, _("removes requires a pattern"))
385 return checkstatus(repo, subset, pat, 2)
385 return checkstatus(repo, subset, pat, 2)
386
386
387 def merge(repo, subset, x):
387 def merge(repo, subset, x):
388 getargs(x, 0, 0, _("merge takes no arguments"))
388 getargs(x, 0, 0, _("merge takes no arguments"))
389 cl = repo.changelog
389 cl = repo.changelog
390 return [r for r in subset if cl.parentrevs(r)[1] != -1]
390 return [r for r in subset if cl.parentrevs(r)[1] != -1]
391
391
392 def closed(repo, subset, x):
392 def closed(repo, subset, x):
393 getargs(x, 0, 0, _("closed takes no arguments"))
393 getargs(x, 0, 0, _("closed takes no arguments"))
394 return [r for r in subset if repo[r].extra().get('close')]
394 return [r for r in subset if repo[r].extra().get('close')]
395
395
396 def head(repo, subset, x):
396 def head(repo, subset, x):
397 getargs(x, 0, 0, _("head takes no arguments"))
397 getargs(x, 0, 0, _("head takes no arguments"))
398 hs = set()
398 hs = set()
399 for b, ls in repo.branchmap().iteritems():
399 for b, ls in repo.branchmap().iteritems():
400 hs.update(repo[h].rev() for h in ls)
400 hs.update(repo[h].rev() for h in ls)
401 return [r for r in subset if r in hs]
401 return [r for r in subset if r in hs]
402
402
403 def reverse(repo, subset, x):
403 def reverse(repo, subset, x):
404 l = getset(repo, subset, x)
404 l = getset(repo, subset, x)
405 l.reverse()
405 l.reverse()
406 return l
406 return l
407
407
408 def present(repo, subset, x):
408 def present(repo, subset, x):
409 try:
409 try:
410 return getset(repo, subset, x)
410 return getset(repo, subset, x)
411 except error.RepoLookupError:
411 except error.RepoLookupError:
412 return []
412 return []
413
413
414 def sort(repo, subset, x):
414 def sort(repo, subset, x):
415 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
415 l = getargs(x, 1, 2, _("sort requires one or two arguments"))
416 keys = "rev"
416 keys = "rev"
417 if len(l) == 2:
417 if len(l) == 2:
418 keys = getstring(l[1], _("sort spec must be a string"))
418 keys = getstring(l[1], _("sort spec must be a string"))
419
419
420 s = l[0]
420 s = l[0]
421 keys = keys.split()
421 keys = keys.split()
422 l = []
422 l = []
423 def invert(s):
423 def invert(s):
424 return "".join(chr(255 - ord(c)) for c in s)
424 return "".join(chr(255 - ord(c)) for c in s)
425 for r in getset(repo, subset, s):
425 for r in getset(repo, subset, s):
426 c = repo[r]
426 c = repo[r]
427 e = []
427 e = []
428 for k in keys:
428 for k in keys:
429 if k == 'rev':
429 if k == 'rev':
430 e.append(r)
430 e.append(r)
431 elif k == '-rev':
431 elif k == '-rev':
432 e.append(-r)
432 e.append(-r)
433 elif k == 'branch':
433 elif k == 'branch':
434 e.append(c.branch())
434 e.append(c.branch())
435 elif k == '-branch':
435 elif k == '-branch':
436 e.append(invert(c.branch()))
436 e.append(invert(c.branch()))
437 elif k == 'desc':
437 elif k == 'desc':
438 e.append(c.description())
438 e.append(c.description())
439 elif k == '-desc':
439 elif k == '-desc':
440 e.append(invert(c.description()))
440 e.append(invert(c.description()))
441 elif k in 'user author':
441 elif k in 'user author':
442 e.append(c.user())
442 e.append(c.user())
443 elif k in '-user -author':
443 elif k in '-user -author':
444 e.append(invert(c.user()))
444 e.append(invert(c.user()))
445 elif k == 'date':
445 elif k == 'date':
446 e.append(c.date()[0])
446 e.append(c.date()[0])
447 elif k == '-date':
447 elif k == '-date':
448 e.append(-c.date()[0])
448 e.append(-c.date()[0])
449 else:
449 else:
450 raise error.ParseError(_("unknown sort key %r") % k)
450 raise error.ParseError(_("unknown sort key %r") % k)
451 e.append(r)
451 e.append(r)
452 l.append(e)
452 l.append(e)
453 l.sort()
453 l.sort()
454 return [e[-1] for e in l]
454 return [e[-1] for e in l]
455
455
456 def getall(repo, subset, x):
456 def getall(repo, subset, x):
457 getargs(x, 0, 0, _("all takes no arguments"))
457 getargs(x, 0, 0, _("all takes no arguments"))
458 return subset
458 return subset
459
459
460 def heads(repo, subset, x):
460 def heads(repo, subset, x):
461 s = getset(repo, subset, x)
461 s = getset(repo, subset, x)
462 ps = set(parents(repo, subset, x))
462 ps = set(parents(repo, subset, x))
463 return [r for r in s if r not in ps]
463 return [r for r in s if r not in ps]
464
464
465 def roots(repo, subset, x):
465 def roots(repo, subset, x):
466 s = getset(repo, subset, x)
466 s = getset(repo, subset, x)
467 cs = set(children(repo, subset, x))
467 cs = set(children(repo, subset, x))
468 return [r for r in s if r not in cs]
468 return [r for r in s if r not in cs]
469
469
470 def outgoing(repo, subset, x):
470 def outgoing(repo, subset, x):
471 import hg # avoid start-up nasties
471 import hg # avoid start-up nasties
472 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
472 l = getargs(x, 0, 1, _("outgoing requires a repository path"))
473 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
473 dest = l and getstring(l[0], _("outgoing requires a repository path")) or ''
474 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
474 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
475 dest, branches = hg.parseurl(dest)
475 dest, branches = hg.parseurl(dest)
476 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
476 revs, checkout = hg.addbranchrevs(repo, repo, branches, [])
477 if revs:
477 if revs:
478 revs = [repo.lookup(rev) for rev in revs]
478 revs = [repo.lookup(rev) for rev in revs]
479 other = hg.repository(hg.remoteui(repo, {}), dest)
479 other = hg.repository(hg.remoteui(repo, {}), dest)
480 repo.ui.pushbuffer()
480 repo.ui.pushbuffer()
481 o = discovery.findoutgoing(repo, other)
481 o = discovery.findoutgoing(repo, other)
482 repo.ui.popbuffer()
482 repo.ui.popbuffer()
483 cl = repo.changelog
483 cl = repo.changelog
484 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
484 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, revs)[0]])
485 return [r for r in subset if r in o]
485 return [r for r in subset if r in o]
486
486
487 def tag(repo, subset, x):
487 def tag(repo, subset, x):
488 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
488 args = getargs(x, 0, 1, _("tag takes one or no arguments"))
489 cl = repo.changelog
489 cl = repo.changelog
490 if args:
490 if args:
491 tn = getstring(args[0],
491 tn = getstring(args[0],
492 _('the argument to tag must be a string'))
492 _('the argument to tag must be a string'))
493 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
493 s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
494 else:
494 else:
495 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
495 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
496 return [r for r in subset if r in s]
496 return [r for r in subset if r in s]
497
497
498 symbols = {
498 symbols = {
499 "adds": adds,
499 "adds": adds,
500 "all": getall,
500 "all": getall,
501 "ancestor": ancestor,
501 "ancestor": ancestor,
502 "ancestors": ancestors,
502 "ancestors": ancestors,
503 "author": author,
503 "author": author,
504 "branch": branch,
504 "branch": branch,
505 "children": children,
505 "children": children,
506 "closed": closed,
506 "closed": closed,
507 "contains": contains,
507 "contains": contains,
508 "date": date,
508 "date": date,
509 "descendants": descendants,
509 "descendants": descendants,
510 "file": hasfile,
510 "file": hasfile,
511 "follow": follow,
511 "follow": follow,
512 "grep": grep,
512 "grep": grep,
513 "head": head,
513 "head": head,
514 "heads": heads,
514 "heads": heads,
515 "keyword": keyword,
515 "keyword": keyword,
516 "limit": limit,
516 "limit": limit,
517 "max": maxrev,
517 "max": maxrev,
518 "min": minrev,
518 "min": minrev,
519 "merge": merge,
519 "merge": merge,
520 "modifies": modifies,
520 "modifies": modifies,
521 "id": node,
521 "id": node,
522 "outgoing": outgoing,
522 "outgoing": outgoing,
523 "p1": p1,
523 "p1": p1,
524 "p2": p2,
524 "p2": p2,
525 "parents": parents,
525 "parents": parents,
526 "present": present,
526 "present": present,
527 "removes": removes,
527 "removes": removes,
528 "reverse": reverse,
528 "reverse": reverse,
529 "rev": rev,
529 "rev": rev,
530 "roots": roots,
530 "roots": roots,
531 "sort": sort,
531 "sort": sort,
532 "tag": tag,
532 "tag": tag,
533 "tagged": tag,
533 "tagged": tag,
534 "user": author,
534 "user": author,
535 }
535 }
536
536
537 methods = {
537 methods = {
538 "range": rangeset,
538 "range": rangeset,
539 "string": stringset,
539 "string": stringset,
540 "symbol": symbolset,
540 "symbol": symbolset,
541 "and": andset,
541 "and": andset,
542 "or": orset,
542 "or": orset,
543 "not": notset,
543 "not": notset,
544 "list": listset,
544 "list": listset,
545 "func": func,
545 "func": func,
546 }
546 }
547
547
548 def optimize(x, small):
548 def optimize(x, small):
549 if x == None:
549 if x == None:
550 return 0, x
550 return 0, x
551
551
552 smallbonus = 1
552 smallbonus = 1
553 if small:
553 if small:
554 smallbonus = .5
554 smallbonus = .5
555
555
556 op = x[0]
556 op = x[0]
557 if op == 'minus':
557 if op == 'minus':
558 return optimize(('and', x[1], ('not', x[2])), small)
558 return optimize(('and', x[1], ('not', x[2])), small)
559 elif op == 'dagrange':
559 elif op == 'dagrange':
560 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
560 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
561 ('func', ('symbol', 'ancestors'), x[2])), small)
561 ('func', ('symbol', 'ancestors'), x[2])), small)
562 elif op == 'dagrangepre':
562 elif op == 'dagrangepre':
563 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
563 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
564 elif op == 'dagrangepost':
564 elif op == 'dagrangepost':
565 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
565 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
566 elif op == 'rangepre':
566 elif op == 'rangepre':
567 return optimize(('range', ('string', '0'), x[1]), small)
567 return optimize(('range', ('string', '0'), x[1]), small)
568 elif op == 'rangepost':
568 elif op == 'rangepost':
569 return optimize(('range', x[1], ('string', 'tip')), small)
569 return optimize(('range', x[1], ('string', 'tip')), small)
570 elif op == 'negate':
570 elif op == 'negate':
571 return optimize(('string',
571 return optimize(('string',
572 '-' + getstring(x[1], _("can't negate that"))), small)
572 '-' + getstring(x[1], _("can't negate that"))), small)
573 elif op in 'string symbol negate':
573 elif op in 'string symbol negate':
574 return smallbonus, x # single revisions are small
574 return smallbonus, x # single revisions are small
575 elif op == 'and' or op == 'dagrange':
575 elif op == 'and' or op == 'dagrange':
576 wa, ta = optimize(x[1], True)
576 wa, ta = optimize(x[1], True)
577 wb, tb = optimize(x[2], True)
577 wb, tb = optimize(x[2], True)
578 w = min(wa, wb)
578 w = min(wa, wb)
579 if wa > wb:
579 if wa > wb:
580 return w, (op, tb, ta)
580 return w, (op, tb, ta)
581 return w, (op, ta, tb)
581 return w, (op, ta, tb)
582 elif op == 'or':
582 elif op == 'or':
583 wa, ta = optimize(x[1], False)
583 wa, ta = optimize(x[1], False)
584 wb, tb = optimize(x[2], False)
584 wb, tb = optimize(x[2], False)
585 if wb < wa:
585 if wb < wa:
586 wb, wa = wa, wb
586 wb, wa = wa, wb
587 return max(wa, wb), (op, ta, tb)
587 return max(wa, wb), (op, ta, tb)
588 elif op == 'not':
588 elif op == 'not':
589 o = optimize(x[1], not small)
589 o = optimize(x[1], not small)
590 return o[0], (op, o[1])
590 return o[0], (op, o[1])
591 elif op == 'group':
591 elif op == 'group':
592 return optimize(x[1], small)
592 return optimize(x[1], small)
593 elif op in 'range list':
593 elif op in 'range list':
594 wa, ta = optimize(x[1], small)
594 wa, ta = optimize(x[1], small)
595 wb, tb = optimize(x[2], small)
595 wb, tb = optimize(x[2], small)
596 return wa + wb, (op, ta, tb)
596 return wa + wb, (op, ta, tb)
597 elif op == 'func':
597 elif op == 'func':
598 f = getstring(x[1], _("not a symbol"))
598 f = getstring(x[1], _("not a symbol"))
599 wa, ta = optimize(x[2], small)
599 wa, ta = optimize(x[2], small)
600 if f in "grep date user author keyword branch file outgoing":
600 if f in "grep date user author keyword branch file outgoing":
601 w = 10 # slow
601 w = 10 # slow
602 elif f in "modifies adds removes":
602 elif f in "modifies adds removes":
603 w = 30 # slower
603 w = 30 # slower
604 elif f == "contains":
604 elif f == "contains":
605 w = 100 # very slow
605 w = 100 # very slow
606 elif f == "ancestor":
606 elif f == "ancestor":
607 w = 1 * smallbonus
607 w = 1 * smallbonus
608 elif f == "reverse limit":
608 elif f == "reverse limit":
609 w = 0
609 w = 0
610 elif f in "sort":
610 elif f in "sort":
611 w = 10 # assume most sorts look at changelog
611 w = 10 # assume most sorts look at changelog
612 else:
612 else:
613 w = 1
613 w = 1
614 return w + wa, (op, x[1], ta)
614 return w + wa, (op, x[1], ta)
615 return 1, x
615 return 1, x
616
616
617 parse = parser.parser(tokenize, elements).parse
617 parse = parser.parser(tokenize, elements).parse
618
618
619 def match(spec):
619 def match(spec):
620 if not spec:
620 if not spec:
621 raise error.ParseError(_("empty query"))
621 raise error.ParseError(_("empty query"))
622 tree = parse(spec)
622 tree = parse(spec)
623 weight, tree = optimize(tree, True)
623 weight, tree = optimize(tree, True)
624 def mfunc(repo, subset):
624 def mfunc(repo, subset):
625 return getset(repo, subset, tree)
625 return getset(repo, subset, tree)
626 return mfunc
626 return mfunc
@@ -1,341 +1,358 b''
1 $ HGENCODING=utf-8
1 $ HGENCODING=utf-8
2 $ export HGENCODING
2 $ export HGENCODING
3
3
4 $ try() {
4 $ try() {
5 > hg debugrevspec --debug $@
5 > hg debugrevspec --debug $@
6 > }
6 > }
7
7
8 $ log() {
8 $ log() {
9 > hg log --template '{rev}\n' -r "$1"
9 > hg log --template '{rev}\n' -r "$1"
10 > }
10 > }
11
11
12 $ hg init repo
12 $ hg init repo
13 $ cd repo
13 $ cd repo
14
14
15 $ echo a > a
15 $ echo a > a
16 $ hg branch a
16 $ hg branch a
17 marked working directory as branch a
17 marked working directory as branch a
18 $ hg ci -Aqm0
18 $ hg ci -Aqm0
19
19
20 $ echo b > b
20 $ echo b > b
21 $ hg branch b
21 $ hg branch b
22 marked working directory as branch b
22 marked working directory as branch b
23 $ hg ci -Aqm1
23 $ hg ci -Aqm1
24
24
25 $ rm a
25 $ rm a
26 $ hg branch a-b-c-
26 $ hg branch a-b-c-
27 marked working directory as branch a-b-c-
27 marked working directory as branch a-b-c-
28 $ hg ci -Aqm2 -u Bob
28 $ hg ci -Aqm2 -u Bob
29
29
30 $ hg co 1
30 $ hg co 1
31 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 $ hg branch +a+b+c+
32 $ hg branch +a+b+c+
33 marked working directory as branch +a+b+c+
33 marked working directory as branch +a+b+c+
34 $ hg ci -Aqm3
34 $ hg ci -Aqm3
35
35
36 $ hg co 2 # interleave
36 $ hg co 2 # interleave
37 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
37 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
38 $ echo bb > b
38 $ echo bb > b
39 $ hg branch -- -a-b-c-
39 $ hg branch -- -a-b-c-
40 marked working directory as branch -a-b-c-
40 marked working directory as branch -a-b-c-
41 $ hg ci -Aqm4 -d "May 12 2005"
41 $ hg ci -Aqm4 -d "May 12 2005"
42
42
43 $ hg co 3
43 $ hg co 3
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
44 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
45 $ hg branch /a/b/c/
45 $ hg branch /a/b/c/
46 marked working directory as branch /a/b/c/
46 marked working directory as branch /a/b/c/
47 $ hg ci -Aqm"5 bug"
47 $ hg ci -Aqm"5 bug"
48
48
49 $ hg merge 4
49 $ hg merge 4
50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
50 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 (branch merge, don't forget to commit)
51 (branch merge, don't forget to commit)
52 $ hg branch _a_b_c_
52 $ hg branch _a_b_c_
53 marked working directory as branch _a_b_c_
53 marked working directory as branch _a_b_c_
54 $ hg ci -Aqm"6 issue619"
54 $ hg ci -Aqm"6 issue619"
55
55
56 $ hg branch .a.b.c.
56 $ hg branch .a.b.c.
57 marked working directory as branch .a.b.c.
57 marked working directory as branch .a.b.c.
58 $ hg ci -Aqm7
58 $ hg ci -Aqm7
59
59
60 $ hg branch all
60 $ hg branch all
61 marked working directory as branch all
61 marked working directory as branch all
62 $ hg ci --close-branch -Aqm8
62 $ hg ci --close-branch -Aqm8
63 abort: can only close branch heads
63 abort: can only close branch heads
64 [255]
64 [255]
65
65
66 $ hg co 4
66 $ hg co 4
67 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
67 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
68 $ hg branch é
68 $ hg branch é
69 marked working directory as branch é
69 marked working directory as branch é
70 $ hg ci -Aqm9
70 $ hg ci -Aqm9
71
71
72 $ hg tag -r6 1.0
72 $ hg tag -r6 1.0
73
73
74 $ hg clone --quiet -U -r 7 . ../remote1
74 $ hg clone --quiet -U -r 7 . ../remote1
75 $ hg clone --quiet -U -r 8 . ../remote2
75 $ hg clone --quiet -U -r 8 . ../remote2
76 $ echo "[paths]" >> .hg/hgrc
76 $ echo "[paths]" >> .hg/hgrc
77 $ echo "default = ../remote1" >> .hg/hgrc
77 $ echo "default = ../remote1" >> .hg/hgrc
78
78
79 names that should work without quoting
79 names that should work without quoting
80
80
81 $ try a
81 $ try a
82 ('symbol', 'a')
82 ('symbol', 'a')
83 0
83 0
84 $ try b-a
84 $ try b-a
85 ('minus', ('symbol', 'b'), ('symbol', 'a'))
85 ('minus', ('symbol', 'b'), ('symbol', 'a'))
86 1
86 1
87 $ try _a_b_c_
87 $ try _a_b_c_
88 ('symbol', '_a_b_c_')
88 ('symbol', '_a_b_c_')
89 6
89 6
90 $ try _a_b_c_-a
90 $ try _a_b_c_-a
91 ('minus', ('symbol', '_a_b_c_'), ('symbol', 'a'))
91 ('minus', ('symbol', '_a_b_c_'), ('symbol', 'a'))
92 6
92 6
93 $ try .a.b.c.
93 $ try .a.b.c.
94 ('symbol', '.a.b.c.')
94 ('symbol', '.a.b.c.')
95 7
95 7
96 $ try .a.b.c.-a
96 $ try .a.b.c.-a
97 ('minus', ('symbol', '.a.b.c.'), ('symbol', 'a'))
97 ('minus', ('symbol', '.a.b.c.'), ('symbol', 'a'))
98 7
98 7
99 $ try -- '-a-b-c-' # complains
99 $ try -- '-a-b-c-' # complains
100 hg: parse error at 7: not a prefix: end
100 hg: parse error at 7: not a prefix: end
101 [255]
101 [255]
102 $ log -a-b-c- # succeeds with fallback
102 $ log -a-b-c- # succeeds with fallback
103 4
103 4
104 $ try -- -a-b-c--a # complains
104 $ try -- -a-b-c--a # complains
105 ('minus', ('minus', ('minus', ('negate', ('symbol', 'a')), ('symbol', 'b')), ('symbol', 'c')), ('negate', ('symbol', 'a')))
105 ('minus', ('minus', ('minus', ('negate', ('symbol', 'a')), ('symbol', 'b')), ('symbol', 'c')), ('negate', ('symbol', 'a')))
106 abort: unknown revision '-a'!
106 abort: unknown revision '-a'!
107 [255]
107 [255]
108 $ try é
108 $ try é
109 ('symbol', '\xc3\xa9')
109 ('symbol', '\xc3\xa9')
110 9
110 9
111
111
112 quoting needed
112 quoting needed
113
113
114 $ try '"-a-b-c-"-a'
114 $ try '"-a-b-c-"-a'
115 ('minus', ('string', '-a-b-c-'), ('symbol', 'a'))
115 ('minus', ('string', '-a-b-c-'), ('symbol', 'a'))
116 4
116 4
117
117
118 $ log '1 or 2'
118 $ log '1 or 2'
119 1
119 1
120 2
120 2
121 $ log '1|2'
121 $ log '1|2'
122 1
122 1
123 2
123 2
124 $ log '1 and 2'
124 $ log '1 and 2'
125 $ log '1&2'
125 $ log '1&2'
126 $ try '1&2|3' # precedence - and is higher
126 $ try '1&2|3' # precedence - and is higher
127 ('or', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
127 ('or', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
128 3
128 3
129 $ try '1|2&3'
129 $ try '1|2&3'
130 ('or', ('symbol', '1'), ('and', ('symbol', '2'), ('symbol', '3')))
130 ('or', ('symbol', '1'), ('and', ('symbol', '2'), ('symbol', '3')))
131 1
131 1
132 $ try '1&2&3' # associativity
132 $ try '1&2&3' # associativity
133 ('and', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
133 ('and', ('and', ('symbol', '1'), ('symbol', '2')), ('symbol', '3'))
134 $ try '1|(2|3)'
134 $ try '1|(2|3)'
135 ('or', ('symbol', '1'), ('group', ('or', ('symbol', '2'), ('symbol', '3'))))
135 ('or', ('symbol', '1'), ('group', ('or', ('symbol', '2'), ('symbol', '3'))))
136 1
136 1
137 2
137 2
138 3
138 3
139 $ log '1.0' # tag
139 $ log '1.0' # tag
140 6
140 6
141 $ log 'a' # branch
141 $ log 'a' # branch
142 0
142 0
143 $ log '2785f51ee'
143 $ log '2785f51ee'
144 0
144 0
145 $ log 'date(2005)'
145 $ log 'date(2005)'
146 4
146 4
147 $ log 'date(this is a test)'
147 $ log 'date(this is a test)'
148 hg: parse error at 10: unexpected token: symbol
148 hg: parse error at 10: unexpected token: symbol
149 [255]
149 [255]
150 $ log 'date()'
150 $ log 'date()'
151 hg: parse error: date requires a string
151 hg: parse error: date requires a string
152 [255]
152 [255]
153 $ log 'date'
153 $ log 'date'
154 hg: parse error: can't use date here
154 hg: parse error: can't use date here
155 [255]
155 [255]
156 $ log 'date('
156 $ log 'date('
157 hg: parse error at 5: not a prefix: end
157 hg: parse error at 5: not a prefix: end
158 [255]
158 [255]
159 $ log 'date(tip)'
159 $ log 'date(tip)'
160 abort: invalid date: 'tip'
160 abort: invalid date: 'tip'
161 [255]
161 [255]
162 $ log '"date"'
162 $ log '"date"'
163 abort: unknown revision 'date'!
163 abort: unknown revision 'date'!
164 [255]
164 [255]
165 $ log 'date(2005) and 1::'
165 $ log 'date(2005) and 1::'
166 4
166 4
167
167
168 $ log 'ancestor(1)'
168 $ log 'ancestor(1)'
169 hg: parse error: ancestor requires two arguments
169 hg: parse error: ancestor requires two arguments
170 [255]
170 [255]
171 $ log 'ancestor(4,5)'
171 $ log 'ancestor(4,5)'
172 1
172 1
173 $ log 'ancestor(4,5) and 4'
173 $ log 'ancestor(4,5) and 4'
174 $ log 'ancestors(5)'
174 $ log 'ancestors(5)'
175 0
175 0
176 1
176 1
177 3
177 3
178 5
178 5
179 $ log 'author(bob)'
179 $ log 'author(bob)'
180 2
180 2
181 $ log 'branch(é)'
181 $ log 'branch(é)'
182 8
182 8
183 9
183 9
184 $ log 'children(ancestor(4,5))'
184 $ log 'children(ancestor(4,5))'
185 2
185 2
186 3
186 3
187 $ log 'closed()'
187 $ log 'closed()'
188 $ log 'contains(a)'
188 $ log 'contains(a)'
189 0
189 0
190 1
190 1
191 3
191 3
192 5
192 5
193 $ log 'descendants(2 or 3)'
193 $ log 'descendants(2 or 3)'
194 2
194 2
195 3
195 3
196 4
196 4
197 5
197 5
198 6
198 6
199 7
199 7
200 8
200 8
201 9
201 9
202 $ log 'file(b)'
202 $ log 'file(b)'
203 1
203 1
204 4
204 4
205 $ log 'follow()'
205 $ log 'follow()'
206 0
206 0
207 1
207 1
208 2
208 2
209 4
209 4
210 8
210 8
211 9
211 9
212 $ log 'grep("issue\d+")'
212 $ log 'grep("issue\d+")'
213 6
213 6
214 $ try 'grep("(")' # invalid regular expression
214 $ try 'grep("(")' # invalid regular expression
215 ('func', ('symbol', 'grep'), ('string', '('))
215 ('func', ('symbol', 'grep'), ('string', '('))
216 hg: parse error: invalid match pattern: unbalanced parenthesis
216 hg: parse error: invalid match pattern: unbalanced parenthesis
217 [255]
217 [255]
218 $ try 'grep("\bissue\d+")'
218 $ try 'grep("\bissue\d+")'
219 ('func', ('symbol', 'grep'), ('string', '\x08issue\\d+'))
219 ('func', ('symbol', 'grep'), ('string', '\x08issue\\d+'))
220 $ try 'grep(r"\bissue\d+")'
220 $ try 'grep(r"\bissue\d+")'
221 ('func', ('symbol', 'grep'), ('string', '\\bissue\\d+'))
221 ('func', ('symbol', 'grep'), ('string', '\\bissue\\d+'))
222 6
222 6
223 $ try 'grep(r"\")'
223 $ try 'grep(r"\")'
224 hg: parse error at 7: unterminated string
224 hg: parse error at 7: unterminated string
225 [255]
225 [255]
226 $ log 'head()'
226 $ log 'head()'
227 0
227 0
228 1
228 1
229 2
229 2
230 3
230 3
231 4
231 4
232 5
232 5
233 6
233 6
234 7
234 7
235 9
235 9
236 $ log 'heads(6::)'
236 $ log 'heads(6::)'
237 7
237 7
238 $ log 'keyword(issue)'
238 $ log 'keyword(issue)'
239 6
239 6
240 $ log 'limit(head(), 1)'
240 $ log 'limit(head(), 1)'
241 0
241 0
242 $ log 'max(contains(a))'
242 $ log 'max(contains(a))'
243 5
243 5
244 $ log 'min(contains(a))'
244 $ log 'min(contains(a))'
245 0
245 0
246 $ log 'merge()'
246 $ log 'merge()'
247 6
247 6
248 $ log 'modifies(b)'
248 $ log 'modifies(b)'
249 4
249 4
250 $ log 'id(5)'
250 $ log 'id(5)'
251 2
251 2
252 $ log 'outgoing()'
252 $ log 'outgoing()'
253 8
253 8
254 9
254 9
255 $ log 'outgoing("../remote1")'
255 $ log 'outgoing("../remote1")'
256 8
256 8
257 9
257 9
258 $ log 'outgoing("../remote2")'
258 $ log 'outgoing("../remote2")'
259 3
259 3
260 5
260 5
261 6
261 6
262 7
262 7
263 9
263 9
264 $ log 'p1(merge())'
264 $ log 'p1(merge())'
265 5
265 5
266 $ log 'p2(merge())'
266 $ log 'p2(merge())'
267 4
267 4
268 $ log 'parents(merge())'
268 $ log 'parents(merge())'
269 4
269 4
270 5
270 5
271 $ log 'removes(a)'
271 $ log 'removes(a)'
272 2
272 2
273 6
273 6
274 $ log 'roots(all())'
274 $ log 'roots(all())'
275 0
275 0
276 $ log 'reverse(2 or 3 or 4 or 5)'
276 $ log 'reverse(2 or 3 or 4 or 5)'
277 5
277 5
278 4
278 4
279 3
279 3
280 2
280 2
281 $ log 'rev(5)'
281 $ log 'rev(5)'
282 5
282 5
283 $ log 'sort(limit(reverse(all()), 3))'
283 $ log 'sort(limit(reverse(all()), 3))'
284 7
284 7
285 8
285 8
286 9
286 9
287 $ log 'sort(2 or 3 or 4 or 5, date)'
287 $ log 'sort(2 or 3 or 4 or 5, date)'
288 2
288 2
289 3
289 3
290 5
290 5
291 4
291 4
292 $ log 'tagged()'
292 $ log 'tagged()'
293 6
293 6
294 $ log 'tag()'
294 $ log 'tag()'
295 6
295 6
296 $ log 'tag(1.0)'
296 $ log 'tag(1.0)'
297 6
297 6
298 $ log 'tag(tip)'
298 $ log 'tag(tip)'
299 9
299 9
300 $ log 'user(bob)'
300 $ log 'user(bob)'
301 2
301 2
302
302
303 $ log '4::8'
303 $ log '4::8'
304 4
304 4
305 8
305 8
306 $ log '4:8'
306 $ log '4:8'
307 4
307 4
308 5
308 5
309 6
309 6
310 7
310 7
311 8
311 8
312
312
313 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
313 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
314 4
314 4
315 2
315 2
316 5
316 5
317
317
318 $ log 'not 0 and 0:2'
318 $ log 'not 0 and 0:2'
319 1
319 1
320 2
320 2
321 $ log 'not 1 and 0:2'
321 $ log 'not 1 and 0:2'
322 0
322 0
323 2
323 2
324 $ log 'not 2 and 0:2'
324 $ log 'not 2 and 0:2'
325 0
325 0
326 1
326 1
327 $ log '(1 and 2)::'
327 $ log '(1 and 2)::'
328 $ log '(1 and 2):'
328 $ log '(1 and 2):'
329 $ log '(1 and 2):3'
329 $ log '(1 and 2):3'
330 $ log 'sort(head(), -rev)'
330 $ log 'sort(head(), -rev)'
331 9
331 9
332 7
332 7
333 6
333 6
334 5
334 5
335 4
335 4
336 3
336 3
337 2
337 2
338 1
338 1
339 0
339 0
340 $ log '4::8 - 8'
340 $ log '4::8 - 8'
341 4
341 4
342
343 issue2437
344
345 $ log '3 and p1(5)'
346 3
347 $ log '4 and p2(6)'
348 4
349 $ log '1 and parents(:2)'
350 1
351 $ log '2 and children(1:)'
352 2
353 $ log 'roots(all()) or roots(all())'
354 0
355 $ log 'heads(branch(é)) or heads(branch(é))'
356 9
357 $ log 'ancestors(8) and (heads(branch("-a-b-c-")) or heads(branch(é)))'
358 4
General Comments 0
You need to be logged in to leave comments. Login now