##// END OF EJS Templates
revset: support raw string literals...
Brodie Rao -
r12408:78a97859 default
parent child Browse files
Show More
@@ -1,173 +1,177
1 Mercurial supports a functional language for selecting a set of
1 Mercurial supports a functional language for selecting a set of
2 revisions.
2 revisions.
3
3
4 The language supports a number of predicates which are joined by infix
4 The language supports a number of predicates which are joined by infix
5 operators. Parenthesis can be used for grouping.
5 operators. Parenthesis can be used for grouping.
6
6
7 Identifiers such as branch names must be quoted with single or double
7 Identifiers such as branch names must be quoted with single or double
8 quotes if they contain characters outside of
8 quotes if they contain characters outside of
9 ``[._a-zA-Z0-9\x80-\xff]`` or if they match one of the predefined
9 ``[._a-zA-Z0-9\x80-\xff]`` or if they match one of the predefined
10 predicates. Special characters can be used in quoted identifiers by
10 predicates.
11 escaping them, e.g., ``\n`` is interpreted as a newline.
11
12 Special characters can be used in quoted identifiers by escaping them,
13 e.g., ``\n`` is interpreted as a newline. To prevent them from being
14 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
12
15
13 There is a single prefix operator:
16 There is a single prefix operator:
14
17
15 ``not x``
18 ``not x``
16 Changesets not in x. Short form is ``! x``.
19 Changesets not in x. Short form is ``! x``.
17
20
18 These are the supported infix operators:
21 These are the supported infix operators:
19
22
20 ``x::y``
23 ``x::y``
21 A DAG range, meaning all changesets that are descendants of x and
24 A DAG range, meaning all changesets that are descendants of x and
22 ancestors of y, including x and y themselves. If the first endpoint
25 ancestors of y, including x and y themselves. If the first endpoint
23 is left out, this is equivalent to ``ancestors(y)``, if the second
26 is left out, this is equivalent to ``ancestors(y)``, if the second
24 is left out it is equivalent to ``descendants(x)``.
27 is left out it is equivalent to ``descendants(x)``.
25
28
26 An alternative syntax is ``x..y``.
29 An alternative syntax is ``x..y``.
27
30
28 ``x:y``
31 ``x:y``
29 All changesets with revision numbers between x and y, both
32 All changesets with revision numbers between x and y, both
30 inclusive. Either endpoint can be left out, they default to 0 and
33 inclusive. Either endpoint can be left out, they default to 0 and
31 tip.
34 tip.
32
35
33 ``x and y``
36 ``x and y``
34 The intersection of changesets in x and y. Short form is ``x & y``.
37 The intersection of changesets in x and y. Short form is ``x & y``.
35
38
36 ``x or y``
39 ``x or y``
37 The union of changesets in x and y. There are two alternative short
40 The union of changesets in x and y. There are two alternative short
38 forms: ``x | y`` and ``x + y``.
41 forms: ``x | y`` and ``x + y``.
39
42
40 ``x - y``
43 ``x - y``
41 Changesets in x but not in y.
44 Changesets in x but not in y.
42
45
43 The following predicates are supported:
46 The following predicates are supported:
44
47
45 ``adds(pattern)``
48 ``adds(pattern)``
46 Changesets that add a file matching pattern.
49 Changesets that add a file matching pattern.
47
50
48 ``all()``
51 ``all()``
49 All changesets, the same as ``0:tip``.
52 All changesets, the same as ``0:tip``.
50
53
51 ``ancestor(single, single)``
54 ``ancestor(single, single)``
52 Greatest common ancestor of the two changesets.
55 Greatest common ancestor of the two changesets.
53
56
54 ``ancestors(set)``
57 ``ancestors(set)``
55 Changesets that are ancestors of a changeset in set.
58 Changesets that are ancestors of a changeset in set.
56
59
57 ``author(string)``
60 ``author(string)``
58 Alias for ``user(string)``.
61 Alias for ``user(string)``.
59
62
60 ``branch(set)``
63 ``branch(set)``
61 All changesets belonging to the branches of changesets in set.
64 All changesets belonging to the branches of changesets in set.
62
65
63 ``children(set)``
66 ``children(set)``
64 Child changesets of changesets in set.
67 Child changesets of changesets in set.
65
68
66 ``closed()``
69 ``closed()``
67 Changeset is closed.
70 Changeset is closed.
68
71
69 ``contains(pattern)``
72 ``contains(pattern)``
70 Revision contains pattern.
73 Revision contains pattern.
71
74
72 ``date(interval)``
75 ``date(interval)``
73 Changesets within the interval, see :hg:`help dates`.
76 Changesets within the interval, see :hg:`help dates`.
74
77
75 ``descendants(set)``
78 ``descendants(set)``
76 Changesets which are descendants of changesets in set.
79 Changesets which are descendants of changesets in set.
77
80
78 ``file(pattern)``
81 ``file(pattern)``
79 Changesets affecting files matched by pattern.
82 Changesets affecting files matched by pattern.
80
83
81 ``follow()``
84 ``follow()``
82 An alias for ``::.`` (ancestors of the working copy's first parent).
85 An alias for ``::.`` (ancestors of the working copy's first parent).
83
86
84 ``grep(regex)``
87 ``grep(regex)``
85 Like ``keyword(string)`` but accepts a regex.
88 Like ``keyword(string)`` but accepts a regex. Use ``grep(r'...')``
89 to ensure special escape characters are handled correctly.
86
90
87 ``head()``
91 ``head()``
88 Changeset is a head.
92 Changeset is a head.
89
93
90 ``heads(set)``
94 ``heads(set)``
91 Members of set with no children in set.
95 Members of set with no children in set.
92
96
93 ``keyword(string)``
97 ``keyword(string)``
94 Search commit message, user name, and names of changed files for
98 Search commit message, user name, and names of changed files for
95 string.
99 string.
96
100
97 ``limit(set, n)``
101 ``limit(set, n)``
98 First n members of set.
102 First n members of set.
99
103
100 ``max(set)``
104 ``max(set)``
101 Changeset with highest revision number in set.
105 Changeset with highest revision number in set.
102
106
103 ``min(set)``
107 ``min(set)``
104 Changeset with lowest revision number in set.
108 Changeset with lowest revision number in set.
105
109
106 ``merge()``
110 ``merge()``
107 Changeset is a merge changeset.
111 Changeset is a merge changeset.
108
112
109 ``modifies(pattern)``
113 ``modifies(pattern)``
110 Changesets modifying files matched by pattern.
114 Changesets modifying files matched by pattern.
111
115
112 ``outgoing([path])``
116 ``outgoing([path])``
113 Changesets not found in the specified destination repository, or the
117 Changesets not found in the specified destination repository, or the
114 default push location.
118 default push location.
115
119
116 ``p1(set)``
120 ``p1(set)``
117 First parent of changesets in set.
121 First parent of changesets in set.
118
122
119 ``p2(set)``
123 ``p2(set)``
120 Second parent of changesets in set.
124 Second parent of changesets in set.
121
125
122 ``parents(set)``
126 ``parents(set)``
123 The set of all parents for all changesets in set.
127 The set of all parents for all changesets in set.
124
128
125 ``present(set)``
129 ``present(set)``
126 An empty set, if any revision in set isn't found; otherwise,
130 An empty set, if any revision in set isn't found; otherwise,
127 all revisions in set.
131 all revisions in set.
128
132
129 ``removes(pattern)``
133 ``removes(pattern)``
130 Changesets which remove files matching pattern.
134 Changesets which remove files matching pattern.
131
135
132 ``reverse(set)``
136 ``reverse(set)``
133 Reverse order of set.
137 Reverse order of set.
134
138
135 ``roots(set)``
139 ``roots(set)``
136 Changesets with no parent changeset in set.
140 Changesets with no parent changeset in set.
137
141
138 ``sort(set[, [-]key...])``
142 ``sort(set[, [-]key...])``
139 Sort set by keys. The default sort order is ascending, specify a key
143 Sort set by keys. The default sort order is ascending, specify a key
140 as ``-key`` to sort in descending order.
144 as ``-key`` to sort in descending order.
141
145
142 The keys can be:
146 The keys can be:
143
147
144 - ``rev`` for the revision number,
148 - ``rev`` for the revision number,
145 - ``branch`` for the branch name,
149 - ``branch`` for the branch name,
146 - ``desc`` for the commit message (description),
150 - ``desc`` for the commit message (description),
147 - ``user`` for user name (``author`` can be used as an alias),
151 - ``user`` for user name (``author`` can be used as an alias),
148 - ``date`` for the commit date
152 - ``date`` for the commit date
149
153
150 ``tagged()``
154 ``tagged()``
151 Changeset is tagged.
155 Changeset is tagged.
152
156
153 ``user(string)``
157 ``user(string)``
154 User name is string.
158 User name is string.
155
159
156 Command line equivalents for :hg:`log`::
160 Command line equivalents for :hg:`log`::
157
161
158 -f -> ::.
162 -f -> ::.
159 -d x -> date(x)
163 -d x -> date(x)
160 -k x -> keyword(x)
164 -k x -> keyword(x)
161 -m -> merge()
165 -m -> merge()
162 -u x -> user(x)
166 -u x -> user(x)
163 -b x -> branch(x)
167 -b x -> branch(x)
164 -P x -> !::x
168 -P x -> !::x
165 -l x -> limit(expr, x)
169 -l x -> limit(expr, x)
166
170
167 Some sample queries::
171 Some sample queries::
168
172
169 hg log -r 'branch(default)'
173 hg log -r 'branch(default)'
170 hg log -r 'branch(default) and 1.5:: and not merge()'
174 hg log -r 'branch(default) and 1.5:: and not merge()'
171 hg log -r '1.3::1.5 and keyword(bug) and file("hgext/*")'
175 hg log -r '1.3::1.5 and keyword(bug) and file("hgext/*")'
172 hg log -r 'sort(date("May 2008"), user)'
176 hg log -r 'sort(date("May 2008"), user)'
173 hg log -r '(keyword(bug) or keyword(issue)) and not ancestors(tagged())'
177 hg log -r '(keyword(bug) or keyword(issue)) and not ancestors(tagged())'
@@ -1,591 +1,598
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 "-": (19, ("negate", 19), ("minus", 19)),
15 "-": (19, ("negate", 19), ("minus", 19)),
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 '"\'': # handle quoted strings
51 elif (c in '"\'' or c == 'r' and
52 program[pos:pos + 2] in ("r'", 'r"')): # handle quoted strings
53 if c == 'r':
54 pos += 1
55 c = program[pos]
56 decode = lambda x: x
57 else:
58 decode = lambda x: x.decode('string-escape')
52 pos += 1
59 pos += 1
53 s = pos
60 s = pos
54 while pos < l: # find closing quote
61 while pos < l: # find closing quote
55 d = program[pos]
62 d = program[pos]
56 if d == '\\': # skip over escaped characters
63 if d == '\\': # skip over escaped characters
57 pos += 2
64 pos += 2
58 continue
65 continue
59 if d == c:
66 if d == c:
60 yield ('string', program[s:pos].decode('string-escape'), s)
67 yield ('string', decode(program[s:pos]), s)
61 break
68 break
62 pos += 1
69 pos += 1
63 else:
70 else:
64 raise error.ParseError(_("unterminated string"), s)
71 raise error.ParseError(_("unterminated string"), s)
65 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
66 s = pos
73 s = pos
67 pos += 1
74 pos += 1
68 while pos < l: # find end of symbol
75 while pos < l: # find end of symbol
69 d = program[pos]
76 d = program[pos]
70 if not (d.isalnum() or d in "._" or ord(d) > 127):
77 if not (d.isalnum() or d in "._" or ord(d) > 127):
71 break
78 break
72 if d == '.' and program[pos - 1] == '.': # special case for ..
79 if d == '.' and program[pos - 1] == '.': # special case for ..
73 pos -= 1
80 pos -= 1
74 break
81 break
75 pos += 1
82 pos += 1
76 sym = program[s:pos]
83 sym = program[s:pos]
77 if sym in keywords: # operator keywords
84 if sym in keywords: # operator keywords
78 yield (sym, None, s)
85 yield (sym, None, s)
79 else:
86 else:
80 yield ('symbol', sym, s)
87 yield ('symbol', sym, s)
81 pos -= 1
88 pos -= 1
82 else:
89 else:
83 raise error.ParseError(_("syntax error"), pos)
90 raise error.ParseError(_("syntax error"), pos)
84 pos += 1
91 pos += 1
85 yield ('end', None, pos)
92 yield ('end', None, pos)
86
93
87 # helpers
94 # helpers
88
95
89 def getstring(x, err):
96 def getstring(x, err):
90 if x and (x[0] == 'string' or x[0] == 'symbol'):
97 if x and (x[0] == 'string' or x[0] == 'symbol'):
91 return x[1]
98 return x[1]
92 raise error.ParseError(err)
99 raise error.ParseError(err)
93
100
94 def getlist(x):
101 def getlist(x):
95 if not x:
102 if not x:
96 return []
103 return []
97 if x[0] == 'list':
104 if x[0] == 'list':
98 return getlist(x[1]) + [x[2]]
105 return getlist(x[1]) + [x[2]]
99 return [x]
106 return [x]
100
107
101 def getargs(x, min, max, err):
108 def getargs(x, min, max, err):
102 l = getlist(x)
109 l = getlist(x)
103 if len(l) < min or len(l) > max:
110 if len(l) < min or len(l) > max:
104 raise error.ParseError(err)
111 raise error.ParseError(err)
105 return l
112 return l
106
113
107 def getset(repo, subset, x):
114 def getset(repo, subset, x):
108 if not x:
115 if not x:
109 raise error.ParseError(_("missing argument"))
116 raise error.ParseError(_("missing argument"))
110 return methods[x[0]](repo, subset, *x[1:])
117 return methods[x[0]](repo, subset, *x[1:])
111
118
112 # operator methods
119 # operator methods
113
120
114 def stringset(repo, subset, x):
121 def stringset(repo, subset, x):
115 x = repo[x].rev()
122 x = repo[x].rev()
116 if x == -1 and len(subset) == len(repo):
123 if x == -1 and len(subset) == len(repo):
117 return [-1]
124 return [-1]
118 if x in subset:
125 if x in subset:
119 return [x]
126 return [x]
120 return []
127 return []
121
128
122 def symbolset(repo, subset, x):
129 def symbolset(repo, subset, x):
123 if x in symbols:
130 if x in symbols:
124 raise error.ParseError(_("can't use %s here") % x)
131 raise error.ParseError(_("can't use %s here") % x)
125 return stringset(repo, subset, x)
132 return stringset(repo, subset, x)
126
133
127 def rangeset(repo, subset, x, y):
134 def rangeset(repo, subset, x, y):
128 m = getset(repo, subset, x)
135 m = getset(repo, subset, x)
129 if not m:
136 if not m:
130 m = getset(repo, range(len(repo)), x)
137 m = getset(repo, range(len(repo)), x)
131
138
132 n = getset(repo, subset, y)
139 n = getset(repo, subset, y)
133 if not n:
140 if not n:
134 n = getset(repo, range(len(repo)), y)
141 n = getset(repo, range(len(repo)), y)
135
142
136 if not m or not n:
143 if not m or not n:
137 return []
144 return []
138 m, n = m[0], n[-1]
145 m, n = m[0], n[-1]
139
146
140 if m < n:
147 if m < n:
141 r = range(m, n + 1)
148 r = range(m, n + 1)
142 else:
149 else:
143 r = range(m, n - 1, -1)
150 r = range(m, n - 1, -1)
144 s = set(subset)
151 s = set(subset)
145 return [x for x in r if x in s]
152 return [x for x in r if x in s]
146
153
147 def andset(repo, subset, x, y):
154 def andset(repo, subset, x, y):
148 return getset(repo, getset(repo, subset, x), y)
155 return getset(repo, getset(repo, subset, x), y)
149
156
150 def orset(repo, subset, x, y):
157 def orset(repo, subset, x, y):
151 s = set(getset(repo, subset, x))
158 s = set(getset(repo, subset, x))
152 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))
153 return [r for r in subset if r in s]
160 return [r for r in subset if r in s]
154
161
155 def notset(repo, subset, x):
162 def notset(repo, subset, x):
156 s = set(getset(repo, subset, x))
163 s = set(getset(repo, subset, x))
157 return [r for r in subset if r not in s]
164 return [r for r in subset if r not in s]
158
165
159 def listset(repo, subset, a, b):
166 def listset(repo, subset, a, b):
160 raise error.ParseError(_("can't use a list in this context"))
167 raise error.ParseError(_("can't use a list in this context"))
161
168
162 def func(repo, subset, a, b):
169 def func(repo, subset, a, b):
163 if a[0] == 'symbol' and a[1] in symbols:
170 if a[0] == 'symbol' and a[1] in symbols:
164 return symbols[a[1]](repo, subset, b)
171 return symbols[a[1]](repo, subset, b)
165 raise error.ParseError(_("not a function: %s") % a[1])
172 raise error.ParseError(_("not a function: %s") % a[1])
166
173
167 # functions
174 # functions
168
175
169 def p1(repo, subset, x):
176 def p1(repo, subset, x):
170 ps = set()
177 ps = set()
171 cl = repo.changelog
178 cl = repo.changelog
172 for r in getset(repo, subset, x):
179 for r in getset(repo, subset, x):
173 ps.add(cl.parentrevs(r)[0])
180 ps.add(cl.parentrevs(r)[0])
174 return [r for r in subset if r in ps]
181 return [r for r in subset if r in ps]
175
182
176 def p2(repo, subset, x):
183 def p2(repo, subset, x):
177 ps = set()
184 ps = set()
178 cl = repo.changelog
185 cl = repo.changelog
179 for r in getset(repo, subset, x):
186 for r in getset(repo, subset, x):
180 ps.add(cl.parentrevs(r)[1])
187 ps.add(cl.parentrevs(r)[1])
181 return [r for r in subset if r in ps]
188 return [r for r in subset if r in ps]
182
189
183 def parents(repo, subset, x):
190 def parents(repo, subset, x):
184 ps = set()
191 ps = set()
185 cl = repo.changelog
192 cl = repo.changelog
186 for r in getset(repo, subset, x):
193 for r in getset(repo, subset, x):
187 ps.update(cl.parentrevs(r))
194 ps.update(cl.parentrevs(r))
188 return [r for r in subset if r in ps]
195 return [r for r in subset if r in ps]
189
196
190 def maxrev(repo, subset, x):
197 def maxrev(repo, subset, x):
191 s = getset(repo, subset, x)
198 s = getset(repo, subset, x)
192 if s:
199 if s:
193 m = max(s)
200 m = max(s)
194 if m in subset:
201 if m in subset:
195 return [m]
202 return [m]
196 return []
203 return []
197
204
198 def minrev(repo, subset, x):
205 def minrev(repo, subset, x):
199 s = getset(repo, subset, x)
206 s = getset(repo, subset, x)
200 if s:
207 if s:
201 m = min(s)
208 m = min(s)
202 if m in subset:
209 if m in subset:
203 return [m]
210 return [m]
204 return []
211 return []
205
212
206 def limit(repo, subset, x):
213 def limit(repo, subset, x):
207 l = getargs(x, 2, 2, _("limit wants two arguments"))
214 l = getargs(x, 2, 2, _("limit wants two arguments"))
208 try:
215 try:
209 lim = int(getstring(l[1], _("limit wants a number")))
216 lim = int(getstring(l[1], _("limit wants a number")))
210 except ValueError:
217 except ValueError:
211 raise error.ParseError(_("limit expects a number"))
218 raise error.ParseError(_("limit expects a number"))
212 return getset(repo, subset, l[0])[:lim]
219 return getset(repo, subset, l[0])[:lim]
213
220
214 def children(repo, subset, x):
221 def children(repo, subset, x):
215 cs = set()
222 cs = set()
216 cl = repo.changelog
223 cl = repo.changelog
217 s = set(getset(repo, subset, x))
224 s = set(getset(repo, subset, x))
218 for r in xrange(0, len(repo)):
225 for r in xrange(0, len(repo)):
219 for p in cl.parentrevs(r):
226 for p in cl.parentrevs(r):
220 if p in s:
227 if p in s:
221 cs.add(r)
228 cs.add(r)
222 return [r for r in subset if r in cs]
229 return [r for r in subset if r in cs]
223
230
224 def branch(repo, subset, x):
231 def branch(repo, subset, x):
225 s = getset(repo, range(len(repo)), x)
232 s = getset(repo, range(len(repo)), x)
226 b = set()
233 b = set()
227 for r in s:
234 for r in s:
228 b.add(repo[r].branch())
235 b.add(repo[r].branch())
229 s = set(s)
236 s = set(s)
230 return [r for r in subset if r in s or repo[r].branch() in b]
237 return [r for r in subset if r in s or repo[r].branch() in b]
231
238
232 def ancestor(repo, subset, x):
239 def ancestor(repo, subset, x):
233 l = getargs(x, 2, 2, _("ancestor wants two arguments"))
240 l = getargs(x, 2, 2, _("ancestor wants two arguments"))
234 r = range(len(repo))
241 r = range(len(repo))
235 a = getset(repo, r, l[0])
242 a = getset(repo, r, l[0])
236 b = getset(repo, r, l[1])
243 b = getset(repo, r, l[1])
237 if len(a) != 1 or len(b) != 1:
244 if len(a) != 1 or len(b) != 1:
238 raise error.ParseError(_("ancestor arguments must be single revisions"))
245 raise error.ParseError(_("ancestor arguments must be single revisions"))
239 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
246 an = [repo[a[0]].ancestor(repo[b[0]]).rev()]
240
247
241 return [r for r in an if r in subset]
248 return [r for r in an if r in subset]
242
249
243 def ancestors(repo, subset, x):
250 def ancestors(repo, subset, x):
244 args = getset(repo, range(len(repo)), x)
251 args = getset(repo, range(len(repo)), x)
245 if not args:
252 if not args:
246 return []
253 return []
247 s = set(repo.changelog.ancestors(*args)) | set(args)
254 s = set(repo.changelog.ancestors(*args)) | set(args)
248 return [r for r in subset if r in s]
255 return [r for r in subset if r in s]
249
256
250 def descendants(repo, subset, x):
257 def descendants(repo, subset, x):
251 args = getset(repo, range(len(repo)), x)
258 args = getset(repo, range(len(repo)), x)
252 if not args:
259 if not args:
253 return []
260 return []
254 s = set(repo.changelog.descendants(*args)) | set(args)
261 s = set(repo.changelog.descendants(*args)) | set(args)
255 return [r for r in subset if r in s]
262 return [r for r in subset if r in s]
256
263
257 def follow(repo, subset, x):
264 def follow(repo, subset, x):
258 getargs(x, 0, 0, _("follow takes no arguments"))
265 getargs(x, 0, 0, _("follow takes no arguments"))
259 p = repo['.'].rev()
266 p = repo['.'].rev()
260 s = set(repo.changelog.ancestors(p)) | set([p])
267 s = set(repo.changelog.ancestors(p)) | set([p])
261 return [r for r in subset if r in s]
268 return [r for r in subset if r in s]
262
269
263 def date(repo, subset, x):
270 def date(repo, subset, x):
264 ds = getstring(x, _("date wants a string"))
271 ds = getstring(x, _("date wants a string"))
265 dm = util.matchdate(ds)
272 dm = util.matchdate(ds)
266 return [r for r in subset if dm(repo[r].date()[0])]
273 return [r for r in subset if dm(repo[r].date()[0])]
267
274
268 def keyword(repo, subset, x):
275 def keyword(repo, subset, x):
269 kw = getstring(x, _("keyword wants a string")).lower()
276 kw = getstring(x, _("keyword wants a string")).lower()
270 l = []
277 l = []
271 for r in subset:
278 for r in subset:
272 c = repo[r]
279 c = repo[r]
273 t = " ".join(c.files() + [c.user(), c.description()])
280 t = " ".join(c.files() + [c.user(), c.description()])
274 if kw in t.lower():
281 if kw in t.lower():
275 l.append(r)
282 l.append(r)
276 return l
283 return l
277
284
278 def grep(repo, subset, x):
285 def grep(repo, subset, x):
279 try:
286 try:
280 gr = re.compile(getstring(x, _("grep wants a string")))
287 gr = re.compile(getstring(x, _("grep wants a string")))
281 except re.error, e:
288 except re.error, e:
282 raise error.ParseError(_('invalid match pattern: %s') % e)
289 raise error.ParseError(_('invalid match pattern: %s') % e)
283 l = []
290 l = []
284 for r in subset:
291 for r in subset:
285 c = repo[r]
292 c = repo[r]
286 for e in c.files() + [c.user(), c.description()]:
293 for e in c.files() + [c.user(), c.description()]:
287 if gr.search(e):
294 if gr.search(e):
288 l.append(r)
295 l.append(r)
289 continue
296 continue
290 return l
297 return l
291
298
292 def author(repo, subset, x):
299 def author(repo, subset, x):
293 n = getstring(x, _("author wants a string")).lower()
300 n = getstring(x, _("author wants a string")).lower()
294 return [r for r in subset if n in repo[r].user().lower()]
301 return [r for r in subset if n in repo[r].user().lower()]
295
302
296 def hasfile(repo, subset, x):
303 def hasfile(repo, subset, x):
297 pat = getstring(x, _("file wants a pattern"))
304 pat = getstring(x, _("file wants a pattern"))
298 m = matchmod.match(repo.root, repo.getcwd(), [pat])
305 m = matchmod.match(repo.root, repo.getcwd(), [pat])
299 s = []
306 s = []
300 for r in subset:
307 for r in subset:
301 for f in repo[r].files():
308 for f in repo[r].files():
302 if m(f):
309 if m(f):
303 s.append(r)
310 s.append(r)
304 continue
311 continue
305 return s
312 return s
306
313
307 def contains(repo, subset, x):
314 def contains(repo, subset, x):
308 pat = getstring(x, _("contains wants a pattern"))
315 pat = getstring(x, _("contains wants a pattern"))
309 m = matchmod.match(repo.root, repo.getcwd(), [pat])
316 m = matchmod.match(repo.root, repo.getcwd(), [pat])
310 s = []
317 s = []
311 if m.files() == [pat]:
318 if m.files() == [pat]:
312 for r in subset:
319 for r in subset:
313 if pat in repo[r]:
320 if pat in repo[r]:
314 s.append(r)
321 s.append(r)
315 continue
322 continue
316 else:
323 else:
317 for r in subset:
324 for r in subset:
318 for f in repo[r].manifest():
325 for f in repo[r].manifest():
319 if m(f):
326 if m(f):
320 s.append(r)
327 s.append(r)
321 continue
328 continue
322 return s
329 return s
323
330
324 def checkstatus(repo, subset, pat, field):
331 def checkstatus(repo, subset, pat, field):
325 m = matchmod.match(repo.root, repo.getcwd(), [pat])
332 m = matchmod.match(repo.root, repo.getcwd(), [pat])
326 s = []
333 s = []
327 fast = (m.files() == [pat])
334 fast = (m.files() == [pat])
328 for r in subset:
335 for r in subset:
329 c = repo[r]
336 c = repo[r]
330 if fast:
337 if fast:
331 if pat not in c.files():
338 if pat not in c.files():
332 continue
339 continue
333 else:
340 else:
334 for f in c.files():
341 for f in c.files():
335 if m(f):
342 if m(f):
336 break
343 break
337 else:
344 else:
338 continue
345 continue
339 files = repo.status(c.p1().node(), c.node())[field]
346 files = repo.status(c.p1().node(), c.node())[field]
340 if fast:
347 if fast:
341 if pat in files:
348 if pat in files:
342 s.append(r)
349 s.append(r)
343 continue
350 continue
344 else:
351 else:
345 for f in files:
352 for f in files:
346 if m(f):
353 if m(f):
347 s.append(r)
354 s.append(r)
348 continue
355 continue
349 return s
356 return s
350
357
351 def modifies(repo, subset, x):
358 def modifies(repo, subset, x):
352 pat = getstring(x, _("modifies wants a pattern"))
359 pat = getstring(x, _("modifies wants a pattern"))
353 return checkstatus(repo, subset, pat, 0)
360 return checkstatus(repo, subset, pat, 0)
354
361
355 def adds(repo, subset, x):
362 def adds(repo, subset, x):
356 pat = getstring(x, _("adds wants a pattern"))
363 pat = getstring(x, _("adds wants a pattern"))
357 return checkstatus(repo, subset, pat, 1)
364 return checkstatus(repo, subset, pat, 1)
358
365
359 def removes(repo, subset, x):
366 def removes(repo, subset, x):
360 pat = getstring(x, _("removes wants a pattern"))
367 pat = getstring(x, _("removes wants a pattern"))
361 return checkstatus(repo, subset, pat, 2)
368 return checkstatus(repo, subset, pat, 2)
362
369
363 def merge(repo, subset, x):
370 def merge(repo, subset, x):
364 getargs(x, 0, 0, _("merge takes no arguments"))
371 getargs(x, 0, 0, _("merge takes no arguments"))
365 cl = repo.changelog
372 cl = repo.changelog
366 return [r for r in subset if cl.parentrevs(r)[1] != -1]
373 return [r for r in subset if cl.parentrevs(r)[1] != -1]
367
374
368 def closed(repo, subset, x):
375 def closed(repo, subset, x):
369 getargs(x, 0, 0, _("closed takes no arguments"))
376 getargs(x, 0, 0, _("closed takes no arguments"))
370 return [r for r in subset if repo[r].extra().get('close')]
377 return [r for r in subset if repo[r].extra().get('close')]
371
378
372 def head(repo, subset, x):
379 def head(repo, subset, x):
373 getargs(x, 0, 0, _("head takes no arguments"))
380 getargs(x, 0, 0, _("head takes no arguments"))
374 hs = set()
381 hs = set()
375 for b, ls in repo.branchmap().iteritems():
382 for b, ls in repo.branchmap().iteritems():
376 hs.update(repo[h].rev() for h in ls)
383 hs.update(repo[h].rev() for h in ls)
377 return [r for r in subset if r in hs]
384 return [r for r in subset if r in hs]
378
385
379 def reverse(repo, subset, x):
386 def reverse(repo, subset, x):
380 l = getset(repo, subset, x)
387 l = getset(repo, subset, x)
381 l.reverse()
388 l.reverse()
382 return l
389 return l
383
390
384 def present(repo, subset, x):
391 def present(repo, subset, x):
385 try:
392 try:
386 return getset(repo, subset, x)
393 return getset(repo, subset, x)
387 except error.RepoLookupError:
394 except error.RepoLookupError:
388 return []
395 return []
389
396
390 def sort(repo, subset, x):
397 def sort(repo, subset, x):
391 l = getargs(x, 1, 2, _("sort wants one or two arguments"))
398 l = getargs(x, 1, 2, _("sort wants one or two arguments"))
392 keys = "rev"
399 keys = "rev"
393 if len(l) == 2:
400 if len(l) == 2:
394 keys = getstring(l[1], _("sort spec must be a string"))
401 keys = getstring(l[1], _("sort spec must be a string"))
395
402
396 s = l[0]
403 s = l[0]
397 keys = keys.split()
404 keys = keys.split()
398 l = []
405 l = []
399 def invert(s):
406 def invert(s):
400 return "".join(chr(255 - ord(c)) for c in s)
407 return "".join(chr(255 - ord(c)) for c in s)
401 for r in getset(repo, subset, s):
408 for r in getset(repo, subset, s):
402 c = repo[r]
409 c = repo[r]
403 e = []
410 e = []
404 for k in keys:
411 for k in keys:
405 if k == 'rev':
412 if k == 'rev':
406 e.append(r)
413 e.append(r)
407 elif k == '-rev':
414 elif k == '-rev':
408 e.append(-r)
415 e.append(-r)
409 elif k == 'branch':
416 elif k == 'branch':
410 e.append(c.branch())
417 e.append(c.branch())
411 elif k == '-branch':
418 elif k == '-branch':
412 e.append(invert(c.branch()))
419 e.append(invert(c.branch()))
413 elif k == 'desc':
420 elif k == 'desc':
414 e.append(c.description())
421 e.append(c.description())
415 elif k == '-desc':
422 elif k == '-desc':
416 e.append(invert(c.description()))
423 e.append(invert(c.description()))
417 elif k in 'user author':
424 elif k in 'user author':
418 e.append(c.user())
425 e.append(c.user())
419 elif k in '-user -author':
426 elif k in '-user -author':
420 e.append(invert(c.user()))
427 e.append(invert(c.user()))
421 elif k == 'date':
428 elif k == 'date':
422 e.append(c.date()[0])
429 e.append(c.date()[0])
423 elif k == '-date':
430 elif k == '-date':
424 e.append(-c.date()[0])
431 e.append(-c.date()[0])
425 else:
432 else:
426 raise error.ParseError(_("unknown sort key %r") % k)
433 raise error.ParseError(_("unknown sort key %r") % k)
427 e.append(r)
434 e.append(r)
428 l.append(e)
435 l.append(e)
429 l.sort()
436 l.sort()
430 return [e[-1] for e in l]
437 return [e[-1] for e in l]
431
438
432 def getall(repo, subset, x):
439 def getall(repo, subset, x):
433 getargs(x, 0, 0, _("all takes no arguments"))
440 getargs(x, 0, 0, _("all takes no arguments"))
434 return subset
441 return subset
435
442
436 def heads(repo, subset, x):
443 def heads(repo, subset, x):
437 s = getset(repo, subset, x)
444 s = getset(repo, subset, x)
438 ps = set(parents(repo, subset, x))
445 ps = set(parents(repo, subset, x))
439 return [r for r in s if r not in ps]
446 return [r for r in s if r not in ps]
440
447
441 def roots(repo, subset, x):
448 def roots(repo, subset, x):
442 s = getset(repo, subset, x)
449 s = getset(repo, subset, x)
443 cs = set(children(repo, subset, x))
450 cs = set(children(repo, subset, x))
444 return [r for r in s if r not in cs]
451 return [r for r in s if r not in cs]
445
452
446 def outgoing(repo, subset, x):
453 def outgoing(repo, subset, x):
447 import hg # avoid start-up nasties
454 import hg # avoid start-up nasties
448 l = getargs(x, 0, 1, _("outgoing wants a repository path"))
455 l = getargs(x, 0, 1, _("outgoing wants a repository path"))
449 dest = l and getstring(l[0], _("outgoing wants a repository path")) or ''
456 dest = l and getstring(l[0], _("outgoing wants a repository path")) or ''
450 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
457 dest = repo.ui.expandpath(dest or 'default-push', dest or 'default')
451 dest, branches = hg.parseurl(dest)
458 dest, branches = hg.parseurl(dest)
452 other = hg.repository(hg.remoteui(repo, {}), dest)
459 other = hg.repository(hg.remoteui(repo, {}), dest)
453 repo.ui.pushbuffer()
460 repo.ui.pushbuffer()
454 o = discovery.findoutgoing(repo, other)
461 o = discovery.findoutgoing(repo, other)
455 repo.ui.popbuffer()
462 repo.ui.popbuffer()
456 cl = repo.changelog
463 cl = repo.changelog
457 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, None)[0]])
464 o = set([cl.rev(r) for r in repo.changelog.nodesbetween(o, None)[0]])
458 return [r for r in subset if r in o]
465 return [r for r in subset if r in o]
459
466
460 def tagged(repo, subset, x):
467 def tagged(repo, subset, x):
461 getargs(x, 0, 0, _("tagged takes no arguments"))
468 getargs(x, 0, 0, _("tagged takes no arguments"))
462 cl = repo.changelog
469 cl = repo.changelog
463 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
470 s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
464 return [r for r in subset if r in s]
471 return [r for r in subset if r in s]
465
472
466 symbols = {
473 symbols = {
467 "adds": adds,
474 "adds": adds,
468 "all": getall,
475 "all": getall,
469 "ancestor": ancestor,
476 "ancestor": ancestor,
470 "ancestors": ancestors,
477 "ancestors": ancestors,
471 "author": author,
478 "author": author,
472 "branch": branch,
479 "branch": branch,
473 "children": children,
480 "children": children,
474 "closed": closed,
481 "closed": closed,
475 "contains": contains,
482 "contains": contains,
476 "date": date,
483 "date": date,
477 "descendants": descendants,
484 "descendants": descendants,
478 "file": hasfile,
485 "file": hasfile,
479 "follow": follow,
486 "follow": follow,
480 "grep": grep,
487 "grep": grep,
481 "head": head,
488 "head": head,
482 "heads": heads,
489 "heads": heads,
483 "keyword": keyword,
490 "keyword": keyword,
484 "limit": limit,
491 "limit": limit,
485 "max": maxrev,
492 "max": maxrev,
486 "min": minrev,
493 "min": minrev,
487 "merge": merge,
494 "merge": merge,
488 "modifies": modifies,
495 "modifies": modifies,
489 "outgoing": outgoing,
496 "outgoing": outgoing,
490 "p1": p1,
497 "p1": p1,
491 "p2": p2,
498 "p2": p2,
492 "parents": parents,
499 "parents": parents,
493 "present": present,
500 "present": present,
494 "removes": removes,
501 "removes": removes,
495 "reverse": reverse,
502 "reverse": reverse,
496 "roots": roots,
503 "roots": roots,
497 "sort": sort,
504 "sort": sort,
498 "tagged": tagged,
505 "tagged": tagged,
499 "user": author,
506 "user": author,
500 }
507 }
501
508
502 methods = {
509 methods = {
503 "range": rangeset,
510 "range": rangeset,
504 "string": stringset,
511 "string": stringset,
505 "symbol": symbolset,
512 "symbol": symbolset,
506 "and": andset,
513 "and": andset,
507 "or": orset,
514 "or": orset,
508 "not": notset,
515 "not": notset,
509 "list": listset,
516 "list": listset,
510 "func": func,
517 "func": func,
511 }
518 }
512
519
513 def optimize(x, small):
520 def optimize(x, small):
514 if x == None:
521 if x == None:
515 return 0, x
522 return 0, x
516
523
517 smallbonus = 1
524 smallbonus = 1
518 if small:
525 if small:
519 smallbonus = .5
526 smallbonus = .5
520
527
521 op = x[0]
528 op = x[0]
522 if op == 'minus':
529 if op == 'minus':
523 return optimize(('and', x[1], ('not', x[2])), small)
530 return optimize(('and', x[1], ('not', x[2])), small)
524 elif op == 'dagrange':
531 elif op == 'dagrange':
525 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
532 return optimize(('and', ('func', ('symbol', 'descendants'), x[1]),
526 ('func', ('symbol', 'ancestors'), x[2])), small)
533 ('func', ('symbol', 'ancestors'), x[2])), small)
527 elif op == 'dagrangepre':
534 elif op == 'dagrangepre':
528 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
535 return optimize(('func', ('symbol', 'ancestors'), x[1]), small)
529 elif op == 'dagrangepost':
536 elif op == 'dagrangepost':
530 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
537 return optimize(('func', ('symbol', 'descendants'), x[1]), small)
531 elif op == 'rangepre':
538 elif op == 'rangepre':
532 return optimize(('range', ('string', '0'), x[1]), small)
539 return optimize(('range', ('string', '0'), x[1]), small)
533 elif op == 'rangepost':
540 elif op == 'rangepost':
534 return optimize(('range', x[1], ('string', 'tip')), small)
541 return optimize(('range', x[1], ('string', 'tip')), small)
535 elif op == 'negate':
542 elif op == 'negate':
536 return optimize(('string',
543 return optimize(('string',
537 '-' + getstring(x[1], _("can't negate that"))), small)
544 '-' + getstring(x[1], _("can't negate that"))), small)
538 elif op in 'string symbol negate':
545 elif op in 'string symbol negate':
539 return smallbonus, x # single revisions are small
546 return smallbonus, x # single revisions are small
540 elif op == 'and' or op == 'dagrange':
547 elif op == 'and' or op == 'dagrange':
541 wa, ta = optimize(x[1], True)
548 wa, ta = optimize(x[1], True)
542 wb, tb = optimize(x[2], True)
549 wb, tb = optimize(x[2], True)
543 w = min(wa, wb)
550 w = min(wa, wb)
544 if wa > wb:
551 if wa > wb:
545 return w, (op, tb, ta)
552 return w, (op, tb, ta)
546 return w, (op, ta, tb)
553 return w, (op, ta, tb)
547 elif op == 'or':
554 elif op == 'or':
548 wa, ta = optimize(x[1], False)
555 wa, ta = optimize(x[1], False)
549 wb, tb = optimize(x[2], False)
556 wb, tb = optimize(x[2], False)
550 if wb < wa:
557 if wb < wa:
551 wb, wa = wa, wb
558 wb, wa = wa, wb
552 return max(wa, wb), (op, ta, tb)
559 return max(wa, wb), (op, ta, tb)
553 elif op == 'not':
560 elif op == 'not':
554 o = optimize(x[1], not small)
561 o = optimize(x[1], not small)
555 return o[0], (op, o[1])
562 return o[0], (op, o[1])
556 elif op == 'group':
563 elif op == 'group':
557 return optimize(x[1], small)
564 return optimize(x[1], small)
558 elif op in 'range list':
565 elif op in 'range list':
559 wa, ta = optimize(x[1], small)
566 wa, ta = optimize(x[1], small)
560 wb, tb = optimize(x[2], small)
567 wb, tb = optimize(x[2], small)
561 return wa + wb, (op, ta, tb)
568 return wa + wb, (op, ta, tb)
562 elif op == 'func':
569 elif op == 'func':
563 f = getstring(x[1], _("not a symbol"))
570 f = getstring(x[1], _("not a symbol"))
564 wa, ta = optimize(x[2], small)
571 wa, ta = optimize(x[2], small)
565 if f in "grep date user author keyword branch file outgoing":
572 if f in "grep date user author keyword branch file outgoing":
566 w = 10 # slow
573 w = 10 # slow
567 elif f in "modifies adds removes":
574 elif f in "modifies adds removes":
568 w = 30 # slower
575 w = 30 # slower
569 elif f == "contains":
576 elif f == "contains":
570 w = 100 # very slow
577 w = 100 # very slow
571 elif f == "ancestor":
578 elif f == "ancestor":
572 w = 1 * smallbonus
579 w = 1 * smallbonus
573 elif f == "reverse limit":
580 elif f == "reverse limit":
574 w = 0
581 w = 0
575 elif f in "sort":
582 elif f in "sort":
576 w = 10 # assume most sorts look at changelog
583 w = 10 # assume most sorts look at changelog
577 else:
584 else:
578 w = 1
585 w = 1
579 return w + wa, (op, x[1], ta)
586 return w + wa, (op, x[1], ta)
580 return 1, x
587 return 1, x
581
588
582 parse = parser.parser(tokenize, elements).parse
589 parse = parser.parser(tokenize, elements).parse
583
590
584 def match(spec):
591 def match(spec):
585 if not spec:
592 if not spec:
586 raise error.ParseError(_("empty query"))
593 raise error.ParseError(_("empty query"))
587 tree = parse(spec)
594 tree = parse(spec)
588 weight, tree = optimize(tree, True)
595 weight, tree = optimize(tree, True)
589 def mfunc(repo, subset):
596 def mfunc(repo, subset):
590 return getset(repo, subset, tree)
597 return getset(repo, subset, tree)
591 return mfunc
598 return mfunc
@@ -1,321 +1,329
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 wants a string
151 hg: parse error: date wants 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 wants two arguments
169 hg: parse error: ancestor wants 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+")'
219 ('func', ('symbol', 'grep'), ('string', '\x08issue\\d+'))
220 $ try 'grep(r"\bissue\d+")'
221 ('func', ('symbol', 'grep'), ('string', '\\bissue\\d+'))
222 6
223 $ try 'grep(r"\")'
224 hg: parse error at 7: unterminated string
225 [255]
218 $ log 'head()'
226 $ log 'head()'
219 0
227 0
220 1
228 1
221 2
229 2
222 3
230 3
223 4
231 4
224 5
232 5
225 6
233 6
226 7
234 7
227 9
235 9
228 $ log 'heads(6::)'
236 $ log 'heads(6::)'
229 7
237 7
230 $ log 'keyword(issue)'
238 $ log 'keyword(issue)'
231 6
239 6
232 $ log 'limit(head(), 1)'
240 $ log 'limit(head(), 1)'
233 0
241 0
234 $ log 'max(contains(a))'
242 $ log 'max(contains(a))'
235 5
243 5
236 $ log 'min(contains(a))'
244 $ log 'min(contains(a))'
237 0
245 0
238 $ log 'merge()'
246 $ log 'merge()'
239 6
247 6
240 $ log 'modifies(b)'
248 $ log 'modifies(b)'
241 4
249 4
242 $ log 'outgoing()'
250 $ log 'outgoing()'
243 8
251 8
244 9
252 9
245 $ log 'outgoing("../remote1")'
253 $ log 'outgoing("../remote1")'
246 8
254 8
247 9
255 9
248 $ log 'outgoing("../remote2")'
256 $ log 'outgoing("../remote2")'
249 3
257 3
250 5
258 5
251 6
259 6
252 7
260 7
253 9
261 9
254 $ log 'p1(merge())'
262 $ log 'p1(merge())'
255 5
263 5
256 $ log 'p2(merge())'
264 $ log 'p2(merge())'
257 4
265 4
258 $ log 'parents(merge())'
266 $ log 'parents(merge())'
259 4
267 4
260 5
268 5
261 $ log 'removes(a)'
269 $ log 'removes(a)'
262 2
270 2
263 6
271 6
264 $ log 'roots(all())'
272 $ log 'roots(all())'
265 0
273 0
266 $ log 'reverse(2 or 3 or 4 or 5)'
274 $ log 'reverse(2 or 3 or 4 or 5)'
267 5
275 5
268 4
276 4
269 3
277 3
270 2
278 2
271 $ log 'sort(limit(reverse(all()), 3))'
279 $ log 'sort(limit(reverse(all()), 3))'
272 7
280 7
273 8
281 8
274 9
282 9
275 $ log 'sort(2 or 3 or 4 or 5, date)'
283 $ log 'sort(2 or 3 or 4 or 5, date)'
276 2
284 2
277 3
285 3
278 5
286 5
279 4
287 4
280 $ log 'tagged()'
288 $ log 'tagged()'
281 6
289 6
282 $ log 'user(bob)'
290 $ log 'user(bob)'
283 2
291 2
284
292
285 $ log '4::8'
293 $ log '4::8'
286 4
294 4
287 8
295 8
288 $ log '4:8'
296 $ log '4:8'
289 4
297 4
290 5
298 5
291 6
299 6
292 7
300 7
293 8
301 8
294
302
295 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
303 $ log 'sort(!merge() & (modifies(b) | user(bob) | keyword(bug) | keyword(issue) & 1::9), "-date")'
296 4
304 4
297 2
305 2
298 5
306 5
299
307
300 $ log 'not 0 and 0:2'
308 $ log 'not 0 and 0:2'
301 1
309 1
302 2
310 2
303 $ log 'not 1 and 0:2'
311 $ log 'not 1 and 0:2'
304 0
312 0
305 2
313 2
306 $ log 'not 2 and 0:2'
314 $ log 'not 2 and 0:2'
307 0
315 0
308 1
316 1
309 $ log '(1 and 2)::'
317 $ log '(1 and 2)::'
310 $ log '(1 and 2):'
318 $ log '(1 and 2):'
311 $ log '(1 and 2):3'
319 $ log '(1 and 2):3'
312 $ log 'sort(head(), -rev)'
320 $ log 'sort(head(), -rev)'
313 9
321 9
314 7
322 7
315 6
323 6
316 5
324 5
317 4
325 4
318 3
326 3
319 2
327 2
320 1
328 1
321 0
329 0
General Comments 0
You need to be logged in to leave comments. Login now